Apache Pulsar 消息队列集群部署与运维实战
一、Pulsar 概述
1.1 什么是 Apache Pulsar
Apache Pulsar 是 Apache 软件基金会顶级项目,是一款云原生分布式消息流平台。它结合了消息队列和流处理的特点,支持 pub-sub 和 queue 两种消费模式。
1.2 Pulsar 核心特性
| 特性 |
说明 |
| 多租户 |
原生支持多租户,租户/命名空间/主题三层模型 |
| 持久化 |
消息持久化到 Apache BookKeeper,保证数据可靠性 |
| 高可用 |
无单点故障,支持跨地域复制 |
| 低延迟 |
发布 - 订阅延迟低至毫秒级 |
| 弹性扩展 |
计算(Broker)与存储(BookKeeper)分离,独立扩展 |
| 多协议 |
支持 Pulsar、Kafka、AMQP、MQTT、STOMP 等协议 |
| 消息追溯 |
支持消息回溯消费,保留策略灵活配置 |
1.3 Pulsar vs Kafka 对比
| 对比项 |
Apache Pulsar |
Apache Kafka |
| 架构 |
计算存储分离 |
计算存储一体 |
| 分区扩展 |
自动分片,无需数据迁移 |
需手动 rebalance,数据迁移 |
| 消息追溯 |
支持任意位置回溯 |
依赖日志保留 |
| 多租户 |
原生支持 |
需额外配置 |
| 地域复制 |
内置支持 |
需 MirrorMaker |
| 存储引擎 |
BookKeeper(分段) |
文件系统日志 |
| 协议支持 |
多协议原生支持 |
主要 Kafka 协议 |
1.4 Pulsar 架构组件
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51
| ┌─────────────────────────────────────────────────────────────────┐ │ Pulsar 架构 │ ├─────────────────────────────────────────────────────────────────┤ │ │ │ ┌─────────────┐ ┌─────────────┐ ┌─────────────┐ │ │ │ Producer │ │ Producer │ │ Producer │ │ │ └──────┬──────┘ └──────┬──────┘ └──────┬──────┘ │ │ │ │ │ │ │ └───────────────────┼───────────────────┘ │ │ │ │ │ ┌────────▼────────┐ │ │ │ Load Balancer │ │ │ └────────┬────────┘ │ │ │ │ │ ┌───────────────────┼───────────────────┐ │ │ │ │ │ │ │ ┌──────▼──────┐ ┌──────▼──────┐ ┌──────▼──────┐ │ │ │ Broker │ │ Broker │ │ Broker │ │ │ │ (Stateless)│ │ (Stateless)│ │ (Stateless)│ │ │ └──────┬──────┘ └──────┬──────┘ └──────┬──────┘ │ │ │ │ │ │ │ └───────────────────┼───────────────────┘ │ │ │ │ │ ┌────────▼────────┐ │ │ │ ZooKeeper │ │ │ │ (Metadata) │ │ │ └────────┬────────┘ │ │ │ │ │ ┌───────────────────┼───────────────────┐ │ │ │ │ │ │ │ ┌──────▼──────┐ ┌──────▼──────┘ ┌──────▼──────┐ │ │ │ BookKeeper │ │ BookKeeper │ │ BookKeeper │ │ │ │ Bookie 1 │ │ Bookie 2 │ │ Bookie 3 │ │ │ └─────────────┘ └─────────────┘ └─────────────┘ │ │ │ │ │ │ │ ┌──────▼──────┐ ┌──────▼──────┐ ┌──────▼──────┐ │ │ │ Ledger 1 │ │ Ledger 2 │ │ Ledger 3 │ │ │ └─────────────┘ └─────────────┘ └─────────────┘ │ │ │ │ ┌─────────────┐ ┌─────────────┐ ┌─────────────┐ │ │ │ Consumer │ │ Consumer │ │ Consumer │ │ │ └─────────────┘ └─────────────┘ └─────────────┘ │ │ │ └─────────────────────────────────────────────────────────────────┘
核心组件: - Broker: 无状态服务,处理消息路由和负载均衡 - BookKeeper: 分布式账本存储,由多个 Bookie 组成 - ZooKeeper: 存储元数据和配置信息 - Producer: 消息生产者 - Consumer: 消息消费者
|
二、环境准备
2.1 硬件要求
| 组件 |
最小配置 |
推荐配置 |
生产配置 |
| Broker |
2 核 4GB |
4 核 8GB |
8 核 16GB+ |
| Bookie |
2 核 4GB |
4 核 8GB |
8 核 16GB+ |
| ZooKeeper |
1 核 2GB |
2 核 4GB |
4 核 8GB |
| 磁盘 (Bookie) |
50GB SSD |
200GB SSD |
1TB+ NVMe |
| 网络 |
1Gbps |
1Gbps |
10Gbps |
2.2 软件要求
- 操作系统:Linux(CentOS 7+/Ubuntu 18.04+)
- Java:OpenJDK 11 或 17
- Python:Python 3.7+(用于 CLI 工具)
- ZooKeeper:3.6+(可内置或独立部署)
2.3 系统优化
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16
| pulsar soft nofile 1048576 pulsar hard nofile 1048576 pulsar soft nproc 65536 pulsar hard nproc 65536
vm.max_map_count=262144 vm.swappiness=1 net.core.somaxconn=65536 net.ipv4.tcp_max_syn_backlog=65536 fs.file-max=2097152
sysctl -p ulimit -n 1048576
|
三、集群部署
3.1 部署规划
假设部署 3 节点集群:
| 节点 |
主机名 |
IP |
角色 |
| Node1 |
pulsar-node1 |
192.168.1.101 |
ZK+Bookie+Broker |
| Node2 |
pulsar-node2 |
192.168.1.102 |
ZK+Bookie+Broker |
| Node3 |
pulsar-node3 |
192.168.1.103 |
ZK+Bookie+Broker |
3.2 安装 Pulsar
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17
|
cd /opt wget https://archive.apache.org/dist/pulsar/pulsar-3.3.0/apache-pulsar-3.3.0-bin.tar.gz
tar -xzf apache-pulsar-3.3.0-bin.tar.gz ln -s apache-pulsar-3.3.0 pulsar
useradd -m -s /bin/bash pulsar chown -R pulsar:pulsar /opt/pulsar
mkdir -p /data/pulsar/{bookkeeper,zookeeper} chown -R pulsar:pulsar /data/pulsar
|
3.3 配置 ZooKeeper
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37
| cd /opt/pulsar bin/pulsar initialize-cluster-metadata \ --cluster pulsar-cluster \ --zookeeper pulsar-node1:2181 \ --configuration-store pulsar-node1:2181 \ --web-service-url http://pulsar-node1:8080 \ --web-service-url-tls https://pulsar-node1:8443 \ --broker-service-url pulsar://pulsar-node1:6650 \ --broker-service-url-tls pulsar+ssl://pulsar-node1:6651
cat > conf/zookeeper.conf << EOF dataDir=/data/pulsar/zookeeper clientPort=2181 initLimit=10 syncLimit=5 tickTime=2000 admin.enableServer=false admin.serverPort=9990 4lw.commands.whitelist=ruok,stat,mntr,conf,envi EOF
echo "1" > /data/pulsar/zookeeper/myid
echo "2" > /data/pulsar/zookeeper/myid
echo "3" > /data/pulsar/zookeeper/myid
cat >> conf/zookeeper.conf << EOF server.1=pulsar-node1:2888:3888 server.2=pulsar-node2:2888:3888 server.3=pulsar-node3:2888:3888 EOF
|
3.4 配置 BookKeeper
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29
| cat > conf/bookkeeper.conf << EOF # 基础配置 bookiePort=3181 journalDirectory=/data/pulsar/bookkeeper/journal ledgerDirectories=/data/pulsar/bookkeeper/ledgers
# 集群配置 zkServers=pulsar-node1:2181,pulsar-node2:2181,pulsar-node3:2181 zkLedgersRootPath=/ledgers
# 网络配置 advertisedAddress=pulsar-node1 # 各节点修改为对应主机名 allowLoopback=false
# 性能优化 journalMaxSizeMB=4096 gcWaitTime=300000 nettyMaxFrameSizeBytes=104857600
# 存储优化 diskUsageThreshold=0.90 diskUsageWarnThreshold=0.85 minorCompactionThreshold=0.1 majorCompactionThreshold=0.5 EOF
bin/bookkeeper shell metaformat -nonInteractive
|
3.5 配置 Broker
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27
| cat > conf/standalone.conf << EOF # 集群配置 clusterName=pulsar-cluster zookeeperServers=pulsar-node1:2181,pulsar-node2:2181,pulsar-node3:2181 configurationStoreServers=pulsar-node1:2181,pulsar-node2:2181,pulsar-node3:2181
# 网络配置 advertisedAddress=pulsar-node1 # 各节点修改 bindAddress=0.0.0.0 webServicePort=8080 brokerServicePort=6650
# BookKeeper 配置 bookkeeperClientHealthCheckEnabled=true bookkeeperClientHealthCheckErrorThresholdPerBookie=5 bookkeeperClientSpeculativeReadTimeoutInMillis=3000
# 消息配置 defaultRetentionTimeInMinutes=10080 defaultRetentionSizeInMB=10240 defaultBacklogQuotaCheckEnabled=true
# 性能优化 numHttpServerThreads=16 brokerShutdownTimeoutMs=30000 EOF
|
3.6 启动服务
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79
|
cat > /etc/systemd/system/pulsar-zookeeper.service << EOF [Unit] Description=Apache Pulsar ZooKeeper After=network.target
[Service] Type=forking User=pulsar Group=pulsar Environment=JAVA_HOME=/usr/lib/jvm/java-11-openjdk Environment=PULSAR_HOME=/opt/pulsar Environment=BOOKIE_MEM="-Xms2g -Xmx2g" Environment=ZOOKEEPER_MEM="-Xms1g -Xmx1g" ExecStart=/opt/pulsar/bin/pulsar-daemon start zookeeper ExecStop=/opt/pulsar/bin/pulsar-daemon stop zookeeper Restart=on-failure LimitNOFILE=1048576
[Install] WantedBy=multi-user.target EOF
cat > /etc/systemd/system/pulsar-bookkeeper.service << EOF [Unit] Description=Apache Pulsar BookKeeper After=pulsar-zookeeper.service Requires=pulsar-zookeeper.service
[Service] Type=forking User=pulsar Group=pulsar Environment=JAVA_HOME=/usr/lib/jvm/java-11-openjdk Environment=PULSAR_HOME=/opt/pulsar Environment=BOOKIE_MEM="-Xms4g -Xmx4g -XX:MaxDirectMemorySize=4g" ExecStart=/opt/pulsar/bin/pulsar-daemon start bookkeeper ExecStop=/opt/pulsar/bin/pulsar-daemon stop bookkeeper Restart=on-failure LimitNOFILE=1048576
[Install] WantedBy=multi-user.target EOF
cat > /etc/systemd/system/pulsar-broker.service << EOF [Unit] Description=Apache Pulsar Broker After=pulsar-bookkeeper.service Requires=pulsar-bookkeeper.service
[Service] Type=forking User=pulsar Group=pulsar Environment=JAVA_HOME=/usr/lib/jvm/java-11-openjdk Environment=PULSAR_HOME=/opt/pulsar Environment=PULSAR_MEM="-Xms4g -Xmx4g -XX:MaxDirectMemorySize=4g" ExecStart=/opt/pulsar/bin/pulsar-daemon start broker ExecStop=/opt/pulsar/bin/pulsar-daemon stop broker Restart=on-failure LimitNOFILE=1048576
[Install] WantedBy=multi-user.target EOF
systemctl daemon-reload systemctl enable pulsar-zookeeper pulsar-bookkeeper pulsar-broker systemctl start pulsar-zookeeper sleep 10 systemctl start pulsar-bookkeeper sleep 10 systemctl start pulsar-broker
|
3.7 验证集群状态
1 2 3 4 5 6 7 8 9 10 11 12 13 14
| echo ruok | nc pulsar-node1 2181
/opt/pulsar/bin/bookkeeper shell bookie_info
curl http://pulsar-node1:8080/admin/v2/brokers/cluster/pulsar-cluster
/opt/pulsar/bin/pulsar-admin clusters get pulsar-cluster
/opt/pulsar/bin/bookkeeper shell whatisinstanceid
|
四、租户与命名空间管理
4.1 创建租户
1 2 3 4 5 6 7 8 9 10
| /opt/pulsar/bin/pulsar-admin tenants create tenant-a \ --admin-roles admin \ --allowed-clusters pulsar-cluster
/opt/pulsar/bin/pulsar-admin tenants list
/opt/pulsar/bin/pulsar-admin tenants get tenant-a
|
4.2 创建命名空间
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15
| /opt/pulsar/bin/pulsar-admin namespaces create tenant-a/namespace-prod
/opt/pulsar/bin/pulsar-admin namespaces set-retention tenant-a/namespace-prod \ --size -1 --time 10080
/opt/pulsar/bin/pulsar-admin namespaces set-backlog-quota tenant-a/namespace-prod \ --limit 10737418240 --limitTime 86400 --policy producer_exception
/opt/pulsar/bin/pulsar-admin namespaces set-message-ttl tenant-a/namespace-prod \ --ttl 259200
/opt/pulsar/bin/pulsar-admin namespaces list tenant-a
|
4.3 创建主题
1 2 3 4 5 6 7 8 9
| /opt/pulsar/bin/pulsar-admin topics create persistent://tenant-a/namespace-prod/topic-orders \ --partitions 6
/opt/pulsar/bin/pulsar-admin topics stats persistent://tenant-a/namespace-prod/topic-orders
/opt/pulsar/bin/pulsar-admin topics list tenant-a/namespace-prod
|
五、生产消费示例
5.1 Java 客户端
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31
| import org.apache.pulsar.client.api.*;
PulsarClient client = PulsarClient.builder() .serviceUrl("pulsar://pulsar-node1:6650,pulsar-node2:6650,pulsar-node3:6650") .build();
Producer<String> producer = client.newProducer(Schema.STRING) .topic("persistent://tenant-a/namespace-prod/topic-orders") .create();
for (int i = 0; i < 100; i++) { MessageId msgId = producer.send("Order-" + i); System.out.println("Sent message: " + msgId); }
producer.close(); client.close();
Consumer<String> consumer = client.newConsumer(Schema.STRING) .topic("persistent://tenant-a/namespace-prod/topic-orders") .subscriptionName("order-processor") .subscriptionType(SubscriptionType.Shared) .subscribe();
while (true) { Message<String> msg = consumer.receive(); System.out.println("Received: " + msg.getValue()); consumer.acknowledge(msg); }
|
5.2 Python 客户端
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25
| import pulsar
client = pulsar.Client('pulsar://pulsar-node1:6650') producer = client.create_producer('persistent://tenant-a/namespace-prod/topic-orders')
for i in range(100): producer.send(f'Order-{i}'.encode('utf-8')) print(f"Sent Order-{i}")
producer.close() client.close()
client = pulsar.Client('pulsar://pulsar-node1:6650') consumer = client.subscribe( 'persistent://tenant-a/namespace-prod/topic-orders', subscription_name='order-processor', consumer_type=pulsar.ConsumerType.Shared )
while True: msg = consumer.receive() print(f"Received: {msg.data().decode('utf-8')}") consumer.acknowledge(msg)
|
5.3 命令行测试
1 2 3 4 5 6 7
| /opt/pulsar/bin/pulsar-client produce persistent://tenant-a/namespace-prod/topic-orders \ --messages "Hello Pulsar"
/opt/pulsar/bin/pulsar-client consume persistent://tenant-a/namespace-prod/topic-orders \ --subscription-name test-sub -n 10
|
六、运维管理
6.1 监控指标
Pulsar 暴露 Prometheus 格式的指标:
1 2 3 4 5 6 7 8 9 10 11
| curl http://pulsar-node1:8080/metrics/
curl http://pulsar-node1:8000/metrics/
|
6.2 常用运维命令
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25
| /opt/pulsar/bin/pulsar-admin brokers list pulsar-cluster
/opt/pulsar/bin/bookkeeper shell listbookies -rw
/opt/pulsar/bin/bookkeeper shell listledgers
/opt/pulsar/bin/bookkeeper shell ledgerchecker
/opt/pulsar/bin/pulsar-admin topics stats persistent://tenant-a/namespace-prod/topic-orders
/opt/pulsar/bin/pulsar-admin topics stats-internal persistent://tenant-a/namespace-prod/topic-orders
/opt/pulsar/bin/pulsar-admin topics reset-cursor persistent://tenant-a/namespace-prod/topic-orders \ --subscription order-processor --time 1710316800000
/opt/pulsar/bin/pulsar-admin topics skip persistent://tenant-a/namespace-prod/topic-orders \ --subscription order-processor -n 1000
|
6.3 备份与恢复
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17
|
tar -czf /backup/zk_backup_$(date +%Y%m%d).tar.gz /data/pulsar/zookeeper
/opt/pulsar/bin/bookkeeper shell ledgermanager dump > /backup/ledger_dump.txt
|
6.4 扩容操作
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15
|
/opt/pulsar/bin/pulsar-admin brokers list pulsar-cluster /opt/pulsar/bin/bookkeeper shell listbookies -rw
|
七、故障排查
7.1 Bookie 只读模式
现象: Bookie 进入只读模式,无法写入新数据
排查:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18
| /opt/pulsar/bin/bookkeeper shell bookie_info
df -h /data/pulsar/bookkeeper
tail -f /opt/pulsar/logs/bookkeeper.log
|
7.2 Broker 连接 BookKeeper 失败
现象: Broker 日志出现 BookKeeper 连接错误
排查:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16
| echo stat | nc pulsar-node1 2181
/opt/pulsar/bin/bookkeeper shell listbookies -rw
telnet pulsar-node1 3181
tail -f /opt/pulsar/logs/pulsar-broker.log | grep -i bookkeeper
|
7.3 消息积压
现象: Consumer 消费速度慢,消息大量积压
排查:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15
| /opt/pulsar/bin/pulsar-admin topics stats persistent://tenant-a/namespace-prod/topic-orders
/opt/pulsar/bin/pulsar-admin topics stats-internal persistent://tenant-a/namespace-prod/topic-orders
/opt/pulsar/bin/pulsar-admin topics peek-messages persistent://tenant-a/namespace-prod/topic-orders \ --subscription order-processor -n 10
|
7.4 ZooKeeper 性能问题
现象: ZK 响应慢,影响 Pulsar 操作
排查:
1 2 3 4 5 6 7 8 9 10 11 12 13 14
| echo mntr | nc pulsar-node1 2181 | grep latency
echo stat | nc pulsar-node1 2181
tail -f /opt/pulsar/logs/zookeeper.log
|
7.5 常见错误码
| 错误 |
原因 |
解决方案 |
ServiceUnitNotReady |
Broker 未准备好 |
等待 Broker 启动完成 |
BrokerPersistenceException |
BookKeeper 写入失败 |
检查 Bookie 状态 |
MetadataNotFoundException |
主题/命名空间不存在 |
检查路径是否正确 |
ConsumerBusyException |
Consumer 独占模式冲突 |
检查订阅模式 |
ProducerFencedException |
Producer 被隔离 |
重新创建 Producer |
八、性能调优
8.1 JVM 调优
1 2 3 4 5 6 7 8 9 10 11 12 13 14
| PULSAR_MEM="-Xms8g -Xmx8g \ -XX:MaxDirectMemorySize=8g \ -XX:+UseG1GC \ -XX:MaxGCPauseMillis=200 \ -XX:+ParallelRefProcEnabled \ -XX:+UnlockExperimentalVMOptions \ -XX:+AggressiveOpts"
BOOKIE_MEM="-Xms4g -Xmx4g \ -XX:MaxDirectMemorySize=4g \ -XX:+UseG1GC \ -XX:MaxGCPauseMillis=200"
|
8.2 BookKeeper 调优
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15
|
journalMaxSizeMB=8192
gcWaitTime=600000
ledgersPerBookie=10000000 maxAddPerMsecs=10000
nettyMaxFrameSizeBytes=16777216 recvBufferSize=1048576 sendBufferSize=1048576
|
8.3 Broker 调优
1 2 3 4 5 6 7 8 9 10 11 12 13
|
numHttpServerThreads=32 numAccepterThreads=8
maxMessageSize=10485760 brokerMaxPublishRate=100000 brokerMaxPublishMessageRate=500000
managedLedgerCacheSizeMB=1024 managedLedgerDefaultMarkDeleteRateLimit=100
|
8.4 生产环境建议
| 配置项 |
建议值 |
说明 |
| Bookie 数量 |
≥3 |
保证数据副本 |
| Broker 数量 |
≥2 |
高可用 |
| ZooKeeper 数量 |
3 或 5 |
奇数节点 |
| 分区数 |
消息量/10 万/天 |
根据吞吐量调整 |
| 副本数 |
2 或 3 |
平衡可靠性和性能 |
| 保留策略 |
7-30 天 |
根据业务需求 |
九、高可用配置
9.1 跨地域复制
1 2 3 4 5 6 7 8 9 10 11
| /opt/pulsar/bin/pulsar-admin clusters create cluster-b \ --service-url http://cluster-b:8080 \ --broker-url pulsar://cluster-b:6650
/opt/pulsar/bin/pulsar-admin namespaces set-replication-clusters \ tenant-a/namespace-prod pulsar-cluster,cluster-b
/opt/pulsar/bin/pulsar-admin topics stats persistent://tenant-a/namespace-prod/topic-orders
|
9.2 故障转移
1 2 3 4 5 6 7 8 9
|
systemctl stop pulsar-broker
/opt/pulsar/bin/pulsar-admin brokers list pulsar-cluster
|
十、总结
Apache Pulsar 作为云原生消息流平台,具有以下优势:
- 架构优势:计算存储分离,弹性扩展
- 功能丰富:多租户、多协议、消息追溯
- 高可用:内置副本、跨地域复制
- 运维友好:完善的监控指标和管理工具
部署运维要点:
- 规划先行:合理评估硬件资源和网络拓扑
- 监控完善:配置 Prometheus+Grafana 监控
- 定期维护:检查磁盘、清理日志、更新固件
- 故障预案:制定故障处理和恢复流程
参考文档: