首先定义什么是消息的一致性:
产生消息的业务动作与发送的一致,就是说,如果操作成功了,那么这个操作产生的消息一定要发送出去,否则就丢失消息了。另一方面,如果业务行为没有发生或者失败则不能把消息发送出去。
经常的思路是:先写业务,然后写消息,这样不能保证业务完成,消息一定写成功了;或者先写消息,后写业务,这也不能保证消息写成功后,业务一定会执行成功。
现在有种思路如下:
,但是上面第五到第六步还是可能存在问题,
1)业务操作未进行,消息存入存储,状态为待处理
2)业务操作成功,消息存入存储,状态为待处理
所以此时还需要消息中间件遍历状态为待处理的消息进行如下流程的处理,
如果业务成功,修改消息状态为待发送;如果失败,则直接删除消息。
但是上面的系统会带来如下问题:
业务系统对消息系统的依赖性过强,如果因为消息的无法写入导致整个业务系统不能用,是得不偿失的,也是不合理的,那么推荐方案如下:
也就是降低业务系统对消息中间件的依赖,上图中业务系统与消息中间件之间是虚线,就是说业务处理成功时,如果中间件存在问题,业务可以不向消息中间件发送消息,而是在和业务数据表所在库中建一个临时的消息表,业务向该消息表中写消息,然后再由中间件来读取。需要说明的是:
消息表和业务数据表在同一库中,可以保证业务和消息具有相同的可靠性,并且业务操作可以和写入消息作为一个本地事务来完成。但是上面的方案
- 增加了业务数据库的压力
- 需要消息中间件访问业务数据库
- 业务操作的对象必须是单个数据库,支持事务(将写业务数据和写消息数据放在同一事务中)的存储
上面2的问题可以通过如下方案解决:
即中间件不在访问业务数据库中的消息表,完全有业务来控制消息的生成、获取、发送、重试等。问题是:
上面的两个方案都要求业务操作支持事务的数据库操作。
继续,存在如下解决方案:
即本地磁盘作为消息存储,也就是如果消息中间件不可用,又不想将消息的数据写到业务数据库时,可以把消息存储到本地磁盘,消息中间件恢复后,再从磁盘中读取。
好了 ,over