Apache Pulsar 2.9.1 bin包实战:从standalone到伪集群部署与避坑指南
简介Apache Pulsar 2.9.1 二进制发行包面向分布式消息中间件开发者、云原生架构师及大数据实时计算从业者用于快速搭建高吞吐、可扩展的发布/订阅消息系统。压缩包为 gz 格式整体约 321.53MB内含部署运行 Pulsar 所需的二进制文件、客户端库、启动脚本及辅助工具解压后即可按官方文档配置并启动服务。Pulsar 依托 ZooKeeper 管理主题分区、集群配置与租约信息实现高可用与一致性借助 BookKeeper 提供低延迟持久化存储并支持分层存储、Pulsar Functions 轻量流处理以及共享、独占、故障转移等多种订阅类型可跨节点与数据中心部署无缝集成 Kubernetes 等容器化环境。目前已有 151 人学习关注适合需要构建大规模实时数据流、研究分布式消息模型或进行云原生消息队列选型的技术人员参考使用。1. 拿到 apache pulsar 2.9.1 bin.tar.gz 之后为什么有人十分钟跑通有人卡一整天很多人第一次接触 Pulsar是从下载页那个apache-pulsar-2.9.1-bin.tar.gz开始的。压缩包解开目录里躺着bin、conf、lib、examples看起来和普通中间件没什么两样于是直接bin/pulsar standalone一把梭。结果有人十分钟就在本机把消息发出去、收回来有人却卡在启动脚本报 Java 版本不对、BookKeeper 目录权限不够、或者客户端连上却一直超时。差别不在手速而在有没有先搞清楚这个 bin 包到底把哪些东西打包进来了、standalone 模式默认开了哪些端口、以及 2.9.1 这个版本在配置上跟后面几个大版本有哪些不一样。这篇笔记就围绕apache pulsar 2.9.1 bin.tar.gz这个具体产物展开讲清楚它解压后每个目录干什么、怎么用最小代价在本地跑通一条生产消费链路、参数该动哪几个、以及那些看起来像玄学其实都有明确原因的翻车点。适合两类人一类是要在本地或测试环境快速验证 Pulsar 能力、不想一上来就搭集群的开发者另一类是已经在用 Pulsar但想回头把 2.9.1 这个长期被当作稳定基线版本的部署细节吃透的运维同学。下面所有操作都基于这个 bin 包本身不依赖任何外部托管服务。2. 拆开 bin.tar.gz目录结构、启动脚本与 standalone 到底起了什么2.1 解压后先别急着启动把这几个目录看清楚把apache-pulsar-2.9.1-bin.tar.gz解压到一个路径里没有空格、没有中文的目录比如/opt/pulsar。进去之后你会看到这样一层结构目录/文件作用2.9.1 里值得注意的点bin/所有可执行脚本包括pulsar、pulsar-daemon、bookkeeperpulsar是总入口子命令靠参数区分conf/配置模板standalone.conf、broker.conf、bookkeeper.conf都在这里standalone 模式读的是standalone.conflib/运行时依赖 jarPulsar 自身模块和第三方库都在这不要手动往这里塞 jar容易类冲突examples/示例程序和配置文件里面有现成的生产消费示例可参考data/默认数据目录standalone 首次启动后才会生成2.9.1 默认放在解压目录下生产要改logs/日志输出目录排查启动失败第一站这里有个容易被忽略的点data/和logs/在刚解压时可能不存在是启动脚本运行时按配置创建的。如果你把包解压到只读挂载点或者用了一个没有写权限的系统账号去启动脚本会在创建目录这一步就失败但报错信息往往被日志刷过去看起来像是“启动到一半卡住”。2.2 standalone 模式其实是一个进程里塞了三套角色bin/pulsar standalone这个命令做的事情远不止“启动一个 broker”。它在一个 JVM 里同时拉起了三样东西一个 ZooKeeper 实例用于元数据存储和协调、一个 BookKeeper 书签用于消息持久化存储、以及一个 Pulsar broker对外提供生产和消费服务。这就是为什么 standalone 对本地资源有要求也是为什么它启动比单跑一个 broker 慢。启动命令本身很简单# 进入解压目录 cd /opt/pulsar # 前台启动 standalone日志直接打到终端方便第一次排查 bin/pulsar standalone第一次启动建议用前台方式不要加-daemon。因为初始化元数据、创建 BookKeeper 账本目录这些动作在首次运行时耗时明显更长前台能看到进度。等确认能稳定启动后再改成后台# 后台启动日志写入 logs/ 目录 bin/pulsar-daemon start standalone # 停止 bin/pulsar-daemon stop standalone启动成功的标志是日志里出现 broker 开始监听 6650 端口、以及 web 服务监听 8080 端口。这两个端口是后面所有操作的入口6650 给客户端做二进制协议通信8080 提供 HTTP 管理接口和 Web 控制台。2.3 用内置示例验证链路比你自己写客户端更快在动手写代码之前先用包里自带的示例确认整条链路是通的。Pulsar 的pulsar-client子命令可以直接在命令行生产消费# 消费端订阅一个不存在的 topic 会自动创建-s 指定订阅名 bin/pulsar-client consume my-topic -s demo-sub -n 0 # 另开一个终端生产一条消息 bin/pulsar-client produce my-topic -m hello-pulsar-2.9.1 -n 1-n 0表示消费端持续监听不退出-n 1表示只发一条。如果消费端终端里打印出了hello-pulsar-2.9.1说明 ZooKeeper、BookKeeper、broker 三层都正常工作了。这一步看起来简单但它把网络、持久化、订阅管理全串了一遍比直接上 Java 客户端更容易定位问题——如果这里不通写客户端也是白写。提示standalone 默认会在data/下创建standalone子目录存放 BookKeeper 数据。如果你之前启动失败过残留的元数据可能导致再次启动时行为异常最稳妥的做法是停掉进程后清空data/standalone再重来。3. 把 standalone 调成能扛住本地压测四个必调参数与内存账3.1 默认配置为什么一压就崩standalone 的默认配置是奔着“能跑起来”去的不是奔着“能压”去的。最典型的问题是 BookKeeper 的写缓存和 broker 的内存上限都偏保守本地做几百 QPS 的压测就可能看到客户端超时或者 broker 频繁 GC。要改的参数集中在conf/standalone.conf里这个文件本质上是 broker 配置加了一部分 standalone 专属项。先看几个必须理解的参数参数默认值2.9.1作用本地压测建议managedLedgerDefaultEnsembleSize1每条消息写入的 BookKeeper 节点数standalone 下保持 1managedLedgerDefaultWriteQuorum1写成功需要确认的节点数保持 1managedLedgerDefaultAckQuorum1返回 ack 前需要确认的节点数保持 1managedLedgerMaxEntriesPerLedger50000单个 ledger 最大条目数压测可降到 10000 加快滚动journalSyncDatatrue是否每次写入都 fsync本地压测可设 false 换吞吐standalone 下 ensemble、write quorum、ack quorum 都只能是 1因为只有一个 BookKeeper 实例。这三个值不要乱改改了反而启动报错。真正影响压测表现的是journalSyncData和 ledger 滚动策略。3.2 改内存之前先算一笔账Pulsar 的 JVM 内存分两块堆内存和直接内存。BookKeeper 大量使用直接内存做网络和磁盘缓冲所以只调-Xmx是不够的。启动脚本bin/pulsar里通过环境变量PULSAR_MEM控制堆通过PULSAR_EXTRA_OPTS可以追加直接内存相关参数。一个本地压测可用的配置示例# 在启动前导出环境变量4G 堆 2G 直接内存适合 8G 内存的开发机 export PULSAR_MEM-Xms2g -Xmx4g -XX:MaxDirectMemorySize2g export PULSAR_EXTRA_OPTS-XX:UseG1GC -XX:MaxGCPauseMillis200 bin/pulsar standalone-Xms和-Xmx设成不一样的值在本地没问题但生产环境建议设成一样避免运行期堆伸缩带来的抖动。MaxDirectMemorySize如果给太小BookKeeper 在写入量上来后会抛直接内存溢出日志里能看到OutOfDirectMemoryError这个错误比堆溢出更难排查因为堆监控看起来一切正常。3.3 用 pulsar-admin 确认 broker 真的吃到了配置改完配置重启后不要假设配置一定生效了。用管理接口查一下关键指标# 查看 broker 的动态配置确认内存和 ledger 相关项 bin/pulsar-admin brokers get-all-dynamic-config # 查看某个 topic 的内部统计确认消息确实写进去了 bin/pulsar-admin topics stats persistent://public/default/my-topictopics stats返回的 JSON 里重点看msgRateIn、msgThroughputIn、storageSize这几个字段。如果生产端显示发送成功但storageSize一直是 0说明消息可能只进了内存没落盘这时候要回头检查journalSyncData和 BookKeeper 的日志。3.4 压测时观察什么指标才算看对了地方本地压测最容易犯的错是只看客户端吞吐不看 broker 侧。Pulsar 在 8080 端口暴露了大量指标standalone 下可以直接用 curl 拉# 拉取 broker 的指标过滤出与存储和订阅相关的部分 curl -s http://localhost:8080/metrics/ | grep -E pulsar_storage|pulsar_subscription重点盯pulsar_storage_write_latency_le_*这组直方图指标它反映的是写入延迟分布。如果le_10001 秒内完成的比例明显下降说明 BookKeeper 那边已经跟不上了这时候加客户端线程只会让情况更糟。正确的做法是先把journalSyncData关掉确认瓶颈在磁盘同步再决定是加盘还是调 ledger 参数。4. 避坑standalone 启动与客户端连接的五个高频翻车点4.1 启动脚本报 UnsupportedClassVersionError现象执行bin/pulsar standalone后立刻退出日志里出现UnsupportedClassVersionError提示类文件版本高于当前 JVM。原因Pulsar 2.9.1 编译时用的 Java 版本比机器上默认的java命令版本高。2.9.1 官方要求 Java 8 或 11但如果你机器上JAVA_HOME指向的是更老的版本或者 PATH 里java是另一个版本就会撞上。解决先java -version确认版本再echo $JAVA_HOME确认环境变量。两个要一致且都在 8 或 11 范围内。改完之后重新开一个终端再启动避免 shell 缓存了旧的环境变量。4.2 卡在 “Starting bookkeeper” 不动现象前台启动后日志停在Starting bookkeeper这一行几分钟没有新输出也没有报错。原因BookKeeper 在初始化账本目录时如果data/standalone目录的属主和当前启动用户不一致或者磁盘 IO 被其他进程占满就会长时间阻塞。另一种情况是之前异常退出的进程还占着 2181 端口ZooKeeper新进程在等端口释放。解决先ps -ef | grep pulsar确认没有残留进程再检查data/standalone的权限。如果是端口占用lsof -i:2181找到进程后清理。确认无误后删掉data/standalone重新启动让 BookKeeper 重新初始化。4.3 客户端连 6650 端口超时现象命令行示例能跑通但自己写的客户端连pulsar://localhost:6650时报连接超时。原因standalone 默认只监听localhost如果你的客户端跑在容器里或者另一台机器上就连不上。另外 2.9.1 的standalone.conf里advertisedAddress默认没配broker 返回给客户端的是本机主机名客户端解析不了这个主机名也会超时。解决在conf/standalone.conf里显式设置advertisedAddress127.0.0.1本机访问或实际 IP跨机访问然后重启。跨机访问还要确认防火墙放行了 6650 和 8080。4.4 消费端收不到历史消息现象生产端已经发了几条消息新起的消费端用-s指定了一个新订阅名却一条都收不到。原因Pulsar 的订阅位置取决于订阅类型和创建时的策略。默认pulsar-client consume创建的是 Exclusive 订阅且初始位置是Latest也就是只收订阅创建之后的新消息。历史消息不会自动补发。解决如果要消费历史消息创建订阅时指定-p Earliestbin/pulsar-client consume my-topic -s demo-sub-earliest -p Earliest -n 0注意订阅名要换一个因为同一个订阅名不能同时用两种初始位置。4.5 磁盘空间悄悄被吃满现象本地跑了一段时间后data/standalone目录越来越大最后磁盘告警。原因standalone 默认不清理已经消费完的消息BookKeeper 的 ledger 会一直保留直到达到managedLedgerMaxEntriesPerLedger滚动或者手动触发清理。本地测试如果反复生产不消费积压会非常快。解决测试完及时清理 topic或者配置 retention 策略。用管理命令删 topicbin/pulsar-admin topics delete persistent://public/default/my-topic删完之后磁盘空间不会立刻释放BookKeeper 有延迟回收机制等下一次 ledger 滚动或者 GC 周期才会真正释放。急着回收就停掉 standalone 清空data/standalone。5. 从 standalone 走向可复现的本地多节点用 bin 包搭一个三节点伪集群5.1 为什么要在本地搭伪集群standalone 验证功能够用但它掩盖了真实部署里的很多问题多节点之间的元数据同步、BookKeeper 的 ensemble 写入、broker 的无状态扩缩容。如果你准备把 Pulsar 用到测试环境甚至生产最好在本地先用同一个 bin 包搭一个三节点伪集群把副本和故障转移的逻辑跑一遍。这样后面上真实机器时配置项和排查路径都是熟的。5.2 用同一份解压包复制三份改端口和目录思路很简单把apache-pulsar-2.9.1解压目录复制三份分别作为 node1、node2、node3每份改掉冲突的端口和数据目录。关键配置在conf/broker.conf和conf/bookkeeper.conf里。以 node1 为例需要改的项# conf/broker.conf brokerServicePort6650 webServicePort8080 advertisedAddress127.0.0.1 zookeeperServers127.0.0.1:2181 configurationStoreServers127.0.0.1:2181 managedLedgerDefaultEnsembleSize3 managedLedgerDefaultWriteQuorum2 managedLedgerDefaultAckQuorum2node2 把端口改成 6651/8081node3 改成 6652/8082。ZooKeeper 可以三个节点共用一个外部实例也可以在每个节点里各起一个然后组 ensemble本地验证用前者更省事。5.3 启动顺序和验证方法先起 ZooKeeper可以单独用 bin 包里的bin/pulsar zookeeper再起三个 BookKeeper最后起三个 broker。每起一个用bin/pulsar-admin --url http://127.0.0.1:8080 brokers list确认节点注册进来了。验证副本是否生效创建一个 topic 然后看内部统计bin/pulsar-admin topics create persistent://public/default/replicated-topic bin/pulsar-admin topics stats persistent://public/default/replicated-topic返回的 JSON 里ledgers字段会列出当前使用的 ledger每个 ledger 的ensembleSize应该是 3。这时候手动停掉一个 BookKeeper再发消息如果writeQuorum2配置正确生产端应该仍然成功只是延迟略有上升。这个实验能让你直观感受到 quorum 参数的实际含义比看文档管用。5.4 伪集群里最容易忽略的配置一致性三个节点的managedLedgerDefaultEnsembleSize、writeQuorum、ackQuorum必须一致否则 topic 创建时会因为策略冲突失败。另外zookeeperServers和configurationStoreServers在 2.9.1 里可以指向同一个 ZooKeeper但如果你后面要拆开记得两个配置都要改只改一个会出现元数据读写不一致的怪现象。注意伪集群跑完后三个节点的data目录都要清理否则下次启动时旧的 ledger 信息会干扰新集群的元数据表现为 topic 创建成功但无法写入。5.5 从伪集群带走的三个习惯第一任何配置改动都记录在版本控制里不要靠记忆。第二启动顺序固定为 ZooKeeper → BookKeeper → broker停的时候反序。第三每次验证副本行为时先确认topics stats里的 ensemble 信息再看客户端表现。这三个习惯搬到真实环境同样适用能省掉大量“明明配置一样为什么行为不同”的排查时间。6. 把 2.9.1 的 bin 包用出长期价值版本锁定、配置基线与升级前的验证动作apache-pulsar-2.9.1-bin.tar.gz这个包本身会过时但围绕它建立起来的一套本地验证方法不会过时。我自己的习惯是每接触一个新中间件先用它的 bin 包在本地跑通最小链路然后把配置基线、启动脚本、验证命令整理成一个可重复执行的目录。后面无论升级到哪个版本都拿这套基线去对比差异点就是升级风险点。具体到 Pulsar 2.9.1有三件事值得在本地做完再考虑上测试环境。第一把standalone.conf和broker.conf里所有你改过的项列成一张表标注默认值和修改原因。第二用伪集群验证一遍ensembleSize3、writeQuorum2下的故障转移记录停掉一个 BookKeeper 后生产端的延迟变化和恢复时间。第三把bin/pulsar-client的常用子命令整理成脚本包括生产、消费、查 stats、删 topic后面排查问题时直接调用不用现查帮助。升级前的验证动作也有套路拿新版本的 bin 包解压到另一个目录用同样的配置基线启动 standalone跑一遍你整理的那组命令对比topics stats里的关键指标和日志里的警告信息。2.9.1 到后续版本在配置项命名上有过调整比如部分managedLedger前缀的项被迁移到了新的命名空间直接拿旧配置启动新版本会看到大量unknown config警告。这些警告本身不致命但会掩盖真正重要的错误所以升级时配置基线要跟着版本走。我踩过最深的一个坑是早期图省事把 standalone 的data目录直接复制到另一台机器上想“迁移”环境结果新机器启动后 topic 列表对不上消费位点也乱了。后来才明白 Pulsar 的元数据在 ZooKeeper 和 BookKeeper 里各存一部分单独复制数据目录没有意义。正确的做法是用pulsar-admin导出 topic 和订阅信息在新环境重建数据用 Pulsar 自己的复制或迁移工具同步。这个教训让我后来养成了一个习惯任何中间件的“数据目录”都不等于“全部状态”迁移前先搞清楚状态存在哪几个地方。希望帮到你。本文还有配套的精品资源点击获取