简介:Apache Pulsar 2.9.1 二进制发行包,专为分布式消息队列与流处理场景设计,面向需要高吞吐、低延迟、可扩展消息中间件的开发者、架构师及运维团队。压缩包为 gz 格式,体积约 321.53MB,内含服务端启动程序、客户端 API 库、命令行工具与部署辅助脚本,解压即可按官方文档配置集群并启动服务。该版本以 Apache ZooKeeper 为元数据协调核心,负责主题分区、集群配置与租约管理,配合 BookKeeper 实现高可用持久化;并原生支持发布/订阅模型与共享、独占、故障转移等订阅类型,可无缝接入 Kubernetes 等云原生环境,同时支持消息分层存储以优化成本。借助 Pulsar Functions 可在消息传递同时完成轻量级流处理,适合构建实时数据管道或事件驱动应用。已有 151 人下载学习,可作为入门 Pulsar 的基础环境,用于本地实验、消息流转验证及生产集群选型参考。
1. 先动手前搞清楚:这份 pulsar-2.9.1-bin 包到底解决了什么问题
把 apache pulsar 2.9.1 的 bin.tar.gz 下载到内网机器,解压后执行bin/pulsar standalone,大约十分钟就能跑出一个可收发消息的实例——这份资源的核心价值就落在这条命令上。Pulsar 是云原生消息中间件里绕不开的名字,broker 无状态、存储与计算分离,但元数据层需要挂在 ZooKeeper 上;直接用官方编译好的二进制包,能避开源码编译对 JDK、Maven 仓库和网速的多重依赖。适合两类人:刚接触分布式消息中间件的新手,想先把整体架构跑通;以及要在离线内网环境做部署验证的一线工程师。下文按单机到三节点集群的顺序逐步拆解,参数和坑都来自实际部署过程。
2. 先把资源本身摸清:目录结构、standalone 启动与端到端验证
2.1 为什么直接要 bin.tar.gz:源码编译的成本与选择逻辑
先说一个我自己的经历:第一次接触 Pulsar 时,我按官方文档从源码编译 2.9.1,Maven 依赖在本地仓库反复拉不全,中间还因为 JDK 版本不对编不过去,折腾了两三小时。后来换用现成的 bin.tar.gz,解压之后直接跑,十分钟内就走通了生产消费。这个对比基本可以代表大多数人的处境:你需要的是一个能跑、能改配置、能看日志的环境,而不是再经历一次构建链路的折腾。
bin.tar.gz 和源码包的最大区别在于:二进制包把所有依赖 jar 都锁在 lib 目录里,版本是官方测试过的组合。你不需要关心某次提交之后依赖版本漂移,也不需要在编译阶段去匹配 ZooKeeper、BookKeeper 的版本号。对于线上排障来说,这种「黑匣子」反而是优点——基础版本固定了,出问题时排查范围收窄到配置与网络。我一般会额外做一件事:把 bin.tar.gz 的 SHA256 校验一遍再解压,避免在内网传输时出现截断导致的启动异常。
2.2 解压后先看四个目录:bin、conf、lib、examples
解压后的主要目录如下。
| 路径 | 作用 | 什么时候动它 |
|---|---|---|
| bin/ | pulsar、pulsar-admin、pulsar-client、pulsar-daemon 等可执行脚本 | 日常启动、运维入口 |
| conf/ | standalone.conf、broker.conf、zookeeper.conf、bookkeeper.conf | 部署前必改 |
| lib/ | 三大组件的 jar 包与依赖 | 升级组件版本时 |
| examples/ | 官方示例源码 | 学习用,不需要改 |
注意:Windows 上解压后直接双击 bin/pulsar 是跑不起来的,脚本是 bash 写的,需要 Git Bash 或 WSL。第一次启动会自动生成 data 目录,standalone 模式下 ZooKeeper、BookKeeper、Broker 的数据都落在里面。这相当于整个环境的「后悔药」:数据乱了,停掉进程把 data 目录改名备份,再启动就是全新集群。
standalone 模式为什么不用去改 zookeeper.conf?因为 conf/standalone.conf 已经内置了 ZooKeeper 和 BookKeeper 的相关配置,你只需要关注其中的 broker 参数即可。这里常见误用是去改 conf/broker.conf 再跑 standalone,结果启动后没有生效——standalone 模式读取的是 standalone.conf,不是 broker.conf。
2.3 standalone 启动:一条命令拉起三个进程
执行:
cd /opt/pulsar bin/pulsar standalone默认情况下,这条命令会在同一进程里拉起内嵌 ZooKeeper(端口 2181)、单节点 BookKeeper 和 Broker。Broker 暴露两个端口:6650 是客户端二进制协议端口,8080 是管理接口端口。Pulsar 的 topic 在第一次生产消费时自动创建,默认单分区。
参数理解:
bin/pulsar standalone --no-functions-worker--no-functions-worker 表示不启动 Pulsar Functions worker,单机验证用不到函数计算,不加的话会多占一块内存。
然后验证生产和消费:
bin/pulsar-client produce -m 'hello-standalone' -n 5 my-topic bin/pulsar-client consume my-topic -s demo-sub -n 0参数说明:-m 指定消息内容,-n 5 表示发送 5 条消息,-s 指定订阅名称,-n 0 表示持续消费直到手动 Ctrl+C 退出。produce 命令会把消息写入 BookKeeper 的 ledger 中,consume 命令创建或复用 demo-sub 订阅并开始读取。看到连续输出 5 条消息就说明端到端链路是通的。
提示:如果 consume 时提示 topic 不存在或权限错误,先检查 standalone.conf 里的 allowAutoTopicCreation 是否被设置为 false;这个参数默认是 true,但部分二次打包的版本会把它关闭。
standalone.conf 里值得先认识的几个参数如下。
| 参数 | 默认值 | 说明 |
|---|---|---|
| brokerServicePort | 6650 | 客户端二进制协议端口 |
| webServicePort | 8080 | 管理接口与 admin 端口 |
| zookeeperServers | localhost:2181 | 内嵌 ZK 地址,单机无需改 |
| bookkeeperMetadataServiceUri | metadata_store:zk:localhost:2181 | ledger 元数据地址 |
| allowAutoTopicCreation | true | 是否允许 topic 自动创建 |
单机模式下这些参数基本不用动,但理解它们的含义对后面切集群很有帮助。尤其是 bookkeeperMetadataServiceUri,它决定了 BookKeeper 的 ledger 元数据写到哪个 ZooKeeper 路径,集群模式下这行配置会和单机完全不同。
2.4 单机验证与真实集群的差异:什么时候必须切到集群模式
standalone 模式把所有组件塞进一个 JVM,好处是环境干净、排障简单,坏处是它掩盖了 Pulsar 最重要的分布式特性:故障转移与元数据协调。比如你想验证「某个 broker 挂了,消费者是否会自动重连」,standalone 模式就做不到,因为 broker 只有一个且和 ZooKeeper 同进程。
我一般把 standalone 当成两件事来用:一是验证客户端配置和消息模型,二是当本地开发环境。生产验证至少需要三台机器,ZooKeeper、BookKeeper、Broker 拆开部署,这也正好是下一章的内容。
3. 拆成真正的分布式集群:ZooKeeper 元数据先落地,BookKeeper 与 Broker 再谈
Pulsar 在 2.9.1 里的架构可以这样理解:Broker 是无状态的接入层,只处理生产消费请求和消息路由;消息数据写入 BookKeeper 的 ledger;而哪个 topic 由哪个 broker 负责、命名空间和租户配置、订阅游标元数据,都放在 ZooKeeper 里。换句话说,ZooKeeper 是整个集群的「记忆体」,Broker 可以被随时替换,但 ZooKeeper 的数据丢了,集群的元数据就全乱了。
这也是为什么云原生环境下 Pulsar 的部署习惯是:broker 可以跑在容器里随意扩缩容,但 ZooKeeper 一定要用独立的三节点集群来保底。启动顺序有严格约定:先 ZooKeeper,再 BookKeeper,最后 Broker。顺序反了会报连接失败或服务不可用。如果先启动 Broker,broker 启动时会尝试连接 ZK 读取集群元数据并把自身地址注册进去,ZK 没起来就会一直初始化失败或反复重试。BookKeeper 同理,bookie 注册写 ZK 也需要 ZK 先行。
3.1 ZooKeeper 三节点集群:myid、server.list 与端口含义
先把三台机器的 hosts 映射配好,假设内网 IP 是 10.0.0.11~10.0.0.13:
cat >> /etc/hosts <<'EOF' 10.0.0.11 node1 10.0.0.12 node2 10.0.0.13 node3 EOF然后修改 conf/zookeeper.conf,三台机器配置内容一致,只有 dataDir 下的 myid 文件不同:
tickTime=2000 initLimit=5 syncLimit=2 dataDir=/data/zookeeper clientPort=2181 server.1=node1:2888:3888 server.2=node2:2888:3888 server.3=node3:2888:3888参数说明:tickTime 是 ZooKeeper 的最小时间单元,单位毫秒;initLimit 是 follower 启动后与 leader 完成初始同步的超时阈值,5 个 tick 也就是 10 秒;syncLimit 是运行期 follower 与 leader 心跳超时,2 个 tick 为 4 秒。2888 端口是 leader 向 follower 同步数据的端口,3888 是选举端口。这两个端口只在内网开放即可。
初始化 myid:
# node1 上执行 mkdir -p /data/zookeeper echo 1 > /data/zookeeper/myidnode2 写 2,node3 写 3。myid 必须与 server.N 的 N 对应,写错了会出现无法选举或加入失败。启动并验证:
bin/pulsar-daemon start zookeeper bin/pulsar zookeeper-shell node1:2181 ls /pulsar-daemon start zookeeper 会把进程放到后台并写入 logs 目录。zookeeper-shell 连上后执行 ls /,能看到当前根节点列表。如果这里超时,优先检查三台机器防火墙是否放行 2181、2888、3888,以及 hosts 是否一致。常见做法是先在每台机器上执行telnet node1 2181验证连通性,再往下走。
注意:不要在生产环境的 ZooKeeper dataDir 上放系统和应用日志,目录空间不足会导致 ZooKeeper 直接拒绝写事务,进而让整个 Pulsar 集群失去元数据读写能力。磁盘监控至少要覆盖这三个数据目录。
3.2 BookKeeper 先于 Broker:metaformat 初始化与 ledger 目录规划
ZooKeeper 就绪后,配置每台机器的 conf/bookkeeper.conf:
zkServers=node1:2181,node2:2181,node3:2181 journalDirectory=/data/bookkeeper/journal ledgerDirectories=/data/bookkeeper/ledger metadataServiceUri=zk://node1:2181,node2:2181,node3:2181/ledgersmetadataServiceUri 指定了 ledger 元数据在 ZooKeeper 中的存储路径;journalDirectory 放写入日志,ledgerDirectories 放实际数据块。性能敏感场景下我一般会把 journal 放到 SSD,ledger 放到容量盘,两个目录不要共用同一块物理盘。
首次部署需要在任意一台机器执行一次元数据初始化:
bin/bookkeeper shell metaformat -nonInteractive参数说明:-nonInteractive 表示自动回答初始化确认,不传的话脚本会停下来等输入 yes。重复执行会提示已有 ledgers 元数据,没关系,不会破坏已有数据。然后每台机器启动 bookie:
bin/pulsar-daemon start bookie验证 BookKeeper 集群:
bin/bookkeeper shell listbookies -a看到三台机器都出现在可写 bookie 列表里,说明 ledger 层已经就绪。此时如果 listbookies 输出为空,多半是 bookie 没有成功注册到 ZooKeeper,去看 logs/bookkeeper.log 里有没有报连接 ZK 失败或端口占用。
为了进一步确认消息真的写进了 ledger,可以发一条消息后执行bin/bookkeeper shell listledgers | head -5。如果输出为空,说明消息还没写进 bookie,或者元数据没落对。这个检查比只看管理端更直接。
3.3 Broker 接入:advertisedAddress 是最大的玄学,不要留空
BookKeeper 起来之后,最后启动 Broker。三台机器的 conf/broker.conf 关键配置如下(以 node1 为例):
zookeeperServers=node1:2181,node2:2181,node3:2181 configurationStoreServers=node1:2181,node2:2181,node3:2181 advertisedAddress=10.0.0.11 brokerServicePort=6650 webServicePort=8080 clusterName=pulsar-clusterzookeeperServers 用于 broker 访问集群元数据,configurationStoreServers 在 2.9.1 里一般与前者保持一致。advertisedAddress 是 broker 向客户端广播的地址,这里必须写本机内网 IP,不能留空,也不能写 localhost。留空时 broker 会尝试用主机名解析出地址,一旦 /etc/hosts 里没配好,客户端拿到的就是 127.0.0.1,握手必然失败。这个坑我踩过不止一次,所以每次部署都会先hostname -i确认解析结果再填。
启动 broker:
bin/pulsar-daemon start broker验证注册情况:
bin/pulsar-admin --admin-url http://node1:8080 brokers list pulsar-cluster bin/pulsar-admin --admin-url http://node1:8080 clusters listbrokers list 会输出三个 broker 地址,clusters list 至少看到 pulsar-cluster。接着做一个跨节点收发验证:在 node2 上执行消费者,node1 上执行生产者,用同一个 topic 名。
# node2 bin/pulsar-client consume my-topic -s sub2 -n 0# node1 bin/pulsar-client produce -m 'cluster-ok' -n 5 my-topic看到消费端连续收到 5 条消息,分布式集群的基本链路就算通了。此时可以顺手做一次容错验证:在 node3 上执行bin/pulsar-daemon stop zookeeper,然后在 node1 上执行bin/pulsar zookeeper-shell node2:2181 ls /。只要集群里超过半数节点存活,命令仍能正常返回,说明三节点 ZK 的多数派机制生效;如果连不上,就该检查选举配置与网络。
4. 部署常见问题与排查清单:五个值得留备忘录的坑
这一章结合自己部署 2.9.1 时踩过的坑整理成清单,每一条都按「现象、原因、解决」三步展开。这些坑单独看都不复杂,但日志里表现的形态各异,不熟悉底层数据流的时候确实会绕不少弯路。
4.1 启动阶段的坑:残留数据与 JDK 版本引起的「玄学」
坑一:standalone 跑过之后直接切集群,ZooKeeper 起不来
现象:第一次用 standalone 模式在本机跑过,数据都落在解压目录的 data 下。后来在同一台机器部署三节点集群,启动 zookeeper 后日志报错,出现 NoSuchNode、Metadata store error 之类,或者进程起来几秒就退出。
原因:standalone 初始化时已经在 ZooKeeper 里写了 standalone 场景的元数据结构,和集群模式下期望的节点路径不一致。残留 data 是最大的干扰源。
解决:停掉所有相关进程后,把整个 data 目录改名备份,比如mv data /tmp/data-standalone-backup,再重新初始化。如果需要保留原来的消息数据,先导出或迁移,不要直接删除。从那以后我每次从单机切集群都会先确认 data 目录是干净的。
坑二:JDK 版本不匹配,bookie 起不来
现象:bin/pulsar-daemon start bookie 后,logs 里出现 java.lang.NoSuchMethodError 或 UnsupportedClassVersionError,具体类名每次都不一样,看上去像随机报错。
原因:2.9.1 编译时基于 JDK 8u252+,某些方法在老版本 JDK 8 里还没引入;换到 JDK 9 或 10 也有部分 API 不兼容。这是我排查时间最长的一次,最后发现是默认 JAVA_HOME 指向了很老的 JRE。
解决:统一安装 JDK 11,并把 JAVA_HOME 指向新版本。Pulsar 2.9.1 官方支持 JDK 11,推荐直接用 JDK 11 而不是纠结 JDK 8 的小版本。改完 JAVA_HOME 后,先执行java -version确认版本再重启。
坑三:解压后 bin 脚本没有执行权限
现象:解压完成后执行 ./bin/pulsar 报 Permission denied,用 ls -l 看脚本没有 x 权限位。
原因:部分内网传输工具或解压程序在解包时丢了执行位,特别是从 Windows 侧用某些压缩软件解压 tar.gz 最容易出现。
解决:进入解压目录执行chmod +x bin/*,然后重新运行。这个操作也可以在解压后第一件事就做,避免启动时报错误判成别的配置问题。
4.2 运行期的坑:advertisedAddress、订阅与防火墙
坑四:broker 注册成功,但客户端连 6650 握手超时
现象:三台 Broker 都出现在 brokers list 里,pulsar-admin 也能正常访问,但客户端连接 6650 端口时一直超时,生产者把消息卡在 pending 队列。
原因:客户端在连接 broker 时,拿到的地址不是连接目标,而是 broker 广播出去的 advertisedAddress。我第一次部署时没有显式配置 advertisedAddress,broker 把主机名解析成了 127.0.0.1 或错误的内网地址,客户端拿着这个地址去握手,自然连不通。
解决:在 broker.conf 中显式写advertisedAddress=<本机内网IP>,然后重启 broker。要特别注意的是,不要通过改 /etc/hosts 把主机名解析成 127.0.0.1 来绕过,这样会引入新问题。正确做法是让每个 broker 都广播自己能连通的内网地址。
坑五:生产和消费都正常,但 topic 的 backlog 只增不减
现象:生产者和消费者的统计都显示连接正常,也没有报错,但通过 pulsar-admin 查看 topic stats 时,backlog 数量持续上涨,消息没有被消费掉。
原因:Pulsar 的 topic 下可以有多个 subscription,每个订阅各自维护消费游标。消费者指定了-s subA,而检查时看的却是另一个 subscription,或者消费者根本没有指定订阅名导致消息没有真正被读取。
解决:统一生产和消费的订阅名,用pulsar-admin topics subscriptions查看当前 topic 下有哪些订阅,确认消费端连的是同一个。检查消费组是不是处于 Activate 状态,如果订阅名不一致,直接把消费命令的 -s 参数改一致即可。
这五条坑基本覆盖了个人在 2.9.1 部署中遇到的大部分阻塞问题。每条看着都不复杂,但不熟悉组件之间的依赖关系时,确实会花掉一整晚去翻日志。
5. 上线前的最后一步:健康检查脚本与优雅下线
部署完成不等于可以交付。我一般会在验收前跑一份固定的健康检查脚本,把 broker 注册、topic 收发、backlog 三个维度都过一遍。脚本内容很简单,但能覆盖最常见的两类故障:broker 掉线未被自动剔除、消费者游标卡死导致消息积压。
#!/usr/bin/env bash set -euo pipefail BIN=/opt/pulsar/bin ADMIN_URL=http://node1:8080 TOPIC=persistent://public/default/health-check $BIN/pulsar-admin --admin-url $ADMIN_URL brokers list pulsar-cluster $BIN/pulsar-client produce -m "health" --count 1 "$TOPIC" $BIN/pulsar-admin --admin-url $ADMIN_URL topics stats "$TOPIC"brokers list 检查三个 broker 是否都在;produce 一条消息验证写入链路;topics stats 输出里重点看 backlog 是否为 0,以及最后一条消息的 publish time 是不是刚刚。三项都正常,才算通过了基础验收。
另一个容易被忽略的操作是优雅下线。很多人习惯 kill -9 直接干掉 broker 进程,这在单机环境影响不大,但分布式集群里会让 ZooKeeper 等待 session 超时后再重新分配 topic ownership,客户端会多等几十秒,严重的会出现短时间重复连接。
正确的停法是用启动脚本反向操作:
bin/pulsar-daemon stop broker bin/pulsar-daemon stop bookie bin/pulsar-daemon stop zookeeperstop 指令会让 broker 主动从 ZooKeeper 摘除自己,把对应的 topic ownership 交还给其他节点,客户端感知不到断连就完成了接管。
我从第一次搭建三节点集群之后,每次交付前都会强制走一遍健康检查脚本和优雅停机流程,尤其是 topics stats 里的 backlog 字段,它会暴露绝大多数配置问题。这份 2.9.1 的二进制包在离线环境里也能直接跑,解压后按第 2 章到第 4 章的顺序执行,基本能一次通过。希望帮到你。
本文还有配套的精品资源,点击获取