一.消息中间件
1.1消息中间件本质
一次RPC变成两次RPC、内容存储和择机投递;基于消息的通信模式,从关注处理到关注通知。
1.2 消息中间件的使用场景
- 解耦
解耦是消息中间件解决的最本质问题,核心业务只关心通知,不关心处理结果
- 最终一致性
可以用消息中间件实现微服务之间状态的最终一致性(只是理论上的,实际集群环境相当恶劣,宕机和假死频繁发生)
- 广播
微服务之间消息的订阅和发布及集群消息
- 错峰和限流
缓冲高并发请求洪峰,解决微服务机器网卡短板以及微服务db资源连接存在上限的问题
二.Rocketmq消息中间件
2.1Rocketmq物理集群架构
- NameServer节点无状态,节点之间不存在同步通信,通常都是集群部署
- Broker部署区分Master和Slave,一个Master可以对应多个Slave,但是一个Slave只能对应一个Master;集群中Master和Slave是通过指定相同的BrokerName,不同的BrokerId来唯一确定主从关系;BrokerId为0表示Master,非0表示Slave,Master是可以多个部署的;每个Broker与NameServer集群中所有节点建立长连接,定时的注册Topic信息到所有NameServer。
- Producer与NameServer集群随机一个节点建立长连接,定时的从NameServer取Topic路由信息,并向提供Topic服务的Master建立长连接,且定时向Master发送心跳,Producer无状态,可以集群部署。
- Consumer与Name Server集群随机一个节点建立长连接,定期从NameServer取Topic路由信息,并向提供Topic服务的Master、Slave建立长连接,且定时向Master、Slave发送心跳,Consumer既可以从Master订阅消息,也可以从Slave订阅消息,订阅规则由Broker配置决定。
2.2 Rocketmq逻辑结构
- Producer Group发送消息组,一个Producer Group包含多个Producer实例,可以是分布式的多机器,可以是一台机器的多进程,或者是一个进程的多个Producer对象。一个Producer Group可以发送多个Topic消息。
Producer Group可以标识一类Producer,发送分布式事务消息时,如果Producer意外宕机,Broker会主动回调Producer Group内任意一台机器来确认事务状态。
- Consumer Group 消费组,一个Consumer Group下包含多个Consumer实例,可以是多台机器,也可以是多个进程,或者是一个进程的多个Consumer对象;一个Consumer Group下的多个Consumer以均摊方式消费消息,如果设置为广播方式,Consumer Group下每个Consumer实例会消费全量数据。
2.3 Rocketmq功能特性剖析
2.3.1 单机支持 1 万以上持久化队列
单机支持1万以上的持久化队列的方案,尽量让队列轻量化,让单个队列消息负载均衡;对磁盘访问串行化,避免磁盘竞争,导致I/O等待超时。
- 所有数据单独存储到一个 Commit Log,完全顺序写,随机读
- 对最终用户展现的队列实际只存储消息在 Commit Log 的位置信息,并且串行方式刷盘
方案的缺陷:
- 写虽然完全是顺序写,但是读却发成了完全的随机读
- 读一条消息,会先读 Consume Queue,再读 Commit Log,增加了开销
- 要保证 Commit Log 与Consume Queue 完全的一致,增加了编程的复杂度
单机系统配置
- 随机读,尽可能让读命中 PAGECACHE,减少 IO 读操作,所以内存越大越好
- 访问 PAGECACHE 时,即使只访问 1k 的消息,系统也会提前预读出更多数据,在下次读时,就可能命
中内存。
- 随机访问 Commit Log 磁盘数据,系统 IO 调度算法设置为 NOOP 方式,会在一定程度上将完全的随机
读变成顺序跳跃方式,而顺序跳跃方式读较完全的随机读性能会高 5 倍以上。
2. 由于Consume Queue 存储数据量极少,而且是顺序读,在 PAGECACHE 预读作用下,Consume Queue 的读性能几乎与内存一致。
3. Commit Log 中存储了所有的元信息,包含消息体,只要Commit Log在,消息就不会丢失。
2.3.2 刷盘策略
异步刷盘
测试机器顺序写文件,速度可以达到 300M 每秒左右,而线上的网卡一般都为千兆
网卡,写磁盘速度明显快亍数据网络入口速度,可以做到先写内存,后台线程异步刷盘持久化。如果遇到消息洪峰,写入消息到 PAGECACHE 时,如果内存不足,则尝试丢弃干净的 PAGE,腾出内存供新消息使用,策略是 LRU 方式。如果干净页不足,此时写入PAGECACHE会被阻塞,系统尝试刷盘部分数据,大约每次尝试32个PAGE。
同步刷盘
写入 PAGECACHE 后,线程等待,通知刷盘线程刷盘;刷盘线程刷盘后,唤醒前端等待线程,可能是一批线程;前端等待线程向用户返回成功
2.3.3 顺序消息
一个很简单的业务场景:
上游业务单实例Producer发送了消息Message1(订单创建)、Message2(订单付款)和Message3(扣减库存成功),消息消费要保证严格的顺序;下游业务单实例Consumer接收消息,注意消息在网络传输过程中存在网络抖动(极端情况节点宕机,故障恢复需要时间)如何保证消费者方顺序的消费消息。
RocketMq局部顺序消息:因为考虑Broker性能问题,RocketMq只支持分区顺序消息,不能保证全局顺序消息,消费方靠添加MessageListenerOrderly监听器来保证订阅在同一分区上的消费者会严格的按照发送顺序消费消息,如果要保留集群的failover特性,突发节点宕机,就不能保证消息的分区顺序性了,这个就要求业务方做接口幂等或者接口合法性校验(如果流量路由到从节点,分区路由的策略就变了,消息会自动路由到其他分区,导致消息错乱了)。
2.3.4 事务消息
目前RocketMq是支持事务消息的:
其实RocketMq加入分组和单元的概念就是为事务消息做准备的
2.3.5 存储
2.3.5.1 RocketMq Consumer过程使用了零拷贝
- 使用 mmap write 方式 优点:即使频繁调用,使用小块文件传输,效率也很高。缺点:不能很好的利用 DMA 方式,会比 sendfile 多消耗 CPU,内存安全性控制复杂,需要避免 JVM Crash 问题。
- 使用 sendfile 方式 优点:可以利用 DMA 方式,消耗 CPU 较少,大块文件传输效率高,无内存安全新问题 缺点:小块文件效率低亍 mmap 方式,只能是 BIO 方式传输,不能使用 NIO RocketMQ 选择了第一种方式,mmap write 方式,因为有小块数据传输的需求,效果会比 sendfile 更好 2.3.5.2 文件存储 RocketMQ 选择 Linux Ext4 文件系统,原因如下: Ext4 文件系统删除 1G 大小的文件通常耗时小亍 50ms,而 Ext3 文件系统耗时约 1s 左右,且删除文件时,磁盘 IO 压力极大,会导致 IO 写入超时。 文件系统局面需要做以下调优措施 文件系统 IO 调度算法需要调整为 deadline,因为 deadline 算法在随机读业务场景下,可以合幵读请求为顺序跳跃方式,从而提高读 IO 吞吐量。 2.3.5.3 数据存储结构
三.Rocketmq消息中间件的最佳实践
见实例
四.rocketmq集群部署
4.1多Master多slave集群部署 异步复制
准备4台机器,172.16.5.129 172.16.5.130 172.16.5.133 172.16.5.134
master 172.16.5.129
nohup sh bin/mqnamesrv >mqnamesrv.out &
nohup sh bin/mqbroker -c $ROCKETMQ_HOME/conf/2m-2s-async/broker-a.properties &
master 172.16.5.130
nohup sh bin/mqnamesrv >mqnamesrv.out &
nohup sh bin/mqbroker -c $ROCKETMQ_HOME/conf/2m-2s-async/broker-b.properties &
slave 172.16.5.133
nohup sh bin/mqnamesrv >mqnamesrv.out &
nohup sh bin/mqbroker -c $ROCKETMQ_HOME/conf/2m-2s-async/broker-a-s.properties &
slave 172.16.5.134
nohup sh bin/mqnamesrv >mqnamesrv.out &
nohup sh bin/mqbroker -c $ROCKETMQ_HOME/conf/2m-2s-async/broker-b-s.properties &
4.2多master 多slave集群部署 同步复制
准备4台机器,172.16.5.129 172.16.5.130 172.16.5.133 172.16.5.134
master 172.16.5.129
nohup sh bin/mqnamesrv >mqnamesrv.out &
nohup sh bin/mqbroker -c $ROCKETMQ_HOME/conf/2m-2s-sync/broker-a.properties &
master 172.16.5.130
nohup sh bin/mqnamesrv >mqnamesrv.out &
nohup sh bin/mqbroker -c $ROCKETMQ_HOME/conf/2m-2s-sync/broker-b.properties &
slave 172.16.5.133
nohup sh bin/mqnamesrv >mqnamesrv.out &
nohup sh bin/mqbroker -c $ROCKETMQ_HOME/conf/2m-2s-sync/broker-a-s.properties &
slave 172.16.5.134
nohup sh bin/mqnamesrv >mqnamesrv.out &
nohup sh bin/mqbroker -c $ROCKETMQ_HOME/conf/2m-2s-sync/broker-b-s.properties &
4.3多master
准备两台机器 172.16.5.134 172.16.5.135
master 172.16.5.134
nohup sh bin/mqnamesrv >mqnamesrv.out &
nohup sh bin/mqbroker -c $ROCKETMQ_HOME/conf/2m-noslave/broker-b.properties &
master 172.16.5.135
nohup sh bin/mqnamesrv >mqnamesrv.out &
nohup sh bin/mqbroker -c $ROCKETMQ_HOME/conf/2m-noslave/broker-a.properties &
4.4 单点Master
准备一台机器 172.16.5.135
master 172.16.5.135
nohup sh bin/mqnamesrv >mqnamesrv.out &
nohup sh bin/mqbroker $ROCKETMQ_HOME/conf/broker.conf &
4.5 rocketmq集群管理
- mqadmin
sh mqadmin
##查看集群状态
sh mqadmin clusterList -n '172.16.5.129:9876;172.16.5.130:9876;172.16.5.133:9876;172.16.5.134:9876'
##查看broker状态
sh mqadmin
- rocketmq-console(Spring-boot项目)
java -jar rocketmq-console-ng-1.0.0.jar --server.port=12581 —rocketmq.config.namesrvAddr='172.16.5.129:9876;172.16.5.130:9876;172.16.5.133:9876;172.16.5.134:9876'
五 消息队列选型
特性 | ActiveMQ | RabbitMq | RocketMq | Kafka |
---|---|---|---|---|
Producer-Consumer | 支持 | 支持 | 支持 | 支持 |
Publish-Subscribe | 支持 | 支持 | 支持 | 支持 |
API完整性 | 高 | 高 | 高 | 高 |
多语言支持 | 支持 Java优先 | 语言无关 | 只支持Java | 支持 Java优先 |
单机吞吐量 | 万级 | 万级 | 万级 | 十万级 |
消息延迟 | 微妙级 | 毫秒级 | 毫秒级 | |
高可用性 | 高(主从) | 高(主从) | 非常高(分布式) | 非常高(分布式) |
消息丢失率 | 低 | 低 | 理论上不会丢失 | 理论上不会丢失 |
消息重复性 | 业务控制 | 业务控制 | 业务控制 | |
参考文档完整性 | 高 | 高 | 高 | 高 |
提供快速入门 | 有 | 有 | 有 | 有 |
首次部署难度 | 低 | 低 | 低 | 低 |
社区活跃度 | 高 | 高 | 中 | 高 |
商业支持 | 无 | 无 | 阿里云 | 无 |
成熟度 | 成熟 | 成熟 | 比较成熟 | 成熟日志领域 |
特点 | 功能齐全被大量开源项目使用 | 服务端采用Erlang语言,由于Erlang语言的并发能力,性能好,服务端源码学习门槛高 | 分布式扩展设计,主从HA,支持上万个队列,支持PUSH和PULL双从消费模式,性能比较好,服务端使用java,源码学习门槛低 | 分布式扩展设计,支持分片,分组,服务端采用高效的函数式编程语言Scala,并发能力极强,源码学习门槛高。 |
支持协议 | OpenWire、STOMP、REST、XMPP、AMQP | AMOP | 自定义协议 | |
---|---|---|---|---|
持久化 | 内存、文件、数据库 | 内存、文件 | 磁盘文件 | 磁盘文件 |
负载均衡 | 支持 | 支持 | 支持 | 支持 |
管理界面 | 一般 | 好 | Admin命令以及rocketmq-console界面 | |
部署方式 | 独立和嵌入 | 独立 | 独立 | 独立 |
事务 | 支持 | 不支持 | 支持 | 支持 |
评价 | 优点:产品成熟,普及度比较高(非大规模场景),文档较多,学习成本低,支持协议比较多,多语言客户端缺点:大规模队列系统稳定性不好。 | 优点:普及度比较高,特别是金融和电商领域,Erlang并发性能极高,社区活跃度比较高,学习成本低,Spring和SpringBoot以及SpringCloud对RabbitMq的无缝支持缺点:Erlang学习成本高,集群不能动态扩展 | 优点:使用简单,在阿里巴巴已经大规模应用;性能非常好,Broker可以大量的堆积消息;支持多种消费,包括集群消费、广播消费等;支持集群动态扩展缺点:目前网络资源匮乏,阿里只开源了一个半残次品,比较稳定的目前还没有开源。 |
六 rocketmq分布式事务消息原理设计
具体可以查阅接下来的文章。