RocketMQ 4.x 版本之前,一套完整的 MQ 服务包含的组件有:Namesrv、Broker、Consumer、Producer。
RocketMQ 5.0 版本之后,官方引入了一个新的组件:Proxy,它的作用是什么呢?
RocketMQ 4.x 版本之前架构是这样的:
先启动 Namesrv 再启动 Broker,Broker 会把元数据注册到 Namesrv,包括一共有哪些 Topic、Topic 下有多少队列等等。Consumer 发消息前要先从 Namesrv 拉取 Topic 的路由信息,然后轮询发送到队列,Broker 收到消息后写入磁盘持久化存储。Producer 也要从 Namesrv 拉取路由信息,再和 Broker 建立长连接拉取消息消费,消费成功后上报消费位点。
这个架构看起来没什么问题,RocketMQ 也用了这么久了,怎么到 5.0 突然要引入个 Proxy 组件呢?
顺应趋势,云原生的时代已经来了,RocketMQ 5.0 要全面拥抱云原生,现在这套架构的问题开始显现:
引入 Proxy 后,我们再来看看 RocketMQ 5.0 的架构图:
表面上看,Proxy 只是做了一个转发,在 Namesrv、Broker 和 Consumer、Producer 之间做了一层代理,但是你别小看这层代理,它带来的好处可是不少,把上面的问题全解决了。
多语言客户端SDK & 私有协议的问题
如今的 RocketMQ 早已经不是只给 Java 语言使用了,为了让 C++、Go 等其它语言也可以很方便的使用 RocketMQ,官方必须开发对应语言的客户端 SDK,这意味着要用不同的语言重复实现客户端逻辑,程序员最讨厌重复了,所以客户端要尽可能做到足够轻量,这样重复编写的代码才最少。
如果你看过 RocketMQ 4.x 的源码,你会发现客户端的逻辑太重了,比如:客户端要同时和 Namesrv 和 Broker 交互、消息队列的重平衡、消费位点的上传等等。于是,RocketMQ 5.0 把客户端的很多功能都下沉到了 Proxy,同时 5.x 的客户端统一用 gRPC 协议和 Proxy 通信,Proxy 再把协议适配成 Remoting 转发到 Broker、Namesrv。
使用 gRPC 协议的好处是:
Broker 存算分离
Proxy 不仅承担了客户端的部分功能,还承担了原先 Broker 的部分计算任务,新架构让 Broker 更专注于消息数据的存储,实现了存储计算分离。在云原省时代,更利于资源的调度,Proxy 扩容起来更加方便。
新的 POP 消费模式
RocketMQ 4.x 的 PUSH 消费模式存在一定的局限性,本质上还是 PULL 模式,消息是靠消费者主动去拉取的,PUSH 消费模式的局限性主要体现在:
新的 POP 消费模式就没有这些问题,消费者可以消费所有队列里的消息,增加消费者就可以提高消费能力,不受队列数和消费者数量的限制,消费者无状态,扩容起来很方便。
Proxy 有两种部署方式:
Local 模式部署
由于 Local 模式下 Proxy 和 Broker 是同进程部署,Proxy 本身无状态,因此主要的集群配置仍然以 Broker 为基础进行即可。
不论何种部署方式,都要先启动 Names,再启动 Broker:
$ sh mqnamesrv
# 假设Namesrv地址是:192.168.1.1:9876
$ sh bin/mqbroker -n 192.168.1.1:9876 --enable-proxy
Local 模式下,因为 Proxy 和 Broker 同属一个进程,所以 Proxy 和 Broker 无需再网络通信,适合对延迟敏感、期望部署架构简单的用户。
Cluster 模式部署
在 Cluster 模式下,Broker 与 Proxy 分开部署,存储计算完全分离,Proxy 可以很好的扩容。Proxy 集群和 Broker 集群必须一一对应,可以在配置文件中指定 ClusterName。
{
"rocketMQClusterName": "DefaultCluster"
}
$ sh mqnamesrv
# 假设Namesrv地址是:192.168.1.1:9876
$ sh bin/mqbroker -n 192.168.1.1:9876
$ sh bin/mqproxy -n 192.168.1.1:9876