1 在用户注册后发送消息到MQ,然后会员服务监听消息进行异步处理的场景下,有些时候我们会发现,虽然用户服务先保存数据再发送MQ,但会员服务收到消息后去查询数据库,却发现数据库中还没有新用户的信息。你觉得,这可能是什么问题呢,又该如何解决呢?
解决方案
当时倒不是因为主从的问题,而是因为业务代码把保存数据和发MQ消息放在了一个事务中,有概率收到消息的时候事务还没有提交完成,当时开发同学的处理方式是收MQ消息的时候sleep 1秒,或许应该是先提交事务,完成后再发MQ消息,但是这又出来一个问题MQ消息发送失败怎么办?所以后来演化为建立本地消息表来确保MQ消息可补偿,把业务处理和保存MQ消息到本地消息表操作在相同事务内处理,然后异步发送和补偿发送消息表中的消息到MQ
可能是数据写到了主库,然后查询了从库。但因为主从同步有延迟,导致没有查询到
也可能mq发信息写到了事务中,导致了mq的消费时,事务还没有提交
注册register的代码中把异常都吃掉了,没抛出来,注册又报错了,但还是继续执行并且发了消息
先保存用户注册的数据,同时记录下要发送mq的消息,入库在一个事务
通过异步任务定时拉取mq的消息表,发送到mq,进行处理
(其实这就是本地事务消息的实现)第二步不一定需要定时任务拉取。第一步完成后直接发mq即可 定时任务拉取只用来补偿
生产者发送给mq消息 即使异步发送也会有listener 来监听投递消息是否成功 如果失败 重试不就行了 ? 不是类似kafka 有100%投递 100%保证消费的配置吗?
补偿吗?我遇到过mq瘫痪的情况,没有补偿这个时候除了干着急我们还能做啥
如果有多个补偿实例,会不会造成消息重复?
补偿需要配合幂等,生产应用肯定用数据库做幂等。
2 除了使用Spring AMQP实现死信消息的重投递外,RabbitMQ 2.8.0 后支持的死信交换器DLX也可以实现类似功能。你能尝试用DLX实现吗,并比较下这两种处理机制?
自定义的私信队列,其实是发送失败,主要是生产者发送到mq的时候,发送失败,进了自定义的私信队列;
DLX的方式的方式其实解决已到了mq,但是因为各种原因,无法到达正常的队列中,大概分类下面几种吧:
消息消费时被拒绝(basic.reject / basic.nack),并且requeue = false
消息TTL过期
队列达到最大长度
公司内部分享的RabbitMQ的资料,欢迎大家交流
http://note.youdao.com/noteshare?id=e9f2f88c6c7fcb7ac690463eb230650a