前言:这是在查看源码时生产者消费者初始化的部分源码的思路的记录
1、mq开启的时候会检查相关配置:生产组是否配置,必须配置且不能为null也不能为DEFAULT_PRODUCER
2、生产者实例名的设置,若未主动设置,则采用默认的配置,生成的实例名(格式):pid@hostname的@符号前的数字使用字符串格式化
3、获得生产者的真正意义上的实例,并且以组名为key值,将其缓存在缓存中(此处,生产者与组应是一一对应),生产组在缓存已存在,不能重复放入,否则失败。
4、topicPublishInfoTable会初始化一个默认的topic信息,TBW102
5、MQ客户端实例开启
6、向所有的broker发送心跳
2. 普通消息发送
1、从缓存获取当前要发送消息的topic的TopicPublishInfo,没有则从nameserver更新
2、缓存的每个生产者都要更新下最新的TopicPublishInfo
3、更新topic的订阅信息
4、在小于重试次数且消息未发送成功的条件下,选取一条消息队列,第一次随机选取,队列=(随机数%(总队列数=各个broker队列数之和)),下次轮询为当前队列数加1下
3. 事物消息发送
1、事物消息发送需要传入一个LocalTransactionExecuter本地回调的函数对象(一阶段开始)
2、校验该函数对象不能为null
3、普通消息发送开始发送消息
4、函数回调,本地事务函数对象执行(一阶段结束,二阶段开始)
5、判断事务是否处理成功,返回类型为[COMMIT_MESSAGE,ROLLBACK_MESSAGE,UNKNOW]
6、设置好请求头,根据返回类型进行相应的响应
事务处理结束(二阶段结束)
commitLog中会存有消息的(topic就叫ThirdTopic),普通的消息描述
ThirdTopic vPGROUPTXPRODUCER_THIRDTOPIC_GROUPTAGSluoyKEYS13951818259UNIQ_KEYC0A85C0B220408FD9B4D62BDB0F00000TRAN_MSGtrue ڣ w_
发送失败还是成功,只剩带事务标记的消息
ThirdTopic vPGROUPTXPRODUCER_THIRDTOPIC_GROUPTAGSluoyKEYS13951818259TRAN_MSGtrueUNIQ_KEYC0A85C0B220408FD9B4D62BDB0F00000
4. consumer高可用
consumer启动时,如果name server或broker挂掉或连接失败,依然可以成功启动,不会报异常,等到连接恢复,consumer会定时发送心跳感知到,之后会继续正常进行消费。
5. topic订阅
1、初始化订阅的topic的相关信息
2、将该topic及其订阅信息放入负载实现类里
3、若MQClientInstance实例未初始化(启动时会初始化),则不发送心跳给所有broker
6. 消费者启动
1、检查相关配置(消费队列分配策略、订阅信息、回调的消息监听器类型:顺序or并发等等相关配置,不管什么样的消费者类型涉及的配置都会检查)
2、从订阅信息将topic及tag所有遍历出来,构建SubscriptionData放入负载均衡实现类内
3、判断消息模型,广播不处理,集群:增加重试topic(%RETRY%消费组名字)相关订阅信息
4、初始化MQClientInstance
5、RebalanceImpl(负载均衡)类实例相应设置(消费组、消费模型、分配消息队列策略、MQClientInstance)
6、构建消费进度存储对象:广播:本地文件消费进度;集群:远程broker消费进度
7、加载消费进度,广播:加载处理,集群:不处理
8、顺序or并发初始化相应消息消费服务并启动
9、消费者注册到MQClientInstance并启动MQClientInstance
10、远程客户端通信启动
11、MQClientInstance启动时会启动相关定时任务
-
定时获取name server地址(两分钟)
-
定时从name server更新topic路由信息(选举namer server的时间间隔)
-
清除下线的broker及发送心跳到所有的broker(与broker的心跳时间)
-
持久化所有的消费进度(持久化消费进度的间隔时间)
-
定时调整线程池(1分钟)
12、拉消息服务启动(一个自旋线程,不停的pull消息)
13、负载均衡服务启动
14、生产者启动(消费者也需要这个,内部使用(TBW102,PRODUCER_INNER_GROUP)
15、当订阅信息改变更新订阅信息
16、发送心跳给所有的broker
17、负载均衡服务线程唤醒
7. 负载均衡队列平均分配算法
以下计算针对一个具体的topic
1、消费端索引计算:当前消费端在所有消息端的索引
2、求模:队列数%消费端数
3、平均大小:队列数是否不大于于消费端数,是:1,不是:(模>0并且索引<模,是:队列数除以消费端数并加1,不是:队列数除以消费端数)
4、开始索引:模>0并且索引<模,是:索引*平均大小,不是:索引乘以平均大小再加模
5、队列范围:平均大小与(队列总数送去开始索引)的最小值
8. 负载均衡的结果
负载均衡根据分配算法(有多个分配算法,平均分配只是其中这一),会将指定范围的消息队列分配给消费端,比如只有一个消费端,那它就会获得所有队列,4个消费队列,2个消费端,每个消费端会消费其中的两个队列(不交叉),另外,非当前topic的队列不会被这些消费端给消费。