文章目录
-
- 什么是RocketMQ
-
- RocketMQ组成和工作流程
-
- NameServer
- Broker
- Producer
- Consumer
- 下载
- bin项目启动
- 代码项目启动
- 收发消息
-
- 同步消息
- 异步消息
- 单发消息
- 顺序消息
- 延时消息
- 事务消息
- 广播消费和集群消费
- 消费者组
什么是RocketMQ
- RocketMQ属于消息中间件的一种(Message Queue),支持十万级以上的容量,主要作用是用来进行异步处理,削峰,解耦等
- 异步:异步操作数据。比如在一个消耗物品的场景下,消费物品100ms,记录日志50ms,那么加起来就是150ms,如果再加新功能可能会更慢。如果使用异步那么我们只需要消费物品然后把后边任务放入队列直接返回就只使用100ms就可以。
- 削峰:削弱峰值流量。如果某一个时间点流量特别大的话有可能系统会宕机,那么在这种情况下可以把请求丢进消息队列中,类似于一个缓冲区,然后按照系统消费速度来进行消费的话就不会宕机。
- 解耦:解耦系统。如果代码耦合的比较严重的情况下,比如A调用B的情况下,修改A的代码B可能要随着一起被改变。但是如果解耦的话A调用消息队列,消息队列调用B,那么A不是直接调用B所以修改A时有可能不用修改B。
RocketMQ组成和工作流程
NameServer
- 是一个无状态的节点,可以集群,但相互之间没有信息互通,主要功能有两一个,一个是Broker管理,NameServer接受Broker集群的注册信息并且保存下来作为路由信息的基本数据。然后提供心跳检测机制,检查Broker是否还存活;路由信息管理,每个NameServer将保存关于Broker集群的整个路由信息和用于客户端查询的队列信息。
- 工作流程:启动后相当于一个路由控制中心,等待其余角色连接
Broker
- 主要负责消息的存储、投递和查询以及服务高可用保证.
- 工作流程:启动后会向NameServer建立长链接并定时30s发送心跳包,心跳包包含自己的BrokerId和存储的Topic信息,如果NameServer是集群那么会向所有的NameServer建立长连接,
Producer
- 消息发布的角色,支持分布式集群方式部署。Producer通过MQ的负载均衡模块选择相应的Broker集群队列进行消息投递,投递的过程支持快速失败并且低延迟。
- 工作流程:发送消息时会负载均衡的跟一个NameServer建立长连接,然后通过NameServer找到需要发送的Topic对应的Broker,然后向对应的Broker发送消息
Consumer
- 消息消费的角色,支持分布式集群方式部署。支持以push推,pull拉两种模式对消息进行消费。同时也支持集群方式和广播方式的消费,它提供实时消息订阅机制,可以满足大多数用户的需求。
- 工作流程:启动时获取订阅的Topic在那个Broker上,然后找到Broker开始消费消息
下载
- RocketMQ下载地址
- bin是可以直接运行的代码,source是源代码,两种都可以启动(以下简称bin和代码)
bin项目启动
- 在环境变量配置ROCKETMQ_HOME
- 配置自己的地址
- 然后在bin目录下进入cmd页面,先启动NameServer再启动Broker
- NameServer: start mqnamesrv.cmd
- Broker: start mqbroker.cmd -n localhost:9876 autoCreateTopicEnable=true
- autoCreateTopicEnable:true为自动创建Topic
代码项目启动
- 编译完项目以后把distribution下的conf里的两个文件粘过来,在创建一下对应的目录
- 然后修改broker.conf配置,修改为自己对应的路径
storePathRootDir=D:\\Users\\jianhe\\Desktop\\rocket\\namesrv\\store
#commitlog 存储路径
storePathCommitLog=D:\\Users\\jianhe\\Desktop\\rocket\\namesrv\\store\\commitlog
#消费队列存储路径
storePathConsumeQueue=D:\\Users\\jianhe\\Desktop\\rocket\\namesrv\\store\\consumequeue
#消息索引存储路径
storePathIndex=D:\\Users\\jianhe\\Desktop\\rocket\\namesrv\\store\\index
#checkpoint文件存储路径
storeCheckPoint=D:\\Users\\jianhe\\Desktop\\rocket\\namesrv\\store\\checkpoint
#abort文件存储路径
abortFile=D:\\Users\\jianhe\\Desktop\\rocket\\namesrv\\store\\abort
- 在配置一下启动的环境变量,启动就ok
- broker同理,但是要修改一下config的配置
收发消息
<dependency>
<groupId>org.apache.rocketmq</groupId>
<artifactId>rocketmq-spring-boot-starter</artifactId>
<version>2.0.4</version>
</dependency>
rocketmq:
name-server: localhost:9876
producer:
group: my-group
同步消息
@RestController
public class Producer {
@Autowired
RocketMQTemplate rocketMQTemplate;
@PostConstruct
public void sendMessage() {
SendResult syncSendResult = rocketMQTemplate.syncSend("test:tagA","hello rocketmq" );
}
@Component
@RocketMQMessageListener(topic = "test",consumerGroup = "consumer",
selectorExpression = "tagA")
class ConsumerTest implements RocketMQListener<String> {
@Override
public void onMessage(String str) {
System.out.println(str);
}
}
}
- 输出内容
异步消息
@RestController
public class Test{
@Autowired
RocketMQTemplate rocketMQTemplate;
@PostConstruct
public void sendMessage() {
rocketMQTemplate.asyncSend("test:tagA", "hello rocketmq", new SendCallback() {
@Override
public void onSuccess(SendResult sendResult) {
System.out.println(sendResult);
}
@Override
public void onException(Throwable e) {
System.out.println(e);
}
});
}
@Component
@RocketMQMessageListener(topic = "test",consumerGroup = "consumer",
selectorExpression = "tagA")
class ConsumerTest implements RocketMQListener<String> {
@Override
public void onMessage(String str) {
System.out.println(str);
}
}
}
- 输出内容
单发消息
@RestController
public class Test{
@Autowired
RocketMQTemplate rocketMQTemplate;
@PostConstruct
public void sendMessage() {
rocketMQTemplate.sendOneWay("test:tagA","hello rocketmq");
}
@Component
@RocketMQMessageListener(topic = "test",consumerGroup = "consumer",
selectorExpression = "tagA")
class ConsumerTest implements RocketMQListener<String> {
@Override
public void onMessage(String str) {
System.out.println(str);
}
}
}
顺序消息
- 顺序消息就是保证消息的顺序性,如果下单场景,下单->支付->发货,像这种保证顺序才有意义的场景下可以使用顺序消息
@RestController
public class Test{
@Autowired
RocketMQTemplate rocketMQTemplate;
@PostConstruct
public void sendMessage() {
buildOrders().forEach( order -> {
rocketMQTemplate.syncSendOrderly("test:tagE",order,order.getOrderId() + "");
});
}
@Component
@RocketMQMessageListener(topic = "test",consumerGroup = "order",
selectorExpression = "tagE",consumeMode = ConsumeMode.ORDERLY)
class OrderTest implements RocketMQListener {
@Override
public void onMessage(Object o) {
System.out.println("线程:" +Thread.currentThread().getId() + "消息体:" + o);
}
}
@Data
private static class OrderStep {
private long orderId;
private String desc;
}
private static List<OrderStep> buildOrders() {
List<OrderStep> orderList = new ArrayList<OrderStep>();
OrderStep orderDemo = new OrderStep();
orderDemo.setOrderId(15103111039L);
orderDemo.setDesc("创建");
orderList.add(orderDemo);
orderDemo = new OrderStep();
orderDemo.setOrderId(15103111065L);
orderDemo.setDesc("创建");
orderList.add(orderDemo);
orderDemo = new OrderStep();
orderDemo.setOrderId(15103111039L);
orderDemo.setDesc("付款");
orderList.add(orderDemo);
orderDemo = new OrderStep();
orderDemo.setOrderId(15103117235L);
orderDemo.setDesc("创建");
orderList.add(orderDemo);
orderDemo = new OrderStep();
orderDemo.setOrderId(15103111065L);
orderDemo.setDesc("付款");
orderList.add(orderDemo);
orderDemo = new OrderStep();
orderDemo.setOrderId(15103117235L);
orderDemo.setDesc("付款");
orderList.add(orderDemo);
orderDemo = new OrderStep();
orderDemo.setOrderId(15103111065L);
orderDemo.setDesc("完成");
orderList.add(orderDemo);
orderDemo = new OrderStep();
orderDemo.setOrderId(15103111039L);
orderDemo.setDesc("推送");
orderList.add(orderDemo);
orderDemo = new OrderStep();
orderDemo.setOrderId(15103117235L);
orderDemo.setDesc("完成");
orderList.add(orderDemo);
orderDemo = new OrderStep();
orderDemo.setOrderId(15103111039L);
orderDemo.setDesc("完成");
orderList.add(orderDemo);
return orderList;
}
}
- 输出日志,可以看出一个订单由同一个线程来消费,就保证了顺序
延时消息
@RestController
public class Test{
@Autowired
RocketMQTemplate rocketMQTemplate;
@PostConstruct
public void sendMessage() {
SendResult syncTimeSendResult = rocketMQTemplate.syncSend("test:tagA",new GenericMessage<>("hello rocketmq"),100000,4);
}
@Component
@RocketMQMessageListener(topic = "test",consumerGroup = "consumer",
selectorExpression = "tagA")
class ConsumerTest implements RocketMQListener<String> {
@Override
public void onMessage(String str) {
System.out.println(str);
}
}
}
事务消息
@RestController
public class Test{
@Autowired
RocketMQTemplate rocketMQTemplate;
@PostConstruct
public void sendMessage() {
rocketMQTemplate.sendMessageInTransaction("testProducer","test:tagA", new GenericMessage<>("hello"),null);
}
@Component
@RocketMQTransactionListener(txProducerGroup = "testProducer")
class TransactionTest implements RocketMQLocalTransactionListener {
@Override
public RocketMQLocalTransactionState executeLocalTransaction(Message message, Object o) {
System.out.println("执行事务方法");
return RocketMQLocalTransactionState.UNKNOWN;
}
@Override
public RocketMQLocalTransactionState checkLocalTransaction(Message message) {
System.out.println("执行事务方法未通过,检察事务");
return RocketMQLocalTransactionState.COMMIT;
}
}
@Component
@RocketMQMessageListener(topic = "test",consumerGroup = "consumer",
selectorExpression = "tagA")
class ConsumerTest implements RocketMQListener<String> {
@Override
public void onMessage(String str) {
System.out.println(str);
}
}
}
- 输出日志
广播消费和集群消费
- 广播模式:消费者组中所有的消费者都会消费一次
- 集群模式:一个消费者组只有一个消费者会消费到
- 通过注解的messageModel属性设置,默认集群模式
@RocketMQMessageListener(topic = "test",consumerGroup = "order",selectorExpression = "tagE",
messageModel = MessageModel.BROADCASTING)
消费者组
- 可以将多个消费者指定同一个comsumerGroup来让他们组成一个消费者组
- 一定要保证一个JVM中只有一个组的一个成员
- 比如下边这种两个消费者都指定了同一个消费者组并且在一个JVM中,那么启动会出错,必须分布式的指定为同一个组才可以
@Component
@RocketMQMessageListener(topic = "test",consumerGroup = "consumer",
selectorExpression = "tagA")
public class ConsumerTest1 implements RocketMQListener<String> {
@Override
public void onMessage(String str) {
System.out.println(str);
}
}
@Component
@RocketMQMessageListener(topic = "test",consumerGroup = "consumer",
selectorExpression = "tagA")
public class ConsumerTest2 implements RocketMQListener<String> {
@Override
public void onMessage(String str) {
System.out.println(str);
}
}