Pulsar

Pulsar

为什么要学习Apache Pulsar

什么是云原生

  • DevOps:指的就是开发和运维不再是分开的两个团队,而是你中有我,我中有你的一个团队。
  • 微服务:指是应用需要具备低耦合+高内聚。
  • 持续交付:指的在不影响用户使用服务的前提下,频繁将新功能发布给用户使用,当然这一点也是云原生中比较难以达到的。
  • 容器化:指的是在运维的时候,不需要再关心每个服务所使用的技术栈,每个服务都被无差别的封装在容器中,可以被无差别的管理和维度,比如目前docker和k8s。

Apache Pulsar基本介绍

Apache Pulsar是一个云原生企业级的发布订阅(pub-sub)消息系统。

Apache Pulsar的功能与特性

  • 多租户模式;
  • 灵活的消息系统;
  • 云原生架构;
  • segmented Sreams(分片流);
  • 支持跨地域复制;

多租户模式

  • 租户和命名空间(namespace)是Pulsar支持多租户的两个核心概念。
  • 在租户级别,Pulsar为特定的租户预留合适的存储空间、应用授权和认证机制。
  • 在命名空间级别,Pulsar有一系列的配置策略(policy),包括存储配额、流控制、消息过期策略和命名空间之间的隔离策略。

多租户模式

灵活的消息系统

  • Pulsar做了队列模型和流模型的统一,在Topic级别只需要保存一份数据,同一份数据可多次消费。以流式、队列等方式计算不同的订阅模型,大大提升了灵活度。
  • 同时Pulsar通过事务采用Exactly-Once(精准一次)在进行消息传输过程中,可以确保数据不丢不重。

消息队列模式

消息队列模式

流模式

流模式

云原生架构

  • Pulsar使用计算与存储分离的云原生架构,数据从Broker搬离,存在共享存储内部。上层是无状态的Broker,复制消息分发和服务;下层是持久化的存储层Bookie集群。Pulsar存储是分片的,这种架构可以避免扩容时受限制,实现数据的独立扩展和快速恢复。

云原生架构

segmented Sreams(分片流)

  • Pulsar将无界的数据看作是分片的流,分片分散存储在分层存储(tiered storage)、BookKeeper集群和Broker节点上,而对外提供一个统一的、无界数据的视图。其次,不需要用户显式迁移数据,减少存储成本并保持近似无限的存储。

分片流

支持跨地域复制

  • Pulsar中的跨地域复制是将Pulsar中持久化的消息在多个集群间备份。在Pulsar 2.4.0中新增了复制订阅模式(Replicated-subscriptions),在某个集群失效的情况下,该功能可以在其他集群恢复消费者的消费状态,从而达到热备模式下消息服务的高可用。

支持跨地域复制

Apache Pulsar组件介绍

层级存储

  • Infinite Stream:以流的方式永久保存原始数据;
  • 充分的容量不再受限制;
  • 充分利用云存储或者现有的廉价存储(例如HDFS);
  • 数据统一表征:客户端无需关心数据究竟存储在哪里;

层级存储

Pulsar IO(Connector)连接器

  • Pulsar IO分为输入(Input)和输出(Output)两个模块,输入代表数据从哪里来,通过Source实现数据输入。输出代表数据要往哪里去,通过Sink实现数据输出。
  • Pulsar提出了Connector(也称为Pulsar IO),用于解决Pulsar与周边系统的继承问题,帮助用户高效完成工作。
  • 目前Pulsar IO支持非常多的连接继承操作:例如:HDFS、Spark、Flink、Flume、ES、HBase等。

Pulsar IO(Connector)连接器

Pulsar Functions(轻量级计算框架)

  • Pulsar Functions是一个轻量级计算框架,可以给用户提供一个部署简单、运维简单、API简单的FASS(Function as a Service)平台。Pulsar Functions提供基于事件的服务,支持有状态与无状态的多语言计算,是对复杂的大数据处理框架的有力补充。
  • Pulsar Functions的设计灵感来自于Heron这样的流处理引擎,Pulsar Functions将会拓展Pulsar和整个消息领域的未来。使用Pulsar Functions,用户可以轻松地部署和管理Function,通过Function从Pulsar topic读取数据或者生成新数据到Pulsar topic。

Pulsar Functions(轻量级计算框架)

Pulsar和kafka的对比

  • 模型概念
    • Kafka:producer -- topic -- consumer group -- consumer
    • Pulsar: producer -- topic -- subscription -- consumer
  • 消费模式
    • Kafka:主要集中在流(Stream)模式,对单个partition是独占消费,没有共享(Queue)的消费模式;
    • Pulsar:提供了统一的消息模型和API。流(Stream)模式 -- 独占和故障切换订阅方式;队列(Queue)模式 -- 共享订阅的方式
  • 消息确认(ack)
    • Kafka:使用偏移量offset;
    • Pulsar:使用专门的cursor管理。累计确认和Kafka效果一样;提供单条或选择性确认;
  • 消息保留
    • Kafka:根据设置的保留期来删除消息,有可能消息没被消费,过期后被删除,不支持TTL;
    • Pulsar:消息只有被所有订阅消费后才删除,不会丢失数据。也支持设置保留期,保留被消费的数据,支持TTL。

Apache Kafaka和Apache Pulsar都有类似的消息概念。客户端通过主题与消息系统进行交互。每个主题都可以分为多个分区。然而,Apache Pulsar和Apache Kafka之间的根本区别在于Apache Kafka是以分区为存储中心,而Apache Pulsar是以Segment为存储中心。

对比总结:
Apache Pulsar将高性能的流(Apache Kafka所追求的)和灵活的传统队列(RabbitMQ所追求的)结合到一个统一的消息模型和API中。Pulsar使用统一的API为用户提供一个支持流和队列的系统,且具有同样的高性能。
性能对比:
Pulsar表现出色的就是性能,Pulsar的速度比Kafka快得多,美国德克萨斯州一家名为GigaOm(https://gigaom.com/) 的技术研究和分析公司对Kafka和Pulsar的性能对了比较,并证实了这一点。

扩展说明:Kafka目前存在的痛点

  • Kafka很难进行扩展,因为Kafka把消息持久化在broker中,迁移主题分区时,需要把分区的数据完全复制到其他broker中,这个操作非常耗时。
  • 当需要通过更改分许大小获得更多存储空间时,会与消息索引产生冲突,打乱消息顺序。因此,如果用户需要保证消息的顺序,Kafka就变得非常棘手了。
  • 如果分区副本不处于ISR(同步)状态,那么leader选取可能会紊乱。一般的,当原始主分区出现故障时,应该有一个ISR副本本征用,但是这个点并不能完全被保证。若在设置中并未规定只有ISR副本可被选为leader时,选出一个处于非同步状态的副本作为leader,这比没有broker服务该partition的情况更糟糕。
  • 使用Kafka时,你需要根据现有的情况并充分考虑未来的增量计划,规划broker、主题、分区和副本的数量,才能避免Kafka扩展导致的问题。这是理想状况,实际情况很难规划,不可避免的会出现扩展需求。
  • Kafka集群的分区再均衡会影响相关生产者和消费者的性能。
  • 发生故障时,Kafka主题无法保证消息的完整性(特别是遇到第3点中的情况,需要扩展时极有可能丢失消息)。
  • 使用Kafka需要和offset打交道,这点让人很头痛,因为broker并不维护consumer的消费状态。
  • 如果使用率很高,则必须尽快删除就的消息,否则就会出现磁盘空间不够用的问题。
  • 众所周知,Kafka元神的跨地域复制机制(MirrorMaker)有问题,机试只在两个数据中心也无法正常使用跨地域复制。因此,甚至Uber都不得不创建另一套结局啊方案来解决这个问题,并将其称为uReplication(https://eng.uber.com/ureplicator/)。
  • 想要进行实时数据分析,就不得不选用第三方工具,如Apache Strom、Apache Heron或Apache Spark。同时,你需要保证这些第三方工具足以支撑传入的流量。
  • Kafka没有原生的多租户功能来实现租户的完全隔离,他是通过使用主题授权等安全功能来完成的。

Apache Pulsar集群架构

基本架构介绍

单个Pulsar集群由以下三部分组成:

  • 多个broker负责处理和负载均衡producer发出的消息,并将这些消息分派给consumer;Broker与Pulsar配置存储交互来处理相应的任务,并将消息存储再Bookkeeper示例中(又称bookies);Broker依赖Zookeeper集群处理特定的任务,等等。
  • 多个bookie的BookKeeper集群负责消息的持久化存储。
  • 一个zookeeper集群,用来处理多个Pulsar集群之间的任务调度。
    集群架构

Brokers介绍

Pulsar的broker是一个无状态组件,主要负责运行另外的两个组件:

  • 一个HTTP服务器,他暴露了REST系统管理接口以及在生产者和消费者之间进行Topic查找的API。
  • 一个调度分发器,他是异步的TCP服务器,通过自定义二进制协议应用于所有相关的数据传输。

出于性能考虑,消息通常从Managed Ledger缓存中分派出去,除非积压超过缓存大小。如果积压的消息对于缓存来说太大了,则Broker将开始从BookKeeper那里读取Entries(Entry同样时BookKeeper中的概念,相当于一条记录)。

最后,为了支持全局Topic异地复制,Broker会控制Replicators追踪本地发布的条目,并把这些条目用java客户端重新发布到其他区域。

Zookeeper的元数据存储

Pulsar使用Apache Zookeeper进行元数据存储、集群配置和协调。

  • 配置存储:存储租户,命名域和其他需要全局一致的配置项;
  • 每个集群都有自己独立的Zookeeper保存集群内部配置和协调信息,例如归属信息,Broker负载报告,BookKeeper ledger信息(这个是BookKeeper本身所依赖的)等等。

基于bookkeeper持久化存储

Apache Pulsar为应用程序提供有保证的信息传递,如果消息成功到达Broker,就认为其预期到达了目的地

为了提供这种保证,未确认送达的消息需要持久化存储直到他们被确认送达。这种消息传递通常称为持久消息传递。在Pulsar内部,所有消息都被保存并同步N份,例如,2个服务器保存四份,每个服务器上都有镜像的RAID存储。Puldar用Apache BookKeeper作为持久化存储。BookKeeper是一个分布式的预写日志(WAL)系统,有如下几个特性特别适合Pulsar的应用场景:

  • 使用Pulsar能够利用独立的日志,成为ledgers。可以随着时间的推移为topic创建多个Ledgers
  • 它为处理顺序消息提供了非常有效的存储;
  • 保证了多系统挂掉时Ledgers的读取一致性;
  • 提供不同的Bookies之间均匀的IO分布的特性;
  • 它在容量和吞吐量方面都具有水平伸缩性。能够通过增加bookies立即增加容量到集群中,并提升吞吐量;
  • Bookies被设计成承载数千的并发读写的ledgers。使用多个磁盘设备(一个用于日志,另一个用于一般存储),这样Bookies可以将读写操作的影响对于写操作的延迟分隔开。

    Ledger是一个之追加的数据结构,并且只有一个写入器,这个写入器负责多个BookKeeper存储节点(就是Bookies)的写入。Ledger的条目会被复制到多个Bookies。Ledgers本身有着非常简单的语义:
  • Pulsar Broker可以创建ledger,添加内容到ledger和关闭ledger。
  • 当一个ledger被关闭后,除非明确的要写数据或者是因为写入器挂掉导致ledger关闭,ledger只会以只读模式打开。
  • 最后,当ledger中的条目不在有用的时候,整个ledger可以被删除(ledger分布是跨Bookies的)。

Pulsar代理

Pulsar客户端和Pulsar集群交互的一种方式就是直连Pulsar brokers。然而,在某些情况下,这种直连既不可行也不可取,因为客户端并不知道broker的地址。例如在云环境或者k8s以及其他类似的系统上面运行Pulsar,直连brokers就基本上不可能了。
Pulsar proxy为这个问题提供了一个解决方案,为所有的broker提供了一个网关,如果选择运行了Pulsar Proxy。所有的客户都会通过这个代理而不是直接与brokers通信。

Apache Pulsar可视化监控部署

由于目前传智教育中采用Pulsar主要还是已于多Linux节点方式进行部署,故本次主要为各位提供也是多台linux服务器上构建集群方案,对于Pulsar在k8s、Docker、AWS等部署操作,后续推送给大家。

Apache Pulsar相关使用操作

多租户模式

  • 获取租户列表
cd /exprot/server/brokers/bin
./pulsar-admin tenants list
  • 创建租户
cd /exprot/server/brokers/bin
./pulsar-admin tenants create my-tenant
  • 删除租户
    注意:在删除的时候,如果库下已经有名称空间,是无法删除的,需要先删除名称空间
cd /exprot/server/brokers/bin
./pulsar-admin tenants delete my-tenant

Pulsar的名称空间

  • 在指定的租户下创建名称空间
cd /exprot/server/brokers/bin
./pulsar-admin namespaces create test-tenant/test-namespace
  • 获取名称空间相关的配置策略
cd /exprot/server/brokers/bin
./pulsar-admin namespaces policies test-tenant/test-namespace
  • 获取指定租户下所有的名称空间
cd /exprot/server/brokers/bin
./pulsar-admin namespaces list test-tenant
  • 删除名称空间
cd /exprot/server/brokers/bin
./pulsar-admin namespaces delete test-tenant/test-namespace

Pulsar的topic相关操作

Pulsar提供持久化与非持久化两种topic。持久化topic是消息发布、消费的逻辑端点。持久化topic地址的命名格式如下:persistent://tenant/namespace/topic
非持久化topic应用在仅消费时发布消息与不需要持久化保证的应用程序。通过这种方式,它通过删除持久化消息的开销来减少消息发布延迟。非持久化topic地址的命名格式如下:non-persistent://tenant/namespace/topic

  • 创建Topic
# 方式一:创建一个没有分区的topic
bin/pulsar-admin topics create persistent://my-tenant/my-namespace/my-topic

# 方式二:创建一个有分区的topic
bin/pulsar-admin topics create-partitioned-topic persistent://my-tenant/my-namespace/my-topic -- partitions 4

注意:不管是有分区还是没有分区,创建topic后,如果没有任何操作,60s后Pulsar会认为topic不是活动的,会自动进行删除,以避免生成垃圾数据
相关的配置:
  Brokerdeleteinactivetopicsenabenabled:默认值为true,表示是否启动自动删除
  BrokerDeletenactiveTopicsFrequencySeconds:默认为60s,表示检测未活动的时间
  • 列出房前某个名称空间下的所有topic
./pulsar-admin topics list my-tenant/my-namespace
  • 更新topic操作
我们可以针对所有分区的topic去更新其分区的数量
./pulsar-admin topics update-partitioned-topic persistent://my-tenant/my-namespace/my-topic --partitions 8
  • 删除topic操作
删除没有分区的topic:
./pulsar-admin topics delete persistent://my-tenant/my-namespace/my-topic

删除有分区的topic
./pulsar-admin topics delete-partition-topic persistent://my-tenant/my-namespace/my-topic
  • 查询某个topic被哪个broker进行代理执行
pulsar-admin topics lookup persistent://test-tenant/ns1/tp1

作用:
  一个namespace最终只能被一个broker所代理,那么当这个空间下的topic越来越多,此时broker的压力就会增加,后续可以基于对这个namespace进行bundle切分处理,基于此命令可以看出当前这个topic被那个broker管辖

基于Python操作Pulsar(原生、schema、KOP)

原生

import pulsar


class PulsarProdecerTest(object):
    """生产者"""
    def __init__(*args, **kwargs):
        self.client = pulsar.Client('pulsar://localhost:6650')
        self.producer_ = None

    def producer(self, topic, message, *args, **kwargs):
        self.producer_ = self.client.create_producer(topic)
        self.producer_.send(message.encode('utf-8'))

    def __exit__(self, *args, **kwargs):
        self.producer_.close()
        self.client.close()


class PulsarConsumerTest(object):
    """消费者"""
    def __init__(self, *args, **kwargs):
        self.client = pulsar.Client('pulsar://localhost:6650')
        self.consumer_ = None

    def consumer(self, topic, subscription_name, *args, **kwargs):
        self.consumer_ = self.client.subscribe(topic, subscription_name)
        while True:
            msg = self.consumer.receive()
            try:
                print(msg)
                self.consumer_.acknowledge(msg)
            except Exception as e:
                self.consumer_.negative_acknowledge(msg)

    def __exit__(self, *args, **kwargs)
        self.client.close()

schema

可以自定义类来传递数据,不需要再转换成json格式

KOP

兼容Kafka,可以使不改变Kafka代码结构的情况下将数据推送到Pulsar里。

Pulsar connector连机器(与flume和flink集成)

Pulsar Flink Connector 是Apache Pulsar和Apache Flink(数据处理引擎)的集成,它允许Flink从Pulsar读取数据,并向Pulsar写入数据

认证

如果需要进行token认证,则需要如下定义

client = pulsar.Client(
    'pulsar://localhost:6650', 
 
 
 
 authentication=AuthenticationToken('eyJhbGciOiJIUzI1NiJ9.eyJzdWIiOiJKb2UifQ.ipevRNuRP6HflG8cFKnmUPtypruRC4fb1DWtoLL62SY'))

并确保broker.conf中配置如下:

# 启用认证和鉴权
authenticationEnabled=true
authorizationEnabled=true
authenticationProviders=org.apache.pulsar.broker.authentication.AuthenticationProviderToken
 
# 设置Broker 自身的认证。 Used when the broker connects to other brokers, either in same or other clusters
brokerClientTlsEnabled=true
brokerClientAuthenticationPlugin=org.apache.pulsar.client.impl.auth.AuthenticationToken
brokerClientAuthenticationParameters={"token":"eyJhbGciOiJIUzI1NiJ9.eyJzdWIiOiJ0ZXN0LXVzZXIifQ.9OHgE9ZUDeBTZs7nSMEFIuGNEX18FLR3qvy8mqxSxXw"}
# Or, alternatively, read token from file
# brokerClientAuthenticationParameters={"file":"///path/to/proxy-token.txt"}
brokerClientTrustCertsFilePath=/path/my-ca/certs/ca.cert.pem
 
# If this flag is set then the broker authenticates the original Auth data
# else it just accepts the originalPrincipal and authorizes it (if required).
authenticateOriginalAuthData=true
 
# If using secret key (Note: key files must be DER-encoded)
tokenSecretKey=file:///path/to/secret.key
# The key can also be passed inline:
# tokenSecretKey=data:;base64,FLFyW0oLJ2Fi22KKCm21J18mbAdztfSHN/lAT5ucEKU=
 
# If using public/private (Note: key files must be DER-encoded)
# tokenPublicKey=file:///path/to/public.key

proxy.conf中配置如下:

# For clients connecting to the proxy
authenticationEnabled=true
authorizationEnabled=true
authenticationProviders=org.apache.pulsar.broker.authentication.AuthenticationProviderToken
tokenSecretKey=file:///path/to/secret.key
 
# For the proxy to connect to brokers
brokerClientAuthenticationPlugin=org.apache.pulsar.client.impl.auth.AuthenticationToken
brokerClientAuthenticationParameters={"token":"eyJhbGciOiJIUzI1NiJ9.eyJzdWIiOiJ0ZXN0LXVzZXIifQ.9OHgE9ZUDeBTZs7nSMEFIuGNEX18FLR3qvy8mqxSxXw"}
# Or, alternatively, read token from file
# brokerClientAuthenticationParameters={"file":"///path/to/proxy-token.txt"}
 
# Whether client authorization credentials are forwared to the broker for re-authorization.
# Authentication must be enabled via authenticationEnabled=true for this to take effect.
forwardAuthorizationCredentials=true

才能保证token认证开关是打开的,否则在关闭情况下,穿不穿token都唔那个收到生产者的消息。

posted @ 2024-03-20 17:45  AKA绒滑服贵  阅读(48)  评论(0编辑  收藏  举报