异步日志打印的一些事

一、前言

最近刚刚结束转岗以来的第一次双11压测,收获颇多,难言言表, 本文就先谈谈异步日志吧,在高并发高流量响应延迟要求比较小的系统中同步打日志已经满足不了需求了,同步打日志会阻塞调用打日志的线程,而打日志本身是需要写磁盘的,所以会造成rt增加。异步日志就是为了解决这个问题。

二、日志打印模型

  • 同步日志模型

    异步日志打印的一些事_第1张图片

    image.png

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

  • 异步日志模型

    异步日志打印的一些事_第2张图片

    image.png

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

三、关于异步日志需的一些事

  • 异步日志设置

异步日志打印的一些事_第3张图片

image.png

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

异步日志打印的一些事_第4张图片

image.png

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

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

异步日志打印的一些事_第5张图片

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

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

异步日志打印的一些事_第6张图片

image.png

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

异步日志打印的一些事_第7张图片

image.png

可知如果队列满则直接返回,而不是被挂起当前线程。

异步日志打印的一些事_第8张图片

image.png

四 、总结

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

你可能感兴趣的:(异步日志打印的一些事)