《RocketMQ实战与原理解析》总结 from xichaodong

《RocketMQ实战与原理解析》总结

1.消息队列的作用

解耦:服务之间使用MQ做中介进行通信,服务间不直接调用,互不影响

异步:通过消息实现业务的异步

削峰:MQ本身相当于一个buffer,能够用来平衡生产者和消费者之间的速率

至于其他的延迟消息、事务消息、顺序消息是具体产品的附加功能,不是MQ本身的主要功能
2.阿里MQ中间件发展历史

2007年Notify,推模型,解决了事务消息

2010年Napoli

2011年MetaQ,拉模型,解决了顺序消息和海量堆积

2012年RocketMQ,长轮询的拉模型

2016年RocketMQ开源

2017年双十一RocketMQ承担万亿级消息流转

3.MQ部署和运维命令:https://github.com/apache/rocketmq/blob/master/docs/cn/operation.md
4.控制台部署:https://github.com/apache/rocketmq-dashboard
5.名词解释

Producer:消息生产者

Consumer:消息消费者

Consumer Group:一类消费者的统称,注册时以消费者组为单位

Broker:MQ本身服务,支持主从

Topic:生产者生产消息和消费者消费消息的媒介,发送消息是投到指定的topic,消费消息也是消费指定topic中的消息

Message Queue:Message Queue是Topic的数据分片,每个topic有多个Message Queue,Topic中的数据会分散在内部的Message Queue中

Offset:指某条消息在Message Queue中的具体位置,通过Offset的值能够在Message Queue里定位到这条消息

Tag:同一个Topic的消息可以根据Tag进行再次区分

NameServer:阿里自己实现的轻量级注册中心,功能上类似eureka,提供topic和broker的路由服务

6.消费者类型

DefaultMQPushConsumer:推模式客户端,由系统控制拉取操作,之所以推模式还是用拉的形式是因为RocketMQ用的是拉模型,所谓的推模式只是系统屏蔽了拉取的过程,看起来像是推一样

DefaultMQPullConsumer:拉模式客户端,由用户自己控制拉取操作

7.消息模式

Clustering:集群模式,当一个topic对应多个消费者时,消息会分摊到每个消费者上

Broadcasting:广播模式,当一个topic对应多个消费者时,消息会全量的发送到每个消费者上

8.获取消息的模式

拉模式:客户端主动向broker请求拉取信息,优点是控制权在客户端,可以根据自身运行情况拉取,缺点是拉取间隔不好设定,长了短了都会有问题,同时拉取的代码也需要客户端自己编写

推模式:broker通过长连接主动向客户端推消息,优点是实时性高,且推送逻辑由broker完成,客户端编码简单。缺点是broker负担重,且broker不知道客户端的状态,如果客户端处理速度跟不上会导致消息堆积在客户端

长轮询拉模式:客户端不断的向broker请求拉取信息,如果有消息则即时返回,没有消息则由broker阻塞住该请求或者一定超时时间后才返回。这样就相当于将推和拉进行了一个结合,不仅免去了拉和推模式的各自缺点,同时拥有了各自的优点。RocketMQ使用的是这种方式

9.消费者流量控制

将MessageQueue中还未处理的消息保存成ProcessQueue对象,ProcessQueue内部持有一个TreeMap,key是队列中的位置,value是消息本身

从ProcessQueue中就可以获取到MessageQueue此时的状态,然后和设置的阈值做比较

如果currentQueueCount即当前队列中未处理的消息的总数量大于pullThresholdForTopic时,延迟PULL_TIME_DELAY_MILLS_WHEN_FLOW_CONTROL毫秒再试

如果cachedMessageSizeInMiB即当前队列中未处理的消息的总大小大于pullThresholdForQueue时,延迟PULL_TIME_DELAY_MILLS_WHEN_FLOW_CONTROL毫秒再试

如果当前队列中未处理的消息的偏移量跨度大于consumeMaxSpan时,延迟PULL_TIME_DELAY_MILLS_WHEN_FLOW_CONTROL毫秒再试

pullThresholdForTopic默认1000,pullThresholdForQueue默认100MB,consumeMaxSpan默认2000,PULL_TIME_DELAY_MILLS_WHEN_FLOW_CONTROL默认50ms

10.消息发送结果

SEND_OK:发送成功

FLUSH_DISK_TIMEOUT:没有在规定时间内完成刷盘,此错误只会在broker被设置成同步刷盘时才会出现

FLUSH_SLAVE_TIMEOUT:没有在规定时间内完成主从同步,此错误只会在主从模式下出现

SLAVE_NOT_AVAILABLE:在尝试进行主从同步时找不到从节点

11.延迟消息

发送延迟消息时需要预先设置messageDelayLevel,默认值1s 5s 10s 30s 1m 2m 3m 4m 5m 6m 7m 8m 9m 10m 20m 30m 1h 2h,构造消息时设置delayLevel为对应时间的下标即可

创建延迟消息后会存入专门的以SCHEDULE_TOPIC开头的topic中,根据延迟级别放入对应的queue中

12.指定消息发送到具体的Message Queue

实现MessageQueueSelector接口的select方法,然后在发送消息时把这个selector传进去

13.事务消息

2PC

14.offset存储

对于集群模式,所有消费者的消费进度是共享的,所以进度由broker进行存储

对于广播模式,所有消费者的消费进度是独立的,所以进度由消费者本地存储

15.nameserver清理失效broker的逻辑

长连接断掉时,在channel的回调里移除broker的缓存

每隔10秒检查一次broker上次上报的时间,如果超过两分钟就把broker移掉

16.为什么不用zk而是自己写了个注册中心

zk太重不容易控制,NameServer一共才十个类,逻辑简单更稳定

17.数据存储方式

每个topic下的每一个Message Queue都有一个ConsumeQueue文件,这个文件是消息的索引,文件内容是消息的物理存储地址,一条索引是20字节,默认一个文件存储30万个索引,所以默认文件大小是5.7M

每个broker下有CommitLog文件,文件内容是Consume Queues、Message Key、Tag等所有信息,即使ConsumeQueue丢失,也可以通过commitLog完全恢复出来,默认大小1G,写满了就新增一个,文件名为偏移量

18.broker的高可用

broker通过主从架构实现高可用,主节点能读和写,从节点只能读

消息者不需要指定从主节点读还是从从节点读,当master不可用或者繁忙的时候会自动切换到从节点读

4.5.0版本开始,RocketMQ支持Dledger模式,使用Raft算法进行选举,能够实现主从切换

19.刷盘方式

同步刷盘:消息内容写入PageCache后立刻进行刷盘,刷盘成功后返回成功

异步刷盘:消息内容写入PageCache后就返回成功,当PageCache堆积到一定程度时再统一刷盘

20.主从同步方式

同步复制:主从必须都写成功才返回给客户端成功

异步复制:主节点写入成功就返回成功,后续再异步复制到从节点

21.同步设置的最佳实践

异步刷盘 + 同步复制

22.顺序消息

全局顺序消息:即全局所有消息均有顺序,topic中只有一个Message Queue,消费者和生产者也不能并发

局部顺序消息:即一组消息有顺序,这个功能需要生产者和消费者配合,生产者实现MessageQueueSelector确保同一组消息放入同一个Message Queue中,消费者注册listener的时候需要实现MessageListenerOrderly保证同一个Message Queue中的消息不会被并发消费,MessageListenerOrderly内部对每一个Queue加了一把锁

23.消息重复消费的解决方案

维护一张本地消息已消费集合,把已经消费过的消息维护起来,消费前先查一下

让消费逻辑本身幂等

24.数据可靠性

Broker正常启动和关闭:不会有消息丢失

Broker异常关闭或操作系统异常关闭或机器断电:设置成同步刷盘不会有消息丢失

磁盘等硬件损坏:主从之间设置同步复制不会有消息丢失

25.消息优先级

情景假设,有A,B,C三种消息在同一个Topic中,A,B的量特别大,导致C消费不到,现在想要消费机会均等或者C先消费

第一种方案,按Topic拆分

第二种方案,按Message Queue拆分,然后消费者用拉的方式从Queue中取消息,这样就可以由消费者自主决定消费优先级

26.增大消费者吞吐量的方案

使用Tag/Filter Server 在broker端就进行消息过滤,避免消费者接收到无用的消息

增加消费者线程数

设置消费者批量拉取消息,而不是一次拉一条

发生堆积时,若业务允许则跳过堆积的消息

27.消费者负载均衡的方案

情景假设,6条消息分别为1,2,3,4,5,6,然后有2个消费者,分别为消费者1和消费者2

平均分配策略(默认)(AllocateMessageQueueAveragely):消费者1消费消息1,2,3,消费者2消费消息4,5,6

环形分配策略(AllocateMessageQueueAveragelyByCircle):消费者1消费消息1,3,5,消费者2消费消息2,4,6

手动配置分配策略(AllocateMessageQueueByConfig):该策略内部有个setMessageQueueList方法,可以指定消费哪个Message Queue

机房分配策略(AllocateMessageQueueByMachineRoom):多机房时,只负载指定机房的Message Queue,要求broker名字为“机房名@brokerName”,设置方式为setConsumeridcs方法

一致性哈希分配策略(AllocateMessageQueueConsistentHash):按Consumer的名字做hash,遵循一致性hash的算法进行消费的分发

详细解释:https://blog.csdn.net/qq_38082304/article/details/112378245

28.增大生产者吞吐量的方案

可靠性要求不高的场景可以使用OneWay发送

增大Producer数量,并发发送。RocketMQ使用并发窗口解决了并发写降低写入效率的问题

阿里内部的RocketMQ经过调优写入可达90万+TPS

Linux的文件日志系统使用EXT4,EXT4创建/删除文件的性能比EXT3及其他文件系统要好,适用于RocketMQ这种频繁创建删除的服务

Linux的IO调度算法使用deadline,通过超时队列提高吞吐量

29.调优流程

逐步增大请求量

等待QPS到达峰值

维持峰值观察硬件情况,top看cpu和内存,sar看网卡

30.Nameserver工作流程

入口NamesrvStartup的主函数,解析命令行参数,初始化NamesrvController

NamesrvController开8个线程用于处理命令、1个定时任务扫描失效的broker、1个定时任务打印配置信息,注册DefaultRequestProcessor为请求处理器

DefaultRequestProcessor内部用一个switch case做分发,通过判断request命令中的code调用不同的方法完成命令的处理,code维护在RequestCode里

RouteInfoManager是维护集群元数据信息的类,里面有各种各样的map用来缓存broker、topic、queue的映射关系,通过可重入的读写锁控制线程安全

  • 4
    点赞
  • 7
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值