中间件之Pulsar的概念与特性


title: 中间件之Pulsar的概念与特性
date: 2023-2-2 22:07:19
tags:

  • pulsar
  • kafka
    categories: 中间件
    toc_number: true
    password: 123456qqq
    message: 请联系微信:codewj,获取本文密码

篇幅有限

完整内容及源码关注公众号:ReverseCode,发送

为什么要学习 Apache Pulsar

什么是云原生

云原生的概念是2013年Matt Stine提出的,到目前为止, 云原生的概念发生了多次变更, 目前最新对云原生定义为: DevOps+持续交付+微服务+容器而符合云原生架构的应用程序是: 采用开源堆栈(K8S+Docker)进行容器化,基于微服务架构提高灵活性和可维护性,借助敏捷方法、DevOps支持持续迭代和运维自动化,利用云平台设施实现弹性伸缩、动态调度、优化资源利用率。

在这里插入图片描述

Apache pulsar基本介绍

Apache Pulsar 是一个云原生企业级的发布订阅(pub-sub)消息系统,最初由Yahoo开发,并于2016年底开源,现在是Apache软件基金会顶级开源项目。Pulsar在Yahoo的生产环境运行了三年多,助力Yahoo的主要应用,如Yahoo Mail、Yahoo Finance、Yahoo Sports、Flickr、Gemini广告平台和Yahoo分布式键值存储系统Sherpa。

Apache Pulsar的功能与特性:

  1. 多租户模式

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

    在这里插入图片描述

  2. 灵活的消息系统

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

    在这里插入图片描述

  3. 云原生架构

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

    在这里插入图片描述

  4. segmented Sreams(分片流)

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

在这里插入图片描述

  1. 支持跨地域复制

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

在这里插入图片描述

Apache Pulsar组件介绍

层级存储:

  • Infinite Stream: 以流的方式永久保存原始数据bookKeeper(kafka默认保存7天)
  • 分区的容量不再受限制
  • 充分利⽤云存储或现有的廉价存储 ( 例如 HDFS)
  • 数据统⼀表征:客户端无需关心数据究竟存储在哪⾥

在这里插入图片描述

Pulsar IO(Connector) 连接器:

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

在这里插入图片描述

Pulsar Funcations(轻量级计算框架)

  • 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与kafka的对比

  • 模型概念

    • Kafka: producer – topic – consumer group – consumer
    • Pulsar: producer – topic -subsciption- consumer
  • 消息消费模式

    • Kafka: 主要集中在流(Stream) 模式, 对单个partition是独占消费, 没有共享(Queue)的消费模式(如果需要共享需要独立在不同消费组)
    • Pulsar: 提供了统一的消息模型和API. 流(Stream) 模式 – 独占和故障切换订阅方式 ; 队列(Queue)模式 – 多消费者共享订阅的方式
  • 消息确认(ack)

    • Kafka: 使用偏移量 offset(大量数据消费数据失败重新消费时容易重复消费)
    • Pulsar: 使用专门的cursor管理. 累积确认和kafka效果一样; 提供单条或选择性确认(ack不会重复消费)
  • 消息保留

    • Kafka: 根据设置的保留期来删除消息(7天), 有可能消息没被消费, 过期后被删除, 不支持TTL
    • Pulsar: 消息只有被所有订阅消费后才会删除, 不会丢失数据,. 也运行设置保留期, 保留被消费的数据 , 支持TTL

    Apache Kafka和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 都不得不创建另一套解决方案来解决这个问题,并将其称为 uReplicator (https://eng.uber.com/ureplicator/)。

    • 要想进行实时数据分析,就不得不选用第三方工具,如 Apache Storm、Apache Heron 或 Apache Spark。同时,你需要确保这些第三方工具足以支撑传入的流量。

    • Kafka 没有原生的多租户功能来实现租户的完全隔离,它是通过使用主题授权等安全功能来完成的。

Apache Pulsar的集群架构

架构基本介绍

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

  1. 多个 broker 负责处理和负载均衡 producer 发出的消息,并将这些消息分派给 consumer;Broker 与 Pulsar 配置存储交互来处理相应的任务,并将消息存储在 BookKeeper 实例中(又称 bookies);Broker 依赖 ZooKeeper 集群处理特定的任务,等等。

  2. 多个 bookie 的 BookKeeper 集群负责消息的持久化存储。

  3. 一个zookeeper集群,用来处理多个Pulsar集群之间的协调任务。

在这里插入图片描述

Apache Pulsar提供的组件介绍

Brokers介绍

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

  • 一个 HTTP 服务器service discovery, 它暴露了 REST 系统管理接口以及在生产者和消费者之间进行 Topic查找的API。

  • 一个调度分发器dispatcher, 它是异步的TCP服务器,通过自定义 二进制协议应用于所有相关的数据传输。

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

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

*Zookeeper的元数据存储(每个pulsar集群都有一套zk集群做配置存储,在2.10.版本后可插拔组件)

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

  • 配置存储: 存储租户,命名域和其他需要全局一致的配置项

  • 每个集群有自己独立的ZooKeeper保存集群内部配置和协调信息,例如归属信息,broker负载报告,BookKeeper ledger信息(这个是BookKeeper本身所依赖的)等等。

基于bookKeeper持久化存储

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

为了提供这种保证,未确认送达的消息需要持久化存储直到它们被确认送达。这种消息传递模式通常称为持久消息传递. 在Pulsar内部,所有消息都被保存并同步N份,例如,2个服务器保存四份,每个服务器上面都有镜像的RAID存储。

Pulsar用 Apache bookKeeper作为持久化存储。 bookKeeper是一个分布式的预写日志(WAL)系统,有如下几个特性特别适合Pulsar的应用场景:

  1. 使pulsar能够利用独立的日志,称为ledgers. 可以随着时间的推移为topic创建多个Ledgers

  2. 它为处理顺序消息提供了非常有效的存储

  3. 保证了多系统挂掉时Ledgers的读取一致性

  4. 提供不同的Bookies之间均匀的IO分布的特性

  5. 它在容量和吞吐量方面都具有水平伸缩性。能够通过增加bookies立即增加容量到集群中,并提升吞吐量

  6. Bookies被设计成可以承载数千的并发读写的ledgers。 使用多个磁盘设备 (一个用于日志,另一个用于一般存储) ,这样Bookies可以将读操作的影响和对于写操作的延迟分隔开(读写分离)。

基于bookKeeper持久化存储

在这里插入图片描述

Ledger是一个只追加的数据结构,并且只有一个写入器,这个写入器负责多个bookKeeper存储节点(就是Bookies)的写入。 Ledger的条目会被复制到多个bookies。 Ledgers本身有着非常简单的语义:

  • Pulsar Broker(管理ledeger)可以创建ledeger,添加内容到ledger和关闭ledger。

  • 当一个ledger被关闭后,除非明确的要写数据或者是因为写入器挂掉导致ledger关闭,ledger只会以只读模式打开。

  • 最后,当ledger中的条目不再有用的时候,整个ledger可以被删除(ledger分布是跨Bookies的)。

Pulsar 代理

Pulsar客户端和Pulsar集群交互的一种方式就是直连Pulsar brokers。然而,在某些情况下,这种直连既不可行也不可取,因为客户端并不知道broker的地址。 例如在云环境或者Kubernetes以及其他类似的系统上面运行Pulsar,直连brokers就基本上不可能了。

Pulsar proxy 为这个问题提供了一个解决方案, 为所有的broker提供了一个网关, 如果选择运行了Pulsar Proxy. 所有的客户都会通过这个代理而不是直接与brokers通信

在这里插入图片描述

Apache Pulsar的Local与分布式集群构建

Apache Pulsar本地Local模式

Standalone Local单机本地模式, 是pulsar最简单的安装方式, 此种方式仅适用于测试学习使用, 并无法作为开发中使用。

下载Apache pulsar2.8.1 https://pulsar.apache.org/en/download/

在这里插入图片描述

服务器系统要求:

Currently, Pulsar is available for 64-bit macOS, Linux, and Windows. To use Pulsar, you need to install 64-bit JRE/JDK 8 or later versions. (目前,Pulsar可用于64位macOS、Linux和Windows。使用Pulsar需要安装64位JRE/JDK 8或更高版本。)

  • Apache Pulsar的Local模式构建
cd /export/software
rz  上传即可apache-pulsar-2.8.1-bin.tar.gz   上传Pulsar安装包到linux服务器中,并解压

tar -zxvf apache-pulsar-2.8.1-bin.tar.gz -C /export/server
cd /export/server && ln -s apache-pulsar-2.8.1-bin puslar_2.8.1  构建软连接:

cd /export/server/puslar_2.8.1/bin  启动单机模式Pulsar
./pulsar standalone

在这里插入图片描述

  • Apache Pulsar的Local模式基本使用

在pulsar的bin目录下, 专门提供了一个pulsar-client的客户端工具, Pulsar-Clinet工具允许使用者在运行的集群中消费并发送消息到Pulsar Topic中.

./pulsar-client consume my-topic -s "first-subscription"
./pulsar-client produce my-topic --messages "hello-pulsar"

在这里插入图片描述

在这里插入图片描述

Apache Pulsar分布式集群模式

  • 分布式集群模式构建:搭建 Pulsar 集群至少需要 3 个组件:ZooKeeper 集群、BookKeeper 集群和 broker 集群(Broker 是 Pulsar 的自身实例)。这三个集群组件如下:
    • ZooKeeper 集群(3 个 ZooKeeper 节点组成)
    • bookie 集群(也称为 BookKeeper 集群,3 个 BookKeeper 节点组成)
    • broker 集群(3 个 Pulsar 节点组成)

​ Pulsar 的安装包已包含了搭建集群所需的各个组件库。无需单独下载 ZooKeeper 安装包和 BookKeeper 安装包。(在实际中,zookeeper我们并不仅仅应用在pulsar上, 包括HBase等其他的组件也需要依赖, 所以我们此处zookeeper使用外置zk集群环境)

​ 注意: 如果是在内网测试环境搭建集群,为了避免防火墙造成端口开启繁琐,可以关闭服务器防火墙。

​ 分布式模式 最低需要三台服务器进行安装操作。

搭建Zookeeper集群

在这里插入图片描述

Zookeeper集群具有以下特点:

  1. Zookeeper集群有一个leader服务器和多个follower服务器,leader是运行时动态选举出来的。
  2. Zookeeper集群中只要由半数以上的节点可用,Zookeeper集群就能正常提供服务。
  3. Zookeeper集群中每个服务器保存一份相同的数据副本,客户端无论连接哪台服务器,数据都是一致的。
  4. 更新请求顺序进行,来自同一个客户端的更新请求按其发送的顺序依次执行。
  5. 数据更新原子性,一次数据要么更新成功,要么更新失败。
  6. 实时性,在一定时间范围内,客户端能读到最新数据。
mkdir /opt/zkdata1 /opt/zkdata2 /opt/zkdata3   创建三个dataDir
touch ./zkdata1/myid ./zkdata2/myid ./zkdata3/myid  分别在三个dataDir中创建myid文件,并在myid文件中指定服务器标识
echo 1 > ./zkdata1/myid
echo 2 > ./zkdata2/myid
echo 3 > ./zkdata3/myid

创建三个Zookeeper配置文件,并添加集群配置

zoo1.cfg:

tickTime=2000
initLimit=10
syncLimit=5
# 指定数据存储位置
dataDir=/opt/zkdata1
# 指定客户端连接的端口
clientPort=2181
# 指定集群中服务器
# 端口1:用于数据同步
# 端口2:用于leader选举
server.1=192.168.88.161:2880:3881
server.2=192.168.88.162:2882:3883
server.3=192.168.88.163:2884:3885

zoo2.cfg:

tickTime=2000
initLimit=10
syncLimit=5
# 指定数据存储位置
dataDir=/opt/zkdata2
# 指定客户端连接的端口
clientPort=2182
# 指定集群中服务器
# 端口1:用于数据同步
# 端口2:用于leader选举
server.1=192.168.88.161:2880:3881
server.2=192.168.88.162:2882:3883
server.3=192.168.88.163:2884:3885

zoo3.cfg:

tickTime=2000
initLimit=10
syncLimit=5
# 指定数据存储位置
dataDir=/opt/zkdata3
# 指定客户端连接的端口
clientPort=2183
# 指定集群中服务器
# 端口1:用于数据同步
# 端口2:用于leader选举
server.1=192.168.88.161:2880:3881
server.2=192.168.88.162:2882:3883
server.3=192.168.88.163:2884:3885

**启动zkserver **

./bin/zkServer.sh start ./conf/zoo1.cfg 
./bin/zkServer.sh start ./conf/zoo2.cfg 
./bin/zkServer.sh start ./conf/zoo3.cfg 

客户端连接

[root@192.168.88.161 zookeeper]# ./bin/zkCli.sh -server 192.168.88.161:2183

[zk: 192.168.88.161:2183(CONNECTED) 1] ls /
[zookeeper]
[zk: 192.168.88.161:2183(CONNECTED) 2] create /mynode1 mydata1
Created /mynode1

[root@192.168.88.161 zookeeper]# ./bin/zkCli.sh -server 192.168.88.161:2181

[zk: 192.168.88.161:2181(CONNECTED) 1] ls /
[mynode1, zookeeper]

查看状态角色

./bin/zkServer.sh status ./conf/zoo1.cfg   其中Mode就是zk server的角色
  • LOOKING:表示当前集群中没有leader节点,需要进行选举。
  • LEADING:表示当前节点为leader。
  • FOLLOWING:表示leader已经被选出,当前节点为follower。
  • OBSERVER:表示当前节点为observer。
  1. 服务器1和服务器2启动后进入LOOKING状态,开始进行Leader选举。

  2. 每个服务器都会发出一个投票,在初始阶段,服务器1和服务器2将投票自己作为Leader服务器,每次投票都会包含推荐服务器的myid和zxid,然后将每个投票发送给集群中的其他服务器。

  3. 集群中的每个服务器接收到投票后,首先判断投票的有效性,例如是否为当前轮投票,是否来自处于LOOKING状态的服务器。

  4. 每个服务器都会将其他服务器的投票和自己的投票进行对比,首先对比zxid,较大zxid的服务器优先作为leader。如果zxid一样,则比较myid,myid较大的优先作为leader。

  5. 由于是集群初始化阶段,每个服务器的zxid都为0,所以开始比较myid,服务器2的myid较大,所以服务器2获胜。服务器1将其投票更新为投给服务器2,并将投票重新发送给服务器2,此时服务器的票数已经超过集群节点半数,服务器2被选为leader。

  6. 一旦确定了leader,每个服务器将更新自己的状态。服务器1将状态改为FOLLOWING,服务器2将状态改为LEADING,当服务器3启动时,发现已经有一个Leader,不再进行选举,直接将状态从LOOKING改为FOLLOWING。

当作为leader的服务器2被停止后,又会重新进行leader选举。停止服务器2:./bin/zkServer.sh stop ./conf/zoo2.cfg ,再查看各服务器角色Mode,服务器3被选举为leader,原因是服务器3最近创建了节点,拥有了比服务器1更大的zxid,所以服务器3被选举为leader。(节点的变化会导致zxid递增)

运行流程

在Zookeeper集群中,客户端可用连接集群中任意一台服务器进行操作。

如果是读请求,则直接从当前服务器读取数据。

如果是写请求则分为以下步骤:

  1. 如果请求的服务器不是leader,则当前请求的服务器会把请求转发给leader。

  2. leader将写请求广播给各个服务器,各个服务器写成功后会通知leader。

  3. 当leader收到大多数服务器写成功的通知,则表示写入成功,leader将通知之前的接收请求的服务器,由它进一步的通知客户端写入成功

搭建Pulsar集群

cd /export/software
rz  上传即可apache-pulsar-2.8.1-bin.tar.gz   将下载的pulsar安装包上传到linux服务器, 并解压
tar -zxvf apache-pulsar-2.8.1-bin.tar.gz -C /export/server
cd /export/server  && ln -s apache-pulsar-2.8.1-bin puslar_2.8.1  构建软连接

修改bookkeeper集群配置文件

cd /export/server/pulsar_2.8.1/conf/
vim bookkeeper.conf

修改其第56行:修改本地ip地址
advertisedAddress=192.168.88.161
修改其39行:
journalDirectory=/export/server/pulsar_2.8.1/tmp/journal
修改其389行:
ledgerDirectories=/export/server/pulsar_2.8.1/tmp/ledger
修改602行:
zkServers=192.168.88.161:2181,192.168.88.162:2181,192.168.88.163:2181

修改broker集群的配置文件

cd /export/server/pulsar_2.8.1/conf/
vim broker.conf
修改第98行: 修改集群的名称
clusterName=pulsar-cluster
修改第23行: 配置zookeeper地址
zookeeperServers=192.168.88.161:2181,192.168.88.162:2181,192.168.88.163:2181
修改第26行: 配置zookeeper地址
configurationStoreServers=192.168.88.161:2181,192.168.88.162:2181,192.168.88.163:2181
修改第44行: 更改为本地ip地址
advertisedAddress=192.168.88.161

将配置好bookies目录和brokers目录发送到第二台和第三台

cd /export/server
scp -r apache-pulsar-2.8.1/ node2:$PWD 
scp -r apache-pulsar-2.8.1/ node3:$PWD

在第二台和第三台节点上分别配置软连接
cd /export/server
ln -s apache-pulsar-2.8.1/ pulsar_2.8.1 

修改第二台和第三台的broker的地址和bookies地址

node2:
cd /export/server/pulsar_2.8.1/conf/
vim bookkeeper.conf
修改其第56行:修改本地ip地址
advertisedAddress=192.168.88.162

vim broker.conf
修改第44行: 更改为本地ip地址
advertisedAddress=192.168.88.162

第三台节点: 都更改为对应IP地址或者主机名即可

Apache Pulsar的分布式集群模式启动(只初始化一次)

cd /export/server/zookeeper/bin  启动zk
./zkServer.sh start
注意: 三个节点依次都要启动, 启动后 通过 
./zkServer.sh status   
查看状态, 必须看到一个leader 和两个follower 才可以使用

首先初始化Pulsar集群元数据:
cd /export/server/pulsar_2.8.1/bin
./pulsar initialize-cluster-metadata \
--cluster pulsar-cluster \
--zookeeper 192.168.88.161:2181,192.168.88.162:2181,192.168.88.163:2181 \
--configuration-store 192.168.88.161:2181,192.168.88.162:2181,192.168.88.163:2181 \
--web-service-url http://192.168.88.161:8080,192.168.88.162:8080,192.168.88.163:8080 \
--web-service-url-tls https://192.168.88.161:8443,192.168.88.162:8443,192.168.88.163:8443 \
--broker-service-url pulsar://192.168.88.161:6650,192.168.88.162:6650,192.168.88.163:6650 \
--broker-service-url-tls pulsar+ssl://192.168.88.161::6651,192.168.88.162:6651,192.168.88.163:6651

接着初始化bookkeeper集群: 若出现提示输入Y/N: 请输入Y
./bookkeeper shell metaformat

cd /export/server/pulsar_2.8.1/bin  启动bookkeeper服务
./pulsar-daemon start bookie
注意: 三个节点都需要依次启动

验证是否启动: 可三台都检测
./bookkeeper shell bookiesanity
提示:
    Bookie sanity test succeeded  认为启动成功
    
cd /export/server/pulsar_2.8.1/bin  启动Broker
./pulsar-daemon start broker
注意: 三个节点都需要依次启动

检测是否启动:
   ./pulsar-admin brokers list pulsar-cluster    

在这里插入图片描述

测试

./pulsar-client consume persistent://public/default/test -s "consumer-test"  模拟开启消费者监听数据 永久://租户/名称空间/topicName
./pulsar-client produce persistent://public/default/test --messages "hello-pulsar"  模拟生产一条数据

Apache Pulsar可视化监控部署

下载地址: https://dist.apache.org/repos/dist/release/pulsar/pulsar-manager/pulsar-manager-0.2.0/apache-pulsar-manager-0.2.0-bin.tar.gz

cd /export/software
rz 上传 apache-pulsar-manager-0.2.0-bin.tar.gz

解压操作:
tar -zxf apache-pulsar-manager-0.2.0-bin.tar.gz -C /export/server/

cd /export/server/pulsar-manager
接着再次解压:
tar -xvf pulsar-manager.tar

cd /export/server/pulsar-manager/pulsar-manager
cp -r ../dist ui
cd /export/server/pulsar-manager/pulsar-manager
./bin/pulsar-manager

CSRF_TOKEN=$(curl http://192.168.88.161:7750/pulsar-manager/csrf-token)
curl \
    -H "X-XSRF-TOKEN: $CSRF_TOKEN" \
    -H "Cookie: XSRF-TOKEN=$CSRF_TOKEN;" \
    -H 'Content-Type: application/json' \
    -X PUT http://192.168.88.161:7750/pulsar-manager/users/superuser \
-d '{"name": "pulsar", "password": "pulsar", "description": "test", "email": "username@test.org"}'

访问http://192.168.88.161:7750/ui/index.html 用户名: pulsar密码: pulsar

点击 new Enirconment 构建新环境,连接pulsar

在这里插入图片描述

点击 pulsar_cluster,进入管理界面

在这里插入图片描述

Apache Pulsar的主要组件介绍与命令使用

多租户模式

​ 多租户是一种架构,目的是为了让多用户环境下使用同一套程序,且保证用户间数据隔离

​ 简单讲:在一台服务器上运行单个应用实例,它为多个租户(客户)提供服务。

​ Apache Pulsar 最初诞生于雅虎,当时就是为了解决雅虎内部各个部门之间数据的协调,所以多租户特性显得至关重用,Pulsar 从诞生之日起就考虑到多租户这一特性,并在后续的实现过程中,将其不断的完善。 多租户这一特性,使得各个部门之间可以共享同一份数据,不用单独部署独立的系统来操作数据,很好的保证了各部门间数据一致性的问题,同时简化维护成本。

什么是多租户

Pulsar 的多租户设计符合上述要求:

  • 使用身份验证、授权和 ACL(访问控制列表)确保其安全性

  • 为每个租户强制执行存储配额

  • 支持在运行时更改隔离机制,从而实现操作成本低和管理简单

persistent://tenant/namespace/topic

从URL中可以看出tenant(租户)是topic最基本的单元(比命名空间和topic名称更为基本)

tenant 代表的是租户名,它是一个资源的隔离单位,一个 tenant 下可以有多个 namespace。namespace 用来管理其下面所属的 topics,可以在 namespace 级别给 topic 设置相应的策略,比如 retention,backlog,ratelimit。一个 namespace 下又可以有多个 topic,他们的权限大小也是由上到下。Pulsar 的多租户通过 tenant、namespace、topic 形成多级管理系统。

在这里插入图片描述

Pulsar多租户的相关特性_安全性(认证和授权)

一个多租户系统需要在租户内提供系统级别的安全性,细分来讲,主要可以归类为一下两点:

  • 租户只能访问它有权限访问的 topics

  • 不允许访问它无法访问的 topics

在 Pulsar 中,多租户的安全性是通过身份验证和授权机制实现的。当 client 连接到 pulsar broker 时,broker 会使用身份验证插件来验证此客户端的身份,然后为其分配一个 string 类型的 role token。role token 主要有如下作用:

  • 判断 client 是否有对 topics 进行生产或消费消息的权限
  • 管理租户属性的配置

Pulsar 目前支持一下几种身份认证, 同时支持自定义实现自己的身份认证程序

  • TLS 客户端身份认证
  • 雅虎的身份认证系统: Athenz
  • Kerberos
  • JSON Web Token 认证

在这里插入图片描述

​ 当身份认证系统识别出客户端的 role token 之后,Pulsar broker 会使用授权系统来告诉客户端当前你可以执行哪些操作。授权操作是在 tenant 级别进行配置的,这意味着在 Pulsar 集群中,允许用户根据不同的角色设定多个授权方案。具体的权限操作是在 namespace 级别进行设置和管理的,例如:针对某一个 topic 是否具有 produce 或 consume 的权限归属于 namespace 这个级别来控制。换句话来说:在 tenant 级别 用户可以配置,什么样的 role 拥有对哪些 tenant 操作的权限,在 namespace 级别用户可以配置,针对某一 topic 当前role拥有什么样的权限,又回到了开头所介绍的,namespace 主要用来管理它所包含的 topics 的属性。

Pulsar多租户的相关特性_隔离性

隔离性主要分为如下两种:

软隔离: 通过磁盘配额,流量控制和限制等手段

存储:
Apache Pulsar 使用Bookkeeper来作为其存储层, bookie是Bookkeeper的实例, Bookkeeper本身就是具有I/O分离(读写分离)的特性,可以很好的做好IO隔离, 提升读写的效率
同时, 不同的租户可以为不同的NameSpace配置不同的存储配额, 当租户内消息的大小达到了存储配额的限制, Pulsar会采取相应的措施, 例如: 阻止消息生成, 抛异常 或丢弃数据等

Broker:
每个Borker使用的内存资源都是有上限的, 当Broker达到配置的CPU或内存使用的阈值后, Pulsar会迅速的将流量转移到负载较小的Broker处理
在生产和消费方面, Pulsar都可以进行流量控制,租户可以配置发送和接收的速率,避免出现一个客户端占用当前Broker的所有处理资源

硬隔离: 物理资源隔离

​ Pulsar 允许将某些租户或名称空间与特定 Broker 进行隔离。这可确保这些租户或命名空间可以充分利用该特定 Broker 上的资源。

Pulsar多租户的相关操作

cd /export/server/brokers/bin
./pulsar-admin tenants list  获取租户列表
cd /export/server/brokers/bin
./pulsar-admin tenants create my-tenant

在创建租户时,可以使用-r 或者 --admin-roles标志分配管理角色。可以用逗号分隔的列表指定多个角色。-c或者--allowed-clusters指定跨地域复制的集群
./pulsar-admin tenants create my-tenant --admin-roles role1,role2,role3   创建租户
./pulsar-admin tenants create my-tenant -r role1

pulsar-admin tenants get my-tenant  获取租户配置
{
  "adminRoles": [
    "admin1",
    "admin2"
  ],
  "allowedClusters": [
    "cl1",
    "cl2"
  ]
}

cd /export/server/brokers/bin  
./pulsar-admin tenants update my-tenant  基于update可以更新租户的相关配置信息

cd /export/server/brokers/bin
./pulsar-admin tenants delete my-tenant  删除租户,在删除的时候, 如果库下已经有名称空间, 是无法删除的,需要先删除名称空间

Pulsar的名称空间

什么是名称空间

​ namespace是Pulsar中最基本的管理单元,在namespace这一层面,可以设置权限,调整副本设置,管理跨集群的消息复制,控制消息策略和执行关键操作。一个主题topic可以继承其所对应的namespace的属性,因此我们只需对namespace的属性进行设置,就可以一次性设置该namespace中所有主题topic的属性。

namespace有两种,分别是本地的namespace和全局的namespace:

  • 本地namespace——仅对定义它的集群可见。

  • 全局namespace——跨集群可见,可以是同一个数据中心的集群,也可以是跨地域中心的集群,这依赖于是否在namespace中设置了跨集群拷贝数据的功能。

​ 虽然本地namespace和全局namespace的作用域不同,但是只要对他们进行适当的设置,都可以跨团队和跨组织共享。一旦生产者获得了namespace的写入权限,那么它就可以往namespace中的所有topic主题写入数据,如果某个主题不存在,则在生产者第一次写入数据时动态创建。

cd /export/server/brokers/bin
./pulsar-admin namespaces create test-tenant/test-namespace  在指定的租户下创建名称空间
./pulsar-admin namespaces list test-tenant  获取某租户下所有的名称空间列表
./pulsar-admin namespaces delete test-tenant/test-namespace  删除名称空间
./pulsar-admin namespaces policies test-tenant/test-namespace

在这里插入图片描述

Pulsar NameSpace(名称空间) 相关操作_高级操作

cd /export/server/brokers/bin
pulsar-admin namespaces set-clusters test-tenant/ns1 --clusters cl2  设置复制集群
pulsar-admin namespaces get-clusters test-tenant/ns1  获取给定命名空间复制集群的列表
pulsar-admin namespaces set-backlog-quota --limit 10G --limitTime 36000 --policy producer_request_hold test-tenant/ns1  设置backlog quota 策略
--policy 的值选择:
       producer_request_hold:broker 暂停运行,并不再持久化生产请求负载
       producer_exception:broker 抛出异常,并与客户端断开连接。
       consumer_backlog_eviction:broker 丢弃积压消息
        
pulsar-admin namespaces get-backlog-quotas test-tenant/ns1   获取 backlog quota 策略
{
  "destination_storage": {
    "limit": 10,
    "policy": "producer_request_hold"
  }
}
 
pulsar-admin namespaces remove-backlog-quota test-tenant/ns1       移除backlog quota 策略
 
pulsar-admin namespaces set-persistence --bookkeeper-ack-quorum 2 --bookkeeper-ensemble 3 --bookkeeper-write-quorum 2 --ml-mark-delete-max-rate 0 test-tenant/ns1   设置持久化策略, 持久化策略可以为给定命名空间下 topic 上的所有消息配置持久等级

参数说明:
Bookkeeper-ack-quorum:每个 entry 在等待的 acks(有保证的副本)数量,默认值:0
Bookkeeper-ensemble:单个 topic 使用的 bookie 数量,默认值:0
Bookkeeper-write-quorum:每个 entry 要写入的次数,即两个副本,默认值:0
Ml-mark-delete-max-rate:标记-删除操作的限制速率(0表示无限制),默认值:0.0


pulsar-admin namespaces get-persistence test-tenant/ns1  获取持久化策略
{
  "bookkeeperEnsemble": 3,
  "bookkeeperWriteQuorum": 2,
  "bookkeeperAckQuorum": 2,
  "managedLedgerMaxMarkDeleteRate": 0
}

pulsar-admin namespaces set-message-ttl --messageTTL 100 test-tenant/ns1  设置消息存活时间
pulsar-admin namespaces get-message-ttl test-tenant/ns1  获取消息的存活时间
pulsar-admin namespaces remove-message-ttl test-tenant/ns1  删除消息的存活时间
 
pulsar-admin namespaces set-dispatch-rate test-tenant/ns1 \
  --msg-dispatch-rate 1000 \
  --byte-dispatch-rate 1048576 \
  --dispatch-rate-period 1   设置Topic的消息发送的速率

参数说明:
--msg-dispatch-rate :  每dispatch-rate-period秒钟发送的消息数量
--byte-dispatch-rate : 每dispatch-rate-period秒钟发送的总字节数
--dispatch-rate-period :  设置发送的速率, 比如 1 表示 每秒钟
 
pulsar-admin namespaces get-dispatch-rate test-tenant/ns1  获取topic的消息发送速率
{
  "dispatchThrottlingRatePerTopicInMsg" : 1000,
  "dispatchThrottlingRatePerTopicInByte" : 1048576,
  "ratePeriodInSecond" : 1
}
 
pulsar-admin namespaces set-subscription-dispatch-rate test-tenant/ns1 \
  --msg-dispatch-rate 1000 \
  --byte-dispatch-rate 1048576 \
  --dispatch-rate-period   设置Topic的消息接收的速率

参数说明:
--msg-dispatch-rate :  每dispatch-rate-period秒钟接收的消息数量
--byte-dispatch-rate : 每dispatch-rate-period秒钟接收的总字节数
--dispatch-rate-period :  设置接收的速率, 比如 1 表示 每秒钟
 
pulsar-admin namespaces get-subscription-dispatch-rate test-tenant/ns1  获取topic的消息接收速率
{
  "dispatchThrottlingRatePerTopicInMsg" : 1000,
  "dispatchThrottlingRatePerTopicInByte" : 1048576,
  "ratePeriodInSecond" : 1
}

7.1- 设置Topic的消息复制集群的速率
pulsar-admin namespaces set-replicator-dispatch-rate test-tenant/ns1 \
  --msg-dispatch-rate 1000 \
  --byte-dispatch-rate 1048576 \
  --dispatch-rate-period 1

参数说明:
--msg-dispatch-rate :  每dispatch-rate-period秒钟复制集群的消息数量
--byte-dispatch-rate : 每dispatch-rate-period秒钟复制集群的总字节数
--dispatch-rate-period :  设置复制集群的速率, 比如 1 表示 每秒钟
 
pulsar-admin namespaces get-replicator-dispatch-rate test-tenant/ns1  获取topic的消息复制集群的速率
{
  "dispatchThrottlingRatePerTopicInMsg" : 1000,
  "dispatchThrottlingRatePerTopicInByte" : 1048576,
  "ratePeriodInSecond" : 1
}

Pulsar的topic相关操作

什么是Topic

​ Topic,话题主题的含义, 在一个名称空间下, 可以定义多个Topic 通过Topic进行数据的分类划分, 将不同的类别的消息放置到不同Topic, 消费者也可以从不同Topic中获取到相关的消息, 是一种更细粒度的消息划分操作, 同时在Topic下可以划分为多个分片, 进行分布式的存储操作, 每个分片下还存在有副本操作, 保证数据不丢失, 当然这些分片副本更多是由bookkeeper来提供支持

​ Pulsar 提供持久化与非持久化两种topic。 持久化topic是消息发布、消费的逻辑端点。 持久化topic地址的命名格式如下:persistent://tenant/namespace/topic

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

Pulsar 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

注意: 不管是有分区还是没有分区, 创建topic后,如果没有任何操作, 60s后pulsar会认为此topic是不活动的, 会自动进行删除, 以避免生成垃圾数据

相关配置:
     Brokerdeleteinactivetopicsenabenabled : 默认值为true 表示是否启动自动删除
     BrokerDeleteInactiveTopicsFrequencySeconds: 默认为60s 表示检测未活动的时间
     
./pulsar-admin namespaces list my-tenant 列出当前某个名称空间下的所有Topic
./pulsar-admin topics list my-tenant/my-namespace     


./pulsar-admin topics update-partitioned-topic persistent://my-tenant/my-namespace/my-topic --partitions 8  我们可针对有分区的topic去更新其分区的数量
bin/pulsar-admin topics delete persistent://my-tenant/my-namespace/my-topic  删除没有分区的topic
bin/pulsar-admin topics delete-partitioned-topic persistent://my-tenant/my-namespace/my-topic  删除有分区的topic

Pulsar Topic(主题) 相关操作_高级操作

pulsar-admin topics grant-permission --actions produce,consume --role application1 persistent://test-tenant/ns1/tp1  授权赋予角色
pulsar-admin topics grant-permission --actions produce,consume --role application1 persistent://test-tenant/ns1/tp1  获取权限
pulsar-admin topics revoke-permission --role application1 persistent://test-tenant/ns1/tp1   取消权限

{
  "application1": [
    "consume",
    "produce"
  ]
}

Apache Pulsar的JAVA API相关使用操作

新增依赖

    <dependency>
        <groupId>org.apache.pulsar</groupId>
        <artifactId>pulsar-client-all</artifactId>
        <version>2.8.1</version>
    </dependency>

管理租户

    public static void main(String[] args) throws Exception {

        // 1. 创建Pulsar的Admin管理对象
        String serviceHttpUrl = "http://node1:8080,node2:8080,node3:8080";
        PulsarAdmin pulsarAdmin = PulsarAdmin.builder().serviceHttpUrl(serviceHttpUrl).build();
        //2. 基于Pulsar的Admin对象进行相关的操作

        //2.1: 如何创建 租户操作
        HashSet<String> allowedClusters = new HashSet<>();
        allowedClusters.add("pulsar-cluster");
        TenantInfo config = TenantInfo.builder().allowedClusters(allowedClusters).build();
        pulsarAdmin.tenants().createTenant("pulsar_t",config);

        // 2.2: 查看当前有那些租户
        /*List<String> tenants = pulsarAdmin.tenants().getTenants();
        for (String tenant : tenants) {
            System.out.println("租户信息为:"+tenant);
        }*/

        //2.3: 删除租户操作
        //pulsarAdmin.tenants().deleteTenant("pulsar_t");


        //3. 关闭管理对象
        pulsarAdmin.close();

    }

管理namespace

    public static void main(String[] args) throws Exception {

        //1. 创建Pulsar的Admin管理对象
        String serviceHttpUrl = "http://node1:8080,node2:8080,node3:8080";
        PulsarAdmin pulsarAdmin = PulsarAdmin.builder().serviceHttpUrl(serviceHttpUrl).build();
        //2. 执行相关的操作

        //2.1 如何创建名称空间
        // pulsarAdmin.namespaces().createNamespace("pulsar_t/pulsar_n");

        //2.2 获取在某个租户下, 一共有那些名称空间:
        /*List<String> namespaces = pulsarAdmin.namespaces().getNamespaces("pulsar_t");

        for (String namespace : namespaces) {
            System.out.println(namespace);
        }*/

        //2.3: 删除名称空间
        pulsarAdmin.namespaces().deleteNamespace("pulsar_t/pulsar_n");

        //3. 关闭admin对象
        pulsarAdmin.close();
    }

管理Topic

	public static void main(String[] args) throws Exception {

        //1. 创建Pulsar的Admin管理对象
        String serviceHttpUrl = "http://node1:8080,node2:8080,node3:8080";
        PulsarAdmin pulsarAdmin = PulsarAdmin.builder().serviceHttpUrl(serviceHttpUrl).build();
        //2. 执行相关的操作
        //2.1: 创建 Topic相关的操作: 有分区和没有分区, 以及持久化和非持久化
        pulsarAdmin.topics().createNonPartitionedTopic("persistent://pulsar_t/pulsar_n/t_topic5");
        //pulsarAdmin.topics().createNonPartitionedTopic("non-persistent://pulsar_t/pulsar_n/t_topic2");

        // pulsarAdmin.topics().createPartitionedTopic("persistent://pulsar_t/pulsar_n/t_topic3",5);
        //pulsarAdmin.topics().createPartitionedTopic("non-persistent://pulsar_t/pulsar_n/t_topic5",5);

        //2.2: 查询当前有那些topic:
        /*List<String> topicList = pulsarAdmin.topics().getList("pulsar_t/pulsar_n");
        for (String topic : topicList) {
            System.out.println(topic);
        }*/
        List<String> topicList = pulsarAdmin.topics().getPartitionedTopicList("pulsar_t/pulsar_n");

        for (String topic : topicList) {
            System.out.println(topic);
        }

        //2.3 修改Topic 分片的数量
        //pulsarAdmin.topics().updatePartitionedTopic("persistent://pulsar_t/pulsar_n/t_topic3",7);

        //2.4 一共有多少个分片呢
        //int partitions = pulsarAdmin.topics().getPartitionedTopicMetadata("persistent://pulsar_t/pulsar_n/t_topic3").partitions;
        //System.out.println(partitions);

        //2.5: 删除Topic
        //pulsarAdmin.topics().deletePartitionedTopic("persistent://pulsar_t/pulsar_n/t_topic3");

        //3. 关闭admin对象
        pulsarAdmin.close();
    }

数据同步生产

    public static void main(String[] args) throws Exception {

        //1. 创建Pulsar的客户端对象
        PulsarClient pulsarClient = PulsarClient.builder().serviceUrl("pulsar://node1:6650,node2:6650,node3:6650").build();

        //2. 通过客户端创建生产者的对象

        Producer<String> producer = pulsarClient.newProducer(Schema.STRING)
                .topic("persistent://public/default/test_src")
                .create();
        //3. 使用生产者发送数据
        producer.send("hello java API pulsar ...");

        System.out.println("数据生产完成....");
        //4. 释放资源
        producer.close();
        pulsarClient.close();


    }

数据异步生产

    public static void main(String[] args) throws Exception {

        //1. 创建Pulsar的客户端对象
        PulsarClient pulsarClient = PulsarClient.builder().serviceUrl("pulsar://node1:6650,node2:6650,node3:6650").build();

        //2. 通过客户端构建生产者的对象
        Producer<String> producer = pulsarClient.newProducer(Schema.STRING)
                .topic("persistent://pulsar_t/pulsar_n/t_topic1")
                .create();
        //3. 进行数据发送操作
        // 发现数据并没有生产成功, 主要原因是
        //          因为采用异步的发送方案, 这种发送方案会先将数据写入到客户端缓存中, 当缓存中数据达到一批后 才会进行发送操作
        producer.sendAsync("hello async pulsar...2222");
        System.out.println("数据生产成功....");

        // 可以发送完成后, 让程序等待一下, 让其将缓冲区中数据刷新到pulsar上 然后在结束
        Thread.sleep(1000);
        //4. 释放资源
        producer.close();
        pulsarClient.close();
    }

数据Scheme模式

    public static void main(String[] args) throws Exception {
        //1. 获取pulsar的客户端对象
        ClientBuilder clientBuilder = PulsarClient.builder();
        clientBuilder.serviceUrl("pulsar://node1:6650,node2:6650,node3:6650");
        PulsarClient client = clientBuilder.build();
        //2. 通过客户端创建生产者的对象
        AvroSchema<User2> schema = AvroSchema.of(SchemaDefinition.<User2>builder().withPojo(User2.class).build());
        // AvroSchema<User2> schema = AvroSchema.of(User2.Class);
        Producer<User2> producer = client.newProducer(schema)
                .topic("persistent://pulsar_t/pulsar_n/my-topic3").create();
        //3. 发送消息:
        User2 user = new User2();
        user.setName("张三");
        user.setAge(20);
        user.setAddress("北京");
        user.setRowkey("rk001");
        user.setFamilyName("C1");
        producer.send(user);
        Thread.sleep(10000);
        //4. 释放资源
        producer.close();
        client.close();
    }

数据同步消费

    public static void main(String[] args)  throws Exception{ 
        //1. 创建pulsar的客户端的对象
        PulsarClient pulsarClient = PulsarClient.builder().serviceUrl("pulsar://node1:6650,node2:6650,node3:6650").build();
        //2. 基于客户端构建消费者对象
        Consumer<String> consumer = pulsarClient.newConsumer(Schema.STRING)
                .topic("txn_t4")
                .subscriptionName("sub_04")
                .subscriptionType(SubscriptionType.Exclusive)
                .subscribe();
        //3. 循环从消费者读取数据
        while(true) {
            //3.1: 接收消息
            Message<String> message = consumer.receive();
            //3.2: 获取消息
            String msg = message.getValue();
            //3.3: 处理数据--- 业务操作
            System.out.println("消息数据为:"+msg);
            //3.4: ack确认操作
            consumer.acknowledge(message);
            // 如果消费失败了, 可以采用try catch方式进行捕获异常, 捕获后, 可以进行告知没有消费
            //consumer.negativeAcknowledge(message);
        }  
    }

数据Schema模式

    public static void main(String[] args) throws Exception {
        //1. 创建Pulsar的客户端对象
        PulsarClient pulsarClient = PulsarClient.builder().serviceUrl("pulsar://node1:6650,node2:6650,node3:6650").build();
        //2. 基于客户端对象构建消费者对象
        Consumer<User> consumer = pulsarClient.newConsumer(AvroSchema.of(User.class))
                .topic("persistent://pulsar_t/pulsar_n/my_tt04")
                .subscriptionName("sub_05")
                .subscribe();
        //3. 循环读取数据操作
        while(true){
            //3.1: 接收消息
            Message<User> message = consumer.receive();
            //3.2: 获取消息数据
            User msg = message.getValue();
            System.out.println(msg);
        }
    }

数据批处理

    public static void main(String[] args) throws Exception{
        //1. 构建Pulsar的客户端对象
        PulsarClient pulsarClient = PulsarClient.builder().serviceUrl("pulsar://node1:6650,node2:6650,node3:6650").build();
        //2. 通过客户端构建消费者对象
        Consumer<String> consumer = pulsarClient.newConsumer(Schema.STRING)
                .topic("persistent://pulsar_t/pulsar_n/t_topic1")
                .subscriptionName("sub_04")
                // 设置支持批量读取参数配置
                .batchReceivePolicy(
                        BatchReceivePolicy.builder()
                                .maxNumBytes(1024 * 1024)
                                .maxNumMessages(100)
                                .timeout(2000, TimeUnit.MILLISECONDS)
                                .build()
                )
                .subscribe();
        //3. 循环读取数据
        while (true) {
            //3.1 读取消息(批量)
            Messages<String> messages = consumer.batchReceive();
            //3.2: 获取消息数据
            for (Message<String> message : messages) {
                String msg = message.getValue();
                System.out.println("消息数据为:"+msg);
                //3.3 ack确认
                consumer.acknowledge(message);
            }
        }
    }
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 1
    评论
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

onejane

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值