Log4j2最强的AsyncLogger!

2023-11-23 19:10
文章标签 最强 log4j2 asynclogger

本文主要是介绍Log4j2最强的AsyncLogger!,希望对大家解决编程问题提供一定的参考价值,需要的开发者们随着小编来一起学习吧!

众所周知,对于log4j2比较核心的高性能组件就是AsyncLogger以及Garbage-free Logging。

Garbage-free Logging可以使你在打日志的时候尽可能的避免因为日志框架引发的GC问题。

当然还是得说明一下:Logger和Appender是两个组件,大家不要混为一谈了。

因为AsyncAppender底层是一个阻塞队列,存在锁争用的问题。

所以一般建议还是使用本文介绍的AsyncLogger。

Asynchronous Loggers for Low-Latency Logging


AsyncLogger可以提高系统的性能,因为它可以在一个独立的线程里执行一个写磁盘的IO。Log4j2在这一块做了很多的优化。

Asynchronous Loggers其实是log4j2里面附加的一个新功能,他可以通过Logger.log()往系统里面异步打日志。当然你也可以很容易的去配置异步日志与同步日志混合执行。

在异步这块底层是通过LMAX Disruptor technology技术实现的,其实最核心的就是用了Disruptor,他是一个无锁化线程间的一个通讯库,你也可以认为他是一个高性能内存消息队列。

你可以用Disruptor实现两个线程间的通信,以至于它可以由更高的吞吐量以及更低的延迟。

注:Appender是使用阻塞队列


Asynchronous Loggers的优点:在高并发的场景下他的吞吐量是同步日志的6~68倍,对于拥有大量日志的系统,它可以帮助我们降低延迟,减少写日志的等待时间。如果你把queue size设置的很大的话,就会避免系统突然高峰的时候被磁盘IO给拖垮。所以就特别适合高并发场景。

Asynchronous Loggers的缺点:

  1. 因为他是异步化的,那么我们无法捕获住异常反馈给系统。当然我们也可以去配置一个ExceptionHandler进行回调,但是这个也解决不了所有的问题。当我们的业务类似于审计的时候,无可避免你只能使用同步日志去记录。
  2. 用异步日志去打印可能会打印一个不一致的对象,也可能会产生异常。例如 logger.debug("My object is {}", myObject)。
  3. 系统如果在cpu资源非常紧张的环境下,比如一核cpu,性能不会太好。(官方的这个例子太离谱了。。。)

那么如果使我们的日志变为Asynchronous Loggers呢?

首先你的Log4j至少要是2.9以上的版本。

然后需要把disruptor的jar配置到classpath里面,还要设置一个系统属性:把log4j2.contextSelector设置为org.apache.logging.log4j.core.async.AsyncLoggerContextSelector 或者org.apache.logging.log4j.core.async.BasicAsyncLoggerContextSelector

如果我们用了AsyncLoggerContextSelector 把所有的log都变为异步的,在xml里就用常规的<root> 和 <logger>就行了。他的机制其实与<asyncRoot>和<asyncLogger>是不同的。


在回到文章开头我们聊到过他不会引起JVM GC的问题,这是为啥呢?

很多的日志框架包括老版本的log4j,都会对日志产生的char或者string分配一些临时的对象去打印。肯定会导致jvm的新生代被快速填满,加速youngGC的频率。

但是在最新的模式下log4j是运行在garbage-free里的,他不会对GC有很大的影响。因为这些对象被引用了所以不会被反复回收,而是会重用复用,频繁的使用老年的对象和buffer。这个模式就叫做garbage-free

如图:这是log4j 2.5,每秒会分配809MB,会导致141次youngGC

 log4j 2.6以后 就不会分配对象了。而是驻留在老年代里。


 源码 

当我们执行 logger.info("这是测试的info日志......") 时Debug跟入,由于链路非常长,这里也不会一一赘述,我们只聊关键部分。

随着代码往下走,我们发现了tryEnqueue方法存在一个让人眼前一亮的disruptor队列😀。此时代码执行到了AsyncLoggerConfigDisruptor里。logEvent就是我们打印的日志,是在这里入队的。之后在Disruptor触发了一个Event事件就会被下面的回调捕获住

    @Overridepublic boolean tryEnqueue(final LogEvent event, final AsyncLoggerConfig asyncLoggerConfig) {final LogEvent logEvent = prepareEvent(event);return disruptor.getRingBuffer().tryPublishEvent(translator, logEvent, asyncLoggerConfig);}

那么在这个类中同样有一个内部类处理回调:Log4jEventWrapperHandler。如果收到了一条日志事件,再去使用当前的线程进行日志的记录。

    private static class Log4jEventWrapperHandler implements SequenceReportingEventHandler<Log4jEventWrapper> {private static final int NOTIFY_PROGRESS_THRESHOLD = 50;private Sequence sequenceCallback;private int counter;@Overridepublic void setSequenceCallback(final Sequence sequenceCallback) {this.sequenceCallback = sequenceCallback;}@Overridepublic void onEvent(final Log4jEventWrapper event, final long sequence, final boolean endOfBatch)throws Exception {event.event.setEndOfBatch(endOfBatch);event.loggerConfig.logToAsyncLoggerConfigsOnCurrentThread(event.event);event.clear();notifyIntermediateProgress(sequence);}
    // 初始化代码@Overridepublic synchronized void start() {if (disruptor != null) {LOGGER.trace("AsyncLoggerConfigDisruptor not starting new disruptor for this configuration, "+ "using existing object.");return;}LOGGER.trace("AsyncLoggerConfigDisruptor creating new disruptor for this configuration.");// 我们在配置文件中配置的属性ringBufferSize = DisruptorUtil.calculateRingBufferSize("AsyncLoggerConfig.RingBufferSize");final WaitStrategy waitStrategy = DisruptorUtil.createWaitStrategy("AsyncLoggerConfig.WaitStrategy");// 线程工厂final ThreadFactory threadFactory = new Log4jThreadFactory("AsyncLoggerConfig", true, Thread.NORM_PRIORITY) {@Overridepublic Thread newThread(final Runnable r) {final Thread result = super.newThread(r);backgroundThreadId = result.getId();return result;}};asyncQueueFullPolicy = AsyncQueueFullPolicyFactory.create();translator = mutable ? MUTABLE_TRANSLATOR : TRANSLATOR;factory = mutable ? MUTABLE_FACTORY : FACTORY;// 对disruptor进行一些配置disruptor = new Disruptor<>(factory, ringBufferSize, threadFactory, ProducerType.MULTI, waitStrategy);// 封装Handler 把他设置给disruptorfinal ExceptionHandler<Log4jEventWrapper> errorHandler = DisruptorUtil.getAsyncLoggerConfigExceptionHandler();disruptor.setDefaultExceptionHandler(errorHandler);final Log4jEventWrapperHandler[] handlers = {new Log4jEventWrapperHandler()};disruptor.handleEventsWith(handlers);LOGGER.debug("Starting AsyncLoggerConfig disruptor for this configuration with ringbufferSize={}, "+ "waitStrategy={}, exceptionHandler={}...", disruptor.getRingBuffer().getBufferSize(), waitStrategy.getClass().getSimpleName(), errorHandler);disruptor.start();super.start();}

由此可见:我们一旦把日志交给了disruptor ,他背后的后台线程就会把数据结构中的log日志取出来回调给自己实现的handler。通过handler实现异步化的处理。

这篇关于Log4j2最强的AsyncLogger!的文章就介绍到这儿,希望我们推荐的文章对编程师们有所帮助!



http://www.chinasem.cn/article/420111

相关文章

log4j2相关配置说明以及${sys:catalina.home}应用

${sys:catalina.home} 等价于 System.getProperty("catalina.home") 就是Tomcat的根目录:  C:\apache-tomcat-7.0.77 <PatternLayout pattern="%d{yyyy-MM-dd HH:mm:ss} [%t] %-5p %c{1}:%L - %msg%n" /> 2017-08-10

Vue3+elementplus实现图片上传下载(最强实践)

图片上传子组件: 实现照片的上传,预览,以及转成以逗号隔开的图片地址,即时监听,并发送消息到父组件。 <!-- ImageUploader.vue --> <template><div><el-upload class="avatar-uploader" :http-request="customUpload" :before-upload="beforeUpload":show-fil

最强虚拟机,内置强大插件,绝!

哈喽,各位小伙伴们好,我是给大家带来各类黑科技与前沿资讯的小武。 天给大家安利两款移动端的虚拟机软件,均支持超级权限、Xposed框架和谷歌服务,而其中一款可谓称得上最强虚拟机,不仅含有虚拟机的基本功能,还能多开分身、模拟器以及强大的插件社区,能实现的功能超乎你的想象,一起来看看吧! X8沙箱(安卓) 软件介绍 X8沙箱(手机版的安卓模拟器、虚拟机、多开分身、游戏双开多开挂机)是一款极简、

超强台风摩羯逼近!或成大陆史上最强登陆台风,防御措施需到位

超强台风摩羯逼近!或成大陆史上最强登陆台风,防御措施需到位 摩羯即将登录,各位兄弟姐妹注意安全!#大型纪录片#摩羯#台风 推荐阅读: 一夜蒸发2万亿!英伟达市值遭遇滑铁卢 《火速围观!黑神话悟空IP山西空心月饼,又一波抢购热潮即将来袭》 直击心灵!佤写不来情歌,却意外火爆全网,你听了没? 警告!明年6至9月假期空窗期,你的旅行计划何去何从? 独家揭秘!雷军豪赠《黑神话:悟空》给王腾,

重复采样魔法:用更多样本击败单次尝试的最强模型

这篇文章探讨了通过增加生成样本的数量来扩展大型语言模型(LLMs)在推理任务中的表现。 研究发现,重复采样可以显著提高模型的覆盖率,特别是在具有自动验证工具的任务中。研究还发现,覆盖率与样本数量之间的关系可以用指数幂律建模,揭示了推理时间的扩展规律。尽管多数投票和奖励模型在样本数量增加时趋于饱和,但在没有自动验证工具的任务中,识别正确样本仍然是一个重要的研究方向。 总体而言,重复采样提供了一种

log4j2.xml配置笔记

转载自阿豪聊干货:https://www.cnblogs.com/hafiz/p/6170702.htmlConfiguration Configuration 最外层节点 status:日志打印级别 monitorinterval:重新配置的监测间隔时间 –Appenders ----Console 定义输出到控制台的Appender. name:指定Appender的名字

最强的10个交换机实用配置

号主:老杨丨11年资深网络工程师,更多网工提升干货,请关注公众号:网络工程师俱乐部 下午好,我的网工朋友。 交换机每天都在瞅,但网工对交换机的开发程度不足5%。 交换机工作在OSI模型的第二层,即数据链路层,主要负责数据包的转发。 交换机通过学习MAC地址来构建一张MAC地址表,从而实现数据包的直接转发到目的端口,避免了不必要的网络拥堵和冲突。 今天分享一波实用的交换机配置方法,快速

代码执行漏洞-Log4j2漏洞

1.执行以下命令启动靶场环境并在浏览器访问 cd log4j/CVE-2021-44228docker-compose up -ddocker ps 2.先在自己搭建的DNSLOG平台上获取⼀个域名来监控我们注⼊的效果 3.可以发现 /solr/admin/cores?action= 这⾥有个参数可以传,可以按照上⾯的原理 先构造⼀个请求传过去存在JNDI注⼊那么ldap服务端会执⾏

[ComfyUI]Flux​:不花钱免费白嫖最强反推JoyCaption​,仅需几步无门槛轻松搞定

大家好我是极客菌!!! 今天文章主题将为大家介绍一款优秀的图像反推模型:Joy Caption。这是由作者Fancy Feast开发的Joy Caption模型,是在谷歌的SigLIP模型和Meta的最新Llama3.1 模型的基础之上,使用Adapter适配模式,并通过精心训练出的优秀图像反推描述LLM模型。能够根据用户设置参数,输出相应的具有丰富细节的图像描述提示语。 • Google

最强MoE完全开源模型发布啦~

这篇文章介绍了OLMOE(Open Mixture-of-Experts Language Models)系列模型,这是一款开源的稀疏混合专家模型。OLMOE-1B-7B拥有70亿参数,但每个输入令牌仅使用10亿参数。该模型在5万亿令牌上进行预训练,并进一步适应以创建OLMOE-1B-7B-INSTRUCT。这些模型在相似活跃参数的模型中表现最佳,甚至超越了更大的模型,如Llama2-13B-