1.Envoy源码分析之Dispatcher
2.说下你可能没用过的EventBus
3.Nginx源码分析 - Event事件篇 - Event模块和配置的初始化
4.Nginx源码分析 - Event事件篇 - Nginx的Event事件模块概览
5.Nginx源码分析 - Event事件篇 - Epoll事件模块
6.gem5 源码阅读 之 event
Envoy源码分析之Dispatcher
Dispatcher在Envoy中扮演着核心角色,是EventLoop的实现,负责任务队列、网络事件处理、定时器与信号处理等关键功能。其设计与Libevent库紧密集成,幻想西游页游源码并通过封装与抽象,简化了内存管理。Dispatcher通过EventLoop提供了非阻塞的事件循环机制,支持多种事件类型,如FileEvent、SignalEvent、Timer等,通过继承unique_ptr来管理Libevent的C结构,利用RAII机制自动处理内存。SignalEvent通过初始化与添加事件使事件处于未决状态。Timer事件通过初始化与添加到Dispatcher中实现超时触发机制,确保在超时时执行。Envoy通过封装Libevent的事件类型,实现事件的抽象与统一处理。FileEvent封装了socket套接字相关的事件,支持主动触发与事件类型的设置。Dispatcher内部的任务队列用于调度与处理回调任务,通过post方法投递任务至队列,并通过循环运行这些任务。Envoy还引入了DeferredDeletable接口,允许对象在特定时间点被安全地析构,避免回调时对象已析构导致的野指针问题,同时确保析构操作在Dispatcher生命周期内完成,避免内存泄漏与程序崩溃。通过实现延迟析构机制,Envoy能够在回调执行前确保对象已正确析构,保障了程序的稳定性和安全性。这一设计与任务队列的实现类似,但在对象析构逻辑上有所不同,海下黑马源码更专注于解决多线程环境下对象生命周期管理的复杂性。
说下你可能没用过的EventBus
最近在Code Review过程中,我发现了一个业务场景:业务处理完成后,需要通知审核人员,通知方式包括短信和邮件。代码如下:
这个方法对吗?
针对这种常见的业务场景,我们首先会考虑同步或异步发送的问题。
如果选择同步,会对接口的响应时间产生影响,并且与业务逻辑紧密耦合,这显然不是好的做法。
一般情况下,我们会选择异步方式,使用消息队列(MQ)进行消息的发送和消费,或者使用线程池来处理,这样不会影响主业务逻辑,可以提高性能,并且实现了解耦。
此外,我们还需要考虑数据一致性的问题,邮件是否一定要发送成功?
大多数情况下,我们并不要求邮件必须%发送成功,失败了就失败了,只要监控告警的失败率不超过阈值即可。同时,消息服务一旦收到请求,应该自行保证消息的投递。
因此,总的来说,使用MQ发送消息并自行处理,或者使用线程池进行异步处理,最后自行处理补偿逻辑,就能解决这类问题。
那么,货源码字网今天要介绍的是这两种解决方案之外的处理方式。对于这种场景,我们可以使用EventBus来解决。
EventBus是事件总线的意思,它是Google Guava库的一个工具,基于观察者模式,可以在进程内实现代码的解耦。
以上面的例子来说,引入MQ可能会有些过于复杂,其实使用EventBus也能达到相同的效果。与MQ相比,EventBus只能提供进程内的消息事件传递,但对于我们的业务场景来说,这已经足够了。
接下来,我们来看一下EventBus的使用方法。首先,创建一个EventBus实例。
第二步,创建一个事件消息订阅者,处理方式非常简单,只需在希望处理事件的方法上添加@Subscribe注解即可。
形参只能有一个,如果定义0个或多个,运行时将会报错。
第三步,注册事件。
第四步,发送事件。
这就是EventBus使用的最简单例子。下面我们看看如何结合开头的例子进行处理。
比如上面提到的案例,比如注册和用户下单的场景,都需要发送消息和邮件给用户。eclipse程序app源码
EventBus并不强制要求我们使用单例模式,因为其创建和销毁成本较低,所以更多是根据我们的业务场景和上下文来选择。
在业务逻辑处理完成后,分别注册了邮件和短信两个事件订阅者。
最后,我们发送事件,用户注册时发送一个用户ID,下单成功时发送一个订单ID。
然后写一个测试类进行测试,分别创建两个service,然后分别调用方法。
执行测试类,我们可以看到输出,分别执行了事件订阅的方法。
使用起来你会发现非常简单,对于希望轻量级简单地实现解耦,使用EventBus非常合适。
注意,例子中的参数都是Long类型。如果事件的参数是其他类型,那么消息是无法接收到的。比如,如果我们将下单中发送的订单ID改为String类型,会发现没有消费。因为我们没有定义一个参数类型为String的方法。
去EmailMsgHandler和SmsMsgHandler都新增一个接收String类型的订阅方法,这样就可以接收到了。
除此之外,我们还可以定义一个DeadEvent来处理这种情况,它相当于是一个默认的处理方式。当没有匹配的事件类型参数时,就会默认发送一个DeadEvent事件。
定义一个默认处理器。JAVA群验证源码
给BookingService新增一个pay()支付方法,下单完成后去支付,注册我们的默认事件。
执行测试bookingService.pay(),看到输出结果:
OK,简单的介绍就到这里。到目前为止,我们所说的都是同步调用,这并不符合我们的要求。我们当然希望使用异步处理更好。
那就看看源码它是如何实现的。
identifier是一个名字,标记,默认是default。
executor是执行器,默认创建一个MoreExecutors.directExecutor(),事件订阅者根据你提供的executor来决定如何执行事件订阅的处理方式。
exceptionHandler是异常处理器,默认创建的就是打点日志。
subscribers是我们的消费者,订阅者。
dispatcher用来做事件分发。
默认创建的executor是一个MoreExecutors.directExecutor(),看到command.run()你就会发现这其实是同步执行。
同步执行并不太好。我们希望不仅解耦,还要异步执行。EventBus提供了AsyncEventBus,我们可以自己传入executor。
上面的代码我们改成异步的,这样不就好起来了嘛。实际上,我们可以结合自己的线程池来处理。
OK,这个说清楚了。我们可以顺便再看看事件分发的处理。看到DeadEvent了吗?没有当前事件的订阅者,就会发送一个DeadEvent事件,bingo!
OK,这个使用和源码都比较简单,有兴趣的同学可以自己去看看,花不了多少功夫。
总的来说,EventBus提供了一个更优雅的代码解耦方式,你在实际工作中的业务中肯定能用得上它!
Nginx源码分析 - Event事件篇 - Event模块和配置的初始化
深入探讨Nginx源码分析中的Event事件篇,专注于Event模块和配置的初始化,旨在清晰理解配置解析与模块初始化的协同工作。
Event模块的配置解析分为两层:最外层的events模块以及内层的ngx_events_module事件模块和ngx_event_core_module事件核心模块。
在初始化流程中,最开始配置文件的初始化调用的是核心模块的指令集,即events模块的配置解析指令函数:ngx_events_block。这里涉及的事件模块结构主要包括:事件模块本身和事件核心模块,每层模块拥有特定的角色与功能。
具体而言,事件核心模块初始化函数为ngx_event_module_init,而配置解析流程则始于解析顶层“event”的配置,并通过ngx_conf_parse方法实现。在顶层配置解析完成后,将进入对事件块block中的内容解析,即ngx_events_block方法执行,此方法为事件命令集的回调函数,负责核心模块配置信息的创建。
配置初始化中,首先在ngx_init_cycle方法中完成核心模块初始化,但由于ngx_events_module中的create_conf方法为NULL,故不会调用创建配置的步骤。接着,顶层配置解析完成后,进入事件块block内容解析,通过遍历模块命令集cmd->set方法,完成具体配置的创建与初始化。
在配置获取过程中,首先从ngx_events_module获取配置信息,再通过查找找到ngx_event_core_module的配置信息。配置的获取涉及从事件模块到事件核心模块的层级访问,确保配置信息的准确获取。
综上所述,Event事件篇中的模块和配置初始化通过多层解析与调用,确保了Nginx配置的完整执行与模块功能的有效实现。这一过程不仅涉及配置的层次结构,还涉及到初始化函数的精确调用与配置解析的细致处理,体现了Nginx源码设计的严谨与高效。
Nginx源码分析 - Event事件篇 - Nginx的Event事件模块概览
深入分析Nginx的Event事件模块,从nginx_event.c文件中开始理解事件分发器ngx_process_events_and_timers的机制。在前一章中,我们已经触及到事件模块的一些基础概念,通过这个函数,我们能见到Nginx事件流程的启动。
本章将全面解析Nginx的event模块,对不熟悉网络IO模型的读者,建议先学习这一领域知识。同时,对于Linux下的epoll模型若感到陌生,请先进行深入学习。一切准备工作完成后,我们便可以开始深入探究。
在event模块中,几个常见且至关重要的数据结构包括:
1. ngx_listening_s:此结构专门用于管理监听连接的socket。
2. ngx_connection_s:存储与连接相关的数据及读写事件。
3. ngx_event_s:封装了事件处理的相关信息。
为了帮助大家更深入地理解Nginx源码,推荐以下视频内容:
视频一:从9个组件开始,教你如何高效阅读nginx源码。
视频二:深入理解epoll的原理与使用,以及它相较于select/poll的优越性。
视频三:探讨红黑树在不同场景中的应用,从Linux内核到Nginx源码的关联。
推荐免费学习资源:Linux C/C++开发(涵盖后端/音视频/游戏/嵌入式/高性能网络/存储/基础架构/安全等领域),获取方法如下:加入群获取C/C++ Linux服务器架构师学习资料(包括C/C++、Linux、golang技术、Nginx、ZeroMQ、MySQL、Redis、fastdfs、MongoDB、ZK、流媒体、CDN、P2P、K8S、Docker、TCP/IP、协程、DPDK、ffmpeg等资料),免费分享。
Nginx源码分析 - Event事件篇 - Epoll事件模块
本文重点解析Nginx源码中的epoll事件模块,作为事件模块家族的一员,epoll以其高效性广受开发者喜爱。 Nginx的epoll事件模块位于源码文件 /event/module/ngx_epoll_module.c 中。一、epoll模块的数据结构
epoll模块包含以下三个关键数据结构:ngx_epoll_commands: epoll模块命令集
ngx_epoll_module_ctx: epoll模块上下文
ngx_epoll_module: epoll模块配置
二、epoll模块的初始化
在配置文件初始化阶段,epoll模块的初始化工作主要在核心函数 ngx_events_block 中完成。 随后,ngx_event_process_init 函数负责执行模块的初始化操作,ngx_epoll_init 用于具体实现epoll模块的初始化。三、核心函数
epoll模块的关键功能体现在 ngx_epoll_process_events 函数,此函数实现了事件的收集和分发功能,是Nginx处理事件的核心。以上是对Nginx源码中epoll事件模块的简要分析。
gem5 源码阅读 之 event
Event在gem5中扮演核心角色,本文将聚焦几个关键问题的解答:
gem5作为事件驱动型仿真器,能高效处理每个动作或响应,无需频繁检查全局时间,显著降低执行时间。每个继承自EventManager的SimObject实例均可承担事件管理职责。
SimObject的schedule方法将事件排序并插入全局EventQueue,构建全局事件树。Event执行基于排序后的when+priority值,确保事件有序执行。
以cache为例,事件注册流程始于DCachePort的recvTimingResp函数中的tickEvent自身调用schedule方法,进一步由cpu调用schedule,实际上就是EventManager的schedule函数,将事件插入到event queue中。
事件的执行时机取决于其特性,如cache中的tickEvent执行数据传输动作,通常在recvTimingResp函数中触发,此时代表完整数据请求完成的事件点。
事件树的执行依赖于event queue管理,主event queue在doSimLoop中处理,其他event queue通过thread_loop并行处理,并通过threadBarrier同步所有线程,确保事件同时执行。
全局eventqueue通过getEventQueue函数生成,参数index指定queue索引,第一次使用时创建新对象,每个queue与一个线程关联,执行相关事件。
EventQueue创建在不同使用场景中,例如cxx_config方式下,在main.cc文件中直接调用getEventQueue,生成全局eventqueue;gem5 within systemc方式下,在main.cc中实例化SimControl对象,进而调用simulate函数,管理全局eventqueue。
在Python配置文件中,如fs.py,通过build_test_system函数构建系统组件,cpu的eventq_index参数用于创建全局eventqueue,确保所有相关组件事件同步。
综上所述,gem5通过事件驱动机制高效仿真系统行为,事件注册、执行、管理流程贯穿整个系统仿真过程,确保复杂系统行为的准确模拟。