[零声教育] C++高性能日志课程总结

本文讨论了高性能日志处理中批量写入的必要性,对比了fwrite与write的效率,特别强调了log4cpp库在处理日志性能问题上的不足,如频繁的文件大小检查。文章还介绍了异步设计,包括多线程写入、双缓存机制以及应对程序崩溃时的日志持久化策略。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

高性能日志

1 数据肯定是批量写入的

如果数据单笔写入会造成 磁盘寻址、频繁用户态/内核态的切换 (耗时)

2 fwrite/write 的区别

  • fwrite() 是C标准库中的函数,而 write() 是系统调用接口。
  • fwrite底层也是通过write来实现的。

二者均都有缓冲区,系统调用write的效率取决于你buf的大小和你要写入的总数量,如果buf太小,你进入内核空间的次数增大,效率就低下。而fwrite会替你做缓存,减少了实际出现的系统调用,所以效率比较高。

  • 假如write按照调用者要求写入十个字节的数据在内核缓冲区,这中间会涉及到用户态与内核态之间的切换。(由于使用了系统调用)

  • 而fwrite不一样,fwrite每次都会先把数据写入一个应用进程缓冲区,等到该缓冲区满了,系统会调用write一次性把相应数据写进内核缓冲区中。同样减少了系统调用(即write调用)。

因此当 buf_size 设置的比较大的时候,write 的性能比较优;当 buf_size 设置的比较小的时候,缓冲区会容易写满,频繁使用系统调用,OS会进行变态,增加耗时

3 log4cpp

3.1 设计理念
  • 输出格式

    • c++风格

      warn_log.warnStream() << "xxx = " << 100;箭头运算符重载

    • C语言风格

      warn_log.info("xxx = %d", 100);

  • 输出位置

    • 打印到本地文件

      log4cpp::FileAppender

    • 输出到控制台

      log4cpp::OstreamAppender

3.2 日志性能的问题

支持回滚的日志(RollignFileAppender)

  1. 换了一个文件后,会在程序里面记录每次写入的数据大小,总计超过比如1M 再重写另外一个文件

    此处log4cpp 错误的做法是:每次写日志都会去调用 lseek 函数去获取文件大小(耗时多),这也是影响效率的关键

FileAppender

每次日志都调用write

异步日志的高性能:支持批量写入,日志达到一定量的时候,才会调用write去写入文件

4 异步设计

4.1 多线程写入

多个线程将日志写入到缓存队列里,需要加锁

4.2 日志什么时候写入磁盘

引入双缓存机制:两个缓存队列。

日志写满一个缓存队列的话,才去notify 日志读取线程将日志从缓存队列中取出然后写入,然后下一条日志写到另外一个缓存队列中去。

而不是一个日志写到缓存队列中就通知线程进行日志读取。

实际做法原理:使用多个大数组缓冲区作为日志缓冲区,多个大数组缓冲区以双循环链表方式连接,并使用两个指针p1和p2指向链表两个节点,分别用以生成数据、与消费数据

生产者可以是多线程,共同持有p1来生产数据,消费者是一个后台线程,持有p2去消费数据

4.3 如果缓存队列快满了(还未满),导致日志长时间未写入

日志写线程:notify 唤醒 + 超时唤醒

4.4 程序崩溃了,日志没有及时写入

使用gdb,打开-g,可以产生coredump,通过coredump方式

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值