转自:comparing-pulsar-and-kafka-how-a-segment-based-architecture-delivers-better-performance-scalability-and-resilience
一个pulsar 集群由两层构成:
一个典型的pulsar 架构如图:
应用通过pulsar客户端访问brokers 以生产或消费消息,客户端不直接与BookKeeper 或者 Zookeeper 交互,这种良好的隔离简化了租户下的鉴权。
brokers组成了pulsar的无状态层,“无状态”是因为brokers 不在本地保存消息,消息都保存在分布式日志系统BookKeeper.
每个 topic partition 由 pulsar 分配给一个broker,该broker 成为前者的 owner broker,客户端通过与该broker建立连接来发送或消费消息。
如果这个broker 挂了,pulsar自动将其分配到的topic partition 重新派给集群中剩余可用的broker。此过程只是将topic partition 的所有权进行了转移,不涉及数据拷贝。
下图展示了4个 broker 管理4个 topic partition 的情况
BookKeeper 是 pulsar 的持久层,每个 topic partition 本质上是存在BookKeeper 的分布式日志。
分布式日志被切分成多个段,每段存放到多个bookies(BookKeeper 的存储单元)。
当前段写入时长到达配置的时长、或者当前段大小达到配置的阈值,或topic partition 的所有权进行了变更,都会产生新的段。
通过分段,topic partition 的消息可以均衡的分布与所有bookies,这意味着一个topic partition的容量不局限于一个节点,甚至可以扩展至整个BookKeeper 支持的最大容量。
下图展示了一个topic partition 被分为x段,每一段存3个副本,所有段及其副本分配在4个broker
Pulsar 的主要两个关键设计在于分层架构和段式存储,他们为pulsar 带来了以下便利:
因为 topic partition 被分割为多个段且在 BookKeeper 中分布式存放,一个 topic partition 的容量就不受限于容量最小的bookie 节点,甚至可以支持到整个BookKeeper 集群的容量。集群扩容也只需要添加节点即可,这使得pulsar 可以存放随时间无限增长的数据,并以高效、分布式的方式处理数据,而其本质就是分布式日志存储。
因为消息服务和存储在两个独立的层,将一个 topic partition 从过一个broker 迁移到另一个broker 可以瞬间完整且无需数据rebalance(从前一个broker拷贝数据到后一个)。这个特性对于集群扩容、broker和bookie的崩溃快速响应十分关键。下面用图解释:
Broker 无缝崩溃恢复
下图展示了pulsar 如何处理broker崩溃。Broker 2 因某种原因(如电源耗尽)崩溃了,pulsar 检测到Broker 2 下线,立即将Topic1-Part2 的所有权从Broker2 转移至Broker3.
当broker3接管Topic1-Part2 时,不需要拷贝第1段到第4段数据。新写入的数据直接添加并存放于 Topic1-Part2 新的段x+1(上面提到段所有权变更时会产生新的段)。第x+1段分布式存放于bookies 1, 2 ,4
因为不需要数据拷贝,topic partition的所有权变更几乎瞬间完成,不需要牺牲 topic partitions 的可用性(无缝)。
集群无缝扩容
下图展示了 pulsar 集群如何扩容。
当broker 2 往 Topic1-Part2 第 X段写数据时,bookies X 和Y添加到了集群,broker2会立即发现,并尝试将新写入X+1 段和X+2段的数据写入新的bookie。新的bookie 瞬间被利用起来,也不涉及数据拷贝。
BookKeeper 提供了资源感知(resource-aware)的放置策略,外加机架感知(rack-aware)和区域感知( region-aware)策略,以保证数据能均衡路由到所有节点,防止新的bookie 过于空闲。(BookKeeper 决定了新的段放置在那个bookie,新加入的bookie 也会加以利用,上游无感知)
Bookie 无缝崩溃恢复
下图展示了pulsar 如何处理bookie 或磁盘崩溃。
这里bookie 2的第4段发生了磁盘崩溃。BookKeeper 检测到之后发起副本修复(replica repair)。
副本修复是段层面的多对多的快速修复,相比与整个topic partition 拷贝而言操作粒度更好。BookKeeper 还可以从bookie3 和bookie4读取到第4段数据,并在bookie1复原第4段数据。
副本修复在后台进行,所有brokers 可以继续接受写请求,不需要通过用正常的bookie 替换崩溃的bookie 从而牺牲topic partitions 的可用性
因为服务层与持久化层分开,pulsar 可以对两个层分别进行扩容。这使得容量评估更高效:
更多细节详见 Why BookKeeper?
kafka 和 pulsar 有着相似的消息概念,客户端通过topic 与系统交互。每个topic 分成多个partition。
然而,两者主要区别在于kafka 是以分区为中心(partition-centric )的生产-消费系统,pulsar 是以分段为中心(segment-centric)的系统。
上图展示了分区为中心和分段为中心的系统的区别,kafka 中partition 只能存储在一个节点并复制到另外的节点,因此容量受限于最小的节点。
这意味着扩容需要partition再分配,即需要将整个partition 的数据和路由都拷贝到新加的broker中。重复拷贝数据开销较大且容易出错,消耗更多网络带宽与io。操作时必须小心谨慎,否则很容易把生产环境搞垮。
分区为中心的系统的partition数据拷贝不仅发生在扩容时,很多其他场景会触发数据拷贝,例如副本下线、磁盘挂了、机器宕机。此时partition不可用,直到数据拷贝完成。
例如partition 配置成需存储3个副本,即使丢了其中一个,也需要拷贝整个partition。这种限制通常会被忽略除非亲身体验服务下线,因为大多数使用场景是仅仅用做短期缓存。
pulsar 中,一个partition 被分成多个段,按照易扩展方式分布于集群中。因为是基于分段的所以扩容时不需要数据重新分配,这得益于BookKeeper 的可扩展分段分布式日志存储。当新的节点或partition 加入集群时,流量会迅速补充到新的节点,不需要数据拷贝。
借助分布式日志存储,pulsar 可以最大化分段分布策略的效益以获取较高的读写可用性。当设置topic partition副本数为2时,只要2个bookie 在线就能保证可写入,在topic partition 集群中有1个broker 在线就能保证可读。