- RocketMQ概述
RocketMQ 是一款分布式、队列模型的消息中间件,具有以下特点: 能够保证严格的消息顺序 提供丰富的消息拉取模式 高效的订阅者水平扩展能力 实时的消息订阅机制 亿级消息堆积能力。
阿里巴巴开源其自研的第三代分布式消息中间件,目前双十一当天消息容量可达到万亿级。
- RocketMQ原理
NameServer : 保存broker的信息,并监听borker的心跳,将供Producer和Consumer获取Broker地址。如监听到master不可用,则将salve设为新的主broker。类似于注册中心,默认端口10911
Broker : 定时将borke的Topic信息到注册到Name Server中。Broker以group分开,每个group只允许一个master,多个slave。 只有master才能进行写入操作。默认端口9876
Producer : producer从NameServer获取broker的连接信息,通过连接信息连接对应的broker, 发送消息
Consumer : consumer从NameServer获取broker的连接信息,通过连接信息连接对应的broker, 进行消费
rocker采用分区存储,将消息分开存放在master节点的分区内,然后slave节点同步对应master的数据。
Kafka是采用zk实现对生产者、消费者 topic信息存储,而RocketMQ是自己实现叫做nameServer实现去中心化
默认一个borker有4个队列,可配置 - RocketMQ优点
a.强调集群无单点,可扩展
b.任意一点高可用,水平可扩展
c.海量消息堆积能力,消息堆积后,写入低延迟。
d.支持上万个队列
e.消息失败重试机制
f.消息可查询
g.开源社区活跃
h.成熟度高
- RocketMQ安装
--- 安装对应版本的jdk
安装包地址: http://rocketmq.apache.org
- 整合Rocketmq-console控制台
- 下载程序包
- 解压并导入到IDEA
将解压后的rocketmq-console文件导入到IDEA即可
- 修改application.properties的nameserver地址
- 启动项目
访问http://127.0.0.1:8080/#/
- springboot整合rocketmq
- 创建springboot项目
pom.xml引入依赖<dependency> <groupId>org.apache.rocketmq</groupId> <artifactId>rocketmq-spring-boot-starter</artifactId> <version>2.0.3</version> </dependency>
- 在application.yml中配置如下
rocketmq: ###nameServer地址 name-server: 192.168.2.115:9876 producer: group: pitch_groups server: port: 9001
- 创建UserEntity.java
import lombok.Data; @Data public class UserEntity { private Integer id; private String name; public UserEntity(Integer id, String name) { this.id = id; this.name = name; } }
- 生产者
rocket默认会创建主题import com.pitch.entity.UserEntity; import org.apache.rocketmq.spring.core.RocketMQTemplate; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.web.bind.annotation.RequestMapping; import org.springframework.web.bind.annotation.RestController; @RestController public class ProducerController { @Autowired private RocketMQTemplate rocketMQTemplate; private static int id = 0; // 生产者发送消息 @RequestMapping("/send") public String sendMsg() { id++; UserEntity orderEntity = new UserEntity(id,"张三"); // my_topic主题 默认会自动创建 rocketMQTemplate.convertAndSend("my_topic", orderEntity); return "success:"+id; } }
- 消费者
import com.pitch.entity.UserEntity; import org.apache.rocketmq.spring.annotation.RocketMQMessageListener; import org.apache.rocketmq.spring.core.RocketMQListener; import org.springframework.stereotype.Component; /** * @author xiaobo * @Description UserConsumer * @createTime 2020-03-24 19:59 */ @Component // topic:主题 pitch_groups:组 @RocketMQMessageListener(topic = "my_topic", consumerGroup = "pitch_groups") public class UserConsumer implements RocketMQListener<UserEntity> { @Override public void onMessage(UserEntity o) { System.out.println("消费者获取消息:" + o.toString()); } }
- 启动项目
import org.springframework.boot.SpringApplication; import org.springframework.boot.autoconfigure.SpringBootApplication; @SpringBootApplication public class AppRocket { public static void main( String[] args ) { SpringApplication.run(AppRocket.class); } }
- 访问测试
http://127.0.0.1:9001/send
- rocket实现动态扩容
- 如何解决消息顺序问题
- 产生背景
rocket默认一个broker有4个队列
产生背景: 多个队列、或一个队列对应多个消费者。
- 解决思路
1. 生产者 指定消息存放的队列@RequestMapping("/sort") public String sortMsg() throws Exception{ String id = System.currentTimeMillis()+""; Message message1 = new Message("my_topic", JSONObject.toJSONBytes(new UserEntity(id,"添加用户"))); Message message2 = new Message("my_topic", JSONObject.toJSONBytes(new UserEntity(id,"更新用户"))); Message message3 = new Message("my_topic", JSONObject.toJSONBytes(new UserEntity(id,"删除用户"))); sortSend(message1, id); sortSend(message2, id); sortSend(message3, id); return "success"; } void sortSend(Message message, String flag) throws Exception{ rocketMQTemplate.getProducer().send(message , new MessageQueueSelector() { @Override public MessageQueue select(List<MessageQueue> mqs, Message msg, Object arg) { return mqs.get(0); // 指定消息存放在第0个队列 } }, flag); }
2. 消费者 指定一个队列对应一个消费者线程处理import org.apache.rocketmq.common.message.MessageExt; import org.apache.rocketmq.spring.annotation.ConsumeMode; import org.apache.rocketmq.spring.annotation.RocketMQMessageListener; import org.apache.rocketmq.spring.core.RocketMQListener; import org.springframework.stereotype.Component; /** * @author xiaobo * @Description UserConsumer * @createTime 2020-03-24 19:59 */ @Component // topic:主题 pitch_groups:组 ConsumeMode.ORDERLY: 一个队列对应一个线程 consumeThreadMax:消费者最大线程为1 @RocketMQMessageListener(topic = "my_topic", consumerGroup = "pitch_groups" , consumeMode = ConsumeMode.ORDERLY, consumeThreadMax = 1) public class UserConsumer implements RocketMQListener<MessageExt> { @Override public void onMessage(MessageExt m) { String result = new String(m.getBody()); System.out.println("线程:"+Thread.currentThread().getName()+"--队列:"+m.getQueueId()+"--消息:"+result); } }
- 结果