RocketMq实现原理--PUSH消费者负载均衡
- 双负载均衡
- 消费者客户端hash算法
- broker上消费者集合
- 容灾措施
- 最终一致性
- 缺陷
- 全新的界面设计 ,将会带来全新的写作体验;
双负载均衡
rocketmq是客户端负载均衡实现。
rocketmq消息是使用broker(服务器)与queueid(消息分组)两个单位实现消费逻辑。rocketmq集群是由若干个broker,每个topic在broker上存在若干个queueid。
负载均衡的目的是所有的客户端能够均衡分布在每个broker的每个queueid上。
1.broker负载均衡实现:消费者与namesrv(注册中心,维护者topic分布在哪些broker上,每个broker上拥有多少个queueid),消费者与namesrv建立长连接后会同步topic的路由信息,在消费消息的开始,会随机(当前时间与broker数量取模)出一个broker。从而实现消费者客户端对于broker的负载均衡。
2.queueid负载均衡:消费者通过broker负载均衡算法获得一个broker后,会通过rpc的方式获取到这个broker上消费者列表。通过hash算法计算出应该消费的queueid。
消费者客户端hash算法
(1)首先将所有消费者客户端id进行字符排序
(2)将所有broker与queueid可以出现的所有组合做字符排序
(3)计算出当前客户端在已排序客户端数组中的下标
(4)计算出组合数量与消费者数量的 模,该模作为一个标准,客户端下标超过模的说明与均摊值想成后会产生无效组合下标
(5)broker与queueid所有组合,相对于所有客户端的均摊值(即每个客户端可以消费几个组合),当所有组合的数量小于客户端的时候该 均摊值 为1.
当组合的数量大于等于客户端的时候均摊值为 组合数量去余整除结果。当当前消费者下标值大于模的时候为 去余整除值+1
(6)将自己客户端的下标乘以均摊值会计算出可以消费到的组合的下标。但是在不能完全均摊的情况下计算出来的下标会超出所有组合下标,会出现无效下标,无效下标就 不会被采用。
该hash算法最终实现的效果是,客户端均摊所有组合,并且每种组合只能有一个客户端进行消费。同一个消费者可以同时消费多个组合。
(7)计算偏移量,均摊值乘以下标值,如果下标志大于等于模,加1
(8)计算消费者选择组合的个数,组合总个数减去偏移量,与均摊值取较小的值
(9)根据范围获得下标值。
例如:
服务器:b1 b2 b3 b4 b5
每个服务器上有2个queueid
客户端列表是:c1 c2 c3
组合列表(排序后):[b1_1,b1_2,b2_1,b2_2,b3_1,b3_2,b4_1,b4_2,b5_1,b5_2]
消费者列表(排序后):[c1,c2,c3]
模为:10%3=1
则均摊值为:
当前客户端 | c1 | c2 | c3 |
下标值 | 0 | 1 | 2 |
均摊值 | 10/3+1=4 | 10/3=3 | 10/3=3 |
偏移量 | 0*4=0 | 1*3+1=4 | 2*3+1=7 |
取值个数 | min(4,10-0)=4 | min(3,10-4)=3 | min(3,10-7)=3 |
取值范围 | 0,1,2,3 | 4,5,6 | 7,8,9 |
broker上消费者集合
(1)消费者客户端启动的时候会向所有的broker发送心跳请求,心跳请求会携带所有的订阅topic的原信息。
(2)broker没接收到一个心跳请求,就会在内存中维护一个消费者列表。
(3)broker对消费者提供接口提供broker消费者列表的信息。
容灾措施
(1)新的消费者连接到broker上
(2)消费者与broker的连接断掉
出现上述这些情况的时候,broker会主动与已建立连接的消费者主动发起消费者列表发生改变的消息,消费者客户端接受到这个请求后会立马重新做一次负载均衡计算。
最终一致性
rocketmq在客户端数量固定,服务稳定的情况下,一个broker上的一个queueid是被唯一的client独享的。不存在竞争,所以push到消息并且提交更新消息偏移量的操作的原子性可以得到保障。
但是,在客户端频繁重启,broker服务不稳定,网络抖动多种情况下会出现客户端频繁的重新计算路由值,一定会出现一个broker上的单个queueid被多个客户端消费出现竞争,一致性就不会得到保证。
rocketmq采用的是最终一致性保证消费的一致性。
最终一致性是zookeeper中采用的解决高并发下保持一致性的技术手段。
broker管理topic消费的版本号做一致性校验。
(1)client在发送心跳的时候以当前时间为版本号告知broker
(2)broker同时会受到多个client的心跳请求,broker会维护一个topic与版本号的对应关系,将这个版本号更新为多个client中最大的那个时间版本号。
(3)client在发送pull消息的请求的时候会携带当前client的版本号给broker
(4)broker发现携带小于当前topic最大版本号的pull消息请求后会拒绝这个请求。
(5)当broker接受到一个新申请的client心跳请求的时候会在主动发送给所有已经连接完成的client一个cosumechange消息告知后给新的client正确的回执。
缺陷
(1) rocketmq在消费者与broker之间出现网络抖动的,或者任何出现,段时间内出现多次失联与重连的情况下,会频繁出现强制重新负载均衡。每次重新负载均衡会马上进行消费,会出现多消费客户端broker与queueid的碰撞。会出现重复消费的情况。建议针对时断时续不断重连的client,添加保护模式机制。在client固定时长内保持稳定再纳入正常消费者列表内。针对生产环境中升级上线操作这种场景尤其明显
(2) rocketmq最终一致性的实现使用的是client服务器的服务器时间,生产环境上,服务器时间并非准确,合理的实现方式应该与broker之间做时间对齐。