一、事件驱动架构基础:从一次系统崩溃说起

我记得刚入行那会儿,接手过一个交易系统。每天处理几万笔订单,看起来挺稳的。结果某天行情剧烈波动,系统直接挂了——所有模块互相等待,CPU跑满,内存爆掉。

后来复盘发现,问题出在架构上。每个模块都是同步调用,A等B,B等C,C又等A。说白了,就是耦合太紧。那之后我开始研究事件驱动架构,这一用就是十年。

什么是事件驱动架构?

事件驱动架构,简单说就是:发生了什么事,就触发对应的处理逻辑

你想想看,现实世界就是事件驱动的。你敲键盘,屏幕显示字符;你点鼠标,程序响应。交易系统也一样——行情来了,策略计算;信号产生了,下单执行。

核心思想就一句话:生产者只管发事件,消费者只管处理事件,两者互不干扰

事件驱动架构 = 事件生产者 + 事件总线 + 事件消费者

生产者不需要知道谁在处理,消费者不需要知道谁在发送。这就是解耦的精髓。

核心概念拆解

咱们一个一个来看。这四个概念搞懂了,事件驱动架构就入门了。

1. 事件(Event)

事件就是「发生了某件事」的记录。在交易系统里,常见的事件有:

  • TickEvent:新的行情数据到了
  • OrderEvent:订单状态变了
  • SignalEvent:策略产生了买卖信号
  • RiskEvent:风控触发了

每个事件通常包含:事件类型、发生时间、携带的数据。举个例子:

class TickEvent:
    def __init__(self, symbol, price, volume, timestamp):
        self.type = "TICK"
        self.symbol = symbol
        self.price = price
        self.volume = volume
        self.timestamp = timestamp

嗯,这里要注意:事件是不可变的。一旦创建,就不要修改。我见过有人直接在事件上改数据,结果排查问题排查到崩溃。

2. 事件源(Event Source)

事件源就是产生事件的地方。在量化交易里,常见的事件源有:

  • 行情网关:接收交易所的实时行情
  • 策略引擎:计算后产生交易信号
  • 风控模块:检测到异常时触发告警
  • 用户操作:手动下单、撤单等

事件源只管「发」,不管「谁收」。我曾经犯过一个错误——在事件源里直接调用了下单接口。结果行情一快,下单逻辑阻塞了行情接收,整个系统卡死。后来改成事件驱动,行情只管发事件,下单由专门的消费者处理,问题就解决了。

3. 事件处理器(Event Handler)

事件处理器就是处理事件的模块。每个处理器只关心自己感兴趣的事件类型。

class OrderHandler:
    def handle(self, event):
        if event.type == "SIGNAL":
            # 处理交易信号
            self.execute_order(event)
        elif event.type == "RISK":
            # 处理风控事件
            self.cancel_orders(event)

我个人习惯把处理器设计成「单一职责」——一个处理器只处理一类事件。这样测试起来特别方便,出了问题也容易定位。

4. 事件总线(Event Bus)

事件总线是连接生产者和消费者的桥梁。它负责:

  • 接收事件源发来的事件
  • 根据事件类型分发给对应的处理器
  • 支持异步处理,避免阻塞

说白了,事件总线就是个「消息中转站」。你可以用消息队列(如Kafka、RabbitMQ)实现,也可以用内存队列实现。在低延迟的交易系统里,我通常用内存队列+环形缓冲区,延迟能控制在微秒级。

避坑指南:我曾经用Kafka做事件总线,结果发现行情数据量太大,Kafka的序列化反序列化成了瓶颈。后来改用内存队列+零拷贝技术,延迟降了10倍。选型时一定要考虑性能要求。

与传统架构的对比

咱们拿一个具体的场景来对比:处理一笔订单。

对比维度 传统架构(同步调用) 事件驱动架构
调用方式 A调用B,B调用C,同步等待 A发事件,B和C各自处理,异步执行
耦合度 高,A依赖B的接口 低,A不知道B的存在
扩展性 难,加功能要改调用链 易,加个处理器就行
容错性 差,一个环节挂了整个链断 好,处理器独立运行
性能 受最慢环节限制 可并行处理,吞吐量高
调试难度 容易,调用链清晰 较难,需要事件追踪

你想想看,传统架构就像流水线——每个人等着上一个人干完活。事件驱动就像邮局——你只管寄信,邮递员自己会送,收信人自己会收。

在量化交易里,这个区别特别明显。行情来了,传统架构要等策略算完、风控检查完、下单执行完,才能处理下一个行情。事件驱动呢?行情一来就发事件,策略、风控、下单各干各的,互不耽误。

注意:事件驱动不是银弹。如果你的业务逻辑是强依赖的(比如必须先A再B再C),那事件驱动反而会增加复杂度。我见过有人硬套事件驱动,结果事件满天飞,调试到怀疑人生。

事件驱动架构的核心流程图

下面这张图展示了事件驱动架构的核心流程。我画了张SVG,你可以看到事件从产生到处理的完整路径。

事件驱动架构核心流程图 事件源 行情/策略/风控 产生事件 事件总线 分发/路由/缓冲 策略处理器 风控处理器 下单处理器 执行结果 事件源 → 事件总线 → 事件处理器 → 执行结果

这张图你看懂了吗?事件源产生事件后,通过事件总线分发给各个处理器。每个处理器各司其职,互不干扰。这就是事件驱动架构的核心思想。

什么时候该用事件驱动?

根据我的经验,以下场景特别适合事件驱动架构:

  • 高并发场景:比如处理每秒几万笔行情
  • 多模块协作:策略、风控、下单各干各的
  • 需要弹性扩展:加个新功能,加个处理器就行
  • 异步处理:不需要立即返回结果的操作

但如果你做的是简单的CRUD系统,或者业务逻辑是严格的串行流程,那传统架构可能更合适。别为了用新技术而用新技术。

我的建议:刚开始接触事件驱动时,可以先从一个小模块开始试点。比如先把行情接收改成事件驱动,看看效果。别一上来就全盘改造,容易翻车。

好了,事件驱动架构的基础就讲到这里。记住四个核心概念:事件、事件源、事件处理器、事件总线。下一章咱们会深入事件总线的实现细节,包括内存队列、消息中间件、以及如何保证事件不丢失。


公众号:蓝海资料掘金营,微信deep3321