Apache Pulsar为什么要设计存储分离架构
众所周知,一个传统单套的Kafka集群基本上支持1000个左右的topic。
这是因为Kafka严重依赖于ZooKeeper集群。所有的broker在启动的时候都会往zookeeper进行注册,目的就是选举出一个controller,controller会读取注册上来的从节点的数据(通过监听机制),生成集群的元数据信息,之后把这些信息都分发给其他的服务器,让其他服务器能感知到集群中其它成员的存在 。
从集群规模的角度来看,限制 Kafka 集群规模的一个核心指标就是集群可承载的分区数。集群的分区数对集群的影响主要有两点:ZooKeeper 上存储的元数据量和控制器变动效率。
Kafka 集群依赖于一个单一的 Controller 节点来处理绝大多数的 ZooKeeper 读写和运维操作,并在本地缓存所有 ZooKeeper 上的元数据。分区数增加,ZooKeeper 上需要存储的元数据就会增加,从而加大 ZooKeeper 的负载,给 ZooKeeper 集群带来压力,可能导致 Watch 的延时或丢失。
当 Controller 节点出现变动时,需要进行 Leader 切换、Controller 节点重新选举等行为,分区数越多需要进行越多的 ZooKeeper 操作:比如当一个 Kafka 节点关闭的时候,Controller 需要通过写 ZooKeeper 将这个节点的所有 Leader 分区迁移到其他节点;新的 Controller 节点启动时,首先需要将所有 ZooKeeper 上的元数据读进本地缓存,分区越多,数据量越多,故障恢复耗时也就越长。
这也是新版本的Kafka抛弃Zookeeper的原因,当然在Apache Pulsar在设计之除就考虑到了这个问题进而设计出了存算分离架构。
存储分离架构是如何体现的
和一般的MQ不同,pulsar的数据不直接存储在Broker上,而是保存在最下面的BookKeeper集群中。Broker主要负责Pulsar的业务逻辑,BookKeeper只负责数据的存储。这样也就导致Pulsar集群可以支持几十万个Topic。由于Broker是无状态的,所以它可以很方便地实现容量的动态伸缩,另外Broker内含有一个BookKeeper Client方便与BookKeeper集群建立连接。Broker是Pulsar的逻辑中心,它是数据流和管理流的入口。Producer选择某一Broker建立连接,生产的消息存储在该Broker管理的BookKeeper 存储节点(Bookie)。
Topic为什么要和Broker绑定
当我们通过Pulsar客户端或者系统自动生成Topic时候需要选择Topic类型:non-partitioned或者partitioned,如果是non-partitioned类型需要选择一个broker进行绑定,反之需要根据设置的分片数选择多个broker进行绑定。
Topic怎么和Broker绑定
为了让Pulsar单集群可以承载几十万个Topic/Partition,Pulsar抽象了一个Bundle的概念,并且使用了一致性哈希算法。Topic并不会直接与Broker建立联系,让Bundle作为一致性哈希环中的虚拟节点,Topic通过名称计算哈希值,并且散列到哈希环中,找到对应的Bundle,然后通过Bundle和Broker建立连接。即ZooKeeper中保存Bundle和Broker之间的联系,Bundle归属与哪个Broker,也是通过一致性哈希动态计算出来的。
参考
https://zhuanlan.zhihu.com/p/98030096