消息顺序

消息顺序是只可以按照消息发送的顺序进行消费。一个订单产生3条消息,订单创建、付款、订单完成。消费时只有按照顺序消费才有意义,不可能先消费付款消息再消费订单创建消息,这样就乱了。另外,多笔订单又可以并行消费。如何保证呢?

一个订单产生的消息只能发送给同一个MQ服务器中的同一个分区,并且按顺序发送,这样才能在理论上保证消费者消费时是按照顺序消费的,因为一个分区就是一个逻辑队列。生产者虽然按顺序发送,但是第一条消息到达MQ的耗时比第二条多,那么第二条则会被先消费,这样就又导致消费时不是顺序的。那么如何解决呢?可以采取只有第一条被消费者消费成功后再发送第二条。看下图:

1.png

但是如果第一条被发送到消费者后,消费者没有响应(消费者发送响应但是因为网络问题丢失或者消费者就没有收到消息),那么在这种情况下你是继续发送第二条还是重发第一条呢?如果是严格消息顺序,那肯定是重发第一条,但是如果是消费者消费后的响应丢失了,那么重发第一条就会造成重复消费。


从另外一方面看,如果不考虑网络异常,那么要实现严格消息,就必须采取一种一对一关系,生产者A的消息对应到MQ服务器1的X队列,消费者A消费X队列。这样串行结构就会造成系统吞吐量太低;更多异常需要处理比如消费端出现问题,那么整个消息队列就会出现阻塞。RocketMQ通过轮询所有队列来确定消息发送到哪一个队列(负载均衡),比如相同订单号的消息会被先后发送到统一队列中。所以RocketMQ


消息重复

造成消费重复的根本原因是网络不可达,只要有网络,这种网络的不稳定因素就存在你无法规避。所以解决这个问题的最好办法就是绕过它。这就变成了,消费端收到两个一样的消息后如何处理,而不是从发送端解决不发送2个一样的消息。对于消费端的要求就是:

  • 消费端处理业务消息要保持幂等性,也就是同一个东西执行多次会得到相同结果

  • 保证每条消息都有唯一编号切保证消息处理成功与去重表的日志同时出现

第一条好理解,第二条就是利用一张日志表来记录已经处理成功的消息ID,如果新到的消息ID已经存在表中那么就不再处理这个消息。第一条是在消费端实现的,不属于消息系统的功能;第二条可以是消息系统实现也可以是业务端实现,处于对消息系统的吞吐量和高可用考虑最好还是由消费端去处理。所以这也就是RocketMQ不解决消息重复的原因。


分布式开放消息系统(RocketMQ)的原理与实践