RocketMq的部署方式
NameServer集群
提供轻量级的服务发现和路由。每个NameServer 记录完整的路由信息,提供等效的读写服务,并支持快速存储扩展。
就是一个注册中心,存储当前集群所有Brokers信息、Topic跟Broker的对应关系。
Namesrv用于存储Topic、Broker关系信息,功能简单,稳定性高。多个Namesrv之间相互没有通信,单台Namesrv宕机不影响其他Namesrv与集群;即使整个Namesrv集群宕机,已经正常工作的Producer,Consumer,Broker仍然能正常工作,但新起的Producer,Consumer,Broker就无法工作。
Namesrv压力不会太大,平时主要开销是在维持心跳和提供Topic-Broker的关系数据。但有一点需要注意,Broker向Namesr发心跳时,会带上当前自己所负责的所有Topic信息,如果Topic个数太多(万级别),会导致一次心跳中,就Topic的数据就几十M,网络情况差的话,网络传输失败,心跳失败,导致Namesrv误认为Broker心跳失败。
producer集群
生产者,产生消息的实例,拥有相同Producer Group 的Producer 组成一个集群。
Producer与Name Server集群中的其中一个节点(随机选择)建立长连接,定期从Name Server取Topic路由信息,并向提供Topic服务的Master建立长连接,且定时向Master发送心跳。Producer完全无状态,可集群部署。
Producer Group
用来表示一个发送消息应用,一个Producer Group下包含多个Producer实例,可以是多台机器,也可以是一台机器的多个进程,或者一个进程的多个Producer对象。一个Producer Group可以发送多个Topic消息,Producer Group作用如下:
• 标识一类Producer
• 可以通过运维工具查询这个发送消息应用下有多个Producer实例
• 发送分布式事务消息时,如果Producer中途意外宕机,Broker会主动回调Producer Group内的任意一台机器来确认事务状态。
consumer集群
消息消费者,简单来说,消费MQ 上的消息的应用程序就是消费者,至于消息是否进行逻辑处理,还是直接存储到数据库等取决于业务需要。拥有相同Consumer Group 的
Consumer 组成一个集群。
Consumer与Name Server集群中的其中一个节点(随机选择)建立长连接,定期从Name Server取Topic路由信息,并向提供Topic服务的Master、Slave建立长连接,且定时向Master、Slave发送心跳。Consumer既可以从Master订阅消息,也可以从Slave订阅消息,订阅规则由Broker配置决定。
Consumer Group
用来表示一个消费消息应用,一个Consumer Group下包含多个Consumer实例,可以是多台机器,也可以是多个进程,或者是一个进程的多个Consumer对象。一个Consumer Group下的多个Consumer以均摊方式消费消息,如果设置为广播方式,那么这个Consumer Group下的每个实例都消费全量数据。
broker集群
通过提供轻量级的Topic 和Queue 机制来处理消息存储,同时支持推(push)和拉(pull)模式以及主从结构的容错机制。
集群最核心模块,主要负责Topic消息存储、管理和分发等功能。
单个Broker跟所有Namesrv保持心跳请求,心跳间隔为30秒,心跳请求中包括当前Broker所有的Topic信息。Namesrv会反查Broer的心跳信息,如果某个Broker在2分钟之内都没有心跳,则认为该Broker下线,调整Topic跟Broker的对应关系。但此时Namesrv不会主动通知Producer、Consumer有Broker宕机。
Broker部署相对复杂,Broker分为Master与Slave,一个Master可以对应多个Slave,但是一个Slave只能对应一个Master,Master与Slave的对应关系通过指定相同的BrokerName,不同的BrokerId来定义,BrokerId为0表示Master,非0表示Slave。Master也可以部署多个。每个Broker与Name Server集群中的所有节点建立长连接,定时注册Topic信息到所有Name Server。
消息发送
producer的消息发送流程;
• 所有producer的send()方法都调用了defaultMqProducer.send()方法;
• 这也是为什么我们需要对每一个pdoducer进行配置的原因;
生产者发送时,会自动轮询当前所有可发送的broker,一条消息发送成功,下次换另外一个broker发送,以达到消息平均落到所有的broker上。
这里需要注意一点:假如某个Broker宕机,意味生产者最长需要30秒才能感知到。在这期间会向宕机的Broker发送消息。当一条消息发送到某个Broker失败后,会往该broker自动再重发,假如还是发送失败,则抛出发送失败异常。业务捕获异常,重新发送即可。
TopicPublishInfo类是用于producer端做负载均衡的关键类,producer通过这个类来识别broker并选择broker;
MessageQueue类:
描述了单个消息队列的模型;
• 这个队列用于管理哪个topic以及这个队列在哪个broker里
TopicRouteData类:
Topic路由信息集中管理了当前topic下的所有队列信息和broker信息;
• brokerdata中包含了该broker的brokerGroup名字和物理地址;
producer的负载均衡
producer的负载均衡由MQFaultStratage.selectOneMessageQueue()实现
MQFaultStratage这个类是MQ负载均衡的核心类
这个类描述了MQ负载均衡的策略
如何选择一个broker达到负载均衡
• 1.尽量不要选择刚刚选择过的broker
• 2.不要选择延迟容错内的broker
随机选择broker
producer每次在使用broker的时候会记录这次使用的是哪个broker;下次在选取broker的时候主动排除这个broker;
• 在未推送任何消息时,producer中的mq为空,此时lastBrokerName也为空;
• 选择broker是负载均衡的关键,基于方法selectOneMessageQueue(),这个方法会随机选择一个broker;
避开上次选取的broker
当延迟容错未开启时
延迟容错下选择broker
遍历所有broker直至找到一个broker可用(不在延迟容错里或已经可以从延迟容错里去除);如果所有broker都不可用则随机选取一个;
consumer的负载均衡
consumer在启动的时候会实例化rebalanceImpl,这个类负责消费端的负载均衡
MqClientInstance里会调用doRebalance()来进行负载均衡;
• consumer负载均衡是指将topicMessageQueue中的消息队列分配到消费者组的具体消费者里去;
• consumer的负载均衡由rebalanceImpl调用allocateMesasgeQueueStratage.allocate()完成;
• 每次有新的consumer加入group就会重新做一下负载;
• 每10秒自动做一次负载;
allocateMesasgeQueueStratage.allocate()
consumer负载均衡有6种模式:
• 分页模式(随机分配模式)
• 手动配置模式
• 指定机房模式
• 就近机房模式
• 统一哈希模式
• 环型模式