RocketMQ使用

文章目录

简介

RocketMQ是一款分布式、队列模型的消息中间件,由阿里巴巴团队研发,借鉴参考了 JMS 规范的MQ实现(如 activeMQ),更参考了优秀的开源消息中间件kafka,具有低延迟,高性能和可靠性。

专业术语

  • Producer:消息生产者,负责生产消息,一般由业务系统负责生产消息
  • Consumer:消息消费者,负责消费消息,一般是调用系统负责异步消费
  • Push Consumer:Consumer 的一种,应用通常向Consumer对象注册一个Listener接口,一旦收到消息,Consumer对象立 刻回调Listener接口方法
  • Pull Consumer:Consumer 的一种,应用通常主动调用Consumer的拉消息方法从Broker拉消息,主动权由应用控制
  • Producer Group:一类Producer的集合名称,这类Producer通常发送一类消息,且发送逻辑一致
  • Consumer Group:一类Consumer的集合名称,这类Consumer通常消费一类消息,且消费逻辑一致
  • Broker:消息中转角色,负责存储消息,转发消息,一般也称为Server。在JMS规范中称为Provider
  • 广播消费:一条消息被多个Consumer消费,即使这些Consumer属于同一个Consumer Group,消息也会被Consumer Group中的每个Consumer都消费一次,广播消费中的Consumer Group概念可以认为在消息划分方面无意义。 在JMS规范中,相当于JMS publish/subscribe model
  • 集群消费:一个Consumer Group中的Consumer实例平均分摊消费消息。例如某个Topic有9条消息,其中一个Consumer Group有3个实例(可能是3个进程,或者3台机器),那么每个实例只消费其中的3条消息。
  • 顺序消息:消费消息的顺序要同发送消息的顺序一致,在RocketMQ中,主要指的是局部顺序,即一类消息为满足顺序性,必须Producer单线程顺序发送,且发送到同一个队列,这样Consumer就可以按照Producer发送的顺序去消费消息。
  • 普通顺序消息:顺序消息的一种,正常情况下可以保证完全的顺序消息,但是一旦发生通信异常,Broker重启,由于队列总数发生变化,哈希取模后定位的队列会变化,产生短暂的消息顺序不一致。
  • 严格顺序消息:顺序消息的一种,无论正常异常情况都能保证顺序,但是牺牲了分布式failover特性,即broker集群中要有一台机器不可用,则整个集群都不可用,服务可用性大大降低。如果服务器部署为同步双写模式,此缺陷可通过备机自动切换为主避免,不过仍然会存在几分钟的服务不可用。目前已知的应用只有数据库binlog同步强依赖严格顺序消息,其他应用绝大部分都可以容忍短暂乱序,推荐使用普通的顺序消息。
  • Message Queue:在RocketMQ中,所有消息队列都是持久化,长度无限的数据结构,所谓长度无限是指队列中的每个存储单元都是定长,访问其中的存储单元使用Offset来访问,offset为java long类型,64位,理论上在100年内不会溢出,所以认为是长度无限,另外队列中只保存最近几天的数据,之前的数据会按照过期时间来删除。

消息生产方式

生产普通消息

可靠同步发送(reliable synchronous)

主要运用在比较重要的消息传递或通知等业务

java 复制代码
producer.send(msg);

可靠异步发送(reliable asynchronous)

主要用于对发送消息响应时间要求更高/快的场景

java 复制代码
producer.send(msg, sendCallback);
// sendCallback:onSuccess(SendResult sendResult),onException(Throwable e);

单向发送(one-way transmission)

适用于某些耗时非常短,但对可靠性要求并不高的场景,如日志收集等

java 复制代码
producer.sendOneway(msg);

生产顺序消息

如果需要消息保持顺序,需要生产者生产消息的时候也要保持顺序。

java 复制代码
producer.send(message, new SelectMessageQueueByHash(), hashKey);

rocketMQ通过MessageQueueSelector实现的算法来确定消息发送到哪一个队列上。

  • SelectMessageQueueByHash

按照hash值分配队列,这个是比较常用的,例如可以使用订单号等,同一订单号的则会分配到同一队列上

  • SelectMessageQueueByRandom

按照随机数分配队列

  • SelectMessageQueueByMachineRoom

字面意思是按照机房分配队列,需要重写里面的方法,否则会报错

分布式事务消息

执行过程:

  1. 事务发起方首先发送 prepare 消息到 MQ
  2. 在发送 prepare 消息成功后执行本地事务
  3. 根据本地事务执行结果返回 commit 或者是 rollback
  4. 如果消息是 rollback,MQ 将删除该 prepare 消息不进行下发,如果是 commit 消息,MQ 将会把这个消息发送给 consumer 端
  5. 如果执行本地事务过程中,执行端挂掉,或者超时,MQ 将会不停的询问其同组的其它 producer 来获取状态
  6. Consumer 端的消费成功机制有 MQ 保证,消费端要注意消费的幂等性

示例:

java 复制代码
@MQTransactionProducer(producerGroup = "tmcbGroup")
public class MessageProducer extends AbstractMQTransactionProducer {
    @Override
    public LocalTransactionState executeLocalTransaction(Message msg, Object arg) {
        return LocalTransactionState.UNKNOW;
    }

    @Override
    public LocalTransactionState checkLocalTransaction(MessageExt msg) {
        return LocalTransactionState.COMMIT_MESSAGE;
    }
}

需要实现【TransactionListener】类,然后根据本地事务执行的状况判断消息是发送还是不发送,消费端要做好幂等处理。

LocalTransactionState的三种状态:

  • UNKONW:默认状态,消息不推送
  • COMMIT_MESSAGE:消息推送到消费者端
  • ROLLBACK_MESSAGE:本地事务执行失败,消息不推送

延时发送消息

RocketMQ 支持延时发送消息,不过不是随意延迟时间,有多个等级对应不同的延时时间

  • Level1:1s
  • Level2:5s
  • Level3:10s
  • Level4:30s
  • Level5:1min
  • Level6:2min
  • Level7:3min
  • Level8:4min
  • Level9:5min
  • Level10:6min
  • Level11:7min
  • Level12:8min
  • Level13:9min
  • Level14:10min
  • Level15:20min
  • Level16:30min
  • Level17:1hour
  • Level18:2hour
java 复制代码
message.setDelayTimeLevel(3);

批量发送

RocketMQ 支持批量发送消息,示例如下:

java 复制代码
String topic = "BatchTest";
List<Message> messages = new ArrayList<>();
messages.add(new Message(topic, "TagA", "OrderID001", "Hello world 0".getBytes()));
messages.add(new Message(topic, "TagA", "OrderID002", "Hello world 1".getBytes()));
messages.add(new Message(topic, "TagA", "OrderID003", "Hello world 2".getBytes()));
producer.send(messages);

使用 log 发送

RocketMQ支持使用日志的格式生产消息,支持 log4j、log4j2、logback等,示例如下:

java 复制代码
<appender name="mqAppender1" class="org.apache.rocketmq.logappender.logback.RocketmqLogbackAppender">
    <tag>yourTag</tag>
    <topic>yourLogTopic</topic>
    <producerGroup>yourLogGroup</producerGroup>
    <nameServerAddress>yourRocketmqNameserverAddress</nameServerAddress>
    <layout>
        <pattern>%date %p %t - %m%n</pattern>
    </layout>
</appender>

<appender name="mqAsyncAppender1" class="ch.qos.logback.classic.AsyncAppender">
    <queueSize>1024</queueSize>
    <discardingThreshold>80</discardingThreshold>
    <maxFlushTime>2000</maxFlushTime>
    <neverBlock>true</neverBlock>
    <appender-ref ref="mqAppender1"/>
</appender>

消息消费

消费方式

pull 消费

客户端手动去拉取消息,示例如下

java 复制代码
DefaultMQPullConsumer consumer = new DefaultMQPullConsumer("consumer_first");
PullResult pullResult = consumer.pullBlockIfNotFound(mq, null, getMessageQueueOffset(mq),32);

push 消费

实质还是pull的方式,不过跟消费者保持了长连接,如果有消息产生就会让消费者去消费。

java 复制代码
DefaultMQPushConsumer consumer = new DefaultMQPushConsumer("consumer_first");
consumer.subscribe("rocket_first", "tag-a");
consumer.registerMessageListener((MessageListenerConcurrently) (list, consumeConcurrentlyContext) -> {
     list.forEach(me -> System.out.println("push: " + new String(me.getBody()) + "\n"));
     return ConsumeConcurrentlyStatus.CONSUME_SUCCESS;
});

消费类型

广播消费(BROADCASTING)

类似于ActiveMQ中的发布订阅模式,消息会发给Consume Group中的每一个消费者进行消费。

java 复制代码
consumer.setMessageModel(MessageModel.BROADCASTING);

集群消费(CLUSTERING)

一个 ConsumerGroup 中的 Consumer 实例平均分摊消费生产者发送的消息。

java 复制代码
consumer.setMessageModel(MessageModel.CLUSTERING);

注意:

如果有多个 ConsumerGroup 订阅相同的 topic,则每个 ConsumerGroup 都会消费相同的消息。

消息过滤

标签过滤

常见的过滤方式,示例如下:

java 复制代码
// 方法一:
consumer.subscribe("rocket_first", "tag-a");
// 方法二:
consumer.subscribe("rocket_first", MessageSelector.byTag("tag-a || TAGB"));

SQL92过滤

支持SQL92语法方式过滤,支持的语法如下

  • 数字比较,例如:>、>=、<、<=、BETWEEN、= 等
  • 字符串比较,例如:=、<>、IN 等
  • IS NULL 或 IS NOT NULL
  • 逻辑比较,例如:AND、OR、NOT

举例如下:

java 复制代码
// 生产者
message.putUserProperty("a", "1");
producer.send(message);

// 消费者
consumer.subscribe("rocket_first", MessageSelector.bySql("a < 2"));

如果消费者端报【The broker does not support consumer to filter message by SQL92】,请在 broker 的配置文件里添加如下配置:

xml 复制代码
enablePropertyFilter=true

然后重启下 broker 即可。

参考

相关推荐
RemainderTime5 天前
(七)Spring Cloud Alibaba 2023.x:RocketMQ 消息队列配置与实现
后端·spring cloud·微服务·rocketmq
你啊我啊你好6 天前
常用的消息中间件(ActiveMQ、RabbitMQ、RocketMQ、Kafka)面试精华
rabbitmq·rocketmq·activemq
Hello-Brand6 天前
RocketMQ系列3:核心技术介绍
消息队列·rabbitmq·rocketmq·mq·消息中间件·削峰填谷
_BugMan7 天前
【业务场景】订单超时取消的各种方案
redis·java-ee·rocketmq
Ch.yang10 天前
【架构】从 Socket 的角度认识非阻塞模型
tomcat·rocketmq
码农老起10 天前
从RocketMQ到Dubbo:自研中间件技术的崛起
中间件·dubbo·rocketmq
Steven_Mmm12 天前
关于消息队列性能是否能接收 5 万个 MQ
kafka·rocketmq
小范馆12 天前
RocketMQ面试题合集
java·rocketmq·java-rocketmq
菜菜-plus13 天前
Kafka | RabbitMQ | RocketMQ | ActiveMQ 的区别和入门案例
kafka·rabbitmq·rocketmq
Hello-Brand17 天前
RocketMQ系列2:领域模型和技术概念
消息队列·rocketmq·消息中间件