Pulsar 系统架构
Pulsar 是基于计算存储分离的思想设计的架构,所以 Pulsar 整体架构要分为计算层和存储层两层。我们通常说的 Pulsar 是指计算层的 Broker 集群和存储层的 BookKeeper 集群两部分。
计算层包含 Producer、Broker、ZooKeeper、Consumer 四个组件,用来完成 MQ 相关的功能。存储层是独立的一个组件 BookKeeper,是一个专门用来存储日志数据的开源项目,它由 Bookies(Node)和 ZooKeeper 组成。
协议和网络层
和 Kafka 一样,Pulsar Broker 的协议也是自定义的私有协议。协议的格式是以行格式解析,即自定义的编解码格式。
Pulsar 的整体协议是行格式的自定义编解码,但是协议中的命令(Command)和部分元数据是用 Protobuf 组织来表示的。
从协议的内容上看,Pulsar 协议分为了 SimpleCommands 和 MessageCommands 两种格式。
Simple Commands 指不需要携带消息内容的简单命令,即指在交互过程中不需要携带消息内容的交互请求,如建立连接,心跳检测等等。
Message Commands 指需要携带消息内容的复杂命令,比如生产消息操作就需要携带消息内容、生产者信息、批量消息等等相关数据。
数据存储
元数据存储
Pulsar 元数据存储的核心是 ZooKeeper。最新版本的内核支持可插拔的元数据存储框架,即支持将元数据存储到多种第三方存储引擎,比如 etcd、本地内存、RocksDB 等,架构如下图所示:
消息数据
在计算层,Pulsar 不负责消息存储。流程上就是调用 BookKeeper 的 SDK,往 BookKeeper 写入数据。在 BookKeeper 看来,Pulsar Broker 就是 BookKeeper 集群的一个普通的客户端。
在 Pulsar Broker,消息数据的存储是以分区维度组织的,即一个分区一份文件。在实际的存储中,分区的数据是以一段一段 Ledger 的形式组织的,不同的 Ledger 会存储到不同的 Bookie 上。每段 Ledger 包含一批 Entry,一个 Entry 可以理解为一条消息。存储结构如下图所示:
Pulsar 提供了 TTL 和 Retention 机制来支持消息删除。
生产者和消费者
生产端
Pulsar 生产端支持访问模式的概念。访问模式指的是一个分区在同一时间支持怎样的生产者以何种方式写入。比如一个分区同一时间是所有生产者都可以写,还是只有一个生产者可以写,还是多个生产者灾备写。在其他消息队列中,一般都是默认所有的生产者可以写。
Pulsar 提供了 Shared(共享)、Exclusive(独占)、WaitForExclusive(灾备)三种访问模式。
Shared 指允许多个生产者将消息写入到同一个 Topic。Exclusive 指只有一个生产者可以将消息写入到 Topic,当其他生产者尝试写入消息到这个 Topic 时,会发生错误。WaitForExclusive 指只有一个生产者可以将消息发送到 Topic,其他生产者连接会被挂起而不会产生错误,类似 ZooKeeper 的观察者模式。
消费端
Pulsar 主要支持 Pull 消费模型,即由客户端主动从服务端 Pull 数据来支持消费。
Pulsar 的订阅支持消息和分区两个维度。
在实现上,Pulsar 支持独占、灾备、共享、Key_Shared 四种订阅类型。
- 独占,指一个订阅只可以与一个消费者关联,只有这个消费者能接收到 Topic 的全部消息,如果这个消费者故障了就会停止消费。
- 灾备,指一个订阅可以与多个消费者关联,但只有一个消费者会消费到数据,当该消费者故障时,由另一个消费者来继续消费。
- 共享,指一个订阅可以与多个消费者关联,消息会通过轮询机制发送给不同的消费者。
- Key 共享,指一个订阅可以与多个消费者关联,消息根据给定的映射规则,相同 Key 的消息由同一个消费者消费。
HTTP 协议支持和管控操作
数据流走的是自定义协议通信,管控走的是 HTTP 协议形式的访问。
HTTP 协议的端口和私有协议的端口是独立的,内核中启动了一个单独的 HTTP Server 来提供服务。我们在代码上可以通过 HTTP Rest 的 API 直接进行管控操作。命令行 CLI 的底层也是通过 HTTP Client 发起访问的,用 HTTP 的好处就是,不需要单独在二进制协议、服务端接口、客户端 SDK 方面单独进行管控的支持。
此文章为11月Day13学习笔记,内容来源于极客时间《深入拆解消息队列 47 讲》