RocketMQ总体架构
1.各参与者是如何通信的?
- 一、nameServer集群:
- 本身的高可用可通过部署多台NameServer服务器来实现,但彼此间互不通信,单台nameserver挂掉,不影响其他nameserver;NameServer服务器之间在某一时刻的数据并不完全相同,但保证多台NameServer的最终一致性;NameServe集群可以理解为无状态的。
- nameserver不会有频繁的读写,所以性能开销非常小,稳定性很高
- 二、broker集群:
- 1.@nameserv关系:
- 连接:每一台borker会与所有的nameserver保持长连接, 因为每台broker需要向所有的nameserv汇报路由信息
- 心跳:
- 心跳间隔:每隔30秒(此时间无法更改)向所有nameserver发送心跳,心跳包含了自身的topic配置信息。
- 心跳超时:nameserver每隔10秒钟(此时间无法更改),扫描所有还存活的broker连接,若某个连接2分钟内(当前时间与最后更新时间差值超过2分钟,此时间无法更改)没有发送心跳数据,则断开连接。
- 断开:
- 时机:broker挂掉;心跳超时导致nameserver主动关闭连接
- 动作:一旦连接断开,nameserver会立即感知,更新topc与队列的对应关系,但不会通知生产者和消费者
- 2.Broker集群组成:
- 每个broker集群有统一的名字,即brokerClusterName,默认是DefaultCluster。一个集群下有多个master,每个master下有多个slave。master和slave算是一组,拥有相同的brokerName, master的brokerId是0,而slave则是大于0。master和slave之间可以进行同步复制或者是异步复制。
- 3.可用性
- 一旦某个broker宕机,则该broker上的消息读写都会受到影响。所以rocketmq提供了master/slave的结构,salve定时从master同步数据,如果master宕机,则slave提供消费服务,但是不能写入消息。
- 一旦某个broker master宕机,生产者和消费者多久才能发现?
- 受限于Rocketmq的网络连接机制,默认情况下最多需要30秒,因为消费者每隔30秒从nameserver获取所有topic的最新队列情况,这意味着某个broker如果宕机,客户端最多要30秒才能感知。在此期间,消费者会切换到salve上读取消息,若此时消费者消费消息时发生异常,又会怎样?详见https://cloud.tencent.com/developer/news/158048;生产者则通过高可用的的策略解决broker的宕机情况;
- master恢复恢复后,消息能否恢复。
- 消费者得到master宕机通知后,转向slave消费,但是slave不能保证master的消息100%都同步过来了,因此会有少量的消息丢失。但是消息最终不会丢的,一旦master恢复,未同步过去的消息会被消费掉。
- 4.消息清理
- 文件保留时长
- 默认72小时,由broker配置参数fileReservedTime决定
- 清理时机
- 默认每天凌晨4点,由broker配置参数deleteWhen决定;或者磁盘空间达到阈值
- 文件保留时长
- 不同broker集群建立相同的topic而言是没问题的。但是如果是不同集群间的brokername有一致的则会有很大的问题。
- 1.@nameserv关系:
- 三、生产者:
- 1.@nameserv关系
- 连接:某一时刻只会连接一台namerServer,拉取主题的配置信息;
- 轮询时间:默认情况下,生产者每隔30秒从nameserver获取所有topic的最新队列情况,这意味着某个broker如果宕机,生产者最多要30秒才能感知,在此期间,发往该broker的消息发送失败。该时间由DefaultMQProducer的pollNameServerInteval参数决定,可手动配置。
- 心跳:与namerServ没有心跳
- 2.@Broker关系
- 连接:生产者与消费服务器(Broker)之间的(所有)Master保持长连接。因为生产者发送消息时,要轮询所有Master上的队列。
- 心跳:
- 超时:broker每隔10秒钟(此时间无法更改),扫描所有还存活的连接,若某个连接2分钟内(当前时间与最后更新时间差值超过2分钟,此时间无法更改)没有发送心跳数据,则关闭连接。
- 间隔:默认情况下,生产者每隔30秒向所有broker发送心跳,该时间由DefaultMQProducer的heartbeatBrokerInterval参数决定,可手动配置。
- 连接断开:移除broker上的生产者信息
- 3.负载均衡:每个生产者向broker的所有队列轮询发送消息
- 1.@nameserv关系
- 四、消费者:
- 1.@namerserv关系
- 连接:同一时间与NameServer集群中一台建立长连
- 接轮询时间:默认情况下,消费者每隔30秒从nameserver获取所有topic的最新队列情况,这意味着某个broker如果宕机,客户端最多要30秒才能感知。该时间由DefaultMQPushConsumer的pollNameServerInteval参数决定,可手动配置
- 心跳:与nameserver没有心跳
- 2.@broker关系
- 连接:单个消费者与所有Broker建立长连接,因为拉取消息可以从主服务器,也可以从服务上拉取。
- 心跳:
- 间隔:默认情况下,消费者每隔30秒向所有broker发送心跳,该时间由DefaultMQPushConsumer的heartbeatBrokerInterval参数决定,可手动配置
- 超时:broker每隔10秒钟(此时间无法更改),扫描所有还存活的连接,若某个连接2分钟内(当前时间与最后更新时间差值超过2分钟,此时间无法更改)没有发送心跳数据,则关闭连接,并向该消费者分组的所有消费者发出通知,分组内消费者重新分配队列继续消费。
- 断开:
- 时机:消费者挂掉;心跳超时导致broker主动关闭连接
- 动作:一旦连接断开,broker会立即感知到,并向该消费者分组的所有消费者发出通知,分组内消费者重新分配队列继续消费
- 1.@namerserv关系
2.问题
1.当某一个broker发生宕机,namerServer的剔除是120s,有延迟,那么作为客户端的生产者or消费者,是如何保证消息发送or消费的可靠性的?详见生产者 以及 消费者@NamserServer
2.消费者根据队列分配算法,得到本消费者对应的队列。当该主题的多个消费者动态增加或减少时,消费者的队列负载是没30s一次,不能达到实时性,那消费者是如何实时重新分配队列的呢?见消费者的负载均衡;见RocketMQ消息消费总览-问题
3. 断掉broker时,nameServer就感知到了,是不是与nameServer和broker的长连接断掉有关?tcp中断时,会被handler的监听到NettyConnectManageHandler#close,然后调用链:NettyRemotingAbstract#putNettyEvent->NettyEventExecutor#putNettyEvent->NettyEventExecutor#run->BrokerHousekeepingService#onChannelClose->RouteInfoManager#onChannelDestroy
4.生产者分组以及消费者分组,作用?类似jmq的appname。
5. nameserv无法像zk那样实时感知到生产者、消费者、broker的宕机,设计上由客户端来解决