Curve分布式存储实战:从C++高性能后端到Raft协议解析
CPP-Summit 2022上Curve分布式存储的分享是我印象最深的几场技术talk之一。Curve是网易开源的一套分布式存储系统底层核心由C写成提供块存储CurveBS和文件存储CurveFS两种形态。当时听完现场分享又把源码翻了一遍最大的感受是这套系统不是靠堆RPC框架实现出来的而是把分布式系统设计和C工程能力深度绑在了一起。读Curve源码几乎等于上了一堂C高性能后端实战课。这篇文章就把我从CPP-Summit 2022现场到现在实践过程中的理解、源码阅读心得、常用排查手段整理出来适合正在写C后端、对分布式存储感兴趣、或者想找一个能反复咀嚼的C项目的读者。1. Curve到底在解决什么问题1.1 从CPP-Summit 2022现场说起CPP-Summit上的分享和一般的技术博客有个本质区别演讲者会直接给出面对真实硬件和真实业务压力时的取舍过程。Curve主讲人从头到尾都在强调三个矛盾单机磁盘容量和性能有限业务需要无限扩展元数据和数据必须分离否则控制面会成为瓶颈副本一致性和IO延迟互相拉扯必须在工程上做出可量化的权衡。现场放了一张Curve集群的典型拓扑图覆盖了一套完整存储系统需要的全部角色客户端、MDS元数据服务、ChunkServer数据节点以及配套的etcd和监控体系。CurveBS对外暴露块设备接口适合云硬盘、数据库存储卷这类场景CurveFS则是文件系统语义通过FUSE挂载后可以像普通目录一样使用。分享内容最有价值的不是架构理念而是代码里怎么处理“节点宕机”“磁盘慢”“网络分区”这些分布式存储的日常事故。Curve用C把这些问题在用户态逐一落地Raft日志复制、心跳失效检测、数据再平衡、快照克隆整套逻辑都在读者看得见的源码里。作为一个C开发者我强烈建议把Curve当作学习分布式存储的入口项目它的代码量适中模块边界清晰比从Paxos论文自己推导一套实现要现实得多。1.2 为什么分布式存储要用C硬啃我在现场问过自己一个问题为什么不用Java或者GoCurve团队给的答案其实是三个“不妥协”。第一是内存和IO路径的控制力。存储系统对页缓存、对齐、批处理、O_DIRECT这类底层细节极度敏感。C可以把一块内存的分配、使用、归还、落盘全部掌握在手里避免Java GC引入不可预期的停顿也不用像Go那样担心调度器对高吞吐IO线程的影响。Curve的数据通路里客户端发起的每一个写入请求最终都要落到ChunkServer的磁盘上中间任何一次额外的内存拷贝都会变成性能损耗。第二是模板和零成本抽象。存储协议栈天然适合用泛型抽象出“卷”“文件”“快照”“副本”这些概念的公共逻辑。Curve里大量使用了模板、策略注入和编译期分发让同一套代码能适配不同的存储类型。C的RAII在资源管理上的能力也让文件描述符、IO请求、内存缓冲区的生命周期管理更加可靠。第三是生态兼容。Curve深度依赖brpc和braft这两个都是C社区的高性能分布式基础设施。brpc的bthread协程模型、RPC集成、内置监控都对Curve的工程效率帮助很大。如果你已经有C基础看Curve源码就不会有语言层面的陌生感更多的时间能花在理解分布式协议本身。2. 整体架构管控分离与数据条带化2.1 客户端只做路由不做管理Curve客户端是整个系统里最贴合“用户视角”的模块。它向上层业务提供块设备或文件系统接口向下需要找到正确的数据节点发出IO请求处理副本故障最后把结果返回给业务。从CPP-Summit的分享里我记住的最重要设计原则是“管控分离”。客户端不参与任何元数据管理也不感知集群中哪台ChunkServer挂没挂、MDS是否在切换。它只需要完成三件事从MDS获取或缓存元数据路由信息根据卷的偏移量计算出对应的Segment和Chunk位置向目标ChunkServer发起读写请求这里有个容易被忽略但很重要的实现细节客户端缓存了路由表而不是每次都查MDS。MDS下发给客户端的路由信息带有版本号当数据节点迁移、故障切换或卷扩容时MDS会主动推送新的路由信息。客户端在收到版本不一致时会重试获取并对正在进行的IO做合理排队。CurveBS客户端在Linux下通常使用TCMU或NBD把块设备暴露给宿主机数据通路走的是内核到用户态的协商所以对延迟要求很高。客户端代码为了降低拷贝在IO栈上整层使用了brpc的零拷贝特性避免用户态和内核态之间不必要的数据搬移。2.2 MDS元数据管理的高可用设计MDS是整个Curve集群的“大脑”。它负责管理逻辑池、物理池、卷、Segment、ChunkFile的元数据同时也要调度数据节点的分布、处理心跳、执行故障恢复和数据再平衡。MDS本身是无状态的真正的元数据放在etcd中。这里的设计逻辑和价值值得展开说。etcd负责保证元数据的强一致和高可用MDS只负责在内存里维护热数据缓存并把变更事务写到etcd。当MDS节点发生主备切换时新的主节点可以从etcd恢复全部元数据状态。这种模式在C工程里的优点是MDS不必自己实现一套分布式事务协议只需要认真封装etcd的读写接口和Watch机制。Curve使用多MDS租约机制多个MDS节点里通过etcd上的选举选出一个Leader其余节点作为Follower。Leader负责写元数据变更Follower提供只读查询。这很像把Raft协议的选主能力外包给了etcd而把存储系统的领域逻辑留在自己的代码里。每个MDS节点维护的内存索引使用类似Cacheline对齐的对象池降低锁竞争同时通过异步批量方式减少与etcd的交互次数。对存储系统来说元数据操作的延迟直接影响创建卷、删除快照、挂载文件系统这类控制面操作的体验。Curve在MDS层面用多级缓存、异步复制、预写日志等方式尽量让高频查询不直接打到etcd。2.3 ChunkServerSegment与Copyset的存储模型ChunkServer是数据面的核心。Curve把每个卷在逻辑上切成固定大小的Chunk再把连续的Chunk组合成Segment。一个Segment在多个ChunkServer之间形成副本组这个副本组在Curve里被称为Copyset。Copyset是Curve数据高可用的基本单位每个Copyset内部运行braft实例使用Raft协议同步日志。默认配置下一个卷的Segment会被分散到不同的Copyset中避免把同一卷的所有副本放在同一批物理机上从而降低故障域风险。现场有一页很直观的图物理池划分为多个逻辑池逻辑池下面有若干Copyset每个Copyset里有Leader和Follower副本。Segment在逻辑上映射到Copyset上Chunk按条带化方式分布到多个Copyset。这样设计的好处是数据分布均衡可以充分利用所有ChunkServer的磁盘带宽故障恢复范围可控单个Copyset副本损坏不会影响整个卷扩容时只需要迁移部分Segment不需要全量搬迁我读源码时比较关注的是ChunkServer内部的IO调度。它没有为每个IO请求单独创建线程而是把请求整理成异步任务投递到IO线程池底层用libaio或io_uring发起真正的磁盘读写。C里这套代码非常锻炼人对事件循环、任务队列、生命周期绑定和错误传播的理解。3. 核心实现细节用C落地分布式协议3.1 brpc与braftCurve的通信与一致性底座Curve没有自己重复造RPC框架和一致性协议而是选择了百度开源的brpc和braft。这个选型对分布式存储项目来说很关键。brpc提供了一套高性能的RPC通信框架基于bthread实现M:N协程调度。Curve的客户端到MDS、客户端到ChunkServer、ChunkServer之间的数据复制全部跑在brpc上。使用brpc需要特别注意一点存储场景里的IO线程和协议线程需要隔离否则RPC的编解码和磁盘IO会互相抢占CPU。Curve的做法是把不同Priveleged场景拆到不同bthread worker组里让控制面和数据面共享一套框架但互不干扰。braft则是brpc生态里的Raft实现。它不只是一个日志复制库还内置了选主、心跳、日志快照、工程化的成员变更机制。Curve在ChunkServer内为每个Copyset启动一个braft Node由这个节点负责把客户端写入请求落到日志并完成多数派复制。读braft源码时能学到不少C并发技巧状态机的设计、日志存储的抽象、Leader在异常情况下的降级策略。比如当磁盘写满或IO挂起时braft节点会标记为不可用Curve据此触发Copyset的重新选主和数据修复。这些故障处理逻辑都是CPP-Summit现场QA环节里被追问最细的部分也是生产集群能否“扛事儿”的关键。提示Curve对braft做了自己的封装不要直接把braft node的Raft日志和业务IO绑定在同一把锁里。在Curve源码中写日志和更新业务状态机是分离的否则高并发下锁竞争会被放大到一个无法接受的程度。3.2 快照与克隆COW机制的工程化快照和克隆是Curve的重要卖点它与普通存储系统里“先全量备份再恢复”的做法完全不同。Curve使用写时复制COW技术实现快照核心思想是快照创建时不拷贝任何数据只是在元数据上做一次指针记录后续如果有新的写入先把原始数据保留在快照区再在正常数据区写入新内容。从C实现来看COW需要对Chunk的引用计数做精细管理。Curve里的每个Chunk在被写入时都需要判断是否存在快照引用如果存在则触发COW流程。这个判断必须在IO路径上做到极低开销否则会拖慢普通写入。Curve使用轻量级位图结构记录哪些Chunk属于“快照引用”状态查询时通过位图操作完成避免加锁扫描全量元数据。克隆功能则是从某个快照生成一个新的可写卷。Curve采用“父快照子卷”的层级关系子卷读取时如果自己没有对应数据就向上查找父快照。这样做的好处是创建克隆几乎瞬时完成底层只有元数据变更。但同时也要处理“快照被删除时还有克隆依赖”的问题Curve的做法是保持父快照存活延迟回收。我建议读者重点阅读Curve源码里快照模块的delete路径。这里最容易被忽略的是快照删除不是说把数据删掉就行而是要遍历所有克隆关系确认没有被引用后才能真正释放空间。否则会出现“快照删了克隆卷却读到了不完整数据”的血泪教训。3.3 存储引擎的内存与IO细节Curve在C层面的硬功夫很大部分体现在内存与IO的细节处理上。分布式存储系统的数据面如果内存管理粗糙性能很快会被分配器和大锁拖垮。Curve对内存分配没有采用简单的“来一个请求new一块内存”的做法。它在ChunkServer内部维护了对象池把ChunkFile元数据、IO请求上下文、日志条目这些高频对象做了复用。对象池结合C的智能指针可以大幅度降低系统调用次数。虽然现代高版本malloc和tcmalloc表现不错但存储系统要的不仅仅是吞吐量还有可预测的延迟稳定复用的对象池能让最坏情况更可控。IO路径上Curve使用了对齐内存。这听起来是小事但在Linux的O_DIRECT模式下不对齐的buffer会直接被内核拒绝。Curve的IO请求在发起时会统一整理成4KB对齐并且对块设备的LBA偏移也做了对齐处理。这个细节是从内核块设备驱动层逆向推导出来的项目代码里有大段注释解释为什么必须对齐。另外Curve也花了不少功夫在PageCache的绕过和刷写上。对于写场景如果数据路径经过PageCache一旦机器掉电PageCache里的数据就会丢失因此需要依赖外部机制强制刷盘。Curve通过O_DIRECT绕过PageCache把数据直接写落到磁盘再通过braft日志的fsync保证一致性。这里有一个实践心得不要把“所有IO都走O_DIRECT”当作银弹对于小IO或读多写少场景PageCache反而能带来较大收益。Curve针对不同IO模式做了策略区分这正是生产级存储系统和教学demo的重要差异。4. 实操复盘从读源码到搭环境4.1 写入链路源码级拆解跟着一次卷写入请求我们能完整看到分布式存储系统的核心调用链这也是我阅读Curve源码觉得最有收获的部分。第一步客户端收到上层发来的块设备写请求后根据目标卷id和在卷内的偏移计算出这条IO会落在哪个Segment。第二步客户端从本地路由缓存中查到该Segment对应的Copyset信息包括Leader的地址和Follower列表。第三步客户端通过brpc把写请求发到该Copyset的Leader节点携带的数据包括卷id、Chunk索引、数据内容和校验信息。Leader收到请求后不是直接改本地磁盘。它先把写入操作追加到braft的日志中通过Raft协议复制到多数派Follower。多数派确认日志写入成功后Leader才把数据落盘并给客户端返回成功。这个过程在Curve里做了流水线优化并非每个请求都单独对齐fsync而是通过异步刷新和分组提交来聚合小写。从C开发者视角看这条链路里最值得学习的是错误处理。分布式环境下retry必须谨慎设计如果客户端已经把数据发给Leader但Leader在复制日志前发生了切换客户端必须能分辨出哪些副本已经持久化。Curve使用Raft日志的严格提交语义来判定“写入成功”的标准不会为了降低延迟就接受一个未经过多数派确认的写操作。这也是理解存储系统一致性的最好入门案例。注意当你部署Curve后做性能测试不要直接用小IO的随机写结果来评价整个系统。Curve的条带化和批量提交优化对顺序写和较大块写更有效。这个特性并不是缺陷而是所有基于Raft做同步复制的块存储系统的共性。4.2 编译与运行Curve的最小环境如果你想动手验证Curve的架构设计我建议先搭建一个最简环境不需要云厂商支持一台8核16G内存的机器就能跑起来。Curve提供了docker-compose方式部署在项目仓库的部署目录里可以直接拉起一套包含etcd、MDS、ChunkServer的集群。部署完成后通过自带的curveadm或原生运维命令即可创建卷并挂载。实际动手时要注意Curve对内核版本和libaio版本有要求建议使用较新的Ubuntu或CentOS发行版避免在编译阶段被glibc版本拦住。源码编译方面Curve依赖的第三方库很多官方推荐在容器里用Curve提供的依赖镜像编译。可以直接拉取一个开发环境镜像挂载源码目录后执行构建脚本。整个过程会持续一段时间因为需要编译brpc、braft、etcd client等。如果你用VS Code远程开发建议同时把编译生成的compile_commands.json路径配置给clangd这样代码跳转和错误提示会准确很多。4.3 让IDE正常解析Curve源码很多C学习者遇到Curve这种大型项目第一反应是“VS Code报红怎么这么多”。这个问题几乎每个cpp项目都会遇到Curve因为是分布式项目更明显。根本原因是IntelliSense默认不知道第三方库的头文件路径。需要把includePath配置为项目依赖实际存放的位置。建议用compile_commands.json来驱动clangd而不是手动在c_cpp_properties.json里堆路径。在Curve项目里编译脚本会生成compile_commands.json你只需在VS Code里安装clangd插件设置参数指定该文件路径即可。如果还是报红最常见的原因是依赖没有编译完全某些由生成工具产出的头文件如proto生成的.pb.h还没出现。遇到这种情况先跑一遍完整构建再刷新compile_commands.json大部分报红就会消失。这个排查思路不仅适用于Curve也适用于任何大型C工程。5. 常见问题与避坑指南5.1 用C写存储系统的5个常见坑我接触过不少想用C写存储系统的开发者也看到过Curve社区里反复出现的一些共性问题这里整理成速查表。问题典型表现根因与对策CPU被RPC线程吃满IO吞吐上不去控制面和数据面没有线程隔离检查brpc worker分组内存分配器成为瓶颈高并发下延迟抖动高频对象使用对象池复用减少malloc/freeO_DIRECT报错写入返回Invalid argument检查buffer和LBA是否按4K对齐Raft日志增长失控磁盘空间被大量日志占据没有及时做snapshot需要触发日志压缩故障恢复时IO抖动一台机器宕机后集群性能骤降Copyset分散度不够热节点被打满每个坑背后都有对应的架构决策。比如Copyset分散度不够本质是在创建卷时没有把Segment均匀分配到不同物理机上。Curve在设计MDS调度时引入了平衡策略但如果你手动配置了资源池就很容易造成流量倾斜。建议在生产环境开启自动调度降低人工干预的频率。5.2 CPP-Summit上被问得最多的存储问题每次CPP-Summit的Curve专场QA环节都会被问“为什么不用多线程模型”、“如何调试Raft节点频繁切主”和“快照的COW什么时候触发”。这些问题非常有代表性。多线程模型的问题答案源于分布式存储场景的特殊性。磁盘IO天然是异步等待的如果用阻塞线程模型一个慢盘就能让成千上万个请求卡住。brpc的bthread协程模型让Curve能以近乎同步的编码风格写出异步IO逻辑这比手写状态机回调要容易维护得多。Raft节点频繁切主通常不是因为网络故障而是磁盘延迟抖动导致心跳超时。排查思路是查看节点日志中最近的fsync耗时统计如果p99延迟超过心跳间隔就需要调大心跳时间或优化磁盘刷盘策略。COW快照的触发时机也很容易搞错。Curve并不是每写一个Chunk都去检查快照引用而是通过内存位图和局部检查机制把判断成本降到极低。在性能测试中只有在快照激活后首次写入对应Chunk时才会感受到轻微额外开销连续写入同样位置时基本无感。5.3 C学习路线建议从模板到分布式存储工程如果你看完这篇对Curve产生兴趣但又觉得自己C功底还不足我可以给出一条明确的学习路线。第一阶段把握现代C的基础语法重点掌握智能指针、移动语义、lambda表达式和STL容器。模板能看懂基本语法即可不需要一上来啃完模板元编程。第二阶段深入学习协议栈和网络编程。理解epoll、非阻塞IO和事件循环机制学会用brpc这类框架搭建一个小型RPC服务。第三阶段研究并发与一致性。从互斥锁、条件变量开始逐步理解协程、无锁队列和读写锁的使用场景。再花时间把Raft论文读一遍配合braft源码加深理解。第四阶段系统性阅读Curve源码。建议从MDS模块入手因为元数据管理涉及的数据结构相对明确容易建立整体观感然后再切入数据面的IO路径。我在实际带新人的过程中发现Curve特别适合作为从校招到工程实践的过渡项目。它的复杂度足够真实但每个模块的边界又很清晰。只要沉下心读两三周源码你对C和分布式存储的理解都会有一个明显提升。最后再分享一个小技巧阅读Curve这类大型C项目时不要一开始就按目录顺序逐行读。先跑通部署环境抓一次真实IO请求再顺着调用链回到代码里定位对应模块效率会高很多。代码是被架构驱动的而架构是被问题驱动的理解了“为什么这么设计”读代码自然就流畅了。

相关新闻

揭秘 px0 窗口化语法高亮:Chroma 引擎如何丝滑点亮约 280 种语言?

揭秘 px0 窗口化语法高亮:Chroma 引擎如何丝滑点亮约 280 种语言?

【免费下载链接】px0 px0 is an IDE built for reviewing AI-generated code, optimized for speed. It turns your browser into a zero-latency console with native Git and GitHub integrations, instant search across massive codebases, and seamless handoff to local …

2026/10/11 20:15:02 阅读更多 →
用代码对抗分心:ADHD开发者如何构建低认知负荷的效率工具链

用代码对抗分心:ADHD开发者如何构建低认知负荷的效率工具链

1. 一个看似玩笑的标题,背后藏着多少真实需求第一次看到“i-have-adhd”这个项目标题,我下意识以为是个段子。毕竟在技术社区里,用自嘲式命名来降低预期、拉近距离的做法太常见了。但点进去认真翻了一遍之后,我发现它其实是一个相…

2026/10/11 20:14:02 阅读更多 →
MySQL底层机制深度解析:索引设计、事务隔离与性能调优实战

MySQL底层机制深度解析:索引设计、事务隔离与性能调优实战

MySQL这个名字,一说出来大家都不陌生,做后端、搞数据、写业务的,基本每天都在跟它打交道。但说实话,我见过太多人CRUD写得很溜,一碰上慢查询、死锁、主从延迟就抓瞎。前段时间帮某团队排查一个线上问题,数据…

2026/10/11 20:14:02 阅读更多 →

最新新闻

HDFS存储优化实战:纠删码、压缩与小文件治理策略

HDFS存储优化实战:纠删码、压缩与小文件治理策略

大数据项目的存储层里,HDFS 通常是最先被塞满、却最后一个被优化的组件。大多数团队在容量告警触发之前,并不会认真考虑副本数、文件格式、冷数据沉降这些事,等磁盘真的快满了,第一反应往往是再加节点。这篇文章是我在生产环境里做…

2026/10/11 21:13:02 阅读更多 →
Debian 12下FFmpeg安装全攻略:apt源、静态构建与源码编译

Debian 12下FFmpeg安装全攻略:apt源、静态构建与源码编译

1. 项目概述:为什么要把FFmpeg安装当回事 1.1 FFmpeg到底能做什么 FFmpeg在我眼里从来不只是“一个转码工具”这么简单。它其实是一整套命令行音视频处理工具集,覆盖了视频转码、音频提取、画面裁剪、音量调整、视频拼接、等比缩放、抽帧、推流、截图、…

2026/10/11 21:13:02 阅读更多 →
Claude Code skill 方法论:把工作方法封装成 AI 技能包的四步框架与 TaoToken 接入实践

Claude Code skill 方法论:把工作方法封装成 AI 技能包的四步框架与 TaoToken 接入实践

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

2026/10/11 21:13:02 阅读更多 →
OpenClaw 与 ComfyUI 集成:API 自动化批量出图流水线实战

OpenClaw 与 ComfyUI 集成:API 自动化批量出图流水线实战

1. 为什么要把 OpenClaw 和 ComfyUI 接在一起用第一次听到"OpenClaw ComfyUI"这个组合,很多人会愣一下:一个是偏自动化操作与流程编排的开源工具,一个是当下最火的节点式图像生成前端,这俩凑一块儿到底图什么&#xff…

2026/10/11 21:13:02 阅读更多 →
MySQL SQL100题:从入门到业务实战的刷题路线图

MySQL SQL100题:从入门到业务实战的刷题路线图

带过不少新人,也接过很多想转行做数据分析的人的私信。每次被问到“SQL到底怎么入门”,我的答案从来没变过:找一份靠谱的MySQL SQL100道基础练习题,老老实实刷完,比看十篇教程都管用。这个判断听起来有点“土”&#x…

2026/10/11 21:13:02 阅读更多 →
贝叶斯优化CNN-BiLSTM回归预测:Matlab自动调参实现方案

贝叶斯优化CNN-BiLSTM回归预测:Matlab自动调参实现方案

简介:基于贝叶斯优化的卷积神经网络-双向长短期记忆网络(CNN-BiLSTM)回归预测Matlab实现,面向需要进行多输入单输出回归建模的科研与工程技术人员,适用于风速、负荷、交通流量、股价等连续值预测场景。模型借助贝叶斯优…

2026/10/11 21:12:02 阅读更多 →

日新闻

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

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

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

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

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

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

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

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

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

2026/10/11 0:00:27 阅读更多 →

周新闻

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

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

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

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

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

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

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

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

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

2026/10/11 0:00:27 阅读更多 →

月新闻

我发现了一个新思路:用 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/11 10:45:37 阅读更多 →
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/11 14:36:53 阅读更多 →
黑夜航拍船只数据集训练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/11 14:36:54 阅读更多 →