本文作者:Linkflow首席架构师 – 王鼎,11年软件研发经验,6年SaaS(基于公有云或私有云),熟悉ERP, CDP, omin渠道销售解决方案。参与SaaS产品的大型开发,成员400余人。在一家初创公司从零开始开发新产品。从事SaaS架构和技术管理工作。建立新的开发团队,专注于CDP和Martech SaaS解决方案。
在项目中踏完一系列坑后总结出来,消息的处理有两个要务:

1、消费一定要快,我们喜欢供小于求的市场。生产者生产的消息要满足不了消费者才行。
2、任何消息都不能丢,因为这都是数据啊,即使处理不了也得找地方存着。最好每次的消息都存着,之后就变成了event sourcing(另一个大坑)。

要实现上述2点,其实要解决很多问题。一个快字就不是那么做到的。业务系统收到消息有可能会触发一连串的,并且包裹着事务的逻辑。因为通常我们希望如果这一连串的处理失败的话,可以把ack退回给MQ。一旦业务逻辑过于复杂,work消费消息的速度也会变慢。这就需要开发人员去做权衡了,是不是有些非常heavy的操作可以先记一笔,等业务不繁忙的时候再做。具体实现不在这篇讨论。

问题

回到主题,有一类消息最让人头疼,就是消息之间有依赖,关系一般为单向的父子关系。举个栗子,Product和SKU的关系,一个Product包含多个SKU。比如我们的业务逻辑是要监听这两个消息组成一颗树放到索引中。可想而知,这棵树肯定是至少两层结构,第一级是Product,下面挂着一个或多个SKU。

一般来说,子结构如果是个单独的消息肯定会有个字段说明自己的parent id是什么。那么很自然的,我们在某一刻只收到一个SKU的Create事件,会去通过parent id找到索引中对应的Product,然后挂上去。问题来了,要是索引中没有对应的Product怎么办,消息是没有顺序的,可能是Product的Create事件还没处理到,或者是生产者出了bug消息没发出来造成的。这时SKU的消息就成了孤儿消息。

解决思路一

比较近粗暴的方式,就是利用SKU上的parent id虚拟出一个只有id的Product,由处理SKU事件的worker来帮忙创建这个Product。等下次Product的Create消息进来做一次更新就好了。(处理消息应该不要区分这是Create还是Update还是Delete,消费者就都当Update来做比较好,可以想想为什么)。

当然这个思路一看就有点bad smell,从单一职责的角度上来看,处理SKU的worker应该只关注SKU,不应该关注Product。如果Product也是个孤儿怎么办呢?这个worker可能会越写越复杂。

改进的话可以把创建虚拟Product的这个事情放到SKU这个对象中去做,实现以下setProduct这个方法。那么即使Product也有依赖,那Product自己也得有个setParent的方法,这样就可以递归下去了。(之后想了一下无法处理多级关系,因为Product的消息没来,我们不知道它的parent id,父节点根本建不出来。所以思路一只能处理一个层级的依赖。)

总结一下,思路一是一种不管三七二十一,谁也不能阻止我消费的路线,大不了自下而上的创建虚拟父节点。

解决思路二

相对思路一而言,这种思路还是比较优雅的,但是优雅不等于性能好。

既然SKU是个孤儿,那么我们先收下来放孤儿院好了。新建一张孤儿院表:

上面两条数据就是SKU的,然后为了提升一点性能我们得对对象分个类,一类是有依赖的,一类是无依赖的。没有依赖的直接消费就好,像Product,SKU这种有依赖的,都得打上标签(就是对象里写个isDependency)。例如一个SKU(101010)的消息进来,worker发现这是一个有依赖的消息,那么先拿parent id (1010)去找Product, 发现Product找不到就把这个SKU丢到孤儿院表里去。如果你是用OO的语言,这里其实可以抽象一下。一个BaseWorker,一个SKUWorker,BaseWork负责写个abstract的findParent(),SKUWorker去实现找Product的逻辑就好了。

public abstract class BaseWorker {

public void handle(T t) {if (t.isDependency() && findParent(t) == null) {// 送到孤儿院takeToOrphanage(t);return;}
}abstract Entity findParent(T t);protected void takeToOrphanage(T t) {
}

}
消息记录下来以后,Worker的工作就终止,等待下一条消息进来。过了几分钟,Product(1010)的消息过来了,这时候我们需要给BaseWorker再添加一些代码。

public void handle(T t) {
if (t.isDependency() && findParent(t) == null) {
// 送到孤儿院
takeToOrphanage(t);
return;
}

    // 正常业务...// 正常业务处理之后if (t.isDependency()) {List<Entity> children = findChildren(t);if (children != null) {children.forEach(child -> {sendAsMessage(child);});}}}abstract List<Entity> findChildren(T t);

我们增加一个findChildren方法,让ProductWorker去实现具体逻辑。handle()中增加的代码含义是,当Product这个消息消费完了以后,去孤儿院转一圈看看是不是有等待认领的孩子,简单的利用parent_type和parent_id就能查到。查到以后别直接处理,仍然是以消息的形式发出,让SKUWorker自己去handle,然后可以delete/soft-delete孤儿院中的记录。

可以看到一个有依赖的消息我们在处理的过程,会多一次查询操作,性能多少会受点影响。之前的那次findParent查询其实思路一也有的,目的就是挂靠。

再多一个层级看看是不是罩得住,Category --> Product --> SKU 三层。

如果没有Category的消息进来,孤儿院里是酱紫的。

某一时刻Category的消息进来,CategoryWorker会先到表里查到一条1010的Product消息,把它send出来。ProductWorker收到之后再处理,紧接着又找到SKU的2条消息,再send出来,让SKUWorker去处理。可以看到,自带递归,多层级只要是单向依赖的肯定搞的定。

技术丨如何处理有依赖的消息相关推荐

  1. 此蓝牙设备或计算机无法处理该类型文件,技术丨如何解决蓝牙设备无法连接的问题?...

    原标题:技术丨如何解决蓝牙设备无法连接的问题? 技术丨如何解决蓝牙设备无法连接的问题? 在日常使用PC的过程中,偶尔会遇到蓝牙设备无法连接的情况,那么如何处理这样的问题呢?以下几个步骤来帮你解决. 注 ...

  2. 阿里技术分享:电商IM消息平台,在群聊、直播场景下的技术实践

    本文由淘宝消息业务团队李历岷(花名骨来)原创分享,首次发表于公众号"淘系技术",有修订和改动. 1.引言 本文来自淘宝消息业务团队的技术实践分享,分析了电商IM消息平台在非传统IM ...

  3. 如何处理好依赖关系[Reprint]

    Source: http://book.csdn.net/bookfiles/383/10038314337.shtml "依赖"是和"变化"紧密联系在一起的概 ...

  4. IM技术分享:万人群聊消息投递方案的思考和实践

    本文由融云技术团队原创分享,原题"技术实践丨万人群聊的消息分发控速方案",为使文章更好理解,内容有修订. 1.引言 传统意义上的IM群聊,通常都是像微信这样的500人群,或者QQ的 ...

  5. 搞懂分布式技术19:使用RocketMQ事务消息解决分布式事务

    搞懂分布式技术19:使用RocketMQ事务消息解决分布式事务 初步认识RocketMQ的核心模块 rocketmq模块 rocketmq-broker:接受生产者发来的消息并存储(通过调用rocke ...

  6. dell加装固态硬盘_技术丨如何进行笔记本硬盘拆装?

    遇到笔记本存储空间不足或是对读写速度不满时,很多人会选择对硬盘进行升级,尤其是加装固态硬盘后,启动速度会变得更快,使用体验也会获得极大提升. 本期视频将指导大家如何进行笔记本的硬盘拆装操作,一起来看看 ...

  7. led数字字体_技术丨体育场馆LED显示屏设计与安装要求

    点击上方蓝字关注我们 随着LED显示屏在体育场馆上的应用,体育场馆LED显示屏的安装与设计成为场馆和生产厂家关注的焦点话题.对此有专业人士总结了以下几个方面的体育场馆LED显示屏安装与设计要求. 1. ...

  8. 连不上网_技术丨电脑连不上网,我要如何冲浪?

    身为互联网一级冲浪选手 稳定不断的网络连接可谓是生活必备 但,遇见无法上网的情况时 除了重启路由器,还可以怎么办? 在实际生活工作中,常会遇到无法上网的情况,原因较多.解决方案也同样众多,本文筛选了最 ...

  9. 计算机管理文件破坏怎么办,技术丨电脑系统文件损坏,尝试这几步轻松解决

    原标题:技术丨电脑系统文件损坏,尝试这几步轻松解决 Win10系统作为日常办公最重要的一个系统平台,经常会出现 缺少XX文件等错误提示的现象.那么一旦出现这种情况,要如何解决呢?今天就给大家带来一款居 ...

最新文章

  1. c 运行 java linux命令行参数,Linux下用命令行编译运行Java总结
  2. 科大星云诗社动态20210512
  3. JSP 中EL表达式用法详解
  4. win10 + 独显 + Anaconda3 + tensorflow_gpu1.13 安装教程(跑bert模型)
  5. C/C++语言函数学习(1):atexit、exit、return
  6. python安卓手机编程入门自学_编程入门学习路线(附教程推荐)
  7. 微信网页授权 获取 unionId
  8. android 处理闪屏
  9. 庆贺!浙江省建工集团智能线首根H型钢下线成功
  10. 联想ThinkPad声音扬声器正常但是不能发出声音,插入耳机有声音
  11. GitHub 上值得收藏的100个精选前端项目!
  12. iOS 二维码生成 (Swift代码)
  13. SAP S4 MM配置详解之三:物料主数据-定义物料类型/物料状态/字段选择控制/物料组
  14. LUNA16图片提取
  15. 木曜日威胁情报: 针对学术界的攻击行动和Kelihos僵尸网络之谢幕
  16. 互联网金融公司在信贷风险管理方面,主要面临哪些挑战
  17. cad图框怎么缩小?
  18. vlc多媒体播放器VLC Media Player 3.0.7.1中文版
  19. 《Python编程从入门到实践》外星人入侵游戏——添加 飞船 图片和外星人 图片,素材
  20. 如何通过短信转发在iPad和Mac上发送和接收短信

热门文章

  1. EEE模式的3DES安全性分析
  2. SVGA 礼物动画设计相关
  3. 经历两个月茫然期后粪发图强,四面美团定级3-1,拿到35*16offer
  4. 远程桌面连接无法显示本地磁盘终极解决
  5. rabbitmq java 测试_RabbitMQ 简单测试
  6. (转)“中国第一程序员” 求伯君的传奇经历
  7. uni-app 全局变量globalData的使用
  8. 外卖匹配系统_外卖平台派单规则浅析
  9. java中的强行终止线程的执行
  10. airbnb机器学习模型_机器学习基础:预测Airbnb价格