文章目录
前言
Apache RocketMQ 是一款由阿里巴巴开发并开源给 Apache 软件基金会的分布式消息中间件。这款消息中间件以其高性能、高吞吐量、低延迟和高可靠性而著称,并且能够支持大规模的数据处理。
主要特点:
- 发布/订阅模型:RocketMQ 支持传统的点对点消息模型以及发布/订阅模型,使得多个消费者可以接收同一个消息。
- 事务消息:RocketMQ 支持金融级别的事务消息处理能力,确保消息的强一致性。
- 高可用性:RocketMQ 设计有容错机制,能够在节点故障时继续提供服务。
- 弹性伸缩:在大规模消息处理场景下,RocketMQ 能够实现平滑的水平扩展。
- 消息顺序保障:RocketMQ 在某些场景下可以保证消息的全局顺序或分区内的局部顺序。
- 消息拉取模式:RocketMQ 提供了多种消息拉取策略,以适应不同的应用场景。
架构组件:
- Producer:消息生产者,负责向 Broker 发送消息。
- Broker:消息服务器,负责存储消息并转发给 Consumer。
- Consumer:消息消费者,负责从 Broker 接收并处理消息。
- NameServer:名称服务,负责管理集群的配置信息,帮助客户端发现 Broker。
消费模式:
- 集群消费:消息会被集群中的不同消费者消费,每个消息只被集群中的一个消费者消费。
- 广播消费:所有消息都会被集群中的每一个消费者消费。
使用场景:
- 消息通知:用于重要的通知、短信通知等需要确保消息可靠投递的场景。
- 日志聚合:收集来自不同系统的日志数据,并聚合到统一的日志处理系统中。
- 服务解耦:在微服务架构中作为服务间通信的桥梁,提高系统的灵活性和可扩展性。
- 流量削峰:在高并发场景下,利用消息队列缓存请求,平滑负载。
一、RocketMQ 的基本架构
1、NameServer
NameServer 是一个无状态的服务器,角色类似于 Kafka使用的 Zookeeper,但比 Zookeeper 更轻量。
- 每个 NameServer 结点之间是相互独立,彼此没有任何信息交互。
- Nameserver 被设计成几乎是无状态的,通过部署多个结点来标识自己是一个伪集群,Producer 在发送消息前从 NameServer 中获取 Topic 的路由信息也就是发往哪个 Broker,Consumer 也会定时从 NameServer 获取 Topic 的路由信息,Broker 在启动时会向 NameServer 注册,并定时进行心跳连接,且定时同步维护的 Topic 到 NameServer。
- 和Broker 结点保持长连接。
- 维护 Topic 的路由信息。
2、Broker
消息存储和中转角色,负责存储和转发消息。
- Broker 内部维护着一个个 Consumer Queue,用来存储消息的索引,真正存储消息的地方是 CommitLog(日志文件)。
- 单个 Broker 与所有的 Nameserver 保持着长连接和心跳,并会定时将 Topic 信息同步到NameServer,和 NameServer 的通信底层是通过 Netty 实现的。
3、Producer
消息生产者,业务端负责发送消息,由用户自行实现和分布式部署。
- Producer由用户进行分布式部署,消息由Producer通过多种负载均衡模式发送到Broker集群,发送低延时,支持快速失败。
- RocketMQ 提供了三种方式发送消息:同步、异步和单向
- 同步发送:同步发送指消息发送方发出数据后会在收到接收方发回响应之后才发下一个数据包。一般用于重要通知消息,例如重要通知邮件、营销短信。
- 异步发送:异步发送指发送方发出数据后,不等接收方发回响应,接着发送下个数据包,一般用于可能链路耗时较长而对响应时间敏感的业务场景,例如用户视频上传后通知启动转码服务。
- 单向发送:单向发送是指只负责发送消息而不等待服务器回应且没有回调函数触发,适用于某些耗时非常短但对可靠性要求并不高的场景,例如日志收集。
4、Consumer
消息消费者,负责消费消息,一般是后台系统负责异步消费。
- Consumer也由用户部署,支持PUSH和PULL两种消费模式,支持集群消费和广播消费,提供实时的消息订阅机制。
- Pull:拉取型消费者(Pull Consumer)主动从消息服务器拉取信息,只要批量拉取到消息,用户应用就会启动消费过程,所以 Pull 称为主动消费型。
- Push:推送型消费者(Push Consumer)封装了消息的拉取、消费进度和其他的内部维护工作,将消息到达时执行的回调接口留给用户应用程序来实现。所以 Push 称为被动消费类型,但其实从实现上看还是从消息服务器中拉取消息,不同于 Pull 的是 Push 首先要注册消费监听器,当监听器处触发后才开始消费消息。
二、代码测试
1、引入依赖
<dependency>
<groupId>org.apache.rocketmq</groupId>
<artifactId>rocketmq-spring-boot-starter</artifactId>
<version>2.2.1</version>
</dependency>
2、启动 NameServer 和 Broker
nohup sh mqnamesrv &
nohup sh mqbroker -c /home/qyy/rocketmq/rocketmq-5.2.0/conf/broker.conf &
3、相关配置
rocketmq.name-server=http://localhost:9876
rocketmq.producer.group=yoel_qin
rocketmq.producer.send-message-timeout= 30000
4、创建生产者
编写一个POST接口,将请求体里面的json数据发送到消息队列
@RestController
public class ProducerController {
private static final Logger log = LoggerFactory.getLogger(ProducerController.class);
@Autowired
private RocketMQTemplate rocketMQTemplate;
@PostMapping("/sendMessage")
public String sendMessage(@RequestBody FrontEvent frontEvent) {
String json = JSON.toJSONString(frontEvent);
SendResult sendResult = rocketMQTemplate.syncSend("topic1", json);
log.info("Send message=========={}",json);
return sendResult.getSendStatus().toString();
}
}
5、创建消费者
@Component
@RocketMQMessageListener(topic = "topic1", consumerGroup = "consumer_yoel_qin")
public class Consumer implements RocketMQListener<String> {
private static final Logger log = LoggerFactory.getLogger(Consumer.class);
@Override
public void onMessage(String message) {
try {
FrontEvent frontEvent = JSON.parseObject(message, FrontEvent.class);
log.info("Received message=========={}", frontEvent.toString());
// 保存到数据库
// frontEventRepository.save(frontEvent);
} catch (Exception e) {
// 如果发生异常,则事务回滚,消息不会被确认,会重试
log.error("Failed to process the message: {}", message, e);
}
}
}