消息队列中如何保证消息的顺序性
消息队列中如何保证消息的顺序性
- 场景说明
- 官方文档
- 如何保证消息的顺序性
- 生产顺序性
- 消费顺序性
- 消费建议
场景说明
在证券或者股票这一类项目中,当我们去发出一个报价单的时候,那么对于我们出价相同的交易单,比如说a用户是1000,b用户是1000,c用户也是1000。
按照股票交易的逻辑,谁先出价谁先交易的一个原则,那么下游系统他在处理我们订单的时候,他需要严格按照我们这个顺序机制来去处理我们的订单。
如果我们的MQ系统中出现了消息错乱的问题,那么他就违反了我们本身系统的一个业务。那么在MQ里面,我们如何去保证我们消息的一个顺序性呢?
在这里我们以RocketMQ为例,它本身就是支持我们顺序消息的,但是它也会存在一定的限制。
官方文档
RocketMQ 5.X官方文档中有这样一句话:
Apache RocketMQ顺序消息的顺序关系通过消息组(MessageGroup)判定和识别。发送顺序消息时需要为每条消息设置归属的消息组,相同消息组的多条消息之间遵循先进先出的顺序关系,不同消息组、无消息组的消息之间不涉及顺序性。
如果我们的报价单没有设置归属的消息组,那么就极有可能发生顺序错乱的一个问题。
如何保证消息的顺序性
那么我们如何保证消息的顺序性呢?
- 生产顺序性
- 消费顺序性
生产顺序性
RocketMQ通过生产者和服务端的协议保障单个生产者串行地发送消息,并按序存储和持久化。
如需保证消息生产的顺序性,则必须满足以下条件:
- 单一生产者:消息生产的顺序性仅支持单一生产者,不同生产者分布在不同的系统,即使设置相同的消息组,不同生产者之间产生的消息也无法判定其先后顺序。
- 串行发送:RocketMQ生产者客户端支持多线程安全访问,但如果生产者使用多线程并行发送,则不同线程间产生的消息将无法判断其先后顺序。
那么我们把顺序消息发送到了我们的RocketMQ里面之后,它能够保证我们设置了同一个消息组的消息,它就一定会按照发送顺序,存储在同一个队列里面。
消费顺序性
RocketMQ通过消费者和服务端的协议保障消息消费严格按照存储的先后顺序来处理。
如需保证消息消费的顺序性,则必须满足以下条件:
- 投递顺序:RocketMQ通过客户端SDK和服务端通信协议保证消息按照服务端存储顺序投递,但业务方消费消息时需要严格按照接收—处理—应答的语义处理消息,避免因异步处理导致消息乱序。
- 有限重试:RocketMQ顺序消息投递仅在重试次数限定范围内,即一条消息如果一直重试失败,超过最大重试次数后将不再重试,跳过这条消息消费,不会一直阻塞后续消息处理。
消费建议
- 串行消费,避免批量消费导致乱序(我们尽量一次就消费一条消息,如果我们一次去消费多条消息的话,那么很有可能会出现一个乱序的情况。RocketMQ文档里面是有讲到的,如果说我们去进行了批量的消费的话,那么对于消息的顺序性问题就交给了我们本身的应用来去处理了)。
- 消息组尽可能打散,避免集中导致热点(保证顺序性的时候,我们保证了同一消息组中的消息存在了同一个队列里面。我们在使用MQ的时候,如果我们把不同业务场景里面的消息都集中在这个消费组里面,那么存储压力都集中到了一个队列里面。那么就很有可能会导致我们的性能热点。这样也非常不利于我们的扩展,所以说我们在设计我们的消息组的时候,我们应该按照实际的业务去进行一个拆分。我们可以把不需要保证顺序的消息和需要保证顺序的消息,我们按照这个粒度去对它进行拆分,这样我们就能避免其中导致的一个热点问题)。
参考资料:字节二面:MQ中,如何保证消息的顺序性?
还没有评论,来说两句吧...