一、rocketmq顺序消费的原理
1、消息的有序性是指消息的消费顺序能够与消息的发送顺序一致。但是有时候我们从业务需要上面并不需要保证所有消息严格按照消费顺序完全一致。例如,一个订单的下单、付款、出库等操作是不同替换顺序。但是有A订单和B订单,并不需要保证A订单与B订单的顺序。
2、RocketMQ采用了局部顺序一致性的机制,一组消息发送到同一个队列中来保证发送顺序的有序性,然后再由消费者进行。消费的时候通过一个队列只会被一个线程取到 ,第二个线程无法访问这个队列 来保证队列有序性。rocketmq可以同时多个队列并列消费提高,提高rocketmq的消费速度。其实这个方案很像jdk7 里面ConcurrentHashMap 实现分段锁的实现,通过保证每段的线程安全,多段并行消费提高消费能力。
二、代码的具体实现
1、引入依赖
<!-- https://mvnrepository.com/artifact/org.apache.rocketmq/rocketmq-client -->
<dependency>
<groupId>org.apache.rocketmq</groupId>
<artifactId>rocketmq-client</artifactId>
<version>4.2.0</version>
</dependency>
生产方:
2、rocketmq 生产者的配置文件
###producer
#该应用是否启用生产者
rocketmq.producer.isOnOff=on
#发送同一类消息的设置为同一个group,保证唯一,默认不需要设置,
# rocketmq会使用ip@pid(pid代表jvm名字)作为唯一标示
rocketmq.producer.groupName=rocketProducerGroup
#mq的nameserver地址
rocketmq.producer.addr=192.168.25.128:9876
#消息最大长度 默认1024*4(4M)
rocketmq.producer.maxMessage=4096
#发送消息超时时间,默认3000
rocketmq.send.outTime=3000
#发送消息失败重试次数,默认2
rocketmq.producer.retryNum=2
rocketmq.producer.topic=orderTopi
rocketmq.producer.tag=demoTag
2、生产者的配置类
@Configuration
@Component
public class RocketProduceConfig {
private static final Logger LOGGER = LoggerFactory.getLogger(RocketProduceConfig.class);
/**
* 发送同一类消息的设置为同一个group,
* 保证唯一,默认不需要设置,rocketmq会使用ip@pid(pid代表jvm名字)作为唯一标示
*/
@Value("${rocketmq.producer.groupName}")
private String groupName;
@Value("${rocketmq.producer.addr}")
private String producerAddr;
/**
* 消息最大大小,默认4M
*/
@Value("${rocketmq.producer.maxMessage}")
private Integer maxMessageSize;
/**
* 消息发送超时时间,默认3秒
*/
@Value("${rocketmq.send.outTime}")
private Integer sendMsgTimeOut;
/**
* 消息发送失败重试次数,默认2次
*/
@Value("${rocketmq.producer.retryNum}")
private Integer retryNum;
@Bean
public DefaultMQProducer getRocketMQProducer() throws RocketMQException {
DefaultMQProducer producer = new DefaultMQProducer(this.groupName);
producer.setNamesrvAddr(this.producerAddr);
//如果需要同一个jvm中不同的producer往不同的mq集群发送消息,需要设置不同的instanceName
//producer.setInstanceName(instanceName);
if(this.maxMessageSize!=null){
producer.setMaxMessageSize(this.maxMessageSize);
}
if(this.sendMsgTimeOut!=null){
producer.setSendMsgTimeout(this.sendMsgTimeOut);
}
//如果发送消息失败,设置重试次数,默认为2次
if(this.retryNum!=null){
producer.setRetryTimesWhenSendFailed(this.retryNum);
}
try {
producer.start();
LOGGER.info("producer is start, g