报文乱序的另外一种思路
报文乱序的另外一种思路
按照一般的处理逻辑来说,一般会分为报文分发和报文处理2个部分.
通常的系统设计一般为: 
报文的乱序主要体现在当我业务系统向外发送一个报文以后,有可能会收到多个报文,而这种多个报文需要按照一定的顺序来进行处理.在微服务的体系下,有专门的服务在对接报文系统的时候,报文系统需要对外部乱序的报文做顺序处理.
以银行票据系统为例,票据系统给票交所发送031报文,票交所会同时返回033和034报文.这2种报文需要在票据系统中按照顺序进行处理.还有类似的同行内的兑换报价,成交清算报文等等.
而到目前为止,对于这种报文乱序的处理都是通过业务状态来进行判断实现的.
问题抽象
本质上来说,上述报文乱序是一种行为模式的判断,而在编程语言中解决行为模式的判断,最有效的就是正则表达式.
而报文乱序如果要使用正则表达式来实现,就需要把报文聚拢为一件事情的处理事件,按照报文发生的时间顺序,就能看明白这件事情的发生情况.
业务事情表
| 主键 | 业务ID | 业务类型 | 业务状态 |
|---|---|---|---|
| id | 用户1 | 兑换报价发起方 | 处理中 |
报文表
| 事情ID | 报文类型 | 处理状态 | 发生时间 |
|---|---|---|---|
| 事情1 | 报价 | 成功 | 时间1 |
| 事情1 | 成交 | 未处理 | 时间2 |
通过业务事情表和报文表的抽象,我们可以乱序的问题通过事情和事件的方式来看待.这件事情可以是一张票的承兑行为,也可以是一个人的动作行为.事件模型就指代一件事情在处理过程中,能推进事情的一系列event.
最终的乱序处理,就是让同时发生的event,在处理的时候,变成有序的方式.
乱序的处理流程
当收到一个报文的时候,我们需要通过如下的步骤来处理
- 通过业务信息判断当前的报文属于哪件事情
- 检查乱序规则(当前的报文+事情),是否需要乱序判断---从乱序规则中获得正则表达式,如果表达式存在,则说明当前的报文需要乱序判断,如果表达式不存在,则当前的报文不需要乱序判断
- 如果需要乱序判断,通过事情id,得到之前这件事情的所有报文,按照发生时间排序
- 通过查到的报文列表,得到每个报文排序后的报文类型的字符串
- 匹配得到的正则表达式和(报文类型字符串+当前报文),如果匹配,则认为当前报文可以执行,如果不匹配,当前报文不满足乱序规则.
通过上述的处理流程,可以完全不依赖于任何的业务状态来管理报文,处理并发问题.另外一个重要点在于,应用的扩展性.可以在任意报文,任意过程增加处理流程中切入判断.
在重新整理报文和业务系统的关系以后,我们可以得到如下的示意图 
如果在考虑的多一点,在微服务之间,上游系统和下游系统不能存在循环调用关系,我们可以把查询事情的调用,单独剥离出来,不去调用业务系统,而去单独调用票库会更好.
在引申一下,类似的票据报文,在兑换报价结束的时候,PJS会对报价双方发送成交报文.如果询价双方都是在一个系统内处理,在报文前置会收到2份一样的成交报文,而系统在处理的时候,交易的双方分别是2件事情,第一份事情处理给报价方,生成成交单,增加判断如果交易对手为本系统内,增加状态为等待另外的报文,如果交易对手为外系统,直接执行成交单.
等到第二份成交报文执行的时候,分配给对手方,如果检查系统内没有当前的成交单,则生成成交单,并执行成交单,如果已经存在成交单,完善信息,执行成交单.
插入/更新数据完成,即可视为消息处理完成.而成交单的执行,可以放在一个单独的处理流程中,使用单独的事务进行控制.
提示
什么时候通知报文前置,当前的报文处理完成了??
可以再生成成交单的处理中通知,成交单和状态的变更应该在一个事务内,通知报文处理完成,可以多次通知.这边可以做一个去重检查.
- 当报文前置没有通知成功,使用定时任务轮询补单,不断的发送报文执行消息
- 当业务系统接受到报文,如果发现已经处理成功,直接发送报文处理成功给报文前置
唯一的问题
上述处理中,如何识别一个报文在哪个事情上,是一个难点.
这个问题一定要暴露出去,交给业务系统,通过业务信息来判断.
总结
很久之前接触到的票据的问题,写下此文,方便记忆.
