Kafka 和 RocketMQ 作为2款知名度较高的高性能的消息中间件,究竟有何相同或异同之处?项目中该如何选型? 最近一段时间一直在学习 RocketMQ 的源代码,过程中记录了一些两者的差异,列举一二仅供大家参考。
架构的差异
Kafka的架构
盗图一张
RocketMQ的架构
继续盗图一张
架构中的第一眼差异:RocketMQ 使用 Nameserver,而 Kafka 使用 ZK 作为各自的服务注册中心,两者正是体现了AP和CP之间的区别。阿里血缘的中间件,从来都认为服务发现相关数据应该是可用性大于一致性,比如 nacos 就是秉承了这种理念针对服务发现和配置设计了2套不同一致性实现(Distro 和 JRaft)。理由有几点:
1. 服务注册中心的服务发现相关数据如果不一致,比如一部分节点数据已经过期,会怎么样呢?无非就是客户端调用流量不均衡或者调用失败。如果发生了调用失败,客户端一定要有适合 failover 或者退避策略。除非所有的服务节点数据均无效,否则总有一个节点可以提供服务。 因此,相较于服务中心不可用而言,宁愿选择客户端多做一些工作来弥补服务数据的不一致性。
2. 一致性意味着持久化,而服务发现数据不需要持久化。通常服务提供方会与服务注册中心保持心跳连接,会一直更新注册中心的地址数据。因此如果注册中心重启,销毁了内存中所有服务数据。 不一会就会有心跳过来恢复之前的数据。
所以,Nameserver 没有一致性协议,没有持久化,没有 quorum,不需要线性一致性! 每个 Nameserver 实例均是独立个体,彼此不知道对方存在。Broker,生产者,消费者拥有全量 nameserver 实例列表,比如 broker 发送心跳,需要向全量 nameserver 发送。注意,这里 nameserver 保存 broker 的路由信息和地址信息,不会保存生产者或消费者的任何信息
总结
使用 NameServer 的优势:简单,高性能,高可用(最少只需一个节点存活即可),维护简单。定制的专用 broker 注册中心,日后可以做定制化,比如类似于 nacos 的阈值保护之类的功能
劣势:客户端(消费者和生产者)会看到过期的 broker 数据,需要有应对策略,增加了复杂性