前言
我的上家公司是做餐饮系统的,每天中午和晚上用餐高峰期,系统的并发量不容小觑。为了保险起见,公司规定各部门都要在吃饭的时间轮流值班,防止出现线上问题时能够及时处理。
我当时在后厨显示系统团队,该系统属于订单的下游业务。用户点完菜下单后,订单系统会通过发kafka
消息给我们系统,系统读取消息后,做业务逻辑处理,持久化订单和菜品数据,然后展示到划菜客户端。这样厨师就知道哪个订单要做哪些菜,有些菜做好了,就可以通过该系统出菜。系统自动通知服务员上菜,如果服务员上完菜,修改菜品上菜状态,用户就知道哪些菜已经上了,哪些还没有上。这个系统可以大大提高后厨到用户的效率。
事实证明,这一切的关键是消息中间件:kafka
,如果它有问题,将会直接影响到后厨显示系统的功能。
接下来,我跟大家一起聊聊使用kafka
两年时间踩过哪些坑?
顺序问题
1. 为什么要保证消息的顺序?
刚开始我们系统的商户很少,为了快速实现功能,我们没想太多。既然是走消息中间件kafka
通信,订单系统发消息时将订单详细数据放在消息体,我们后厨显示系统只要订阅topic
,就能获取相关消息数据,然后处理自己的业务即可。
不过这套方案有个关键因素:要保证消息的顺序。
为什么呢?
订单有很多状态,比如:下单、支付、完成、撤销等,不可能下单
的消息都没读取到,就先读取支付
或撤销
的消息吧,如果真的这样,数据不是会产生错乱?
好吧,看来保证消息顺序是有必要的。
2.如何保证消息顺序?
我们都知道kafka
的topic
是无序的,但是一个topic
包含多个partition
,每个partition
内部是有序的。
如此一来,思路就变得清晰了:只要保证生产者写消息时,按照一定的规则写到同一个partition
,不同的消费者读不同的partition
的消息,就能保证生产和消费者消息的顺序。
我们刚开始就是这么做的,同一个商户编号
的消息写到同一个partition
,topic
中创建了4
个partition
,然后部署了4
个消费者节点,构成消费者组
,一个partition
对应一个消费者节点。从理论上说,这套方案是能够保证消息顺序的。
一切规划得看似“天衣无缝”,我们就这样”顺利“上线了。
3.出现意外
该功能上线了一段时间,刚开始还是比较正常的。
但是,好景不长,很快就收到用户投诉,说在划菜客户端有些订单和菜品一直看不到,无法划菜。
我定位到了原因,公司在那段时间网络经常不稳定,业务接口时不时报超时,业务请求时不时会连不上数据库。
这种情况对顺序消息
的打击,可以说是毁灭性
的。
为什么这么说?
假设订单系统发了:”下单“、”支付“、”完成“ 三条消息。
而”下单“消息由于网络原因我们系统处理失败了,而后面的两条消息的数据是无法入库的,因为只有”下单“消息的数据才是完整的数据,其他类型的消息只会更新状态。
加上,我们当时没有做失败重试机制
,使得这个问题被放大了。问题变成:一旦”下单“消息的数据入库失败,用户就永远看不到这个订单和菜品了。
那么这个紧急的问题要如何解决呢?
4.解决过程
最开始我们