大规模分布式系统中, 系统的可观测性是一个待解决的问题,如何以低代码的方式保证并发安全,低性能成本的方式实现高可靠的日志库是实现可观测性的重要手段。同时在学习高性能日志库的实现过程中,我们能够体会到高性能编程的设计原则,以及其中所涉及到的Linux内核原理。
日志库作为一个最基础的组件,既要保证性能,又要保证实用。如何玩转高性能日志,可以说是基础架构研发的HelloWorld,在日志库的研发过程中程序员将领会一些软件设计中的基本问题。现有的日志库如boost.log/glog/log4j等等代码都过于庞大,并不适合提炼出日志库的精髓,因此本文将会手把手带领大家实现一个支持同步/异步等方式的日志库。
- 同步,异步的方式写入日志(字节流)到对端(文件,网络,数据库)
- 高性能高可靠的同时将日志写入多种对端(文件,网络,数据库)
- 不同场景下 需要的定制化信息是不同的,例如分布式场景下每一个请求都需要一个reqid进行标识,所以如何把对输入的日志消息进行统一的格式化是很必要的事情。
- 由于使用枚举来表示日志级别,而8位整型取值和赋值本身就是原子的,无需担心;
- 我们知道计算机组成中,磁盘最慢,因此在系统中我们一般不会同步刷盘,而是单独的后台线程来负责日志的持久化(生产者消费者模式)
- 多线程写日志存在安全问题,本身需要加锁,正是由于需要加锁,反而会降低写文件的效率。所以常见的日志库大多采用多生产单消费者方式来写文件,一个可行的优化,就是使用双buffer机制,来避免每次生产者向队列中push一条消息时,都要唤醒消费者。使用双buffer本质其实是批操作。 如何设计一个并发安全的高性能buffer是日志库设计的关键所在。
- 通过写入次数大于一个阈值的方法来避免写入次数过少的情况下 滚动与刷新日志