logback异步记录日志

本文探讨了异步日志模型及其在高并发系统中的应用,重点介绍了如何配置logback以实现异步日志记录,避免业务线程因日志队列满而阻塞。

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

异步记录日志


注意:该功能需要高版本才能支持,如1.0.11。

AsyncAppender,异步记录日志。

工作原理:
当Logging Event进入AsyncAppender后,AsyncAppender会调用appender方法,append方法中在将event填入Buffer(这里选用的数据结构为BlockingQueue)中前,会先判断当前buffer的容量以及丢弃日志特性是否开启,当消费能力不如生产能力时,AsyncAppender会超出Buffer容量的Logging Event的级别,进行丢弃,作为消费速度一旦跟不上生产速度,中转buffer的溢出处理的一种方案。AsyncAppender有个线程类Worker,它是一个简单的线程类,是AsyncAppender的后台线程,所要做的工作是:从buffer中取出event交给对应的appender进行后面的日志推送。

从上面的描述中可以看出,AsyncAppender并不处理日志,只是将日志缓冲到一个BlockingQueue里面去,并在内部创建一个工作线程从队列头部获取日志,之后将获取的日志循环记录到附加的其他appender上去,从而达到不阻塞主线程的效果。因此AsynAppender仅仅充当事件转发器,必须引用另一个appender来做事。

在使用AsyncAppender的时候,有些选项还是要注意的。由于使用了BlockingQueue来缓存日志,因此就会出现队列满的情况。正如上面原理中所说的,在这种情况下,AsyncAppender做出一些处理:默认情况下,如果队列80%已满,AsyncAppender将丢弃TRACE、DEBUG和INFO级别的event,从这点就可以看出,该策略有一个惊人的对event丢失的代价性能的影响。另外其他的一些选项信息,也会对性能产生影响,下面列出常用的几个属性配置信息:

属性名类型描述
queueSizeintBlockingQueue的最大容量,默认情况下,大小为256。
discardingThresholdint默认情况下,当BlockingQueue还有20%容量,他将丢弃TRACE、DEBUG和INFO级别的event,只保留WARN和ERROR级别的event。为了保持所有的events,设置该值为0
includeCallerDataboolean提取调用者数据的代价是相当昂贵的。为了提升性能,默认情况下,当event被加入到queue时,event关联的调用者数据不会被提取。默认情况下,只有"cheap"的数据,如线程名。


默认情况下,event queue配置最大容量为256个events。如果队列被填满,应用程序线程被阻止记录新的events,直到工作线程有机会来转发一个或多个events。因此队列深度需要根据业务场景进行相应的测试,做出相应的更改,以达到较好的性能。

下面给出一个使用的配置示例


  1. <appender name="FILE" class= "ch.qos.logback.core.rolling.RollingFileAppender">
  2. <!-- 按天来回滚,如果需要按小时来回滚,则设置为{yyyy-MM-dd_HH} -->
  3. <rollingPolicy class="ch.qos.logback.core.rolling.TimeBasedRollingPolicy">
  4. <fileNamePattern>/opt/log/test.%d{yyyy-MM-dd}.log </fileNamePattern>
  5. <!-- 如果按天来回滚,则最大保存时间为1天,1天之前的都将被清理掉 -->
  6. <maxHistory>30 </maxHistory>
  7. <!-- 日志输出格式 -->
  8. <layout class="ch.qos.logback.classic.PatternLayout">
  9. <Pattern>%d{yyyy-MM-dd HH:mm:ss.SSS} [%thread] %-5level %logger{36} -%msg%n </Pattern>
  10. </layout>
  11. </appender>
  12. <!-- 异步输出 -->
  13. <appender name ="ASYNC" class= "ch.qos.logback.classic.AsyncAppender">
  14. <!-- 不丢失日志.默认的,如果队列的80%已满,则会丢弃TRACT、DEBUG、INFO级别的日志 -->
  15. <discardingThreshold >0 </discardingThreshold>
  16. <!-- 更改默认的队列的深度,该值会影响性能.默认值为256 -->
  17. <queueSize>512 </queueSize>
  18. <!-- 添加附加的appender,最多只能添加一个 -->
  19. <appender-ref ref ="FILE"/>
  20. </appender>

  21. <root level ="trace">
  22. <appender-ref ref ="ASYNC"/>
  23. </root>

转自:https://blog.youkuaiyun.com/chenjie2000/article/details/8902727


日志打印模型

  • 同步日志模型

如上图,多个业务线程打印日志时候要等把内容写入磁盘后才会返回,所以打日志的rt就是写入磁盘的耗时。

  • 异步日志模型

如上图多个业务线程打印日志时候是把打印任务放入内存队列后就直接返回了,而具体打印日志是有日志系统的一个日志线程去队列里面获取然后执行,可见这种打印rt就是写入内存队列的耗时。

关于异步日志的一些事

  • 异步日志设置

对于logback来说异步日志里面的队列是一个有界ArrayBlockingQueue,其中queueSize是队列大小,taskLogAppender是引用的普通同步日志

discardingThreshold是一个阈值,通过下面代码看他的作用:

当队列的剩余容量小于这个阈值并且当前日志level TRACE, DEBUG or INFO ,则丢弃这些日志。

在压测时候代码配置如上,也就是配置了异步日志,但是还是出现了线程阻塞在打日志的地方了,经查看是阻塞到了日志队列ArrayBlockingQueue的put方法:

可知put方法在队列满时候会挂起当前线程。那么如何解那?

上面介绍了discardingThreshold,可知本文设置为0说明永远不会丢弃日志level TRACE, DEBUG or INFO的日志,只要discardingThreshold>0则当队列快满时候level TRACE, DEBUG or INFO的日志就会丢弃掉,这个貌似可以解决问题。但是如果打印的是warn级别的日志那?还是会在put的时候阻塞。

通过看代码发现最终写日志时候有个判断:

如果设置了neverBlock=true则写日志队列时候会调用ArrayBlockingQueue对的offer方法而不是put,而offer是非阻塞的:

可知如果队列满则直接返回,而不是被挂起当前线程。
所以配置异步appender时候如下:

总结

在高并发低延迟要求的系统里面不重要的日志可以设置为异步并且要注意设置队列满则丢弃策略,防止业务线程被挂起从而影响rt。

转自:http://www.importnew.com/27247.html
### logback异步日志队列最佳大小配置 Logback异步日志功能通过 `AsyncAppender` 实现,该组件内部维护了一个阻塞队列(Blocking Queue),用于缓存待处理的日志事件。合理设置这个队列的大小对于系统的性能和稳定性至关重要。 #### 默认队列大小 默认情况下,Logback 中 `AsyncAppender` 使用的是有界阻塞队列,默认大小为 256 条日志消息[^1]。然而,在高并发场景下,这一数值可能不足以满足需求,因此需要根据实际应用场景调整队列大小。 #### 调整队列大小的影响 如果队列过小,则可能导致在高负载环境下频繁日志消息,因为生产者线程无法及时将日志放入已满的队列中;而如果队列过大,则会占用更多的内存资源,并且可能会延迟日志的持久化时间,从而影响系统响应速度[^4]。 #### 推荐的最佳实践 通常建议将队列大小设置为 **512 到 8192** 之间,具体取决于以下几个因素: - 应用程序的日志吞吐量:如果应用程序生成大量日志,应适当增大队列容量。 - 日志记录器的工作负荷:评估目标环境中 CPU 和磁盘 IO 性能来决定合适的缓冲区尺寸。 - 可接受的最大失率:当面临极端压力时允许一定程度上的日志损失还是完全不允许任何遗漏也会影响参数的选择[^3]。 以下是修改队列大小的一个示例配置: ```xml <configuration> <!-- 定义一个异步附加器 --> <appender name="ASYNC" class="ch.qos.logback.classic.AsyncAppender"> <!-- 设置队列长度 --> <queueSize>1024</queueSize> <!-- 添加其他属性... --> <!-- 连接到具体的日志输出端 --> <appender-ref ref="FILE"/> </appender> <!-- 文件型日志附加器 --> <appender name="FILE" class="ch.qos.logback.core.FileAppender"> ... </appender> <!-- 将根 logger 绑定到 ASYNC appender 上 --> <root level="info"> <appender-ref ref="ASYNC"/> </root> </configuration> ``` 上述 XML 片段展示了如何设定名为 `ASYNC` 的异步附加器及其关联的具体日志输出位置 `FILE` ,其中 `<queueSize>` 元素指定了阻塞队列为 1024 条目[^2]。 #### 数据状态管理与 MDC 支持 为了确保多线程环境下的数据一致性,Logback 提供了 Mapped Diagnostic Context (MDC) 功能。它允许开发者向每条日志附加额外的信息字段而不必担心跨线程污染问题。这些信息会被自动传递给后台工作者线程并最终反映在生成的日志文件里[^5]。 ---
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值