Pulsar 5.0.0 的 standalone 用官方 tar 包就能起来,Spring Boot 4.1.1 也能对着它收发消息。不过 Boot 默认带进来的客户端还是 4.2.4。想换成 5.0 客户端,只改版本号不够,得改用 pulsar-client-v5-all,再排除 pulsar-client-all 和 log4j-to-slf4j 两个包。下面按实跑的顺序一步步摆出来。

Apache Pulsar 5.0.0 是 2026-10-06 在 GitHub 发的版(北京时间 03:22),官方把它定为新的 LTS。许可证是 Apache-2.0,仓库在 github.com/apache/pulsar。

5.0 到底改了什么

先看官方怎么说。主要来源是 5.0.0 release notes、M1 release notes 和官博 Apache Pulsar 5.0 LTS: Scalable Topics and Faster Existing Workloads。下面挑和 Java 开发者关系大的几条转述。

Scalable Topics。一种新的 topic 类型,用 topic:// 地址。它不再让你建 topic 时就定分区数,而是按 key 的哈希范围切成 segment。热的 segment 会自动拆分,冷的相邻 segment 会自动合并。官博的说法是拆分合并时按 key 的顺序不会乱。总设计在 PIP-460,自动拆合在 PIP-483。官博也写明了限制:5.0 里 Scalable Topics 不支持跨地域复制和 replicated subscriptions。

V5 Java 客户端 API。见 PIP-466。老的 Consumer 加四种订阅类型,再加 Reader,换成了三种消费者:StreamConsumer、QueueConsumer、CheckpointConsumer。官方现在把原来的客户端叫 v4 client,并说它在整个 5.0 LTS 里都继续完整支持。v4 客户端连不上 topic:// 这种 topic。

新的客户端依赖。官博推荐 org.apache.pulsar:pulsar-client-v5-all,里面同时有 v4、v5 API 和 admin 客户端,而且没有做 shade。

Oxia 成为新集群推荐的元数据存储。ZooKeeper 继续支持,PIP-454 提供从 ZooKeeper 在线迁到 Oxia 的框架。Etcd 后端已经删掉了(PIP-462)。

升级要注意的硬条件。官博 Before you upgrade 一节写的是:服务端要求 Java 21 及以上,推荐 Java 25;Java 客户端要求 Java 17 及以上,4.0.x 客户端还支持 Java 8 和 11。Java 客户端默认开启主机名校验。插件里的 javax.* 要换成 jakarta.*(PIP-472)。IO 连接器拆到单独仓库(PIP-465),Docker 镜像 apachepulsar/pulsar-all 要换成 apachepulsar/pulsar。Pulsar Manager 不再维护。

日志。各模块改用 slog 输出结构化日志(PIP-467)。这一条后面在 Spring Boot 里会碰上。

官博还贴了一组 4.0.13 对比 5.0.0 的 IoT 场景压测,500 个生产者、20 个 Key_Shared 消费者。原文数字是:发布加消费合计 128,847 messages/s 对 213,923 messages/s,端到端 p99 延迟 202.3 s 对 1.08 s。官方特别注明这只代表这个负载,不代表 broker 的通用容量。这组数我没有复测。

本机环境

  • Debian,OpenJDK 21.0.12.1
  • Maven Wrapper 构建
  • Pulsar 5.0.0 官方二进制包 apache-pulsar-5.0.0-bin.tar.gz
  • Spring Boot 4.1.1,项目用 start.spring.io 生成,只勾了 Pulsar

起 standalone

下载、校验、解压、启动:

mkdir -p pulsar5-demo && cd pulsar5-demo
curl -LO https://archive.apache.org/dist/pulsar/pulsar-5.0.0/apache-pulsar-5.0.0-bin.tar.gz
curl -LO https://archive.apache.org/dist/pulsar/pulsar-5.0.0/apache-pulsar-5.0.0-bin.tar.gz.sha512
sha512sum -c apache-pulsar-5.0.0-bin.tar.gz.sha512
tar xzf apache-pulsar-5.0.0-bin.tar.gz
cd apache-pulsar-5.0.0
bin/pulsar standalone

standalone 默认用 8080 做 HTTP 端口,6650 做 broker 端口,配置在 conf/standalone.conf。我没改端口,直接起来了,日志里 broker 监听 6650:

2026-10-17T09:01:14,938+0800 [main] INFO  org.apache.pulsar.broker.service.BrokerService - Started Pulsar Broker service {listener=internal, localAddress=/0.0.0.0:6650, tls=(none)}

另开一个终端确认版本和健康状态:

bin/pulsar version 2>&1 | tee pulsar-version.log
bin/pulsar-admin --admin-url http://localhost:8080 brokers healthcheck 2>&1 | tee pulsar-healthcheck.log
Current version of pulsar is: 5.0.0
Git Revision b7b03f72cd4f81d501570588fcf3433ee035629b
Git Branch branch-5.0
Built by Lari Hotari <lhotari@apache.org> on Laris-MacBook-Pro-2.local at 2026-10-01T20:18:40Z

healthcheck 的输出:

ok

官博说 5.0 的启动脚本默认用 ZGC。conf/pulsar_env.sh 第 100–108 行是这段,没设 PULSAR_GC 时就走这里:

# 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

本机是 Java 21,走的是带 -XX:+ZGenerational 的那个分支。standalone 进程的 GC 日志在 logs/ 下,开头就有这一行:

[2026-10-17T09:01:09.097+0800][0.006s][gc,init] Initializing The Z Garbage Collector

Spring Boot 应用

代码只有一个类。启动后用 PulsarTemplate 发 3 条消息,同一个类里用 @PulsarListener 收。另外打印一下实际加载的 pulsar-client 版本。

src/main/java/com/example/demo/PulsarDemoApplication.java:

package com.example.demo;

import org.apache.pulsar.client.api.PulsarClient;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.boot.ApplicationRunner;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.context.annotation.Bean;
import org.springframework.pulsar.annotation.PulsarListener;
import org.springframework.pulsar.core.PulsarTemplate;

@SpringBootApplication
public class PulsarDemoApplication {

    private static final Logger log = LoggerFactory.getLogger(PulsarDemoApplication.class);

    public static void main(String[] args) {
        SpringApplication.run(PulsarDemoApplication.class, args);
    }

    @Bean
    ApplicationRunner sender(PulsarTemplate<String> template) {
        return args -> {
            log.info("pulsar-client version: {}", PulsarClient.class.getPackage().getImplementationVersion());
            for (int i = 1; i <= 3; i++) {
                var id = template.send("hello-pulsar5", "hello #" + i);
                log.info("sent hello #{} -> {}", i, id);
            }
        };
    }

    @PulsarListener(subscriptionName = "demo-sub", topics = "hello-pulsar5")
    void listen(String msg) {
        log.info("received: {}", msg);
    }
}

src/main/resources/application.properties:

spring.application.name=pulsar-demo
spring.pulsar.client.service-url=pulsar://localhost:6650
spring.pulsar.consumer.subscription.initial-position=earliest

第一次:用 Boot 默认的客户端

先看依赖树。用 -Dincludes 只留 Pulsar 和日志相关的坐标,输出是这样:

./mvnw -B dependency:tree -Dincludes=org.apache.pulsar,org.springframework.pulsar,org.springframework.boot:spring-boot-starter-pulsar,org.springframework.boot:spring-boot-pulsar,org.apache.logging.log4j
[INFO] \- org.springframework.boot:spring-boot-starter-pulsar:jar:4.1.1:compile
[INFO]    +- org.springframework.boot:spring-boot-starter:jar:4.1.1:compile
[INFO]    |  \- org.springframework.boot:spring-boot-starter-logging:jar:4.1.1:compile
[INFO]    |     \- org.apache.logging.log4j:log4j-to-slf4j:jar:2.25.5:compile
[INFO]    |        \- org.apache.logging.log4j:log4j-api:jar:2.25.5:compile
[INFO]    \- org.springframework.boot:spring-boot-pulsar:jar:4.1.1:compile
[INFO]       \- org.springframework.pulsar:spring-pulsar:jar:2.0.7:compile
[INFO]          +- org.apache.pulsar:pulsar-client-all:jar:4.2.4:compile
[INFO]          |  +- org.apache.pulsar:pulsar-client-api:jar:4.2.4:compile
[INFO]          |  +- org.apache.pulsar:bouncy-castle-bc:jar:pkg:4.2.4:compile
[INFO]          |  +- org.apache.pulsar:pulsar-client-admin-api:jar:4.2.4:compile
[INFO]          |  \- org.apache.pulsar:pulsar-package-core:jar:4.2.4:compile
[INFO]          +- org.springframework.pulsar:spring-pulsar-cache-provider:jar:2.0.7:compile
[INFO]          \- org.springframework.pulsar:spring-pulsar-cache-provider-caffeine:jar:2.0.7:runtime

Boot 4.1.1 管理的 pulsar.version 是 4.2.4,经 Spring for Apache Pulsar 2.0.7 带进来的是 pulsar-client-all 4.2.4。打包运行:

./mvnw -q -DskipTests package
java -jar target/pulsar-demo-0.0.1-SNAPSHOT.jar

应用日志里收发相关的几行:

2026-10-17T09:02:40.195+08:00  INFO 1154841 --- [pulsar-demo] [           main] com.example.demo.PulsarDemoApplication   : pulsar-client version: 4.2.4
2026-10-17T09:02:40.248+08:00  INFO 1154841 --- [pulsar-demo] [           main] com.example.demo.PulsarDemoApplication   : sent hello #1 -> 11:0:-1
2026-10-17T09:02:40.256+08:00  INFO 1154841 --- [pulsar-demo] [           main] com.example.demo.PulsarDemoApplication   : sent hello #2 -> 11:1:-1
2026-10-17T09:02:40.260+08:00  INFO 1154841 --- [pulsar-demo] [           main] com.example.demo.PulsarDemoApplication   : sent hello #3 -> 11:2:-1
2026-10-17T09:02:40.291+08:00  INFO 1154841 --- [pulsar-demo] [ntainer#0-0-C-1] com.example.demo.PulsarDemoApplication   : received: hello #1
2026-10-17T09:02:40.291+08:00  INFO 1154841 --- [pulsar-demo] [ntainer#0-0-C-1] com.example.demo.PulsarDemoApplication   : received: hello #2
2026-10-17T09:02:40.291+08:00  INFO 1154841 --- [pulsar-demo] [ntainer#0-0-C-1] com.example.demo.PulsarDemoApplication   : received: hello #3

4.2.4 客户端连 5.0.0 broker,收发都正常。这和官方说的 v4 客户端继续可用对得上。

第二次:只把 pulsar.version 改成 5.0.0

在 pom.xml 的 properties 里加一行:

<pulsar.version>5.0.0</pulsar.version>

依赖树里 pulsar-client-all 变成了 5.0.0。打包没问题,一运行就报错,创建 pulsarClient 这个 Bean 时失败:

Caused by: java.lang.NoClassDefFoundError: org/apache/logging/log4j/core/LogEvent
	at io.github.merlimat.slog.impl.LoggerDiscovery.createLogger(LoggerDiscovery.java:55) ~[slog-0.10.0.jar!/:na]
	at io.github.merlimat.slog.impl.LoggerDiscovery.createLogger(LoggerDiscovery.java:50) ~[slog-0.10.0.jar!/:na]
	at io.github.merlimat.slog.Logger.get(Logger.java:75) ~[slog-0.10.0.jar!/:na]
	at io.github.merlimat.slog.Logger.get(Logger.java:65) ~[slog-0.10.0.jar!/:na]
	at org.apache.pulsar.shade.org.apache.pulsar.client.impl.PulsarClientImpl.<clinit>(PulsarClientImpl.java:123) ~[pulsar-client-all-5.0.0.jar!/:5.0.0]

报错来自 5.0 新引入的 slog。它找 log4j-core 的 LogEvent,可 Spring Boot 默认用的是 Logback,classpath 上只有 log4j-to-slf4j 这个桥接包,没有 log4j-core。我把 log4j-to-slf4j 从 spring-boot-starter-pulsar 下面排除掉,再跑,这个错没了,换成了下一个:

Caused by: java.lang.NoClassDefFoundError: org/apache/pulsar/client/impl/schema/JSONSchema

上面那段栈里能看到,pulsar-client-all 5.0.0 里的实现类在 org.apache.pulsar.shade. 前缀下面。Spring for Apache Pulsar 2.0.7 的 DefaultSchemaResolver 引用的是没加前缀的 org.apache.pulsar.client.impl.schema.JSONSchema,所以找不到。

第三次:换成 pulsar-client-v5-all

官博推荐的 pulsar-client-v5-all 是不做 shade 的版本,正好对上第二个错。截至 2026-10-17,Spring for Apache Pulsar 的版本兼容矩阵只列到 4.x 客户端,GitHub 上也没有讲 5.0 客户端的 issue 或 release notes。下面这套写法是我实测能跑的组合,官方没给过。pom.xml 依赖部分:

<properties>
    <java.version>21</java.version>
    <pulsar.version>5.0.0</pulsar.version>
</properties>
<dependencies>
    <dependency>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter-pulsar</artifactId>
        <exclusions>
            <exclusion>
                <groupId>org.apache.logging.log4j</groupId>
                <artifactId>log4j-to-slf4j</artifactId>
            </exclusion>
            <exclusion>
                <groupId>org.apache.pulsar</groupId>
                <artifactId>pulsar-client-all</artifactId>
            </exclusion>
        </exclusions>
    </dependency>

    <dependency>
        <groupId>org.apache.pulsar</groupId>
        <artifactId>pulsar-client-v5-all</artifactId>
    </dependency>
</dependencies>

pulsar-client-v5-all 不用写版本,Boot 导入的 pulsar-bom 按 pulsar.version 给它定成 5.0.0。依赖树里已经没有 pulsar-client-all 和 log4j-to-slf4j:

[INFO] +- org.springframework.boot:spring-boot-starter-pulsar:jar:4.1.1:compile
[INFO] |  \- org.springframework.boot:spring-boot-pulsar:jar:4.1.1:compile
[INFO] |     \- org.springframework.pulsar:spring-pulsar:jar:2.0.7:compile
[INFO] |        +- org.springframework.pulsar:spring-pulsar-cache-provider:jar:2.0.7:compile
[INFO] |        \- org.springframework.pulsar:spring-pulsar-cache-provider-caffeine:jar:2.0.7:runtime
[INFO] \- org.apache.pulsar:pulsar-client-v5-all:jar:5.0.0:compile
[INFO]    +- org.apache.pulsar:pulsar-client-v5:jar:5.0.0:compile
[INFO]    |  +- org.apache.pulsar:pulsar-client-api-v5:jar:5.0.0:compile
[INFO]    |  +- org.apache.pulsar:pulsar-tls-factory-api:jar:5.0.0:compile
[INFO]    |  +- org.apache.pulsar:pulsar-http-client-api:jar:5.0.0:compile
[INFO]    |  +- org.apache.pulsar:pulsar-client-original:jar:5.0.0:compile
[INFO]    |  |  \- org.apache.pulsar:pulsar-client-fastutil-minimized:jar:5.0.0:runtime
[INFO]    |  \- org.apache.pulsar:pulsar-common:jar:5.0.0:compile
[INFO]    +- org.apache.pulsar:pulsar-client-admin-original:jar:5.0.0:compile
[INFO]    |  +- org.apache.pulsar:pulsar-client-admin-api:jar:5.0.0:compile
[INFO]    |  \- org.apache.pulsar:pulsar-package-core:jar:5.0.0:runtime
[INFO]    \- org.apache.pulsar:pulsar-client-messagecrypto-bc:jar:5.0.0:runtime
[INFO]       \- org.apache.pulsar:pulsar-client-api:jar:5.0.0:compile

运行结果,同样只摘收发相关的几行:

2026-10-17T09:03:39.233+08:00  INFO 1156371 --- [pulsar-demo] [           main] com.example.demo.PulsarDemoApplication   : pulsar-client version: 5.0.0
2026-10-17T09:03:39.299+08:00  INFO 1156371 --- [pulsar-demo] [           main] com.example.demo.PulsarDemoApplication   : sent hello #1 -> 11:3:-1
2026-10-17T09:03:39.308+08:00  INFO 1156371 --- [pulsar-demo] [           main] com.example.demo.PulsarDemoApplication   : sent hello #2 -> 11:4:-1
2026-10-17T09:03:39.313+08:00  INFO 1156371 --- [pulsar-demo] [           main] com.example.demo.PulsarDemoApplication   : sent hello #3 -> 11:5:-1
2026-10-17T09:03:39.333+08:00  INFO 1156371 --- [pulsar-demo] [ntainer#0-0-C-1] com.example.demo.PulsarDemoApplication   : received: hello #1
2026-10-17T09:03:39.333+08:00  INFO 1156371 --- [pulsar-demo] [ntainer#0-0-C-1] com.example.demo.PulsarDemoApplication   : received: hello #2
2026-10-17T09:03:39.333+08:00  INFO 1156371 --- [pulsar-demo] [ntainer#0-0-C-1] com.example.demo.PulsarDemoApplication   : received: hello #3

消息 ID 接着第一次的 11:2 往下排,说明是同一个 topic 上的新消息。

我还单独试了一次:保留 pulsar-client-v5-all,去掉 log4j-to-slf4j 的排除。还是同一个 NoClassDefFoundError: org/apache/logging/log4j/core/LogEvent。所以在这套组合里,两处排除都得留着。

官方说法和实测对一下

官博原话:

Switching to it doesn't require changes to code that uses only Pulsar's public APIs

实测:业务代码确实一行没改。不过 Spring for Apache Pulsar 2.0.7 引用了客户端的实现类,Boot 默认日志栈又和 slog 的探测撞上了,所以得在 pom.xml 里做两处排除。

另一条,官方说 v4 客户端继续完整支持。实测 Boot 默认带的 4.2.4 客户端连 5.0.0 standalone,收发正常。

这次只验证了普通持久化 topic 上的 v4 API。Spring for Apache Pulsar 2.0.7 用的就是这套 API,topic:// 这种 Scalable Topic 和 V5 的三种消费者没有走到。

资料来源

文中官方说法核对自 5.0.0 发布页、官博和下载页,命令和输出都来自 2026-10-17 在本机的实跑。

— 感谢阅读 —
广告

一起交流

分享你的思考,让讨论更进一步。