一、RocketMQ概述
简介
RocketMQ 是阿里巴巴开源的分布式消息中间件,现已成为 Apache 软件基金会的顶级项目。支持事务消息、顺序消息、批量消息、定时消息、消息回溯等。
它里面有几个区别于标准消息中件间的概念,如Group、Topic、Queue等。
系统组成则由Producer、Consumer、Broker、NameServer等组件组成。
RocketMQ的作用
1、解耦:
消费者和生产者通过消息队列进行交互,不直接通信
2、异步
生产者只需负责生产消息发送到broker,消费者只需从broker中获取消息执行任务,无需同步等待生产者
3、削峰填谷
在高负载情况下,broker可以充当缓冲区,平滑的处理请求
二、工作原理
1、基本概念
1、1 message
message是消息队列中所传输的消息,是生产和消费的最小单位,每条消息必须属于一个主题
1、2 topic
topic是一类消息的集合,是消息订阅的基本单位
1、3 tag
tag是消息设置的标签,用于区分同一topic下不同类型的消息
1、4 queue
queue是topic中实际存储消息的物理实体,一个topic中有多个queue
1、5 producer
生产者,消息发布的角色,通过mq的负载均衡策略选择相应的broker队列进行消息投递
1、6 consumer
消费者,通过pull或push策略从broker中获取消息
1、7 brokerserver
负责消息的存储,分发以及服务的高可用保证(将消息存储到磁盘中)
1、8 nameServer
是每个broker的注册中心,同时提供心跳检测来检查broker是否存活,存储着每个broker集群的路由信息,使得每个消费者和生产者都能准确的找到broker进行消息的消费和传递
2、工作流程
1)启动nameserver,它会开始监听端口,等待broker,producer和consumer连接
2)启动broker,它会向所有的nameserver建立连接,每隔30秒发送心跳包,包含topic信息
3)producer与nameserver建立连接并获取broker的信息,根据算法策略选择一台broker建立连接推送消息
4)consumer与nameserver建立连接,获取所订阅的topic路由信息,与broker建立连接选择一个queue开始消费消息
3、消息的存储
消息在磁盘中如何存储?
1、commitlog文件,它是消息主体以及元数据的存储主体,存储生产端写入的消息主体内容,包括消息本身的内容数据,消息的topic,消息所在的queue的ID,消息生产者的IP和端口号等
2、consumeQueue文件:记录消息在commitlog文件中的起始位置,存储的长度,消息tag的hashcode,相当于一个索引文件,方便我们快速查找在commitlog中的消息
3、indexFile:提供了一种可以通过key或时间区间来查询消息的方法
消息存储的刷盘机制
RocketMQ 在将消息写到CommitLog文件中时并不是直接就写到文件中,而是先写到PageCache,也就是前面说的内核缓存区
同步刷盘:当broker将消息写入到PageCache时,会等待异步线程将消息成功刷到磁盘上再返回给生产者说消息存储成功
异步刷盘(默认方式):broker将消息写入到PageCache后,就直接返回给生产者说消息存储成功,然后通过另一个线程将消息刷到磁盘上,
三、RocketMQ的消息类型
普通消息
一般来说发送的消息都是普通消息,采用同步发送(producer发送消息后必须等待收到broker返回的ack确认后才能发送下一条消息),异步发送(无需等待ack,但是broker在收到后还是会发送ack确认),单向传输(仅发送消息,不等待,无ack确认)三种方式发送
顺序消息
顺序消息是指消费顺序和产生顺序相同,分为
全局顺序消息:某个topic下的所有消息都要保证顺序,需要控制topic的写队列数为1,生产者和消费者的并发设置也为1,即消除所有的并发处理,设置程单线程
部分顺序消息:只需要保证每一组的消息被顺序消费,比如订单消息,只要保证同一订单ID消息按顺序消费即可
延迟消息
当消息写入到broker中,在指定的时间后才可被消费处理的消息
事务消息
半消息:是指还不能被consumer消费的消息,只有等producer执行完本地事务经二次确实后才能被消费
批量消息
生产者进行消息发送时可以一次发送多条消息,需要注意:批量发送的消息必须具有相同的topic,刷盘策略,不能是延迟消息和事务消息
四、常见问题及解决
重复消费
原因:
1)网络抖动,消费者异常,消费确认丢失,这三个都是由于消费者产生的消费确认消息没有成功的被broker接收
2)从消费模式来看:采用广播模式时,所有注册的消费者都会收到每一条消息,如果没有适当的去重,会导致消息被重复消费;采用负载均衡模式时,如果一个topic被多个consumer消费,也可能会导致重复消费
解决:
1)幂等性设计:在业务逻辑中加入幂等性设计,确保即使消息被重复消费也不会导致业务状态的改变(可以使用全局id或版本号来标识请求,确保同一请求只会被处理一次)
2)分布式锁:使用分布式锁来确保同一时间同一消息只能被一个消费者处理
3)消息确认机制:避免因确实丢失导致消息被重新发送,使用手动确认
4)使用事务:通过事务,确保消息的一致性和准确性
5)优化网络环境
消费堆积
原因:
生产者生产消息太快,消费者处理能力不足,消费者长时间阻塞(缺少io资源),消费者故障,(消息重试机制和死信队列)
解决:
消费者层面:增加消费者实例(写死),动态扩展消费者(动态)
broker层面:调整消费者拉取频率(加快拉取),定期清理过期消息
消息丢失
原因:
生产者网络波动,消息未及时持久化,磁盘损坏,消费者提前确认消息消费,消息轨迹丢失
解决:
使用事务消息,生产者采用同步发送模式(收到broker确实消息后再发送第二条消息),增加重试机制,配置合理的刷盘策略,采用手动模式(消费者消费完后再发送消费确认消息到broker,自动模式时broker过一段时间会自动确认)
五、常见四大消息队列选择
由于ActiveMQ和RabbitMQ的吞吐量小,只有万级,一般现在都不考虑这两个,
RocketMQ和Kafka都是十万级的吞吐量,二者都是目前各大公司常用的消息队列,RocketMQ在支持的topic到达几百几千时吞吐量会有小幅度下降,而Kafa在topic到达几十到几百个时,吞吐量会大幅度下降