前言
上一篇简单的介绍了消息中间件的一些应用,后面的中间件主要围绕着RocketMQ
进行学习,所以这篇来记录一下RocketMQ
的基本组件,以及他们的关联。
MQ和List有什么区别?
在刚接触MQ的时候,我就有一个疑惑,为什么不直接部署一台专门来放消息的List呢?先不讨论RocketMQ中的topic,简单的认为消息推送的时候,就是list.add,消费的时候就list.get + list.remove。的确这个是消息队列的基础,但不是全部。
首先抽象出来的这个中间件必须保证高效、可靠、方便。简单的一个队列肯定是不能满足以上的要求的。常用的MQ至少需要保证的功能:
1.容错机制。即要保证处理消息失败后将消息重推回List内,避免消息丢失,这就要求你在消费List中的消息后全程try,并在意外错误后把消息PUSH到队列尾部。
2.消息的延迟性。 有一些消息要作必要的延迟后才能处理的,比如上面容错机制中出错的消息,一般需要都会要求延迟一段时间后再重试操作,避免在一个时间段内出现大量的重复操作。
比如还有消费者组的概念:为了保证单个服务的高可用,会部署多台服务。而这多台服务只需要消费一条记录。所以在消费的时候还涉及到负载均衡的问题。
所以List只是MQ的一个基础而已,完整的一个MQ涉及到的东西要多得多。
MQ的组件
从网上盗的一张图,对于MQ的组件理解会比较清晰。主要有Produce、NameServer、Broker、Consumer。
Produce
先来看消息的生产者。从上图中1
位置可以看到Produce每一条消息,都指定了对应的topic、broker name以及broker的IP。
1 | Queue:0 broker-a , 127.0.1.23 |
如第一条,先是指定了service这个topic,然后再指定了存放该消息的broker的名称broker-a,以及该broker的IP地址127.0.1.23 ,Queue:0是该条消息的编号。
Broker
Broker在上图的3
标志位。是用来存放消息的组件。先来看一下Broker的配置。
1 | clusterName: default |
clusterName所属集群名字;brokerName是broker名字;brokerId 0 表示 Master,>0 表示 Slave;brokerAddr IP地址;perm 权限的位与运算。
NameServer
nameServer顾名思义,在系统中肯定是做命名服务,服务治理方面的工作,功能应该是和ZooKeeper差不多,据网上资料显示,RocketMQ的早期版本确实是使用的ZooKeeper,后来改为了自己实现的nameServer。功能上和Zookeeper是比较相似的。
留一个问题TODO:为什么需要nameServer而不是直接用zookeeper?后面再来解释现在来看一下nameServer在RocketMQ中的两个主要作用:
1.NameServer维护了一份Broker的地址列表和,broker在启动的时候会去NameServer进行注册,会维护Broker的存活状态.
2.NameServer维护了一份Topic和Topic对应队列的地址列表,broker每次发送心跳过来的时候都会把Topic信息带上.
上图中的BrokerData就是nameServer维护者Broker的地址列表。QueueData就是维护了一份Topic和Topic对应队列的地址列表。
Consumer
Consumer跟Producer类似。跟其中一台nameServer建立长连接,获取当前订阅Topic存在哪些Broker,然后直接跟Broker建立连接通道,开始消费消息。因为有多个Broker可能含有相同的Topic,所以获得一个BrokerData的List,以及该Topic下所有的消息MessageQueue。
MQ工作流程
结合部署的结构图,描述集群工作流程:
1.启动nameServer,nameServer起来后监听端口,等待Broker、Producer、Consumer连上来,相当于一个路由控制中心。
2.Broker启动,跟所有的nameServer保持长连接,定时发送心跳包。心跳包中包含当前Broker信息(IP+端口等)以及存储所有topic信息。注册成功后,nameServer集群中就有Topic跟Broker的映射关系。
3.收发消息前,先创建topic,创建topic时需要指定该topic要存储在哪些Broker上。也可以在发送消息时自动创建Topic。
4.Producer发送消息,启动时先跟nameServer集群中的其中一台建立长连接,并从nameServer中获取当前发送的Topic存在哪些Broker上,然后跟对应的Broker建长连接,直接向Broker发消息。
5.Consumer跟Producer类似。跟其中一台nameServer建立长连接,获取当前订阅Topic存在哪些Broker,然后直接跟Broker建立连接通道,开始消费消息。