返回顶部
首页 > 资讯 > 精选 >从log4j2到Disruptor的示例分析
  • 145
分享到

从log4j2到Disruptor的示例分析

2023-06-22 05:06:24 145人浏览 安东尼
摘要

这篇文章主要为大家展示了“从log4j2到Disruptor的示例分析”,内容简而易懂,条理清晰,希望能够帮助大家解决疑惑,下面让小编带领大家一起研究并学习一下“从log4j2到Disruptor的示例分析”这篇文章吧。log4j2异步日志

这篇文章主要为大家展示了“从log4j2到Disruptor的示例分析”,内容简而易懂,条理清晰,希望能够帮助大家解决疑惑,下面让小编带领大家一起研究并学习一下“从log4j2到Disruptor的示例分析”这篇文章吧。

log4j2异步日志简要回顾

从日志工厂(Log4jLoggerFactory)中获取日志Logger实例

从日志上下文工厂(Log4jContextFactory)获取日志上下文

启用日志上下文(AsyncLoggerContext)

启动Disruptor(AsyncLoggerDisruptor)

序列号屏障(ProcessingSequenceBarrier)等待序列号发布

等待策略(WaitStrategy)等待序列号

返回Logger等待序列号(即等待日志写入)

异步日志(AsyncLogger)写入

日志内容与转化者(RingBufferLogEventTranslator)绑定

Disruptor尝试发布转化者tryPublish

RingBuffer尝试发布事件tryPublishEvent

获取下一个可用序号

转化并发布序号,日志与序号对应的事件绑定,并发布序号

RingBuffer发布序号,MultiProducerSequencer发布

等待策略(waitStrategy)唤醒阻塞

Disruptor在log4j2中的应用

AsyncLoggerDisruptor

异步日志Disruptor启动

创建事件工厂EventFactory

计算ringBufferSize:AsyncLogger.RingBufferSize属性

创建等待策略:AsyncLogger.WaitStrategy属性

创建守护线程执行器executor

创建异步队列满时处理策略AsyncQueueFullPolicy(非Disruptor步骤)

创建Disruptor

  • 创建RingBuffer与Disruptor绑定

  • RingBuffer根据生产者类型创建对应的实例,例如多生产者:MultiProducerSequencer

  • 创建多生产者序号(bufferSize,waitStrategy)

绑定异常句柄(Disruptor.handleExceptionsWith)

绑定事件处理句柄(Disruptor.handleEventsWith)

  • 根据handle列表创建事件处理器createEventProcessors

  • RingBuffer为Sequence(MultiProducerSequencer)序列创建序列屏障ProcessingSequenceBarrier

  • 创建事件批处理器BatchEventProcessor

  • 为事件批处理器绑定异常处理句柄

  • 消费者仓库(consumerRepository)添加消费者,创建事件处理信息EventProcessorInfo添加至消费者信息列表consumerInfos

  • RingBuffer添加处理序列号列表processorSequences为序列号闸

  • 如果存在序列号屏障,从闸门中移除屏障序列号并标识endOfChain为false

启动Disruptor

  • 遍历消费者仓库放入执行器中执行消费者EventProcessorInfo

  • 启动事件批处理器BatchEventProcessor

  • 事件批处理器序列号自增1

  • 死循环

  • 序列号屏障ProcessingSequenceBarrier等待下个有效序列号,默认为超时等待策略,超时会继续下轮循环

  • 事件批处理器序列号如果小于等于有效序列号

  • 从RingBuffer中按照序列号获取event事件

  • 通知回调事件句柄eventHandler.onEvent如果当前消费下标等于有效序列号availableSequence说明是当前批次的最后一个消息,endOfBatch为true:eventHandler.onEvent(event, nextSequence, nextSequence == availableSequence);

  • 事件批处理器序列号设置为有效序列号

异步日志Disruptor写入

尝试发布tryPublish事件转化器EventTranslator:RingBufferLogEventTranslator

Disruptor获取RingBuffer尝试发布事件tryPublishEvent

序列号获取下个有效序号,步进为1,例如:MultiProducerSequencer.tryNext

游标按照步进移动

判断是否有足够的空间,没有则抛出InsufficientCapacityException异常

返回有效序列号

转化器转化消息为对应有效序列号的事件放入entries

发布序列号

  • 设置有效序列号至缓存availableBuffer

  • 等待策略唤醒阻塞waitStrategy.signalAllWhenBlocking

架构及流程

红色数字标识流程为获取logger时Disruptor创建消费者流程

黑色数字标识流程为logger写入日志时Disruptor创建事件并通知消费者流程

RingBuffer对于所有消费者、生产者是同一个实例

  • 环形队列,dataProvide,数据的存储与提供者

Sequencer:生产者

  • 对于所有消费者、生产者(可能是多生产者序列类型对于Multi类型)是同一个实例,包含一个游标序列号Sequence

SequenceBarrier:序列号屏障

  • 对于所有消费者、生产者也是同一个实例,序列号屏障包含一个等待策略、一个RingBuffer引用、一个游标序列号、一个依赖序列号(可能是组序列号类型)

BatchEventProcessor:消费者

  • 消费者包含一个RingBuffer引用

  • 一个序列号屏障,可以包含多个屏障序列号,默认为0个则使用RingBuffer的MultiProducerSequencer的游标序列号Sequence

  • 一个EventHandler:RingBufferLogEventHandler

  • 遍历EventHandler列表将其封装为BatchEventProcessor,将其与原始eventHandler、barrier屏障注册至消费者资源库consumerRepository。

  • 获取batchEventProcessor序列号默认为-1,将其缓存至processorSequences标识正在处理,并将processorSequences、disruptor、consumerRepository绑定至EventHandlerGroup。Disruptor启动遍历消费者资源库启动消费者:BatchEventProcessor

消费者入口

  • 消费者消费前先自增本地序列号(即-1+1=0序号),向序列号屏障申请该序列号的消费,默认为Timeout策略申请。

  • 屏障收到申请waitFor序列号,当前屏障游标序列号小于申请的消费序列号,等待生产者生产至当前序列号,如果超时则抛出异常(本地序列号不更新继续重试);如果没有超时,将屏障的dependentSequence序列号(如果不是非多序列号屏障类型,log4j2使用的是非多序列号屏障,则是屏障的本地游标)赋值为availableSequence返回。

  • 如果availableSequence有效的序列号(即屏障的游标序列号)小于申请要消费的序列号直接返回availableSequence(即消费超出的生产的速度,消费者申请的序列号向后回移至有效序列号)。否则getHighestPublishedSequence判断申请的序列号至availableSequence序列号之间的每个序列号对应的消息事件均是有效的则返回有效序列号(即生产者生产很快,消费者申请消费的序列号很小,向前移动至有效的,可能是本身也可能会跳跃多个下标),根据生产者的availableBuffer判断是否有效,因为生产者先发布序列号再写入数据,此处避免了读取数据异常,如果数据没有写入,有效序列号缓存标识没有写入(即无效),消费者会进行刚刚所说的“重试”,如果之间存在无效序列号则返回申请序列号-1(即回滚一个值,进入逻辑时增加了一个值,也就是回滚至申请前的点,可以理解为与超时相同,即重试)

  • 如果申请的序列号小于等于有效的序列号,则消费序列号对应的消息事件并更新本地BatchEventProcessor的序列号,按照下标去dataProvide(RingBuffer.entries)中提取对应位置的数据消费

  • 如果申请的序列号大于有效的序列号,则将消费者本地序列号设置为有效序列号(即消费超出的生产的速度,消费的序列号向后回移)

  • 如果期间出现任何未catch住的异常则会跳过当前下标,异常出现时的下标及对应的事件会交由exceptionHandler处理,默认为AsyncLoggerDefaultExceptionHandler异步处理,会将异常事件输出至系统的标准错误管道,虽然是异步也是会占用消费者线程池资源

Disruptor:生产者入口

  • 获取RingBuffer尝试发布消息,生产者(例如:MultiProducerSequencer)

  • 生产者游标序列号尝试自增,判断当前是否有足够的空间,当前游标+步进-bufferSize是否大于最小的闸门序列号(gatingSequences,即:所有消费者的本地游标序列号processorSequences列表),最小序列号会缓存至本地gatingSequenceCache用于下次判断减少进行所有闸门序列号的遍历次数,如果是说明已经没有空间(因为生产者生产申请的序列号已经追上了消费者消费序列号的最小值。RingBuffer是一个环形队列结构。上面已经讲到消费者序列号会与生产者序列号同步,同步指消费者申请序列号小于有效序列号时会前进至有效序列号,即使有延迟也保证了有大于等于buffer值的缓冲空间供生产者生产),如果没有空间返回false进入下一轮生产

从log4j2到Disruptor的示例分析

  • 自增成功后,将消息转化为对应序列号下标位置的事件数据

  • Sequencer发布序列号,将当前序列号设置为有效(availableBuffer),并根据等待策略唤醒等待的消费者,被唤醒的消费者根据发布的序列号获取相应下标处事件数据进行处理

从log4j2到Disruptor的示例分析

Disruptor为什么这么快?

Disruptor采用无并发编程框架中主要使用CAS与volatile关键字保证并发安全

使用环形数据结构(另一个典型的应用是时钟算法也是使用的环形数据结构),为环形结构添加序列号屏障来控制对环形队列读写操作,保证存储数据的并发安全

另一个点便是神奇的缓冲行填充了

Log4j2为什么这么快?

使用Disruptor并发编程框架

使用NIO写入日志数据

当然log4j2中有很多细节,如果我们想要获取线程栈信息,可以同样学习一下这样的写法

// LOG4J2-1029 new Throwable().getStackTrace is faster than Thread.currentThread().getStackTrace().final StackTraceElement[] stackTrace = new Throwable().getStackTrace();StackTraceElement last = null;for (int i = stackTrace.length - 1; i > 0; i--) {    final String className = stackTrace[i].getClassName();    if (fqcnOfLogger.equals(className)) {        return last;    }    last = stackTrace[i];}

以上是“从log4j2到Disruptor的示例分析”这篇文章的所有内容,感谢各位的阅读!相信大家都有了一定的了解,希望分享的内容对大家有所帮助,如果还想学习更多知识,欢迎关注编程网精选频道!

--结束END--

本文标题: 从log4j2到Disruptor的示例分析

本文链接: https://lsjlt.com/news/302510.html(转载时请注明来源链接)

有问题或投稿请发送至: 邮箱/279061341@qq.com    QQ/279061341

猜你喜欢
  • 从log4j2到Disruptor的示例分析
    这篇文章主要为大家展示了“从log4j2到Disruptor的示例分析”,内容简而易懂,条理清晰,希望能够帮助大家解决疑惑,下面让小编带领大家一起研究并学习一下“从log4j2到Disruptor的示例分析”这篇文章吧。log4j2异步日志...
    99+
    2023-06-22
  • 从log4j2到Disruptor详解
    目录log4j2异步日志简要回顾Disruptor在log4j2中的应用异步日志Disruptor启动异步日志Disruptor写入架构及流程Disruptor为什么这么快?Log4...
    99+
    2024-04-02
  • Disruptor发生内存溢出的示例分析
    今天给大家介绍一下Disruptor发生内存溢出的示例分析。文章的内容小编觉得不错,现在给大家分享一下,觉得有需要的朋友可以了解一下,希望对大家有所帮助,下面跟着小编的思路一起来阅读吧。前言OutOfMemoryError 问题相...
    99+
    2023-06-04
  • ThinkPHP3.2.3从php5升级到php7的示例分析
    本文将为大家详细介绍“ThinkPHP3.2.3从php5升级到php7的示例分析”,内容步骤清晰详细,细节处理妥当,而小编每天都会更新不同的知识点,希望这篇“ThinkPHP3.2.3从php5升级到php7的示例分析”能够给你意想不到的...
    99+
    2023-06-06
  • log4j2中日志异步打印的示例分析
    这篇文章给大家分享的是有关log4j2中日志异步打印的示例分析的内容。小编觉得挺实用的,因此分享给大家做个参考,一起跟随小编过来看看吧。log4j2支持日志的异步打印,日志异步输出的好处在于,使用单独的进程来执行日志打印的功能,可以提高日志...
    99+
    2023-05-30
    log4j2
  • 基于log4j2.properties踩坑与填坑的示例分析
    这篇文章主要介绍基于log4j2.properties踩坑与填坑的示例分析,文中介绍的非常详细,具有一定的参考价值,感兴趣的小伙伴们一定要看完!log4j2.properties踩坑与填坑日志配置门面模式:slf4j日志库:log4j2引入...
    99+
    2023-06-22
  • JavaScript中从原型到原型链的示例分析
    这篇“JavaScript中从原型到原型链的示例分析”除了程序员外大部分人都不太理解,今天小编为了让大家更加理解“JavaScript中从原型到原型链的示例分析”,给大家总结了以下内容,具有一定借鉴价值,内容详细步骤清晰,细节处理妥当,希望...
    99+
    2023-06-14
  • Javascript中从学习bind到实现bind的示例分析
    这篇文章给大家分享的是有关Javascript中从学习bind到实现bind的示例分析的内容。小编觉得挺实用的,因此分享给大家做个参考,一起跟随小编过来看看吧。bind是什么bind()方法创建一个新的函数...
    99+
    2024-04-02
  • 从css 3d说到空间坐标轴的示例分析
    这篇文章给大家分享的是有关从css 3d说到空间坐标轴的示例分析的内容。小编觉得挺实用的,因此分享给大家做个参考,一起跟随小编过来看看吧。  先上效果图:  基本思路:三层结构:视角容器>>载体...
    99+
    2024-04-02
  • JavaScript中从setTimeout与setInterval到AJAX异步的示例分析
    这篇文章主要介绍JavaScript中从setTimeout与setInterval到AJAX异步的示例分析,文中介绍的非常详细,具有一定的参考价值,感兴趣的小伙伴们一定要看完!setTimeout与set...
    99+
    2024-04-02
  • Linux网络包从中断到接收的示例分析
    这期内容当中小编将会给大家带来有关Linux网络包从中断到接收的示例分析,文章内容丰富且以专业的角度为大家分析和叙述,阅读完这篇文章希望大家可以有所收获。 linux既然要讲,那就把一个包的整个包生都说了算了触发中断在非虚拟化环境...
    99+
    2023-06-15
  • Disruptor高性能线程消息传递并发框架的示例分析
    这篇文章主要介绍了Disruptor高性能线程消息传递并发框架的示例分析,具有一定借鉴价值,感兴趣的朋友可以参考下,希望大家阅读完这篇文章之后大有收获,下面让小编带着大家一起了解一下。前言碎语Disruptor是英国LMAX公司开源的高性能...
    99+
    2023-06-29
  • numpy中从np.random.normal()到正态分布拟合操作的示例分析
    这篇文章将为大家详细讲解有关numpy中从np.random.normal()到正态分布拟合操作的示例分析,小编觉得挺实用的,因此分享给大家做个参考,希望大家阅读完这篇文章后可以有所收获。先看伟大的高斯分布(Gaussian Distrib...
    99+
    2023-06-15
  • MySQL主从配置的示例分析
    这篇文章主要介绍了MySQL主从配置的示例分析,具有一定借鉴价值,感兴趣的朋友可以参考下,希望大家阅读完这篇文章之后大有收获,下面让小编带着大家一起了解一下。1.主节点授权同步用户 官方文档是分两步进行的...
    99+
    2024-04-02
  • MySQL主从搭建的示例分析
    这篇文章给大家分享的是有关MySQL主从搭建的示例分析的内容。小编觉得挺实用的,因此分享给大家做个参考,一起跟随小编过来看看吧。背景:由于最近公司项目好像有点受不住并发压力了,优化迫在眉睫。由于当前系统是单数据库系统原因,能优化的地方也尽力...
    99+
    2023-06-15
  • Redis主从技术的示例分析
    这篇文章主要为大家展示了“Redis主从技术的示例分析”,内容简而易懂,条理清晰,希望能够帮助大家解决疑惑,下面让小编带领大家一起研究并学习一下“Redis主从技术的示例分析”这篇文章吧。Redis复制在生产环境中,Redis通过持久化功能...
    99+
    2023-06-27
  • 如何从入门Three.js到做出3D地球的示例分析
    如何从入门Three.js到做出3D地球的示例分析,针对这个问题,这篇文章详细介绍了相对应的分析和解答,希望可以帮助更多想解决这个问题的小伙伴找到更简单易行的方法。开篇介绍如果你没接触过3d可视化技术, 你...
    99+
    2024-04-02
  • 从新建vue项目到引入组件Element的示例分析
    这篇文章主要介绍从新建vue项目到引入组件Element的示例分析,文中介绍的非常详细,具有一定的参考价值,感兴趣的小伙伴们一定要看完!本文介绍了从新建vue项目到引入组件Element以及Error wh...
    99+
    2024-04-02
  • Redis中主从复制的示例分析
    这篇文章给大家分享的是有关Redis中主从复制的示例分析的内容。小编觉得挺实用的,因此分享给大家做个参考,一起跟随小编过来看看吧。面临问题 机器故障。我们部署到一台 Redis 服务器,当发生机器故障时,需要迁移到另外一台服务器并且要保证数...
    99+
    2023-06-15
  • iptables从入门到应用的实例分析
    iptables从入门到应用的实例分析,很多新手对此不是很清楚,为了帮助大家解决这个难题,下面小编将为大家详细讲解,有这方面需求的人可以来学习下,希望你能有所收获。iptables从入门到应用 一、简介 1.1、是什么?...
    99+
    2023-06-06
软考高级职称资格查询
编程网,编程工程师的家园,是目前国内优秀的开源技术社区之一,形成了由开源软件库、代码分享、资讯、协作翻译、讨论区和博客等几大频道内容,为IT开发者提供了一个发现、使用、并交流开源技术的平台。
  • 官方手机版

  • 微信公众号

  • 商务合作