RocketMQ

RocketMQ 作为一款纯java、分布式、队列模型的开源消息中间件,支持事务消息、顺序消息、批量消息、定时消息、消息回溯等。

核心概念

主要由四大部分组成:
1. Producer:生产者,可以集群部署。它会先和 NameServer 集群中的随机一台建立长连接,得知当前要发送的 Topic 存在哪台 Broke Master上,然后再与其建立长连接,支持多种负载平衡模式发送消息。

2. Consumer:消费者,可以集群部署。它也会先和 NameServer 集群中的随机一台建立长连接,得知当前要消息的 Topic 存在哪台 Broker Master、Slave上,然后它们建立长连接,支持集群消费和广播消费消息。

3. Broker:主要负责消息的存储、查询消费,支持主从部署,一个 Master 可以对应多个 Slave,Master 支持读写,Slave 只支持读。Broker 会向集群中的每一台 NameServer 注册自己的路由信息。

4. NameServer:是一个很简单的 Topic 路由注册中心,支持 Broker 的动态注册和发现,保存 Topic 和 Borker 之间的关系。通常也是集群部署,但是各 NameServer 之间不会互相通信, 各 NameServer 都有完整的路由信息,即无状态。

SpringBoot 集成 RocketMQ

SpringBoot对RocketMQ 进行了封装处理,使用比较简单。

<dependency>
    <groupId>org.apache.rocketmq</groupId>
    <artifactId>rocketmq-spring-boot-starter</artifactId>
    <version>2.2.2</version>
</dependency>

applocation.yml

rocketmq:
	# MQ地址,如果是集群,则使用;分开
	# name-server: ip:端口;ip:端口
  name-server: ip:端口
  # 消费者
  # 当使用阿里云的云Rocketmq,需要配置access-key、secret-key;
  # 也可以是云Rocketmq的账号密码 access-key 对应rmq的账号,secret-key 对应rmq的密码;
  consumer:
    access-key: 111
    secret-key: 222
  # 生产者
  producer:
    access-key: 111
    secret-key: 222
    # 组
    group: group-test
    # 消息发送超时时间 默认3000
    send-message-timeout: 4000
    #消息达到4096字节的时候,消息就会被压缩。默认 4096
    compress-message-body-threshold: 4096
    #最大的消息限制,默认为128K
    max-message-size: 4194304
    #同步消息发送失败重试次数 默认2
    retry-times-when-send-failed: 3
    #在内部发送失败时是否重试其他代理,这个参数在有多个broker时才生效
    retry-next-server: true
    #异步消息发送失败重试的次数 默认2
    retry-times-when-send-async-failed: 3

关键类

1. RocketMQTemplate:提供了各种操作MQ的方法。

        a. 普通消息

// destination:主题 topic 如果有tag,"topic:tag"
// payload:发送消息内容
void convertAndSend(String destination, Object payload);

除了普通消息只能发送 Object 类型的消息外,其他的还可以发送Message类型的消息;

        b. 同步消息

// Object 类型消息
// timeout:消息超时时间,可有可无
// SendResult.getMsgID():发送的消息ID,可以在RocketMQ 中通过ID 查询到该消息
SendResult syncSend(String destination, Object payload, long timeout);

// 发送 Message 类型消息
SendResult syncSend(String destination, Message<?> message, long timeout);

// 延迟消息 只能 Message 类型
// delayLevel:延迟级别,开源版只有固定的延迟级别,不支持任意时间延迟
// 1-18 个级别:1s 5s 10s 30s 1m 2m 3m 4m 5m 6m 7m 8m 9m 10m 20m 30m 1h 2h
SendResult syncSend(String destination, Message<?> message, long timeout, int delayLevel);


// 同步顺序消息 Object 除了 timeout 可有可无,其他参数必须有
// hashKey:使用此参数选择队列。 例如:orderId,productId
SendResult syncSendOrderly(String destination, Object payload, String hashKey, long timeout);

SendResult syncSendOrderly(String destination, Message<?> message, String hashKey, long timeout);

        c. 异步消息

// SendCallback:有两个方法 1. onSuccess():发送成功 2. onException:发送失败
void asyncSend(String destination, Object payload, SendCallback sendCallback, long timeout);

void asyncSend(String destination, Message<?> message, SendCallback sendCallback, long timeout);

void asyncSend(String destination, Message<?> message, SendCallback sendCallback, long timeout, int delayLevel);

// 异步顺序消息
void asyncSendOrderly(String destination, Object payload, String hashKey, SendCallbacksendCallback, long timeout);

void asyncSendOrderly(String destination, Message<?> message, String hashKey, SendCallbacksendCallback, long timeout);

         d. 单向消息:只负责发送消息,不等待服务器回应且没有回调函数触发,即只发送请求不等待应答

void sendOneWay(String destination, Object payload);

void sendOneWay(String destination, Message<?> message);

// 单向顺序消息
void sendOneWayOrderly(String destination, Object payload, String hashKey);

void sendOneWayOrderly(String destination, Message<?> message, String hashKey);

2. RocketMQLocalTransactionListener:本地事务监听器 。

3. RocketMQListener:消费信息监听器 。

4. MessageQueueSelector:消息队列选择策略。

5. DefaultMQProducer:默认的生产者。

生产者

@RestController
@RequestMapping("/test")
public class TestController {

    @Autowired
    private RocketMQTemplate rocketMQTemplate;

    @GetMapping("/test")
    public void test(){
        // 如同需要指定tag:topic:tag
        rocketMQTemplate.convertAndSend("topic-test:TagTest", "普通消息");

        // 指定key,方便后期在 rocketMQ 中查询消息
        Message<String> message = MessageBuilder.withPayload("同步消息").setHeader(RocketMQHeaders.KEYS, "11").build();
        SendResult syncSendResult = rocketMQTemplate.syncSend("topic-test:TagTest", message);

        rocketMQTemplate.asyncSend("topic-test:TagTest", "异步消息", new SendCallback() {
            @Override
            public void onSuccess(SendResult asyncSendResult) {
                System.out.println("发送异步消息成功 msgId:" + asyncSendResult.getMsgId());
            }

            @Override
            public void onException(Throwable e) {
                System.out.println("发送异步消息失败 e:" + e);
            }
        });
    }

}

消费者

@Component
@RocketMQMessageListener(
        consumerGroup = "group-test",
        topic = "topic-test",
        selectorType = SelectorType.TAG,
        selectorExpression = "TagTest")
public class TestConsumer implements RocketMQListener<String> {

    @Override
    public void onMessage(String message) {
        System.out.println("消费者:" + message);
    }
}

测试
消费者:普通消息
消费者:同步消息
发送异步消息成功 msgId:7F00000134C818B4AAC250AD01C80002
消费者:异步消息

 @RocketMQMessageListener 主要参数详情

1. consumerGroup 消费组;
2. topic 主题;
3. selectorType 消息选择器类型;
    SelectorType.TAG 根据tag选择 (默认值)
    SelectorType.SQL92 根据SQL92表达式选择
4. selectorExpression 选择器表达式,默认值 "*"
5. consumeMode 消费模式
	ConsumeMode.CONCURRENTLY 并行处理 (默认值)
	ConsumeMode.ORDERLY 按顺序处理
6. messageModel 消息模型
	MessageModel.CLUSTERING 集群 (默认值)
	MessageModel.BROADCASTING 广播

事务消息

1. 生产者将半事务消息推送给MQ。

2. MQ将消息持久化成功后,向生产者返回ACK,确认消息发送成功,此时消息为半事务消息。

3. 生产者执行本地事务逻辑。

4. 生产者根据本地事务执行结果向MQ二次提交(Commit、Rollback、Unknown)。

        a. TransactionStatus.CommitTransaction: 提交事务,它允许消费者消费此消息。

        b. TransactionStatus.RollbackTransaction: 回滚事务,它代表该消息将被删除,不允许被消费。

        c. TransactionStatus.Unknown: 未知状态,它代表需要检查消息队列来确定状态。

5. 在断网后者未知状态下,MQ没有收到生产者发送的二次确认结果,在经过固定时间后,MQ对生产者发起消息回查。

        a. 生产者收到消息回查后,需要检查对应的消息本地事务执行结果。

        b. 生产者根据检查得到的本地事务的最终状态再次提交二次确认,服务端仍按照步骤4对半事务消息进行处理。

回查

  1. 回查间隔时间:系统默认每隔30秒发起一次定时任务,对未提交的半事务消息进行回查,共持续12小时。
  2. 第一次消息回查最快时间:该参数支持自定义设置。若指定消息未达到设置的最快回查时间前,系统默认每隔30秒一次的回查任务不会检查该消息。

 

生产者

@RestController
@RequestMapping("/test")
public class Test {
    @Autowired
    private RocketMQTemplate rocketMQTemplate;

    @RequestMapping("/sendTransactionMessage")
    public void sendTransactionMessage(@RequestParam("msg") String msg, 
                                       @RequestParam("key") String key) {
        Message<String> message = MessageBuilder.withPayload(msg).setHeader(RocketMQHeaders.KEYS, key).build();

        // 发送事务消息
        TransactionSendResult transactionSendResult = rocketMQTemplate.sendMessageInTransaction("topic-test", message, null);
        // 发送状态
        String sendStatus = transactionSendResult.getSendStatus().name();
        // 本地事务执行状态
        String localState = transactionSendResult.getLocalTransactionState().name();

        System.out.println("发送状态:" + sendStatus + ";本地事务执行状态" + localState);
    }
}

事务监听器

/**
 * 事务消息监听器:监听本地事务执行的状态和检查本地事务状态
 */
@RocketMQTransactionListener
public class MQTransactionListener implements RocketMQLocalTransactionListener {

    /**
     * 执行本地事务(在发送消息成功时执行)
     * 处理业务后,根据业务处理情况,返回事务执行状态
     * rollback:回滚事务,消息将被丢弃不允许消费
     * commit:提交事务,允许消费者消费该消息
     * unknown:暂时无法判断状态,等待固定时间以后消息队列RocketMQ根据回查规则向生产者进行消息回查
     */
    @Override
    public RocketMQLocalTransactionState executeLocalTransaction(Message message, Object o) {
        /**
         * 模拟返回事务状态
         */
        int index = 0;

        switch (index) {
            case 1:
                String jsonStr = new String((byte[]) message.getPayload(), StandardCharsets.UTF_8);
                System.out.println("本地事务回滚,回滚消息:" + jsonStr);
                return RocketMQLocalTransactionState.ROLLBACK;
            case 2:
                System.out.println("unknown");
                return RocketMQLocalTransactionState.UNKNOWN;
            default:
                System.out.println("事务提交,消息正常处理");
                return RocketMQLocalTransactionState.COMMIT;
        }

    }

    /**
     * 检查本地事务的状态
     * 当MQ未得到生产者应答,或者超时,或者应答是unknown的情况,调用此方法进行检查确认,返回值和上面的方法一样
     */
    @Override
    public RocketMQLocalTransactionState checkLocalTransaction(Message message) {
        String jsonStr = new String((byte[]) message.getPayload(), StandardCharsets.UTF_8);
        System.out.println("调用回查本地事务接口:" + jsonStr);
        return RocketMQLocalTransactionState.COMMIT;
    }
}

消费者

@Component
@RocketMQMessageListener(consumerGroup = "group-test", topic = "topic-test")
public class MQConsumer implements RocketMQListener<String> {

    @Override
    public void onMessage(String message) {
        System.out.println("消费者:" + message);
    }
}

测试

Commit

Rollback

模拟 index = 1

Unknown

模拟 index = 2,消息回查

 

  • 1
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值