本文参考官方文档https://pulsar.apache.org/features/
Pulsar官网的定义是:Pulsar是个完全的消息和流平台。
以下特性使得Pulsar不仅仅是一个消息系统。
1.高效水平扩展能力
水平扩展可以应对日益增长的系统负载,它独特的设计和分离的存储层可以秒级扩展以应对突如其来的系统压力。
Pulsar Server,也是Broker,并不会把接收到的消息持久化到本地磁盘的文件上。反而是,把消息写入Bookeeper,Bookeeper简单来说就是一个只支持append写入模式的分布式虚拟文件存储系统。这个设计使得Pulsar Server是个无状态的服务,所以在应对系统压力时,可以秒级进行扩容,即增加一些Pulsar Server节点,topic就会自动分布到这些节点上,不需要进行额外的数据迁移动作。
一个Topic实际上就是一系列ledger(虚拟append-only文件)的集合。一个活跃的ledger可以根据年龄和大小进行进行关闭,新的ledger会被打开,并被使用。
Bookkeeper也可以在秒级进行扩容。增加Bookkeeper节点时,也不需要数据迁移。因为正在写的topic会不停地替换活跃的ledger,新的Bookkeeper节点也可以被选中,作为统一选择器进程分配新文件的一部分。这就意味着,新节点有助于平衡瞬时的流量激增。
2.低延时的消息和流系统
Pulsar支持独立消息确认机制(RabbitMQ风格)、单分区消息累积(像offset),支持分布式工作队列、大规模集群顺序数据流(数百个节点)、低延迟(小于10毫秒)。
Pulsar把消息写入topic后,消息可已不同的方式被消费,有以下三种方式:
(1)Streaming
顺序的、分区隔离、累积消息确认(同一个分区中消息的ID是唯一的)、这和kafka是一样的。
(2)Messaging
随机的、独立对每条消息进行确认(和RabbitMQ一样)。这样可以同时拥有大量的并发消费者,而不管分区数量。这对分布式消息队列和累积机器学习工作负载是完美的方案。
(3)Messaging in-order
顺序的,根据key进行隔离,我们可以按需创建大量的并发消费者,broker会根据key将这些消费者进行隔离,以及隔离消费者消息,这保留了按key顺序消息处理。
以上所有的方式都是低延迟的(低于10毫秒),无论是端到端的消息生产,还是大规模集群(数百节点)。
3.支持一百万topic
Pulsar独特的架构支持单集群一百万个topic,避免将多个流复用到同一个topic中,以此来简化架构。
Pulsar将消息持久化到一个虚拟的append-only的文件中,即ledger,保存在Bookkeeper(独立的系统)中。因为Pulsar中每个topic并不是一个活跃的物理文件,所以不受文件描述符的限制,因此可以达到一百万个topic。Pulsar支持唯一的、简化的架构或用户应用程序。
与传统的系统相比,传统的系统迫使我们将多个流多路复用到同一个topic,使用户程序变得复杂,Pulsar峰会上展示的Cogito案例研究就是一个很好的例子。
4.多租户作为一等公民
使用租户可以为整个组织仅维护一个集群,控制哪些用户可以跨数据(namespaces/topics)和操作(produce/consume/…)。
Pulsar中的租户将Pulsar中的数据划分为多个部分。租户持有命名空间,命名空间又持有主题和Pulsar函数。组织通常为每个部门/团队分配其租户,在租户中,他们为自己拥有的每个域创建命名空间,并为该域所需的实现创建主题。
租户主要与粒度访问控制功能结合使用。租户有一个租户管理员用户列表,这些用户可以向特定用户授予特定命名空间或主题的生产/消费/功能/…等权限。租户还可以配置特定的身份验证插件,例如,允许一个租户使用JWT进行身份验证,另一个租户则使用mTLS进行身份验证。
最后,如果Pulsar实例有多个集群,则租户可以被限制到特定的集群。
租户使组织中的部门能够就其数据和操作的安全性进行自我服务。
5.自动化负载均衡
新增或删除节点时,Pulsar会自动平衡一批topic。热点的topic会自动拆分并分布到broker中。
Pulsar支持跨broker的topic负载均衡,以达到broker在CPU、内存和流量上的负载均衡。因为Pulsar Broker是无状态的,所以broker之间进行topic前移时并不伴随着数据迁移。
因为Pulsar支持一百万个topic,所以平衡的对象并不是一个topic,而是一群topic(bundle),根据hash值进行分组。负载均衡器在broker之间迁移bundle。当某个bundle处于极端负载情况下,会发生自动拆分,允许两个bundle之间进行均衡,这可连续进行,直到达到集群级别的均衡。
6.支持云原生部署(k8s)
Pulsar从第一天就为云而建。Pulsar Broker和Bookkeeper节点都可以快速扩容,因为Pulsar Broker是无状态的,并且Bookkeeper的设计是为了在新节点加入时避免数据重分布。
扩容是原生支持的,表现有两点:
(1)Pulsar Broker是无状态的,消息存储在Bookkeeper中。因此,Broker的扩容并不需要进行数据迁移。Pulsar有自动的负载均衡能力,新节点的加入后,可被均衡分配到topic。
(2)Bookkeeper支持原生扩展,因为它在启动新节点时不会重分布数据。Pulsar中的一个topic是由一系列ledgers组成,其中最后一个ledger是active ledger。active ledger滚动非常快,这意味着新的Bookkeeper节点几乎会立即分担写入消息的负载。
Pulsar需要和k8s helm charts绑定在一起,需要包含以下组件:Pulsar brokers、Bookkeeper、Zookeeper、Function Workers、以及其他。
7.无缝的跨地域复制
通过不同地理区域的副本机制来防止某个区域的完全中断。Pulsar集群支持灵活的、可配置的副本策略。特别支持客户端自动化故障转移到健康的集群。
Pulsar支持Pulsar实例的概念:一组Pulsar集群,每个集群由于一个全局元数据存储(例如ZK)而相互感知。我们可以在群集之间定义复制策略:active-standby、active-active等。这允许我们将每个集群放在不同的区域,实现开箱即用的跨区域复制。它为我们提供数据冗余和灾难恢复。
集群复制数据(消息)和订阅(消费者确认状态)。
如果这还不够,Pulsar客户端支持自动故障转移。如果它检测到主集群(使用指定的URL进行检查)已关闭,它会自动故障转移到辅助集群。由于数据和消费状态(订阅)是复制的,因此您只需在主集群上继续进行。
8.官方多语言客户端支持
官方维护了Java、Go、Python、C++、Node.js、C#编程语言的Pulsar客户端。
还有一些非官方的第三方Pulsar客户端,比如Node.js、.NET、Haskell、PHP、Rust、以及Scala客户端。
9.分级存储支持
通过将数据从Bookkeeper中转移到块存储(如S3)中,我们可以实现永久保存。通过在Bookkeeper和S3中保留热数据,可以保证高性能和弹性。
一个Pulsar topic由一系列ledger组成,只有最新的ledger是可以被打开并写入数据的,其他的ledger都是closed状态,即不可写入的,或者说不变的。
Pulsar支持将这些不可变的ledger转移到分层存储介质中,比如S3、GCS、Azure块存储等。我们可以个性化配置Bookkeeper中保存已转移的ledger的保留时间。
这个特性允许我们以低成本永久保留数据。
Pulsar可以在Bookkeeper和分层存储系统间进行无缝切换,对应的ledger可传递到客户端。他非常适合将冷数据转移到廉价的存储系统,因为假设这些数据的访问频率很低,对读取性能的需求也较低(这也是分层存储系统的性能)。
10.内置模式注册中心
支持根据topic的模式来校验输入输出数据。通过支持每个新模式版本的向后和向前兼容检查来面向未来的变更。
Pulsar有一个内置的模式注册中心(schema registry),可以为topic指定消息的模式结构。注册中心通过内置的向前和向后兼容性检查来支持模式变更,防止生产或消费消息时出现不兼容的错误。
支持多种模式语言,包括Avro和Protobuf
11.颗粒度访问控制
Pulsar支持用户认证,能够实现对具有有限权限(consume、produce等)的namespace或topic的访问控制。
Pulsar有用户的概念,每个用户都会持有给定namespace或topic的一系列权限。有一个用户列表的配置,用于承担超级管理员的角色,可访问所有的资源。每个租户都有一些用户承担租户管理员的角色,这些用户拥有租户内部所有的namepace和topic的权限。
权限包括:producing messages、consuming messages、running functions、installing connectors、sinks、sources。
这使组织能够授权团队自行管理应用的访问权限(通常是在一个租户中)。
12.消息持久化保证
Pulsar对Bookkeeper的写入保证会被写入到磁盘(也称为fsync),从而提高对机器故障的容忍度。如果为了提升吞吐量,可禁止此特性。
当Pulsar接收到一条消息,它会使用自己的客户端将数据写入Bookkeeper中,默认情况下是并行写入3个Bookkeeper节点。这种写入只有当2个Bookkeeper节点写入成功后,才会被认为是成功的。只有成功之后,Pulsar的确认消息才会返回给客户端。
默认情况下,Bookkeeper先将消息写入磁盘,然后写入预写日志(write-ahead-log),最后写入内存,这之后才能说这次对Bookkeeper的写入操作是成功的,并把响应返回给客户端。
Bookkeeper的重要特性是:在认为写入成功前,确保写入磁盘已被flush(保证写入磁盘,也称为fsync)。性能是通过批量消息调用一次昂贵的fsync操作来衡量的。这种默认行为非常适合无法丢失写入消息的场景。我们可以关闭这种特性,从而获得性能提升,并依靠其他副本继续生存,而Bookkeeper的修复机制会在后台修复其他的副本。
13.存算分离架构
由于Pulsar的特特架构,我们需要分别为存储和CPU选择最佳的实例类型。通过直接从Bookkeeper读取来支持大规模并行查询引擎。
Pulsar有一个内置的框架,叫做Pulsar IO,它简化了连接器的编写和执行,可以将数据从第三方系统读取到Pulsar topic,或者将Pulsar topic中的消息写入到第三方系统中。
Pulsar有几个官方维护的连接器:MySQL、Elasticsearch、Cassandra等等,完整列表可查看官方文档https://pulsar.apache.org/docs/3.0.x/io-connectors/
Pulsar IO是在Pulsar Function基础之上编写的,因此连接器(Sink或Source)是一个Pulsar Function。连接器根据所选的运行时资源(线程、进程、或k8s pod)使用Pulsar Function Worker运行。这意味着它还支持并行处理(增加运行连接器的实例数量并在他们之间分配工作)
14.支持外部消息插件
使用提供的流行的消息系统客户端,而Pulsar作为后台服务端,社区提供插件:Kafka、RabbitMQ等。这有助于逐步向Pulsar转移。
Pulsar有多种插件类型,在这些插件中,有一个叫做Protocol Handler。它允许添加额外的消息协议到当前Pulsar的二进制协议中。这个插件负责从socket读取数据,并转换为Pulsar命令。例如写一个消息,展示topic列表等等。
这个特性允许社区对广泛使用的协议的开发支持,例如AMQP、Kafka、RabbitMQ、RocketMQ和MQTT。社区支持的完整的协议处理器列表可参考官方文档https://pulsar.apache.org/ecosystem/
这个特性允许我们使用Kafka或RabbitMQ客户端,但是Pulsar作为服务端系统。
15.Serverless函数
使用Pulsar Functions来编写和部署函数。在Java、Go、Python处理消息时,无需部署功能齐全的应用程序,k8s运行时是捆绑的。
Pulsar适合以各种方式接收消息和消费消息,并可以为消息设置个性化的保留时间。人么总是想写一个功能齐全的应用程序来消费消息,运行逻辑复杂。在某些场景下,我们只需要对消息进行简单的转换,我们可以为此修改我们的应用,或者使用Spark、Flink等提供的流处理工具。这两个也非常有用:修改应用程序进行微笑的消息修改仍需要大量的管道代码,而修改Spark/Flink需要对系统有大量的了解,并需要时间来维护。
Pulsar提供了一个轻量化的流处理框架——Pulsar Funtcions。它使我们能够用Java、Go、Python中的单个文件编写一个函数,并将其部署到Pulsar Functions中,它会为我们运行该函数。Functions可以读取topic中的每条消息进行处理,也可以往任何的topic写入消息。它非常适合消息转换:从一个topic读取消息,消息转换,把转换后的消息写入其他的topic。它也被用于多种更大的任务中,比如机器学习训练。
Pulsar Function支持设置并行执行,允许我们设置函数实例的个数。它有一个独特的进程来协调和执行这些函数,进程称为Pulsar Function Worker。它支持在线程、专用进程以及k8s pod中运行函数。
16.官方支持第三方connector
Pulsar有几个官方维护的连接器:MySQL、Elasticsearch、Cassandra等等,完整列表可查看官方文档https://pulsar.apache.org/docs/3.0.x/io-connectors/
17.支持大消息量
Pulsar使用客户端分块来支持大消息(一条消息大量字节)。
大消息并不会被拒绝。反而Pulsar客户端支持分块:每条大消息都会分成多个块,消费者(Pulsar客户端的一种)会将这些块组装成原始的消息。
18.延迟消息
在消息可被消费之前,以给定的延迟时间写入一条消息。这个特性非常适合计划任务和指数级会退重试。
Pulsar支持写入具有给定延迟的消息,这意味着消息延时到期后,该条消息才能被消费。它还支持提供消息可供使用的具体日期和时间。这对于使用延迟消息调度任务非常有用。Pulsar客户端利用该功能提供具有指数回退的客户端重试功能。
19.支持大量消费者
支持大量消费者消费同一个topic,无需考虑分区数量。
一般通过增加分区数量来扩展对topic的消息写入处理效率。通过增加消费者数量来扩展消费处理效率,这与topic中的分区数量完全无瓜。这既可以用于无序消费,也可以用于根据key排序的有序消费。
20.元数据存储易于操作
Zookeeper只是原书就存储的插件之一。当元数据管理系统与Pulsar本身分离时,快速隔离与元数据相关的问题。允许未来可扩展的元数据存储。
Pulsar元数据存储是插件化的,官方支持Zookeeper和etcd,并可能为未来的社区做贡献。Zookeeper和etcd是有用十多年生产经验的坚如磐石的产品。
这种设计允许我们在系统与Pulsar分离时快速隔离与元数据相关问题。
21.功能易于使用
提供内置的Restful API和客户端命令,用于系统的管理维护操作。
Pulsar内置Restful API,可用于创建topic、删除namespace等管理操作。它还与Admin Cli一起,在Restful API之上提供了一个易于使用的包装器。
22.灵活的消息保留时间
基于时间、大小或者是未确认消息时间的弹性消息保留机制
23.topic消息压缩
支持同一个key,只保留最后一条消息。
24.消息唯一性保证
生产消息时,实现Exactly Once语义,避免消息重复和遗漏。
25.事务支持
生产和响应在同一个原子操作中。