可靠性保障——消息补偿机制
如何保障消息的可靠性?
如何保证消息不会丢失?
如何保证生产者发送的消息消费者一定能够正常消费掉?
这都是一个问题。之前的文章中已经介绍了几种解决方式:
(1)生产者的confirm模式。 包括Producer与Exchange之间的确认模式(ConfirmCallBack),以及Exchange与Queue之间的回退模式(ReturnCallBack)。
(2)消费者的ack机制。 包括自动签收(none)、手动签收(manual)、根据异常情况签收(auto)。
(3)消息持久化。 值得注意的是,交换机和队列的持久化(durable)和消息的持久化(persistent)并不是一回事。另外,持久化显然会影响MQ的性能,是具体情况取舍使用。
这里,再介绍一个极其重要的另一种可靠性保障机制——消息补偿。
延迟检查(1~7)
生产端成功操作数据库后,发送给消费端一个消息,那么,如何保证这个消息会被消费端消费呢?
首先,Producer发送消息给Consumer,Consumer如果正常消费了消息,则会发送一个确认消息,这个确认消息通过一个队列进入消息数据库(MDB);
然后,延迟一段时间后,Producer会再次发送一个消息,这个消息和刚刚发送的消息完全一样(也可以仅仅具有相同的标识),但它会进入另一个队列,并与消息数据库(MDB)中的消息进行比对,从而知道刚刚的消息是否被消费。
定时检查(8)
但是,上面的检查过程中,可能再次出现信息丢失。为了再上一个保险,每隔一段时间,还会对生产端DB与消息MDB进行比对检查。
消息补偿(RPC)
在某次检查中如果发现比对失败,便会通过一次远程过程调用(RPC)让生产者重新发一次消息。这就是消息补偿。
幂等性保障——乐观锁的版本控制机制
首先要搞明白,什么是幂等性(Idempotence)?
幂等性是指一次执行与多次执行对资源本身造成的影响是相同的。在MQ中,就是指Consumer消费一次数据,与消费多次数据,效果是一样的。
举个通俗的例子,Producer向Consumer发送了一个“账户金额-8000人民币”的消息,如果在MQ中出现故障,该消息出现了多个复制,或者该消息被消费者消费多次,那么用户金额可能会-100000000000。
乐观锁的数据版本机制
表中多加一个version版本号字段,它的含义通常设置为该数据被修改的次数,每次修改version加1。比如下面这个消息,它只会在version=12345时执行一次修改,之后version变为12346,与它相同的消息都不会生效,它也不会重复生效。
update account_table set money=money-8000, version=version+1 where id=2334 and version=12345
🐰 Rabbit~