RocketMQ架构解析

1、架构图

在这里插入图片描述

2、角色

总共有四大部分:NameServer,Broker,Producer,Consumer。

2.1、NameServer

NameServer主要包括两个主要功能:

  1. 管理brokers:broker服务器启动时会注册到NameServer上,并且两者之间保持心跳监测机制,以此来保证NameServer知道broker的存活状态;
  2. 路由信息管理:每一台NameServer都存有全部的broker集群信息和生产者/消费者客户端的请求信息;

Namesrv用于存储Topic、Broker关系信息(保存活跃的broker列表,包括Master和Slave),功能简单,稳定性高。多个Namesrv之间相互没有通信,单台Namesrv宕机不影响其他Namesrv与集群;即使整个Namesrv集群宕机,已经正常工作的Producer,Consumer,Broker仍然能正常工作,但新起的Producer, Consumer,Broker就无法工作。

注意:
Namesrv压力不会太大,平时主要开销是在维持心跳和提供Topic-Broker的关系数据。但有一点需要注意,Broker向Namesr发心跳时,会带上当前自己所负责的所有Topic信息,如果Topic个数太多(万级别),会导致一次心跳中,就Topic的数据就几十M,网络情况差的话,网络传输失败,心跳失败,导致Namesrv误认为Broker心跳失败。

NameServer与Broker间的通信和其发挥的作用:

  1. 在NameServer启动后,启动Broker。Broker在启动时会加载配置中的topic信息。加载当前Broker上的所有topic信息:topic名称;topic的Queue权限,可读,可写,可继承等等;Queue的个数。然后将这些数据传输到NameServer,美其名曰registerBroker。
  2. NameServer与Broker间维持着一个SocketChannel,长连接,Broker每隔30S向其配置的所有的NameServer执行registerBroker工作,这就是Broker和NameServer间的心跳。
  3. NameServer在接受到Broker传递的心跳信息时,若这次心跳是其第一次心跳,那么创建BrokerData,创建BrokerLiveInfo,保存其dataVersion和lastUpdateTimestamp;如果不是第一次,那么更新其lastUpdateTimestamp和dataVersion。
  4. 如果这个Broker是Master,且这次心跳信息是其第一次心跳,那么会创建当前Broker的QueueData。如果不是第一次心跳,但当前Broker的dataVersion与NameServer上保存的不一致(当Broker上新增加了topic时会更新dataVersion,dataVersion主要用当前时间戳表示),此时会用当前心跳的数据覆盖之前注册的数据。
  5. 如果当前Broker是Slave,那么将Master的brokerAddr放入心跳注册结果中,返回给Slave,这样Slave就能与Master间进行数据传输。
  6. NameServer维护着与其他组件的SocketChannel对象,针对所有组件(Broker和Client)的长连接注册了ChannelEventListener,监听此SocketChannel的连接事件。当某个SocketChannel出现异常或断开时(注意是长连接断开而不是心跳停止!),会循环遍历所有Broker的长连接,如果发现断开长连接是属于某个Broker的,那么清除此Broker的BrokerData和QueueData,如果不属于Broker,则什么都不做。这样当Client(Producer,Consumer)下次请求指定topic的TopicRouteData时,就不会包含此Broker的的数据了,也就是MessageQueue上不再包含此Broker上的Queue。
  7. 因为ChannelEventListener的连接事件处理里只对Broker做相应处理,没有涉及到Client。所以在Broker宕机或者增加时,不会实时通知Client,Client最晚需要30S时间才能感知到这种变化,因为Client更新TopicRouteData的间隔是30S。
  8. NameServer每隔30S对所有Broker的长连接进行扫描,当发现其lastUpdateTimestamp距离当前时间超过2m时,断开长连接,清空相应数据。


 

2.2、Broker

Broker的四大作用:

  1. 请求分发:是client的入口,接收来自生产者消费者的请求
  2. client管理:管理客户(产品/消费者)并维护消费者的主题订阅。
  3. 数据存储:提供简单的api来查询磁盘上的临时数据
  4. 高可用:主从节点间同步数据保证高可用

Broker的优势

1.负载均衡:Broker上存Topic信息,Topic由多个队列组成,队列会平均分散在多个Broker上,而Producer的发送机制保证消息尽量平均分布到所有队列中,最终效果就是所有消息都平均落在每个Broker上。

2.动态伸缩能力(非顺序消息):Broker的伸缩性体现在两个维度:Topic, Broker。

Topic维度:假如一个Topic的消息量特别大,但集群水位压力还是很低,就可以扩大该Topic的队列数,Topic的队列数跟发送、消费速度成正比。
Broker维度:如果集群水位很高了,需要扩容,直接加机器部署Broker就可以。Broker起来后向Namesrv注册,Producer、Consumer通过Namesrv发现新Broker,立即跟该Broker直连,收发消息。

3.高可用&高可靠

高可用:集群部署时一般都为主备,备机实时从主机同步消息,如果其中一个主机宕机,备机提供消费服务,但不提供写服务。
高可靠:所有发往broker的消息,有同步刷盘和异步刷盘机制;同步刷盘时,消息写入物理文件才会返回成功,异步刷盘时,只有机器宕机,才会产生消息丢失,broker挂掉可能会发生,但是机器宕机崩溃是很少发生的,除非突然断电

2.3、Producer

Producer启动时,需要指定Namesrv的地址,从Namesrv集群中选一台建立长连接。如果该Namesrv宕机,会自动连其他Namesrv。直到有可用的Namesrv为止。生产者每30秒从Namesrv获取Topic跟Broker的映射关系,更新到本地内存中。再跟Topic涉及的所有Broker建立长连接,每隔30秒发一次心跳。Producer完全无状态,可集群部署。
RocketMQ提供三种发送方式:

同步:在广泛的场景中使用可靠的同步传输,如重要的通知信息、短信通知、短信营销系统等。
异步:异步发送通常用于响应时间敏感的业务场景,发送出去即刻返回,利用回调做后续处理。
一次性:一次性发送用于需要中等可靠性的情况,如日志收集,发送出去即完成,不用等待发送结果,回调等等。

下面讲Producer和Consumer与NameServer间的通信:

  1. Producer在发送消息时,首先根据消息的topic查看自身是否含有此topic相应的MessageQueue( 正常情况下第一次发送时是没有的 )。当没有MessageQueue时,会从NameServer处请求指定topic的TopicRouteData,也就是List< BrokerData>和 List< QueueData>。然后根据QueueData里的writeQueueNums和BrokerData里的topic, HashMap< brokerId , broker address > 生成MessageQueue,MessageQueue的id从0开始,依次递增。注意如果BrokerData里不含有Master的Adress,那么其对应的QueueData将会被废弃,因为只有Master才能写入消息。
  2. 生成MessageQueue后,会将此topic存在生产者客户端,客户端每隔30S向NameServer请求此topic的TopicRouteData,生成MessageQueue,覆盖上次更新的值。
  3. Consumer在启动之前就需要指定订阅的topic,因此其在启动时就会想NameServer请求相应topic的TopicRouteData,同样的形式生成MessageQueue,但和Producer不同的是,Consumer可以从Slave处拉取消息,所以不会过滤Master宕机的Broker数据。
  4. Consumer客户端也每隔30S从NameServer处更新当前topic的数据,覆盖上次的值。

生产者端的负载均衡

生产者发送时,会自动轮询当前所有可发送的broker,一条消息发送成功,下次换另外一个broker发送,以达到消息平均落到所有的broker上。

2.4、Consumer

consumer与Name Sever集群中的其中一个节点(随机选择)建立长连接,定期从Name Server获取topic路由信息,并向提供topic服务的Master,Slave建立长连接,定时向Master,Slave发送心跳。consumer既可以从Master订阅消息,也可以从Slave订阅消息,订阅规则由Broker配置决定。

消费者端的负载均衡

先讨论消费者的消费模式,消费者有两种模式消费:集群消费,广播消费。

广播消费:每个消费者消费Topic下的所有队列。
集群消费:一个topic可以由同一个ID下所有消费者分担消费。
具体例子:假如TopicA有6个队列,某个消费者ID起了2个消费者实例,那么每个消费者负责消费3个队列。如果再增加一个消费者ID相同消费者实例,即当前共有3个消费者同时消费6个队列,那每个消费者负责2个队列的消费。

消费者端的负载均衡,就是集群消费模式下,同一个ID的所有消费者实例平均消费该Topic的所有队列。

消费者从用户角度来看有两种类型:

PullConsumer:主动从brokers经纪人处拉取消息。一旦拉取到批量的数据,用户应用的消费进程初始化。
PushConsumer:封装消息拉取、消费进程和内部其他工作维护,留下一个回调接口让用户实现,当消息到达时即可执行用户实现逻辑。

2.5、补充一些概念

Topic:主题,是生产者发送的消息和消费者拉取的消息的规类。Topic与生产者和消费者都是非常松散的关系,一个topic可以有0个或者1个或者多个生产者向其发送消息,换句话说,一个生产者可以同时向不同和topic发送消息。从消费者的解度来说,一个topic可能被0个或者一个或者多个消费组订阅,类似的,一个消费组可以订阅一个或者多个主题只要这个消费组的实例保持他们的订阅一致

Message:消息,要传输的信息。一个message必须有一个主题,主题可以看做是你的信件要邮寄的地址。一个消息也可以拥有一个可选的tag和额处的键值对。如你可能需要给你的message设置一个业务key和要boker服务上查找此message,以便在开发期间查找问题。

Message Queue:消息队列,一个主题被化分为一个或者多个子主题(sub-topics),“消息队列”.

Tag:标签,换而言之为子主题,为用户提供额外的灵活性。使用tag,同一业务模块不同目的的messages就可以用相同topic不同tag来标识。Tags有益于保持你的代码干净而条理清晰,同时促进使用RocketMQ提供的查询系统的效率。Topic:主题,是生产者发送的消息和消费者拉取的消息的规类。Topic与生产者和消费者都是非常松散的关系,一个topic可以有0个或者1个或者多个生产者向其发送消息,换句话说,一个生产者可以同时向不同和topic发送消息。从消费者的解度来说,一个topic可能被0个或者一个或者多个消费组订阅,类似的,一个消费组可以订阅一个或者多个主题只要这个消费组的实例保持他们的订阅一致。

Message Order:当使用DefaultMQPushConsumer时,你需要确定消费消息的方式:

Orderly:顺序地消费消息即表示消费的消息顺序同生产者发送的顺序一致。
Concurrently:并行消费。指定此方式消费,信息消费的最大并行数量仅受限于每个消费者客户端指定的线程池。

Consumer Group:消费组,把同样角色的消费乾分组到一起即消费者组。消费者组是实现负载均衡目标和容错目标的一个重要概念。就信息消费而言,超级easy。
Producer Group:生产者组,是将同样角色生产者的分组在一起。同一生产组的不同生产者实例都会被Broker经纪人联络告知提交或者回滚事务,以避免事务后源生产者崩溃。



作者:激情的狼王
链接:https://www.jianshu.com/p/015a16347640
来源:简书
著作权归作者所有。商业转载请联系作者获得授权,非商业转载请注明出处。

猜你喜欢

转载自blog.csdn.net/meser88/article/details/121351306