如何设计一个事件总线

227 阅读4分钟

前言

基于上一篇文章, 《使用规则引擎改造任务系统》 juejin.cn/spost/74014…\

评论区有网友觉得还需要业务方来对接任务系统,也就是要在业务代码中,将事件消息投递给任务系统,该改造对业务入侵性较大,有无更好的方案呢?

当然有,在对接的过程中,我们也发现了问题,业务方需要对接我们的消息,需要 开发业务代码,且对业务入侵比较重。某些业务方的版本需要一个月,无法满足业务快速增长的需要。


痛点解决

有没有一种可能,搭建一个消息转换系统,由该系统主动监听业务方的变更的动作呢?将业务方的消息转换成任务系统感兴趣的消息格式,从而避免业务方的开发。.

具体流程如下:

消息转换系统.jpg

解释\

这个消息转换系统,有两种监听方式。\

形式1:作为消费者,去监听业务方原本发送给RocketMQ,Kafka的消息。\

形式2: 监听业务数据的binlog,将binlog记录转换。

消息转换系统在拿到消息后,再转换成任务系统,消息系统感兴趣的消息格式,并将转换后的消息进行投递。\

同时,消息投递也是支持投递至RocketMQ,Kafka,Http,甚至支持dubbo/sofa等Rpc协议。


功能设计

通过上述的描述,细心的读者已经发现消息转换系统做的事情:对上游业务方的消息体格式监听,通过配置的方式,转换成下游系统感兴趣的消息格式。

我们将这个消息转换系统定了一个高大上的名字:事件总线

其功能设计如下:

消息转换系统-功能设计.jpg

以下,我将娓娓道来,各个模块的设计思路。


多协议消息监听

这一步,营销总线会作为消费者,去对消息进行监听,读取消息

消息转换系统-多协议消息来源.jpg

项目启动的时候,会营销总线的配置,初始化Kafka消费者,rocketmq消费者,binlog配置

消息转换

在对消息进行监听后,这一步会统一将消费者的消息体转成营销总线定义的 统一格式, 统一对象json格式如下:

    {  

        "userId": "",  

        "deviceId": "",  

        "time": "",  

        "eventId": "",  

        "data": {  

      

        }  

    }

其java对象如下:

image.png

业务方的消息有多种,如果是Json格式,可以解析对应的消息,利用Jsonpath(github.com/json-path/J…\

将业务的消息格式转成营销总线的统一格式.

假如业务原有的消息格式为:

    {  

        "deviceId": "abc1234",  

        "behavior": "loan\_success",

        "businessTime" : 1726578440000

        "extra": {  

            "user": "12345",  

            "loanMoney": 3000,  

            "tradeLimit": 8  

        }  

    }

那么如果要将其转换成营销总线的统一格式,Jsonpath的配置规则为:


"userId": "$.extra.user",

"deviceId": "$.deviceId",

"time":"$.businessTime",

"eventId": "$.behavior"

"data": {

   "money":"$.extra.money",

   "limit": "$.extra.tradeLimit"

}

  


转成统一格式后,统一格式的消息内容如下:


"userId": "12345"

"deviceId": "abc1234",

"time": 1726578440000

"eventId": "loan_success"

"data": {

   "money":3000,

   "limit": 8

}

  


大部分消息体其实都是json格式,但若消息来源是非json格式呢?\

如binlog监听,消费者主题消息内容非json格式。此时需要在营销总线代码编写定制化代码,针对上述的特殊消息协议,转换成事件总线的统一格式。

消息过滤

既然所有的消息来源,都转成了事件总线的统一格式,下游可能只需要对消息来源中的部分消息进行监听,所以这儿需要消息过滤的功能,在发送给下游的时候,先过滤一次。

因为消息来源的所有消息都转成了 标准格式 ,事件总线将标准格式消息转换成json格式后,再使用jsonpath的API,进行过滤。

image.png

如我只想对借款金额 > 1000元的消息发送给下游系统,使用jsonpath表达式表达则为:

    $.data.money > 1000  

多协议消息发送。

指的是将消息发送给不同的生产者,如Kafka, RocketMQ, http等。

消息路由

事件总线将转换好,过滤好的消息,根据配置,按照下游消息要求的格式,发送给下游生产者。\

如任务系统的下游感兴趣的消息格式为:

    {  

        "userid": "12345",  

        "business": "onlineShop",  

        "behavior": "pay_order_success",  

        "behaviorTime": "完成订单时间戳",  

        "extraData": {  

            "tradeTotalMoney": 500000

        }  

    }

事件路由的转换配置则为:


{  

    "userid": "$.ssoId",  

    "business": "event-bus",  

    "behavior": "$.eventId",  

    "behaviorTime": "$.time",  

    "extraData": {  

        "tradeTotalMoney":"$.data.money" 

    }  

}

  


总结

上述是实现营销总线的大概思路,但实际上里面编码细节很多,而且上线后,实际运行的过程中,会碰到大流量Topic产生尖刺,kafkfa多Topic cpu飙升的问题。

如果想要源代码的可以请作者喝个咖啡,备注好你的邮箱,作者看到后会将代码发到邮箱中。

image.png