RabbitMQ可靠消息最终一致性

RabbitMQ可靠消息最终一致性

为什么要使用可靠消息最终一致性?

在实际的开发系统中,各个服务之间的调用可能是异步的,也就是说一个服务发消息给MQ然后,消费者从MQ中拿取消息。在这个过程中针对基于MQ的异步调用我们要保证分布式事务的原子性,要么一起成功,要么一起失败。所以这个时候就需要用上可靠消息最终一致性了。

什么是可靠消息最终一致性

通俗来讲就是上游服务需要保证消息一定会发出给MQ,下游服务一定会接收到消息,并且在成功消费掉消息之后,返回ack。这个方案是通过消息中间件完成的。

可靠消息最终一致性需要解决的问题

1 上游服务把信息成功发送

本地事务与消息发送的原子性问题:事务发起方在本地事务执行成功后消息必须发出去,否则就回滚事务。即实现本地事务和消息发送的原子性,要么都成功,要么都失败。

2 下游服务成把消息成功消费

事务参与方接收消息的可靠性:事务参与方必须能够从消息队列接收到消息。

3 对消息做幂等

消息重复消费的问题:由于网络2的存在,若某一个消费节点响应超时但是消费成功,此时消息中间件会重复投递此消息,就导致了消息的重复消费。

解决方案

问题 1:上游服务把消息成功发送

通过使用本地消息表来进行不断的扫描查看是否还有未发出的消息,通过quartz定时发送消息,如果发送成功,就讲本地消息表的状态改为成功发送状态或者删除。

RabbitMQ可靠消息最终一致性_第1张图片

问题2:消息中间件必须保证消息不丢失

消息中间件的持久化:

  1. MQ容器的持久化:声明的同时将durable属性设置为true
  2. exchange的持久化:声明的同时将durable属性设置为true
  3. Message的持久化:发送消息的时候,将basicProperties属性设置为MessageProperties.PERSISTENT_TEXT_PLAIN

问题3:下游服务成把消息成功消费

手动ack:保证消息投递失败时消息的重新投递

问题4:对消息做幂等

消息去重表:任务B处理消息前,先查询该消息是否被消费,如果没消费,处理任务B成功,记录消息。如果消息已经被消费,直接返回应答成功

RabbitMQ可靠消息最终一致性_第2张图片
附录1 本地消息表生成sql

DROP TABLE IF EXISTS `local_message`;
CREATE TABLE `local_message` (
  `tx_no` varchar(255) NOT NULL,
  `item_id` bigint DEFAULT NULL,
  `state` int(11) DEFAULT NULL,
  PRIMARY KEY (`tx_no`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8;

附录2 去重表生成sql

DROP TABLE IF EXISTS `msg_distinct`;
CREATE TABLE `msg_distinct` (
  `tx_no` varchar(255) NOT NULL,
  `create_time` datetime DEFAULT NULL,
  PRIMARY KEY (`tx_no`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8;

你可能感兴趣的:(java-rabbitmq,rabbitmq,java)