news 2026/10/24 1:01:18

Apache Pulsar 的 Java 17 构建与运行升级之路:从 PIP-156 看 Broker 服务端 Java 版本演进

作者头像

张小明

前端开发工程师

1.2k 24
文章封面图
Apache Pulsar 的 Java 17 构建与运行升级之路:从 PIP-156 看 Broker 服务端 Java 版本演进
  • 消息队列
  • 流处理
  • 后端
  • 微服务
  • 消息路由

【免费下载链接】pulsar

Apache Pulsar - distributed pub-sub messaging system

项目地址:https://gitcode.com/gh_mirrors/pu/pulsar
点击查看免费下载

PIP-156(Build and Run Pulsar Server on Java 17)是 Apache Pulsar 将服务端(Broker)的构建与运行基线从 Java 8/11 提升到 Java 17、并为 ZooKeeper / BookKeeper / Pulsar 全面切换 ZGC 的关键提案。本文以该 PIP 为骨架,结合当前仓库中 README.md、ARCHITECTURE.md、CONTRIBUTING.md 与 conf/pulsar_env.sh 等实现证据,梳理升级动机、版本分层策略、GC 默认值变化、构建配置、测试与发布计划,并对照现状说明这一策略的落地结果,帮助读者理解 Pulsar 的 Java 版本治理模型。

为什么 Pulsar 要升级到 Java 17

PIP-156 提出的时间点是 2022 年 4 月,彼时 Pulsar 官方对构建和运行的最低要求仍是 Java 8 或 Java 11。作者在提案中指出,Java 8/11 相对当时最新发布的 Java 18 已经明显"过时",而近年 Java 版本在两方面带来了实质性收益:

  • 垃圾回收(GC):从 JDK 8 到 17,JVM 引入了 ZGC(Z Garbage Collector,JDK 11 引入)与 Shenandoah GC(JDK 12 引入),两者均为低停顿并发收集器,相比 G1GC 能显著降低长暂停(stop-the-world)对延迟敏感型服务的冲击,官方博客与社区分析均验证了 GC 演进带来的收益;
  • 语言与 API 特性:例如 Java 15 引入的Text Blocks(文本块),可用于改善 Pulsar Function 的格式化输出与模板代码的可读性。

因此,作为常规维护工作,提案建议把 Pulsar 的构建与运行基线升级到当时最新的 LTS(Long Term Support)版本Java 17。升级的收益目标包括:适配 JDK 新的超高速垃圾收集器、启用 Text Blocks 等新语法、并借助 Java 17 上重新审视的运行时 JVM 参数获得整体性能提升。

需要说明的是,PIP-156 面向的是 Pulsar 2.11 时代;当前仓库主线(master)的基线已进一步演进到 Java 21(详见下文"现状与演进"),但该 PIP 确立的"服务端与服务端工具升级、客户端保持低版本兼容"的分层治理思路至今仍是 Pulsar Java 版本策略的基石。

升级范围的三层设计:Broker 升级、CLI 跟随、Client 不动

PIP-156 最核心的设计是按组件分层决定 Java 目标版本,而非一刀切全部升级:

组件变更前变更后(PIP-156 目标)理由
Pulsar Broker(服务端)构建与运行需 Java 8 或 11构建与运行均需 Java 17服务端掌控运行环境,可充分享受新 GC 与 JVM 改进
Pulsar CLI 工具随发行版运行在 Java 8/11 上运行版本升级到 Java 17CLI 运行在 Admin 环境,且本身依赖 Pulsar 发行版
Pulsar Java Client目标版本保持 Java 8保持 Java 8 不变客户端必须兼容用户现有的 Java 运行时环境
client-server 共享模块Java 8保持 Java 8 发布与客户端同基线,保证兼容性

这一分层策略的关键洞察在于:Broker 是部署者可控的组件,而 Client 是被动运行在用户环境里的组件。把两者绑定在同一个版本上,会让客户端升级变成用户迁移的硬约束;反之,让服务端先吃 Java 17 的红利,客户端继续以 Java 8 为目标发布,就能在不破坏用户既有运行环境的前提下完成服务端现代化。

提案还明确声明本 PIP不涉及任何 API 变更(API Changes: None),即升级是纯内部工程改造,对用户可见的 API 与行为不做任何破坏性调整。

从当前仓库看分层策略的落地形态

当前仓库的 Gradle 约定(build-logic/conventions/src/main/kotlin/pulsar.java-conventions.gradle.kts)完整继承并放大了 PIP-156 的分层思想:

  • pulsarJavaVersion(默认 21)决定服务端主代码的编译目标,pulsarClientJavaVersion(默认 17)决定客户端/公开 API 的编译目标;
  • 通过clientProjects清单把pulsar-client-api、pulsar-client-tools、pulsar-cli-utils、pulsar-functions-api等模块划分到客户端基线;
  • 编译统一使用options.release.set(...)(即--release),确保字节码、JDK API 与依赖三方库的签名都严格限制在目标版本内;
  • 客户端项目额外挂载verifyClientJavaCompatibility任务(pulsar.java-conventions.gradle.kts 中VerifyJavaCompatibility),在check与assemble阶段校验客户端/API 字节码及其 compile/runtime 依赖,防止不小心引入超出基线版本的 JDK API 或第三方库。

仓库文档对分层结果给出了更细的描述(见 CONTRIBUTING.md 与 ARCHITECTURE.md):Pulsar 5 服务端组件与 Functions 实现要求 Java 21+;Client CLI 工具保持 Java 17 兼容;客户端库、共享依赖与 Functions/IO 公共接口保持 Java 17 兼容;Java 17 编译的 Function 可以运行在 Java 21+ 的 Functions 实例上。也就是说,PIP-156 的"客户端与服务端解耦"原则在当前主线中被进一步细化为"服务端 21 / 客户端与工具 17"的双基线体系。

GC 默认值迁移:从 G1GC 到 ZGC(或 Shenandoah GC)

变更前 vs 变更后

PIP-156 对运行时 JVM 标志的调整是另一项核心工作。提案给出的对比是:

  • 变更前:ZooKeeper、BookKeeper、Pulsar 的默认 GC 均为G1GC;
  • 变更后:三者的默认 GC 切换为ZGC(或 Shenandoah GC),并在提案中明确:将借助性能测试验证 ZGC / Shenandoah GC 是否确实优于 G1GC,以及新 GC 默认值与相关 Java 标志的合理性。

底层依据是提案的两个假设:其一,期望依赖库(BookKeeper、ZooKeeper)在 Java 17 上正常工作,兼容性问题作为子任务解决;其二,假设 ZGC / Shenandoah GC 对 Pulsar 这类高吞吐、低延迟的消息系统性能优于 G1GC,并用 OpenMessaging 基准测试等验证。

当前仓库中的 GC 默认配置

当前仓库的启动脚本已经把 ZGC 设为默认(同时保留了按 Java 大版本区分行为的能力):

conf/pulsar_env.sh 中:

# Garbage collection options if [ -z "$PULSAR_GC" ]; then PULSAR_GC="-XX:+PerfDisableSharedMem -XX:+AlwaysPreTouch" if [[ $JAVA_MAJOR_VERSION -eq 21 || $JAVA_MAJOR_VERSION -eq 22 ]]; then PULSAR_GC="-XX:+UseZGC -XX:+ZGenerational ${PULSAR_GC}" else PULSAR_GC="-XX:+UseZGC ${PULSAR_GC}" fi fi

conf/bkenv.sh 中 BookKeeper(bookie)使用同样的逻辑,且BOOKIE_GC默认回退到${PULSAR_GC}:

BOOKIE_GC="${BOOKIE_GC:-${PULSAR_GC}}" if [ -z "$BOOKIE_GC" ]; then BOOKIE_GC="-XX:+PerfDisableSharedMem -XX:+AlwaysPreTouch" if [[ $JAVA_MAJOR_VERSION -eq 21 || $JAVA_MAJOR_VERSION -eq 22 ]]; then BOOKIE_GC="-XX:+UseZGC -XX:+ZGenerational ${BOOKIE_GC}" else BOOKIE_GC="-XX:+UseZGC ${BOOKIE_GC}" fi fi

要点解读:

  • 未显式设置PULSAR_GC/BOOKIE_GC时,默认启用ZGC,并叠加-XX:+PerfDisableSharedMem -XX:+AlwaysPreTouch(禁用共享内存性能监控、启动时预触达所有堆页,减少运行时首触停顿);
  • 在 Java 21/22 上进一步启用-XX:+ZGenerational(分代 ZGC),其余大版本走普通 ZGC;
  • bin/pulsar(见 bin/pulsar)在启动 broker 时拼接$PULSAR_MEM $PULSAR_GC $PULSAR_GC_LOG,启动 bookie 时拼接$BOOKIE_MEM $BOOKIE_GC ...;bin/function-localrunner 对本地 Function Runner 应用相同的PULSAR_GC逻辑;bin/pulsar-perf 也会透传调用方设置的PULSAR_GC。若需显式覆盖,可在环境中预置PULSAR_GC/BOOKIE_GC变量,脚本会跳过默认赋值。

GC 日志参数也随 Java 版本分化

脚本还根据 Java 大版本选择不同的 GC 日志语法(这同样是"升级后重访运行时标志"的一部分):

  • Java 9+:使用统一日志-Xlog:gc*,safepoint:${PULSAR_GC_LOG_DIR}/pulsar_gc_%p.log:time,uptime,tags:filecount=10,filesize=20M;
  • Java 17+:额外前置-Xlog:async启用异步日志(参考 JDK-8264323,避免 GC 日志 I/O 阻塞应用线程);
  • Java 8:回退到旧式-Xloggc:... -XX:+PrintGCDetails -XX:+PrintGCDateStamps ...组合。

这解释了为什么 PIP 要求同时"升级 Java 版本"和"重访运行时标志"——两者必须配套,才能吃到 Java 17 的完整收益。

构建层面的落地:构建要求与兼容性校验

构建所需的 JDK

按 README.md 中记录的版本对应表,PIP-156 对应的 Pulsar 2.11 及之后版本构建需要JDK 17;当前 master 分支则需要 JDK 21(可选 25/26),且 CONTRIBUTING.md 明确 master 构建要求JDK 21、25 或 26(可用-PskipJavaVersionCheck跳过版本检查),同时需要zip命令。构建统一通过项目自带的 Gradle Wrapper(./gradlew)执行,无需单独安装 Gradle。

用 Gradle 属性自定义 Java 目标版本

当前构建系统支持通过属性显式指定目标版本(build-logic/conventions/src/main/kotlin/pulsar.java-conventions.gradle.kts):

  • -PpulsarJavaVersion=17:将服务端代码与常规测试源码目标设为 Java 17(自定义构建,不参与 CI 默认流程);
  • -PpulsarClientJavaVersion=17:控制客户端/公开 API 目标与消费者测试工具链(17 本来就是默认);
  • -PtestJavaVersion=17:用已安装的 JDK 17 编译并运行测试(仅适用于整个测试依赖图都支持 Java 17 的模块);
  • -PdockerJavaVersion=...:覆盖 Docker 基础镜像中的 JDK 版本(settings.gradle.kts 中有注释说明)。

CONTRIBUTING.md 给出的自定义 Java 17 构建示例:

./gradlew assemble -PpulsarJavaVersion=17 PULSAR_MIN_JAVA_VERSION=17 bin/pulsar standalone

其中PULSAR_MIN_JAVA_VERSION用于覆盖启动脚本默认的版本检查(默认 21),它只影响启动时的校验,不改变已编译的字节码或依赖要求;使用 Java 21 专有特性(如虚拟线程)的代码会使 Java 17 目标构建失效。Gradle Docker 构建会把pulsarJavaVersion作为PULSAR_MIN_JAVA_VERSION烘焙进镜像,docker/pulsar/build.gradle.kts 中默认值为 21;直接执行 Docker 构建时也可通过--build-arg PULSAR_MIN_JAVA_VERSION=17覆盖(docker/pulsar/Dockerfile 与 Wolfi 变体默认同为 21)。

测试计划与发布计划

测试策略

PIP-156 规划的验证手段包括:

  1. 通过 Pulsar OSS CI 测试:主干 CI 全量回归,确保 Java 17 下编译与测试通过;
  2. 通过 SN 持续集成框架中的集成测试:在更完整的集成环境(含 ZooKeeper、BookKeeper 组合)下验证;
  3. 新增 Java 8 Client 运行时兼容性集成测试:把"客户端保持 Java 8"从口头承诺变成 CI 强制约束;
  4. 运行 OpenMessaging 基准测试:对比 Java 17 与旧版本在默认 JVM 标志变化下的性能改进,用于验证 ZGC 默认值调整的收益。

这一"兼容性测试进 CI"的做法延续至今:当前仓库通过:tests:pulsar-client-java-compatibility模块(tests/pulsar-client-java-compatibility/src)在 Java 17 工具链下编译并运行消费者示例(CONTRIBUTING.md 给出命令:./gradlew :tests:pulsar-client-java-compatibility:test -PtestRetryCount=0),从运行时层面验证客户端基线。从代码结构看,该模块还依赖 buildtools 与 testmocks 的 Java 17 兼容版本,用于支撑消费者兼容性测试的加载。

发布计划

PIP-156 将本次升级随Pulsar 2.11 版本发布。结合 README.md 中记录的运行时矩阵,2.10 ≤ ver ≤ 3.0 的 Broker / Functions / IO / CLI 均为 Java 17、Java Client 支持 8/11/17,可见该计划已按预期落地。

现状与演进:PIP-156 之后 Pulsar 的 Java 版本矩阵

PIP-156 确立的"服务端用新版本、客户端保兼容"框架在后续版本中持续演进,当前仓库 README.md 给出了完整的分版本矩阵:

版本范围BrokerFunctions / IOCLIJava ClientDocker 运行时
master(≥ 4.1)212117 或 2117 或 2121
3.3 ≤ ver ≤ 4.0212117 或 218、11、17 或 2121
2.10 ≤ ver ≤ 3.01717178、11 或 1717
2.8 ≤ ver ≤ 2.1011118 或 118 或 1111
ver < 2.88 或 118 或 118 或 118 或 118 或 11

同时 README.md 给出两条重要运维建议:

  • 选择 Java 版本时应使用带最新 bug 修复与安全补丁的较新小版本(如 17 或 21 系列),例如 JVM 缺陷 JDK-8351933 可能引发 Pulsar 稳定性问题,该缺陷在 Java 17.0.17+ 与 Java 21.0.8+ 中被修复;
  • Pulsar 官方 Docker 镜像在发布时内置当时最新的 Java 版本。

小结

PIP-156 是 Pulsar Java 版本现代化的一次里程碑式改造,其核心成果可以归纳为四点:

  1. 服务端升级:Broker 的构建与运行基线提升到 Java 17,享受新 GC(ZGC / Shenandoah)与 JVM 改进;
  2. 客户端不动:Java Client 与 client-server 共享模块保持 Java 8 目标,且无任何 API 变更,保证用户运行环境兼容;
  3. CLI 跟随服务端:CLI 运行版本升级到 Java 17(CLI 运行在 Admin 环境,随发行版分发);
  4. GC 默认值切换:ZK / BK / Pulsar 默认 GC 从 G1GC 切换为 ZGC(或 Shenandoah GC),并用基准测试验证收益。

这一分层策略在仓库中的实现痕迹清晰可见:Gradle 约定层(pulsar.java-conventions.gradle.kts)与启动脚本层(conf/pulsar_env.sh、conf/bkenv.sh)共同把"服务端新版本、客户端旧兼容、GC 默认 ZGC"固化成了可持续维护的工程约定,并在此后的 Pulsar 3.x / 4.x / 5.x 中演化为更细粒度的双基线(服务端 21 / 客户端 17)体系。对于需要规划消息中间件 JVM 升级的团队,PIP-156 提供的组件分层、GC 切换与兼容性测试三者并行的思路,是一份值得参考的实践范本。

  • 消息队列
  • 流处理
  • 后端
  • 微服务
  • 消息路由

【免费下载链接】pulsar

Apache Pulsar - distributed pub-sub messaging system

项目地址:https://gitcode.com/gh_mirrors/pu/pulsar
点击查看免费下载
上一篇:Sangria入门指南:如何用Scala构建完整的GraphQL服务器
下一篇:Yuedu项目测试策略:单元测试与集成测试

创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考

版权声明: 本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若内容造成侵权/违法违规/事实不符,请联系邮箱:809451989@qq.com进行投诉反馈,一经查实,立即删除!
网站建设 2026/10/16 12:45:17

猫抓资源嗅探扩展:3 步完成网页视频音频下载的完整指南

猫抓资源嗅探扩展&#xff1a;3 步完成网页视频音频下载的完整指南 【免费下载链接】cat-catch 猫抓 浏览器资源嗅探扩展 / cat-catch Browser Resource Sniffing Extension 项目地址: https://gitcode.com/GitHub_Trending/ca/cat-catch 整理在线课程时&#xff0c;我想…

作者头像 李华