Apache Pulsar 2.9.1部署实战:从单机到集群的配置与避坑指南

简介:Pulsar 2.9.1 是一个由 Apache 社区维护的高性能消息中间件二进制发布包,专为分布式与云原生场景设计。它依托 ZooKeeper 完成元数据协调与集群一致性管理,适合需要在大规模多节点之间搭建高可靠消息通道的开发者或架构师。压缩包约321.53MB,内部包含服务端可执行程序、客户端开发库、启动与停止脚本以及辅助配置工具,免去源码编译步骤,解压后即可部署。目前已有151人学习下载。通过直接使用该二进制包,可以深入实践发布订阅模型,以及共享、独占、故障转移等多种订阅方式,还能了解 BookKeeper 持久化与分层存储机制;容器友好的架构便于在 Kubernetes 等环境中验证弹性伸缩与故障迁移。这套资源对理解消息队列原理、积累分布式系统运维经验很有帮助,也是快速搭建真实消息服务的实用选择。

1. Pulsar 2.9.1 二进制包:最值得先跑起来的云原生消息中间件

如果你所在团队正在做微服务拆分、数据管道或者实时数仓,消息队列选型基本绕不开 Apache Pulsar。Pulsar 2.9.1 这个版本处于 2.9 系列较稳定的后期,把分层存储、跨地域复制、事务消息这些云原生场景的主干能力都收了进去,而且 broker 和 bookie 可以分离部署。我实际拆过很多开源中间件,Pulsar 2.9.1 的 bin.tar.gz 包是我见过最容易从零跑到生产验证的发行包之一——因为它自带了 Zookeeper 和 BookKeeper 的完整生态,单机一条命令就能把整个集群组件唤醒,不需要预先装一堆依赖,适合新手熟手快速复现。

这包适合谁呢?正在做技术选型对比的架构师、第一次搭 Pulsar 想要看真实行为的后端开发、以及准备把现有数据管道从其他 MQ 迁过来的运维工程师。它能帮你解决的问题很具体:消息不丢不重怎么配置、层级存储怎么开、认证和命名空间怎么隔离、集群扩缩容时哪些参数会造成坑。往下我会按真实拆包顺序讲清楚:从解压目录的每个文件干什么开始,到单机和集群两种部署姿势,再到参数配置和性能验证,最后把配置项、资源和踩坑经验揉到一起。中间每段命令都可以直接抄,我尽量把参数含义说透。

2. 拆包后先看目录与核心组件:Pulsar 的架构分层与 Zookeeper 的角色

2.1 Pulsar 2.9.1 组件架构:Broker、Bookie 与 Zookeeper 各管什么

Pulsar 不是一台机器扛所有活。它把一个消息系统拆成了三层:Broker 负责处理生产消费请求和 topic 的路由,它本身不存任何消息数据;BookKeeper 的 Bookie 节点负责持久化消息,以 segment 形式写入 ledger;Zookeeper 负责元数据管理,比如 topic 归属、broker 心跳、全局配置、Bookie 存活列表。这三层在 Pulsar 2.9.1 的 bin.tar.gz 里都能找到对应启动脚本,分别是pulsar broker、pulsar bookkeeper和内置 ZK。

你可能会问:为什么一定要引入 Zookeeper?Pulsar 把 topic 的 ownership 分配给不同 broker,这个过程需要分布式协调。Zookeeper 在这里承担的是集群大脑角色——broker 启动时往 ZK 注册,bookie 的 ledgers 信息也写在这里。Pulsar 2.9.1 在 ZK 里存储/ledgers、/brokers、/namespace等节点,这些路径不需要你手动建,首次启动时 Pulsar 会自动初始化。

2.2 解压目录里每个关键文件的实际用途

拿到apache-pulsar-2.9.1-bin.tar.gz之后,先别急着启动,花两分钟把目录结构看清,后面排错会少走很多弯路。解压后最核心的几块是:

  • bin/:所有命令行入口,pulsar、pulsar-admin、pulsar-client、bookkeeper 脚本都在这里。
  • conf/:所有配置文件,broker.conf、standalone.conf、zookeeper.conf、bookkeeper.conf 都在这个目录。
  • lib/:Pulsar 各组件的 jar 包,升级或调试时看这里。
  • examples/:官方示例,包括多语言 client 的 demo。
  • logs/:默认日志输出目录。
tar -xzf apache-pulsar-2.9.1-bin.tar.gz cd apache-pulsar-2.9.1 ls -la conf/

执行后你会看到 broker.conf、client.conf、standalone.conf、zookeeper.conf、bookkeeper.conf 等文件。你要改的核心就四个:broker.conf控制 broker 行为,standalone.conf是单机模式的总配置,zookeeper.conf管元数据服务,bookkeeper.conf管存储服务。参数需要说明的是:broker.conf里默认配置的zookeeperServers=localhost:2181和configurationStoreServers=localhost:2184,前者是集群元数据,后者是全局配置,单机跑可以都指向本机不同端口。

2.3 单机模式启动:一条命令拉起完整集群组件

Pulsar 2.9.1 的单机模式适合第一次跑通链路。它会自动启动一个 Zookeeper 实例、一个 Bookie、一个 Broker,不用你自己去分别拉起组件。这里有个细节容易被忽略:单机模式的standalone.conf继承了 broker.conf 的配置,但zookeeperServers会被强制覆盖为localhost:2181。

bin/pulsar standalone

看到Started Broker with name ...的日志,再等几秒让 BookKeeper 完成 ledger 初始化,整个实例就起来了。我一般习惯同时另开终端跑一条bin/pulsar-client produce my-topic --messages "hello"验证写入通路,再消费回来,确保链路是通的,再继续做配置实验。

3. 集群部署与配置实战:从单机切到多节点要改哪些参数

3.1 节点角色划分与配置文件准备

Pulsar 2.9.1 的集群部署建议至少三台以上机器,分别跑 Zookeeper、Bookie、Broker。我一般按「下层存储」和「上层计算」来分:Zookeeper 和 Bookie 属于存储层,Broker 属于计算层。生产环境 ZK 最好有三节点,防止脑裂。

每个节点都需要一份完整的 Pulsar 二进制包,但只需要启用不同进程。核心改动在三处:conf/zookeeper.conf里的dataDir、servers;conf/bookkeeper.conf里的zkServers和journalDirectory;conf/broker.conf里的zookeeperServers、advertisedAddress、webServicePort、brokerServicePort。

3.2 修改 Zookeeper 配置:从单机指向集群模式

ZK 节点配置时,zookeeper.conf除了要写dataDir之外,还需要在conf/zookeeper.conf底部追加集群成员列表。Pulsar 自带的是单机配置,不加集群列表的话,多节点互相发现不了。

# conf/zookeeper.conf dataDir=data/standalone/zookeeper server.1=zk1.example.com:2888:3888 server.2=zk2.example.com:2888:3888 server.3=zk3.example.com:2888:3888

注意server.N行必须有,同时你的dataDir里要手动建一个myid文件,内容是当前节点的编号。如果漏了myid,ZK 会直接拒绝启动,报Invalid myid错误。这是新手翻车最集中的地方之一。

3.3 Bookie 配置:存储目录、Journal 与 ZK 地址

BookKeeper 写入消息时,先写 journal(类似消息日志),再刷写 entry log。conf/bookkeeper.conf里最关键的参数是zkServers和journalDirectory,还有ledgerDirectories。默认journalDirectory指向data/bookkeeper/journal,如果磁盘空间不够或者 IO 延迟高,写入会直接卡住。生产建议 journal 与 ledger 放到不同物理磁盘。

# conf/bookkeeper.conf zkServers=zk1.example.com:2181,zk2.example.com:2181,zk3.example.com:2181 journalDirectory=/data1/pulsar/journal ledgerDirectories=/data2/pulsar/ledgers

参数说明:zkServers必须指向真正的 ZK 集群地址;journalDirectory是 Bookie 的预写日志路径;ledgerDirectories可以配置多个目录,逗号分隔,Pulsar 会按多目录做数据条带化写入。

3.4 Broker 配置:对外地址与 ZK 集群对接

conf/broker.conf里要改的包括advertisedAddress、zookeeperServers、configurationStoreServers和clusterName。advertisedAddress必须填 client 能访问到的地址,很多部署场景 broker 启动成功但生产消费连不上,十有八九就是advertisedAddress填了 localhost,客户端无法路由到 broker。

# conf/broker.conf zookeeperServers=zk1.example.com:2181,zk2.example.com:2181,zk3.example.com:2181 configurationStoreServers=zk1.example.com:2181,zk2.example.com:2181,zk3.example.com:2181 advertisedAddress=10.0.0.8 clusterName=pulsar-cluster

如果你的部署只用一个 ZK 集群,configurationStoreServers与zookeeperServers可以相同;生产环境把二者分开,是逻辑隔离元数据与全局策略。

3.5 集群启动顺序:Zookeeper → Bookie → Broker

启动有严格顺序,倒过来会出现 broker 报错连不上 BookKeeper。

# 在 ZK 节点上 bin/pulsar zookeeper # 在 Bookie 节点上 bin/pulsar bookkeeper # 在 Broker 节点上 bin/pulsar broker

启动完要验证集群状态。用bin/pulsar-admin brokers list pulsar-cluster能列出所有 broker,如果只看到自己,说明 broker 注册失败;用bin/pulsar-admin bookies list可以列出存活 bookie。这一步过完,基础集群就通了。

4. 生产级参数调优:从默认配置到高吞吐路径的完整过程

4.1 Broker 内存与线程模型配置

Pulsar 2.9.1 的 broker 默认 JVM 堆大小是 1G,低流量验证绰绰有余,但生产模式下必须调。conf/pulsar_env.sh中修改PULSAR_MEM,常见配置如下:

# conf/pulsar_env.sh PULSAR_MEM="-Xms8g -Xmx8g -XX:MaxDirectMemorySize=8g"

参数说明:-Xms和-Xmx控制堆内存,MaxDirectMemorySize控制 Netty 的堆外内存。Pulsar 的 Broker 关键路径大量走 Netty 的 Direct Buffer,如果堆外内存给小了,高并发下直接内存溢出,日志报OutOfMemoryError: Direct buffer memory,这个很隐蔽。

4.2 Bookie 写入路径调整:Journal 刷盘策略与 Ledger 存储

Bookie 的性能瓶颈基本在 journal 刷盘。conf/bookkeeper.conf里journalSyncData默认是 true,每次写入都强制 fsync,安全但吞吐低。云盘 IOPS 够用的场景,可以调大journalMaxGroupWaitMSec,把多次写入合并成一次 fsync。

# conf/bookkeeper.conf journalSyncData=true journalMaxGroupWaitMSec=2 journalMaxGroupSizeMB=16 flushInterval=60000

参数两句话解释:journalMaxGroupWaitMSec=2让 Bookie 等 2 毫秒攒一批数据再落盘;flushInterval=60000表示 ledger 数据 60 秒往磁盘刷一次。前者影响写延迟,后者影响崩溃时的数据丢失窗口。

4.3 Topic 自动创建与保留策略

Pulsar 默认会在生产时自动创建 topic,很多团队第一次用会踩在这里:线上误操作生产了一个错名字的 topic,数据写进去了,但是没有人消费。可以关掉自动创建,或者设置allowAutoTopicCreationType=non-partitioned。保留策略默认是-1,即不删除,磁盘会被无限撑大,所以必须显式配置。

# conf/broker.conf allowAutoTopicCreation=false defaultRetentionTimeInMinutes=43200 defaultRetentionSizeInMB=10240

allowAutoTopicCreation=false关掉 topic 自动创建,配合bin/pulsar-admin topics create显式建;defaultRetentionTimeInMinutes=43200是保留 30 天,defaultRetentionSizeInMB=10240是上限 10GB,两个参数前者优先。

4.4 认证与授权:用 token 做最小权限控制

Pulsar 2.9.1 的认证机制做得很完整,使用 JWT token 认证生产环境很常见。先要生成一对密钥,然后再给 token 签名。

bin/pulsar tokens create-key-pair --output-private-key my-private.key --output-public-key my-public.key bin/pulsar tokens create --secret-key my-private.key --subject user-1

第二行会输出一个 token 字符串,复制下来后面客户端连接用。Broker 打开认证校验:

# conf/broker.conf authenticationEnabled=true authorizationEnabled=true authenticationProviders=org.apache.pulsar.broker.authentication.AuthenticationProviderToken tokenSecretKey=file:///path/to/my-private.key superUserRoles=admin

这里需要注意两个点:tokenSecretKey支持file://前缀,要求密钥文件和 broker 同一台机器;superUserRoles要填 token 生成时的--subject名称,不然 admin 自己访问也会被拒。

5. 避坑指南:Pulsar 2.9.1 部署过程中的四个翻车点

5.1 现象一:Broker 一直报错连不上 BookKeeper

  • 现象:broker 启动后,日志周期性出现No bookie available,producer 生产消息直接超时。
  • 原因:最常见是bookkeeper.conf里的zkServers和 broker 的zookeeperServers配置不一致, broker 不知道 bookie 在哪。另一个隐蔽原因是ledgerDirectories没有写权限,bookie 注册不成功。
  • 解决:先bin/pulsar-admin bookies list看存活列表,空列表说明 bookie 没注册成功;检查data/bookkeeper目录属主和权限,再逐行对照两边的 ZK 地址,确保指向同一个 ZK 集群。

5.2 现象二:Consume 总是拿不到最早的消息

  • 现象:消费者连接成功,但pulsar-client consume -s sub -n 0就是收不到已生产的历史消息。
  • 原因:Pulsar 的订阅模式不同,消费行为不同。Exclusive 模式下只能有一个消费者,如果之前有一个消费者断线没关闭,新消费者永远拿不到消息;-n 0表示无限阻塞读取。
  • 解决:确认 topic 的 subscription 模式,bin/pulsar-admin topics stats my-topic看订阅列表,先把旧订阅删除或改用 Failover 模式,再重新发起消费。

5.3 现象三:层级存储开启后读取数据报错

  • 现象:配置了bookkeeperClientReadTimeout或managedLedgerInfoCacheSize之后,消息读取出现随机超时。
  • 原因:Pulsar 2.9.1 的分层存储(Tiered Storage)默认对接 AWS S3,但很多人没改managedLedgerOffloadConfig,直接把磁盘文件当 S3 路径配置,导致 BookKeeper 读旧 segment 时路径对不上。
  • 解决:检查broker.conf里managedLedgerOffloadDriver=aws-s3是否和实际存储匹配;非 AWS 环境可以使用filesystem驱动,并把offloadersDirectory指向 bin.tar.gz 自带的lib/目录里的 offloader 包。

5.4 现象四:JVM 频繁 Full GC 导致生产延迟飙高

  • 现象:压测时 Pulsar 吞吐冲上去之后,P99 延迟突然从几毫秒跳到几十毫秒。
  • 原因:Broker JVM 堆太小或 GC 策略不适合低停顿场景,默认的 ParallelGC 在堆外内存大量分配时表现不佳。
  • 解决:换用 G1,并且明确设置MaxGCPauseMillis。我一般会在pulsar_env.sh里加一行:PULSAR_GC="-XX:+UseG1GC -XX:MaxGCPauseMillis=100"。

6. 验证部署好坏的硬指标:消息不丢不重

Pulsar 的 QoS 保证核心在 producer 和 consumer 的确认机制,我用这套方法验证集群没问题:

先创建一个带 key 的 topic,持续生产 10 万条消息,每个消息带唯一序号;再启动消费者,记录收到的序号集合,和发送序号集合做差集。对账代码大概是:

from pulsar import Client client = Client('pulsar://10.0.0.8:6650') producer = client.create_producer('persistent://public/default/qos-check') for i in range(100000): producer.send(f"key-{i}".encode()) consumer = client.subscribe('persistent://public/default/qos-check', 'check-sub') received = set() for _ in range(100000): msg = consumer.receive(timeout_millis=5000) received.add(msg.data().decode()) consumer.acknowledge(msg) missing = set(range(100000)) - received print(f"missing count: {len(missing)}") client.close()

说下这个脚本的逻辑:生产 10 万条,每条消息内容就是自身序号;消费时装入集合,最后做差集判断有没有丢消息。timeout_millis=5000表示超过 5 秒没等到下一条消息就放弃,避免无限阻塞。如果missing count不为 0,优先查消费者是否在 broker 宕机时自动 failover,以及 broker 的acknowledgmentAtBatchIndexLevelEnabled是否开启——默认关闭时,批量消息只要有一条确认失败,整个 batch 会重新投递。

我自己每次部署完 Pulsar 都强制走一遍这套流程:先确认集群注册状态,再跑对账,最后开 1 小时压测观察 P99 延迟和磁盘使用。中间有一次在ledgerDirectories权限配置错了,跑对账时missing count高达 2000 多条,后来定位到是 bookie 写入间歇性失败,修掉权限后对账干净通过。这套流程能帮你把大部分黑匣子问题在进生产前筛掉。

希望这套对账方式能帮到你——毕竟消息中间件最怕的就是「看起来在跑,实际在丢」。

本文还有配套的精品资源,点击获取

相关新闻

Spring Boot + Vue 在线图书商城毕设源码详解:从环境搭建到系统部署

Spring Boot + Vue 在线图书商城毕设源码详解:从环境搭建到系统部署

简介:面向毕业设计或课程设计场景的Spring Boot与Vue.js前后端分离图书商城实战项目,适合需要完整可运行源码、论文及答辩材料的计算机相关专业学生。资源包约66.44MB,包含全套前后端源码、SQL数据库脚本、毕业设计论文与开题报告&#xff0c…

2026/10/20 16:53:05 阅读更多 →
BES2500串口烧录环境搭建全流程:配置、避坑与验证指南

BES2500串口烧录环境搭建全流程:配置、避坑与验证指南

简介:恒玄BES系列串口烧录工具是面向BES2500等恒玄蓝牙SoC芯片的Windows平台烧写软件,服务于无线音频、智能穿戴与智能家居等物联网产品开发者,用于固件升级、代码调试和参数配置。包体共101个文件,约11.54MB,以dll/py…

2026/10/20 16:53:05 阅读更多 →
【单片机课程设计/毕业设计】基于STM32的智能门禁云平台管理与视频监控系统设计 基于单片机的智能门禁远程开锁摄像头与云平台装置设计(033009)

【单片机课程设计/毕业设计】基于STM32的智能门禁云平台管理与视频监控系统设计 基于单片机的智能门禁远程开锁摄像头与云平台装置设计(033009)

博主介绍:✌️码农一枚 ,专注于大学生项目实战开发、讲解和毕业🚢文撰写修改等。全栈领域优质创作者,博客之星、掘金/华为云/阿里云/InfoQ等平台优质作者、专注于嵌入式单片机,Java、小程序技术领域和毕业项目实战 ✌️…

2026/10/20 16:53:05 阅读更多 →

最新新闻

Ubuntu下PostgreSQL安装配置与Navicat连接指南

Ubuntu下PostgreSQL安装配置与Navicat连接指南

做后端开发或者数据相关工作的朋友,应该都经历过这么一幕:好不容易在 Ubuntu 上把 PostgreSQL 装好了,却发现命令行操作没问题,客户端工具却怎么都连不上;或者反过来,Navicat 装好了,连接时报一…

2026/10/20 17:33:06 阅读更多 →
uniCloud Serverless 实战:英语学习小程序全链路开发

uniCloud Serverless 实战:英语学习小程序全链路开发

简介:这是一套面向英语学习者与小程序开发者的完整项目源码,基于uniapp与uniCloud Serverless架构构建,可直接在微信环境中运行。项目集生词本记录、拍照识别单词、内置词典查询、AI语音翻译、跟读打分评测于一体,并针对考研人群补…

2026/10/20 17:33:06 阅读更多 →
WiFi指纹室内定位实战:从原理到Demo搭建

WiFi指纹室内定位实战:从原理到Demo搭建

1. 室内定位的现实困境与WiFi方案的破局点实话实说,第一次接手“基于WiFi的室内定位”这个方向时,我心里是打鼓的。日常大家用GPS导航已经习惯了,掏出手机就能知道自己在哪,但一旦走进大型商场、地下车库、机场航站楼,…

2026/10/20 17:33:06 阅读更多 →
大模型后端长对话记忆架构全解析:从无状态到有状态

大模型后端长对话记忆架构全解析:从无状态到有状态

做后端的人都有过这种体验:用户和AI助手聊了三十轮,前二十轮里明明已经把需求背景、偏好、禁忌都交代清楚了,结果聊到第三十一轮,AI突然反问一句“您刚刚提到的那个项目背景,方便再描述一下吗?”当场血压就…

2026/10/20 17:33:06 阅读更多 →
D435相机+OpenCV快速上手:彩色图与深度图实时显示全攻略

D435相机+OpenCV快速上手:彩色图与深度图实时显示全攻略

最近不少做视觉入门的朋友卡在第一关——把D435相机的画面真正“看”到屏幕上。很多人买了一台Intel D435深度相机,兴冲冲插上USB线,结果CPU占用飙高、程序报错、画面黑屏,折腾一晚上就劝退了。其实用D435搭配OpenCV显示彩色图和深度图&#…

2026/10/20 17:33:06 阅读更多 →
自考论文降AI率实战:智能体改写与人工复核全流程

自考论文降AI率实战:智能体改写与人工复核全流程

自考论文写到提交前,最让人血压升高的往往不是查重率,而是学校突然要求提交一份AI检测报告。A同学就是这种状况:论文初稿在查重系统里已经降到合格线,结果学院的通知里多了一句“AI疑似率不得超过20%”。他拿自己的稿子去测了一下…

2026/10/20 17:32:04 阅读更多 →

日新闻

CLRC663芯片Pin-to-Pin替代实战:从评估到量产全记录

CLRC663芯片Pin-to-Pin替代实战:从评估到量产全记录

/* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views …

2026/10/20 1:01:30 阅读更多 →
ESP32舵机控制指南:原理、多路驱动与避坑实战

ESP32舵机控制指南:原理、多路驱动与避坑实战

/* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views …

2026/10/20 1:01:30 阅读更多 →
位移法实现一阶低通滤波:单片机ADC采样降噪实战

位移法实现一阶低通滤波:单片机ADC采样降噪实战

/* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views …

2026/10/20 1:01:30 阅读更多 →

周新闻

基于GMM的语音识别系统原理与MATLAB实现详解

基于GMM的语音识别系统原理与MATLAB实现详解

说到基于高斯混合模型(GMM)的语音识别系统,很多人第一反应就是一堆数学公式,觉得门槛很高。但如果你真的在MATLAB里把它落地跑通,会发现核心其实就是三件事:把声音变成特征向量,用GMM给每个类别…

2026/10/20 10:02:13 阅读更多 →
数字图像处理入门:反白、灰度化、调色板修改与导出txt实践

数字图像处理入门:反白、灰度化、调色板修改与导出txt实践

数字图像处理这四个字听起来挺唬人,但落到具体操作上,无非就是让计算机按你的想法“摆弄”像素。我在一个模拟项目X里用了一套特别经典的基础处理流程:对图像做反白、改调色板、彩色转灰度,最后把像素数据导出成txt文件。单看每一…

2026/10/19 17:32:41 阅读更多 →
机器人大脑技术盘点:具身智能的感知、决策与数据闭环

机器人大脑技术盘点:具身智能的感知、决策与数据闭环

如果你的信息流最近也天天刷到“机器人大脑”这个词,你会发现一个很有意思的现象:每个人说的“大脑”根本不是同一个东西。有人指的是大语言模型,有人指的是运动控制系统,还有人指的是能理解物理世界的端到端模型。在2026年这个时…

2026/10/20 2:50:50 阅读更多 →

月新闻

我发现了一个新思路:用 Remotion + Claude Code 像写代码一样自动化生成短视频

我发现了一个新思路:用 Remotion + Claude Code 像写代码一样自动化生成短视频

/* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views …

2026/10/20 10:02:08 阅读更多 →
Windows下 Codex 中 Chrome 和 Computer Use 插件不可用问题排查及解决参考方式:TaoToken 统一 Key 配置与验证

Windows下 Codex 中 Chrome 和 Computer Use 插件不可用问题排查及解决参考方式:TaoToken 统一 Key 配置与验证

/* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views …

2026/10/20 9:50:17 阅读更多 →
黑夜航拍船只数据集训练YOLOV5模型全流程解析

黑夜航拍船只数据集训练YOLOV5模型全流程解析

/* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views …

2026/10/20 9:50:45 阅读更多 →