RocketMQ核心机制与生产实践:从消息队列原理到高可用部署
先说明一点这个标题看着简单但学习总结四个字最容易写成流水账。我这边梳理了完整的学习路径和实战心得重点放在那些官方文档里不会写的为什么和怎么做上希望对正在啃RocketMQ的朋友有点实际帮助。1. 为什么是RocketMQ从选型开始说起1.1 消息队列到底在解决什么问题在学习具体技术之前我建议先想清楚一个问题系统里到底需不需要消息队列还是说只是别人都在用所以我也要用。消息队列的核心价值就三件事解耦、削峰、异步。我做过的项目里最典型的场景是订单系统。下单核心链路要扣库存、发优惠券、加积分、通知物流如果这些全在请求线程里同步执行高峰期接口响应直接飙升到几秒。用上消息队列之后订单主流程只管写库发消息后面那些操作全部丢给消费者异步处理响应时间降下来了系统吞吐也上去了。另一个价值是削峰。电商大促或者秒杀场景瞬时流量可能是平时的几十倍直接打到数据库上再好的库也会被打挂。通过队列把峰值流量缓冲起来下游按自己的消费速率慢慢处理系统就不会被瞬间冲垮。1.2 市场上这么多种MQ为什么选择RocketMQ现在业界常见的消息中间件有RabbitMQ、Kafka还有RocketMQ选型时确实需要犹豫一下。从学习角度来说重点关注的差异点可以整理成一张表对比维度RabbitMQKafkaRocketMQ开发语言ErlangScala/JavaJava部署复杂度较低较高中等吞吐量较低极高高消息可靠性高高极高事务消息不支持需插件不支持有改进版支持延迟消息支持需插件不支持支持原生顺序消息有限支持支持分区顺序支持分区顺序社区活跃度高高中高国内活跃为什么我最终选择重点研究RocketMQ首先是事务消息。这个能力在金融、订单场景太实用了Kafka和RabbitMQ原生都不支持要么引入外部组件要么自己实现一套分布式事务方案。其次是延迟消息订单超时未支付、定时任务这些场景直接用一个API就能搞定不用额外起任务调度系统。还有一个重要原因是存储模型。RocketMQ的存储设计借鉴了Kafka的磁盘顺序写思路但做了一些调整需要深入理解。2. 核心架构与运行机制解析2.1 四个角色的职责划分RocketMQ的架构很清晰四个核心角色包括NameServer、Broker、Producer、Consumer理解它们的关系是整个学习过程的基础。NameServer本质上是一个注册中心负责保存Broker的路由信息。它和ZooKeeper不一样没有复杂的选举逻辑每个NameServer节点之间不通信。这就带来一个有意思的结论NameServer是支持水平扩展的不需要太多节点一般两到三台就足够了。Broker是真正干活的节点消息的存储、读取、过滤都在这里完成。Broker启动后需要主动向NameServer注册自己的路由信息包括Topic和队列信息。每个Broker又分为Master和SlaveMaster负责读写Slave负责同步数据和故障切换这样设计是为了追求高可用。Producer负责发消息。需要注意的是Producer并不是直接连接Broker的地址去发而是先向NameServer拉取Topic的路由信息获取到对应的Broker地址然后才建立连接发送消息。Consumer同理也是先找NameServer拿路由信息再连上Broker拉取消息。2.2 存储模型CommitLog与ConsumeQueue这是RocketMQ高性能的秘密核心所在值得重点理解。Kafka的思路为一个Topic单独建一批文件而RocketMQ选择所有Topic的数据都写入同一个CommitLog文件在这个文件内部顺序追加。这就把随机写变成了顺序写磁盘IO效率非常高这也是RocketMQ能够支撑百万级吞吐的关键基础。但所有Topic混在一起写消费的时候怎么知道哪些数据属于哪个Topic答案就是异步构建的ConsumeQueue。Broker在写入CommitLog之后后台线程会异步构建消费队列本质上是一个基于Topic和QueueID的索引文件。每个Queue对应一个目录里面存放的是消息在CommitLog中的物理偏移量。学习这个存储模型时最大的收获是理解了为什么RocketMQ支持高堆积。只要消费者速度跟不上消息就会一直堆积在CommitLog中存储上是顺序写的性能不会显著下降。很多同学一看到消息堆积就慌其实堆积本身不可怕可怕的是没有监控、不知道堆积了多少。2.3 消息从生产到消费的完整流转链路理解消息流转过程可以画出一条链路Producer发送消息到Broker的某个MessageQueueBroker写入CommitLog、构建ConsumeQueueConsumer通过pull模式或push模式从Broker拉取消息消费成功之后返回确认。这里有一个容易混淆的概念Topic和MessageQueue。Topic是逻辑上的分类一个Topic下会分成多个MessageQueue默认是一个Topic创建4个读队列、4个写队列。MessageQueue才是消息真正的物理存储单元一条消息最终只会落到其中一个Queue里面。生产端在写入时如果指定了MessageQueueSelector就可以基于业务参数把消息路由到同一个Queue上实现局部顺序。消费端在拉取消息时是按Queue为单位的一个Queue在同一时间只会被一个消费者消费这个约束非常重要顺序消息的实现基础就在于此。3. 关键功能与使用场景拆解3.1 顺序消息不是做不到而是要知道限制在哪里顺序消息在很多业务场景中都是刚需比如订单的状态流转创建订单必须先于支付通知支付通知必须先于订单完成通知。RocketMQ的顺序消息分为全局顺序和分区顺序。全局顺序就是整个Topic只有一个Queue消息严格按顺序消费。这种方式实现最简单但吞吐量上不去适合数据量不大的场景。分区顺序是通过MessageQueueSelector把相同业务标识的消息发送到同一个Queue中保证这个Queue内部的消息是顺序的。我实际做订单场景时用的就是分区顺序。按订单号取模选择Queue每个订单的消息都会落到同一个Queue中消费者在拉取时顺序执行下单、支付、完成等流程。这里要特别注意有序消息的消费者端要自己维护一个单线程消费模型用MessageListenerOrderly而不是MessageListenerConcurrently。网上搜解决方案时很多资料把顺序消息写得很复杂其实核心就是这三个要点。3.2 事务消息的理解与应用事务消息是我认为RocketMQ区别于其他MQ最亮眼的功能应用价值极高。分布式事务的问题在于本地数据库操作和消息发送操作无法在一个事务中完成。比如订单支付后要发一条消息通知积分系统加分如果先更新数据库再发消息可能消息发出去了但数据库更新失败也可能数据库更新成功但消息没发出去。两边要么都成功、要么都失败这就需要一个协调机制。RocketMQ的事务消息机制分成几个阶段发送方先发送一条半消息这个半消息对消费者不可见只是暂存在Broker上。然后发送方执行业务操作比如扣库存、加订单。根据本地事务执行结果提交或回滚半消息。如果提交了半消息消费者才能看到这条消息并开始消费。看到这里你可能已经想到一个问题如果执行完本地事务之后应用崩溃了没有通知Broker半消息该提交还是回滚。RocketMQ的处理方式是Broker会主动发起回查询问事务发起方该消息到底能不能发出去。回查会触发事务监听器中的checkLocalTransaction方法由业务系统自己判断本地事务是否执行成功。3.3 延迟消息预定时间后触发原生的时间调度能力RocketMQ默认支持18个延迟级别从1秒到2小时不等。延迟消息在延迟时间到达之前消费者是看不到的延迟时间到了之后消息才变为正常状态可以被消费。延迟消息的实现机制比较巧妙并不是真的把消息扔到某个地方等待而是利用了调度线程扫描消息队列到达延迟时间之后把消息重新投递到真正的Topic中。这个机制带来的启示是定时精度不算特别高适合分钟级别以上的业务场景。如果你想实现秒级精确触发的定时任务这个方案就不合适了。延迟级别配置的灵活性是RocketMQ的一个亮点18个级别写死在Broker配置文件里不同级别对应不同的延迟时间比如1s、5s、10s、30s、1m、2m等。如果现有级别不够用可以修改配置文件重新定义网上有很多文章讨论这个扩展方案。3.4 消息过滤使用Tag还是SQL表达式RocketMQ支持两种过滤方式。一种是基于Tag的过滤消费者订阅时指定TagBroker在投递消息时直接跳过不匹配的消息。这种方式效率最高因为过滤可以发生在文件读取阶段。另一种是基于SQL92表达式过滤可以在多个属性上进行复杂判断比如age BETWEEN 18 AND 30 AND city Hangzhou但性能上比Tag过滤差一些。实际开发中我的习惯是能用Tag就用Tag只有业务需要使用属性维度做复杂判断时才用SQL过滤。一个需要注意的点是Tag过滤是Broker端处理的不是消费者端。很多初学者以为在消费端代码里用if判断过滤就够了这其实会白白浪费网络带宽和存储资源消息都已经拉取到消费者端了才发现不需要。4. 部署与配置实操记录4.1 单机部署步骤与Docker快速实践学习阶段最快的方式当然是Docker化部署。我通常会用一条命令拉起NameServer再用一条命令拉起Broker。这里分享一个Docker部署的配置细节Broker在容器内运行时必须指定几个关键参数-e NAMESRV_ADDRnameserver:9876 -e BROKER_CLUSTER_NAMEDefaultCluster -e BROKER_NAMEbroker-a -e BROKER_ID0 -e AUTO_CREATE_TOPIC_ENABLEtrue要特别注意brokerIP1这个参数如果宿主机访问容器内的Broker需要把brokerIP1设置成宿主机的IP不设置的话会使用容器自动分配的IP外部客户端连不上消息服务。还有一个比较隐蔽的坑是autoCreateTopicEnable。生产环境我会把它关掉原因很简单一旦打开任何应用都可以自动创建任意Topic整个消息集中管理就失控了而且自动创建的Topic默认队列数量不一定是预期值。学习环境可以先开着省得每次建Topic都手动执行管理命令。4.2 环境准备与JVM参数调优思路RocketMQ的默认启动脚本runbroker.sh和runserver.sh里面写好了JVM参数但生产环境建议自己调整。堆内存设置一般是4G到8G主要取决于日志量。重点提醒一下RocketMQ的存储用了内存映射文件的方式所以还要额外预留一定的堆外内存。JVM调优这块我踩过的一个坑是默认堆内存对于小规格机器来说太大了。阿里云2G内存的测试服务器跑默认配置Broker直接启动不了查看日志发现是系统OOM导致进程被杀。后来调整为-Xms1g -Xmx1g就好了。如果你发现Broker启动即退出第一反应是看看进程是否OOM这是最常见的原因。磁盘布局上建议把RocketMQ的数据目录放在独立的磁盘上比如单独的SSD云盘。因为CommitLog的写入IO非常高如果和系统盘共享IO会导致整个服务器性能下降。数据目录的调整方式是在broker.conf里配置storePathRootDir。4.3 集群模式下高可用设计生产环境部署RocketMQ无论如何都要用多Master模式绝对不能单点。最简单的多机高可用方案是两主两从异步复制四台Broker两台Master各自对应一台Slave。Broker的角色和复制方式在broker.conf里配置。Master节点的配置brokerClusterNameDefaultCluster brokerNamebroker-a brokerId0 brokerRoleSYNC_MASTER flushDiskTypeASYNC_FLUSHSlave节点的配置brokerClusterNameDefaultCluster brokerNamebroker-a brokerId1 brokerRoleSLAVE flushDiskTypeASYNC_FLUSHbrokerName相同表示属于同一个主备组brokerId为0表示Master大于0表示Slave。这样设计的好处是Master挂了之后Consumer可以自动从Slave拉取消息消息不丢失应用无感知。5. 生产实践与踩坑实录5.1 消息丢失的可能性分析消息丢失从整个链路来看可能发生在三个环节可以逐一排查。生产端丢失在默认状态下Producer发消息使用的是异步发送应用代码里如果没检查发送结果Broker返回失败也不会被感知。建议生产环境用同步发送并且检查SendResult中的sendStatus。即使同步发送失败也要有本地重试机制把发送失败的消息记录下来人工或者定时任务补偿。Broker端丢失Broker在刷盘过程中如果宕机内存中的数据会丢失。解决办法是配置刷盘策略把默认的ASYNC_FLUSH改成SYNC_FLUSH保证消息在内存中写入后立即刷入磁盘持久化。同步刷盘和异步刷盘性能大约差一个数量级但可靠性完全不同。消费端丢失默认情况是消费者拉取到消息后先执行业务逻辑处理成功之后才返回CONSUME_SUCCESS。如果是自动提交offset且消息处理失败也当作成功提交了offset那消息就丢了。建议把消费模式调整为CLUSTERING集群模式配合手动ACK提交。5.2 重复消费与幂等设计消息队列实现不重复几乎是做不到的因为网络抖动、消费端重启都可能造成消息重发。所以正确的态度是接受重复保证幂等。我在项目里的做法是给每条消息一个全局唯一的消息ID在消费端维护一张已处理消息ID表消费时先查一下是否已经处理过。如果是新增场景更推荐利用数据库的唯一索引来天然防重插入相同主键直接报错根据报错判断是否为重复消息。另一个容易忽略的点是消费者端要有快速失败和限流机制。一旦下游数据库出现性能问题消费者会不断重试反而加剧问题。我习惯在消费接口里设置超时时间超时就抛异常让消息进入重试队列而不是一直阻塞。5.3 常见问题排查手册学习实践中遇到的高频问题整理成表格方便对照问题现象可能原因解决方案Broker启动后立刻退出JVM堆内存配置过大调整启动脚本降低内存消费者收不到消息消费者组名与其他消费者冲突确认group id全局唯一发送超时Broker负载过高或网络不稳调整sendMsgTimeout配置消息大量堆积消费者消费速度跟不上检查是否没有开启多线程消费磁盘写满告警CommitLog文件增长过快清理过期文件或扩容消息顺序错乱使用了普通消费监听器换成Orderly监听器5.4 消费者端性能调优的实践经验消费者性能优化有几个参数值得反复调整。第一个是消费线程数默认是20个拉取消息后实际上会分配这些线程并发执行业务逻辑。如果业务逻辑很轻量可以把消费线程数调高到40甚至更高。第二个是consumeMessageBatchMaxSize一次从Broker拉取的消息条数。这个值默认是1如果业务逻辑是逐条处理且单条耗时很短可以调到8或者16减少网络RTT次数。还有一个实践经验是消费端逻辑一定要精简只做核心业务操作。比如消费订单消息时不要在消费线程里做复杂的计算、调用多个外部服务否则消费速度会被拖得很慢。如果必须要调外部服务建议在消费线程内做超时控制超时就快速返回失败避免长时间占用消费线程。5.5 关于消息轨迹与监控生产上出了问题是需要抓现场定位的所以消息轨迹的开启还是很有必要的。RocketMQ支持消息轨迹即记录一条消息从生产、Broker存储、消费三个阶段的关键路径信息。排查消息丢失时这个功能能告诉我们消息到底有没有到达Broker、有没有被消费者拉取。我建议重要的业务Topic开启消息轨迹配置文件里设置traceTopicEnabletrue然后生产端和消费端初始化时传入enableMsgTracetrue的参数。这样每条消息的流转历史都可以在后台查看找问题时效率提升明显但也需要注意额外存储开销所以整个集群里重要业务开启即可。6. 学习路径规划和拓展思考6.1 一条清晰的学习路径建议先花两周时间把核心概念吃透不要一上来就埋头敲代码。我的建议是按这个顺序推进第一步搭好环境跑通生产消费Demo感受一下消息队列工作流程。第二步深入理解存储模型把CommitLog和ConsumeQueue的关系理清楚这是看懂RocketMQ所有机制的前提。第三步研究事务消息和延迟消息的实现原理。第四步模拟生产环境做集群部署制造各种故障场景来触发故障切换机制。第五步针对近期项目里的具体问题做针对性优化。6.2 基于RocketMQ可以做的扩展实践学完之后如果想进一步巩固可以试着做一个消息监控平台采集RocketMQ的JMX指标数据展示在Dashboards上实时掌握消息堆积量、生产消费吞吐量。这也顺便能积累一些监控系统的建设经验。另一个方向是写一个通用的消息处理框架封装生产端发送逻辑、消费端幂等逻辑、重试机制和死信队列处理方便团队其他业务快速接入消息中间件。写一个简单的死信处理服务也很有价值。当消息多次消费仍失败时把它转入独立的死信Topic后续通过管理后台人工干预、重新投递。这个机制是消息中间件能力拼图中必不可少的一环很多系统设计了它才敢放心把核心链路交给MQ。根据我个人的带教经验踩过几次坑之后反而对RocketMQ的认知是最清晰的。消息队列这套东西术语和组件看着多但只要动手把环境搭起来、把链路调通再回头理解那些概念一切都会顺理成章。希望这些总结能帮你在学习RocketMQ的路上少走一些弯路。

相关新闻

跨平台代码生成CLI设计:iOS/Android/Electron工作流实战

跨平台代码生成CLI设计:iOS/Android/Electron工作流实战

1. “t3code”不是工具名,而是开发者社区里一个被反复误传的CLI代号最近在多个技术论坛、GitHub Issues和iOS/Android开发群聊里,频繁看到“t3code”这个词——有人问“t3code怎么安装”,有人贴报错截图“t3code init失败”,还有人…

2026/10/14 4:09:47 阅读更多 →
本科生降AI率实用指南:10个工具与操作流程详解

本科生降AI率实用指南:10个工具与操作流程详解

前几天有个本科三年级的学弟给我发消息,说交上去的课程报告被学校系统标了“疑似AI生成”,全文标红率78%,整个人直接慌了。2025年到这个时候,“降AI率工具”在本科生里的讨论热度,已经远超当年的“降重三件套”。几乎每…

2026/10/14 4:08:47 阅读更多 →
git cherry-pick 引发大量新文件?原因、规避与恢复实操

git cherry-pick 引发大量新文件?原因、规避与恢复实操

某次深夜在做发布分支维护&#xff0c;我敲下一行再熟悉不过的命令git cherry-pick <commit>&#xff0c;紧接着屏幕上刷过一大串“create mode”提示&#xff0c;工作区里凭空多出两百多个文件。那瞬间我意识到一件事&#xff1a;cherry-pick并不是我原来以为的“挑一个…

2026/10/14 4:08:47 阅读更多 →

最新新闻

POST型SQL注入实战全解:从原理到防御的完整链路

POST型SQL注入实战全解:从原理到防御的完整链路

我不是来讲理论的。这篇东西的起因&#xff0c;是上周我帮一个朋友看他的后台系统&#xff0c;他一脸委屈地说“我们这系统登录接口绝对安全”&#xff0c;结果我拿Burp随手改了一个POST参数&#xff0c;三分钟不到就把用户表整个捞出来了。他那个登录接口用的就是POST传参&…

2026/10/14 4:55:59 阅读更多 →
GitHub新手快速上手:从安装配置到分支协作

GitHub新手快速上手:从安装配置到分支协作

很多同学第一次接触 GitHub 的体验并不愉快。计算机导论课老师强调“GitHub 是计算机专业学生的必修课”&#xff0c;你下载了一个安装包&#xff0c;却不知道安装对象是什么&#xff1b;接着是 SSH 密钥、远程仓库、分支、Pull Request。这个过程在 2020 年的教程中非常典型&a…

2026/10/14 4:55:59 阅读更多 →
AI视频运动控制实战:提示词轨迹与MotionLoRA训练指南

AI视频运动控制实战:提示词轨迹与MotionLoRA训练指南

1. AI视频运动控制到底在控什么1.1 从“画面动起来”到“画面按我的意思动”接触AI视频生成有一段时间的朋友应该都有同感&#xff1a;早期玩文生视频&#xff0c;最兴奋的是“它居然真的动了”&#xff0c;但新鲜劲过去之后&#xff0c;痛点立刻暴露——画面确实在动&#xff…

2026/10/14 4:55:59 阅读更多 →
企业微信API开发案例解析:如何打造企业专属消息机器人

企业微信API开发案例解析:如何打造企业专属消息机器人

通用机器人回复千篇一律&#xff0c;企业要的是懂自己业务的专属机器人——知道产品信息、客户分级、内部流程。我们做了一个可配置的企业专属机器人&#xff0c;运营自己配规则和知识库&#xff0c;不用研发改代码。这篇讲机器人的设计思路。底层用的是 Eyun 平台开放的企微 A…

2026/10/14 4:55:59 阅读更多 →
测试求职黄金期:接口自动化与内推如何提升捞人概率

测试求职黄金期:接口自动化与内推如何提升捞人概率

每年3月中旬&#xff0c;都是测试求职帖子最密集的时候。最近在某技术社区刷到一个帖子&#xff0c;标题只有一句&#xff1a;“3月中旬了&#xff0c;测试求捞呀额&#xff0c;不知道有没有人能看到。”就这么一句话&#xff0c;评论区聊出了上百层共鸣。我当时的第一反应是&a…

2026/10/14 4:55:59 阅读更多 →
Agent Lightning强化学习框架:Qwen 9B编程成功率提升14.6个百分点实战

Agent Lightning强化学习框架:Qwen 9B编程成功率提升14.6个百分点实战

1. 从“能跑”到“跑对”&#xff1a;一个9B模型编程成功率提升14.6个百分点的背后如果你最近在折腾小参数模型的代码生成能力&#xff0c;大概率会遇到一个很尴尬的局面&#xff1a;模型明明能把代码写出来&#xff0c;语法也没问题&#xff0c;但跑起来就是不对&#xff0c;单…

2026/10/14 4:54:59 阅读更多 →

日新闻

AnyPS5通用适配层设计:兼容性与性能的工程取舍

AnyPS5通用适配层设计:兼容性与性能的工程取舍

1. 从"AnyPS5"这个名字说起&#xff1a;它到底想解决什么问题第一次看到"AnyPS5"这个标题&#xff0c;我脑子里冒出来的第一个念头是&#xff1a;这大概率是一个围绕"跨平台运行"或者"通用适配"做文章的项目。名字里的"Any"…

2026/10/14 0:00:41 阅读更多 →
Flutter跨平台开发实战:二手交易应用与HarmonyOS适配

Flutter跨平台开发实战:二手交易应用与HarmonyOS适配

1. 项目概述&#xff1a;Flutter跨平台二手交易应用开发作为一名长期从事移动应用开发的工程师&#xff0c;我最近完成了一个基于Flutter框架的二手物品交易平台项目。这个项目最吸引我的地方在于它完美结合了Flutter的跨平台优势与HarmonyOS的生态特性&#xff0c;实现了"…

2026/10/14 0:00:41 阅读更多 →
DFS算法解决飞机降落调度问题实战

DFS算法解决飞机降落调度问题实战

1. 项目背景与核心思路飞机降落问题是一个经典的调度优化场景&#xff0c;也是算法竞赛和面试中的高频题目。这个题目要求我们合理安排多架飞机的降落顺序和时间&#xff0c;确保所有飞机都能安全着陆而不发生冲突。在实际航空管制中&#xff0c;这类问题直接关系到飞行安全和机…

2026/10/14 0:00:41 阅读更多 →

周新闻

流感时间序列预测实战:ARIMA/LSTM全流程拆解与避坑指南

流感时间序列预测实战:ARIMA/LSTM全流程拆解与避坑指南

简介&#xff1a;基于 ARIMA、LSTM、Transformer 等模型的流感时间序列预测 Python 源码&#xff0c;面向计算机相关专业课程设计与期末大作业学生&#xff0c;以及项目实战学习者。内容覆盖预处理、平稳性检验、定阶、残差分析、多模型对比预测的完整时序建模流程&#xff0c;…

2026/10/14 3:30:28 阅读更多 →
影刀RPA新手教程:键盘模拟输入实战——输入文本与模拟按键的区别

影刀RPA新手教程:键盘模拟输入实战——输入文本与模拟按键的区别

影刀RPA新手教程&#xff1a;键盘模拟输入实战——输入文本与模拟按键的区别 做影刀RPA自动化&#xff0c;十个新手有八个栽在"往输入框里填东西"这件事上&#xff1a;要么填不进去&#xff0c;要么填了一半&#xff0c;要么直接把原来内容追加在后面。这背后的根因&…

2026/10/13 16:22:04 阅读更多 →
影刀RPA新手教程:阅文起点小说数据采集实战——书籍信息与章节内容

影刀RPA新手教程:阅文起点小说数据采集实战——书籍信息与章节内容

影刀RPA新手教程&#xff1a;阅文起点小说数据采集实战——书籍信息与章节内容 1. 认识影刀&#xff1a;什么场景该用RPA采小说数据 起点中文网的页面结构相对稳定——分类榜单、书籍详情、章节内容三块独立页面&#xff0c;跳转链路清晰。这种场景非常适合影刀自动化&#x…

2026/10/14 3:29:58 阅读更多 →

月新闻

我发现了一个新思路:用 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/13 22:01:27 阅读更多 →
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/13 14:57:39 阅读更多 →
黑夜航拍船只数据集训练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/12 18:11:17 阅读更多 →