CommitLog是真正存储消息的地方。RocketMQ所有生产者的消息都是往这一个地方存储。 ConsumeQueue是一个逻辑队列。和上文中Topic下的Queue是一一对应的。消费者是直接和ConsumeQueue打交道。ConsumeQueue记录了消费位点,这个消费位点关联了commitlog的位置。 所以即使ConsumeQueue出问题,只要commitlog还在,消息就没丢,可以恢复出来。还可以通过修改消费位点来重放或跳过一些消息
消费者负载均衡
集群模式下,如果多个实例同时消费一个queue的消息,由于拉取消息是consumer主动控制的,那样会导致同一个消息在不同的实例下被消费多次,所以算法上一个queue只分给一个consumer实例,一个consumer实例可以允许同时分到不同的queue。 通过增加consumer实例去分摊queue的消费,可以起到水平扩展的消费能力的作用。而有实例下线的时候,会重新触发负载均衡,这时候原来分配到的queue将分配到其他实例上继续消费。
重复消费情况
集群模式下,生产端如果消息发送失败,生产端会重试。但是有时候,生产端发送消息broker保存成功,但是在向producer反馈的时候,网络异常,导致生产端误以为失败,重复发送消息。
消费端,消费成功,但是网络原因ack的时候失败。导致broker重复发送消息到消费端。
消费端消费消息超时(默认30s),会导致服务端重新投递消息。
保证消费幂等性
在生产端发送消息的时候,message可以传递key,这个key必须是全局唯一的(可以是一个UUID),这样消费端在消费的时候可以看是否有改key的成功消费结果。如果有直接反馈成功结果给broker,如果没有继续消费。 在消息中有唯一性的业务主键,这样可以使用业务主键而不使用key来保证不重复消费。