TDengine高吞吐写入存储配置调优:WAL、buffer与磁盘选型实践 1. 先聊聊我为什么盯上了存储配置这件事早些年调时序数据库大家的习惯是先装上、跑起来再说存储这块基本靠默认值打天下。等到数据量真涨上去了写入开始变慢查询变卡才回头翻配置文件结果发现瓶颈根本不在数据库本身而是磁盘I/O被默认参数活活拖死了。TDengine作为一款专为时序场景设计的数据库单机写入吞吐本来很能打但如果你用的是普通机械盘、默认WAL策略、文件块大小也没调过那高并发写入时八成会看到磁盘使用率直接飙到100%而CPU还在那儿闲着。这篇文章不聊怎么装TDengine也不讲SQL怎么写只聚焦一件事存储配置。具体来说是高吞吐写入场景下怎么通过合理设置WAL预写日志、缓存、文件块、磁盘选型这些底层参数把磁盘I/O这个瓶颈给打通。适合正在做IoT数据采集、工业实时监控、或者任何“每秒要灌进去几万条甚至几十万条时间序列数据”的团队参考。先说一个反直觉的结论很多人以为写入慢是数据库不行其实在TDengine的场景里80%以上的写入性能问题都出在存储层配置和磁盘选型上。你把配置调对了同样的机器吞吐翻倍是常有的事。2. 理解TDengine的写入链路才能看懂瓶颈在哪2.1 一条数据从进入到落盘的完整路径要调存储配置首先得知道数据是怎么写进去的。这里我不堆架构图就用大白话拆一下TDengine的写入链路客户端通过REST API、JDBC或者taoscTDengine客户端驱动把数据发到taosd服务端进程。taosd收到数据后先做解析、表名校验、schema匹配然后写入内存中的Hash表结构同时按表组织数据。关键一步数据在写入内存的同时会先追加到WALWrite-Ahead Log预写日志文件里。这个WAL存在的意义是防止进程崩溃时丢数据——内存里的数据还没刷盘但WAL已经把操作记录下来了。内存缓冲攒到一定量或者到一定时间触发落盘操作把数据合并写入数据文件。数据文件按时间分片vnode内部又按时间顺序排列配合元数据索引查询时才能快速定位。看到没有写入路径上真正和磁盘I/O发生关系的有两处WAL写入和数据文件落盘。这两处的配置直接决定了你的写入吞吐极限。2.2 为什么WAL会成为第一个瓶颈WAL的设计逻辑是每次写入请求都要“顺序写”一次日志文件用来保证数据不丢。顺序写在机械盘上其实不算慢但问题在于——默认配置下TDengine的WAL刷盘策略可能是每次写入都强制fsync。fsync意味着操作系统把数据真正写到磁盘物理介质上才返回而不仅是写到页缓存里。一次fsync在普通SATA SSD上大约0.1~1ms不等在机械盘上可能2~10ms。如果每条请求都触发一次fsync换算下来单线程每秒最多写几百条记录这基本上就把吞吐锁死了。提示这里说的“刷盘策略”对应TDengine配置项里的walLevel和fsyncInterval后面会具体讲怎么调。2.3 数据文件落盘顺序写和合并的博弈数据从内存缓冲刷到数据文件时正常情况下是顺序写的顺序写在磁盘上效率很高。但如果你的表非常多每个表的数据量又不大vnode内部的文件碎片化就会加剧导致写入从“顺序追加”退化成“随机写”。随机写在机械盘上的性能是灾难性的在SSD上也会明显影响寿命和吞吐。所以存储配置里有个核心思路尽量减少数据文件的碎片化尽量让写入变成大块顺序追加而不是零散小写。3. 高吞吐写入下最关键的三个存储配置项3.1 WAL策略walLevel、fsyncInterval与walBufferSize的取舍TDengine的WAL相关配置是老生常谈但很多人要么不敢动要么一刀切全关掉。我的建议是关闭WAL保性能那是走极端完全不调那是浪费硬件。合理的配置取决于你对数据丢失的容忍度。配置项有三个关键参数配置项默认值作用高吞吐建议walLevel1WAL级别0关闭WAL1写WAL但不强制fsync2写WAL且强制fsync可容忍少量数据丢失时设1不能容忍设2fsyncInterval3000毫秒周期性fsync的时间间隔3000~10000越大写入性能越好但崩溃恢复时丢的数据越多walBufferSize512MBWAL缓冲区大小建议根据单条记录大小和并发线程数适当调大这里要解释清楚walLevel1和walLevel2的区别walLevel2每条写入都调用fsync数据安全性最好但写入吞吐直接打骨折。如果你用机械盘这个模式基本告别高并发写入。walLevel1写入只到操作系统页缓存靠fsyncInterval周期性的把脏页刷到磁盘。这个模式下操作系统帮你把多次零散写入合并成一次大块刷盘吞吐能提升一个数量级。实测过一个案例同样一台8核16G的服务器配SATA SSDwalLevel2的时候单节点写入大概2万条/秒改成walLevel1、fsyncInterval5000之后直接跑到15万条/秒。代价是如果机器突然断电可能丢失最近几秒的写入数据。3.2 内存缓冲buffer、cache与pagesize的联动关系TDengine的内存缓冲分几层buffer每个vnode的内存缓冲大小、cache结果缓存主要影响查询、pagesize内存页大小影响刷盘粒度。先说buffer。这个参数直接决定了数据在内存里能攒多大才落盘。默认值可能很小如果你写入压力大buffer太小会导致频繁落盘每次落盘都触发磁盘I/O写得细碎效率低。建议先把buffer调大到能容纳至少10秒的写入数据量。算一下假设你每秒钟写入10万条记录每条记录平均100字节那10秒就是100MB。这种情况下buffer至少要设到128MB以上最好256MB。但这个值不是越大越好——buffer太大意味着崩溃时内存中的数据全部丢失恢复时间也长。pagesize是数据页的大小默认4KB还是8KB取决于版本。对于时序数据每条记录通常很小几十到几百字节page太小会导致每页存不了多少条数据索引和元数据膨胀page太大会导致读取时加载无用数据。我的经验是如果你的记录以几十字节的小记录为主pagesize选4KB如果记录里有较多字符串或长字段选8KB或16KB会更合适。3.3 文件块和vnode规划别让一个vnode扛下所有TDengine把数据按vnode虚拟节点切分每个vnode是一个独立的数据管理单元。vnode数量、每个vnode的数据文件块大小都会影响写入的并发粒度。vnodeGroups这个参数控制每个dnode上的vnode组数量。高并发写入时多个vnode可以并行落盘所以vnode太少会形成写入瓶颈。但vnode也不是越多越好——每个vnode都有自己的元数据和内存结构vnode数量太多会导致内存碎片化和管理开销增大。具体规划建议单节点场景建议vnodeGroups设为CPU核心数的1~2倍。每个vnode的days参数数据文件按多少天切分一次不要设太大默认10天左右可以数据量特别大的场景建议缩小到3~7天防止单个数据文件过大影响落盘和查询效率。minRows和maxRows每个数据文件块的最小/最大记录数要保持默认值不要随便调——这个参数和压缩率、索引效率都有关系新手容易改崩。4. 磁盘选型HDD、SATA SSD还是NVMe SSD预算怎么花4.1 不同盘在高吞吐写入场景下的表现差异很多人觉得“时序数据库嘛写得多读得少机械盘便宜容量大就够了”。这个想法在数据量很小的时候没错但高吞吐写入场景下机械盘和固态盘的差距不是用“快一点”能形容的。我用同一套TDengine配置分别在三种盘上做了写入压测结果大致如下磁盘类型顺序写带宽随机写4K IOPSTDengine单节点实测写入walLevel17200转HDD约180MB/s约80~1203~5万条/秒SATA SSD约500MB/s约8000~1500010~15万条/秒NVMe SSD约3500MB/s约50000以上25万条/秒以上注意上面是单盘的数据。生产环境如果做了RAID或者多盘数据目录数字还会变。4.2 数据目录拆分的两种实践方案磁盘选型之外更便宜的优化手段是把不同的I/O路径拆到不同的物理盘上。具体来说方案AWAL目录放一块小容量但高性能的盘比如128G NVMe数据文件目录放一块大容量普通盘比如4T SATA SSD或者HDD。WAL是高频顺序写需要低延迟数据文件是批量落盘顺序写为主对延迟不敏感。方案B多块数据盘做数据目录配置让TDengine把不同的vnode数据自动分布到不同盘上提升并行落盘能力。方案A是我个人最推荐的组合。WAL体积不大但每次写入都碰它给它一块NVMe盘能立竿见影数据文件是大头用大容量盘把成本压下来。4.3 文件系统选型与挂载参数这一块容易被忽略但影响很大。TDengine官方支持ext4和XFS实测在XFS上的大文件顺序写性能略优于ext4而且XFS对并发写入的锁竞争处理更好建议新环境直接用XFS。挂载参数上有几个建议使用noatime挂载选项减少文件访问时间更新带来的额外I/O。如果用的是SSD确保开启了TRIM防止长期写入后性能衰减。不要用LVM的默认配置做条带化它的条带宽度对数据库文件写入不友好如果一定要用LVM务必把条带大小调大比如1MB以上。5. 从默认配置到高吞吐配置一套可以直接抄的调整清单5.1 基于常见硬件的推荐配置模板下面这套配置是基本盘适配大多数单节点或两节点起步的场景。硬件参考8核16G、1块NVMe 512G做系统盘和WAL、1块SATA SSD 2T做数据盘。# TAOS.CFG 关键配置 # 内存总量的一半给buffer这里是8G buffer 4096 # WAL级别生产环境可容忍少量丢失时用1 walLevel 1 # fsync间隔5000ms fsyncInterval 5000 # WAL缓冲区大小256MB walBufferSize 256 # 缓存大小给查询留点余量 cache 1024 # 每dnode的vnode组数CPU核心数的1.5倍左右 vnodeGroups 12 # 数据按7天一个文件分片 days 7 # 文件块最小/最大行数维持默认 minRows 100 maxRows 4096注意几个细节buffer的单位是MB不是字节。上面写4096表示4GB。walBufferSize在部分版本的单位是MB老版本可能是KB升级迁移时留意单位变化。如果你的内存只有16Gbuffer给4G已经比较大查询缓存别给太多否则内存会被吃紧。5.2 参数调整后的验证方法改配置不能凭感觉必须用数据说话。验证分三步第一步看写入吞吐。用taosBenchmark压测工具跑一个高并发写入场景对比调整前后的吞吐和延迟百分位P99尤其重要。第二步看磁盘I/O。压测的同时用iostat -x 1观察磁盘的%util和await如果%util长期在90%以上说明磁盘还是瓶颈如果%util只有60%而吞吐上不去了说明瓶颈转移到了CPU或网络。第三步看落盘频率。日志里或者通过监控看flush操作的频率理想情况下是“攒一批、刷一次”刷得越少效率越高。5.3 调整过程中最容易踩的坑配置调优这件事最怕的不是调错参数而是只调一个参数然后觉得万事大吉。我列几个亲历过的坑只关WAL不调buffer有人为了性能直接把walLevel设成0写入确实快但一旦进程崩溃最近内存里的数据全部丢失。对于IoT数据采集场景这种丢法有时候比数据库不可用还严重。buffer给太大导致OOMbuffer参数并不是越大越好它要和你的写入速度、落盘频率匹配。给太大内存被占用过多其他进程或者查询进程就容易OOM。vnodeGroups和实际写入表数量不匹配表特别多但vnode太少每个vnode要管理的表数量过大内部索引变大写入时要更新多个表CPU消耗反而上去了。SSD不开启TRIM长期高负载写入后SSD的垃圾回收机制如果没有TRIM辅助写入放大越来越严重吞吐逐步下降看起来像是数据库变慢了实际上是SSD没做保养。6. 时序数据特征对存储配置的反作用力6.1 不同写入模型下的配置差异并非所有“高吞吐写入”场景长得都一样。我总结四种常见的写入模型它们的存储配置侧重完全不同写入模型数据特征主要瓶颈存储配置重点高频小记录每秒百万级、每条50字节WAL写入频率加大WAL缓冲区walLevel设1大批量攒批每分钟一次、每次百万条数据文件落盘带宽提高buffer降低落盘频率多表稀疏写入几十万个设备、每台每秒一条表数量与vnode管理增加vnodeGroups调整表结构乱序补采数据时间戳回退、延迟上报数据文件合并开启乱序数据支持留意落盘策略如果你拿同样的配置去套两种完全不同的写入模型大概率有一方会吃亏。比如高频小记录场景下WAL是命门而大批量攒批场景下WAL反而没压力瓶颈在大文件刷盘带宽。6.2 数据保留策略与磁盘空间的联动时序数据库一般需要设置数据过期时间keep用来控制磁盘占用。这里有个容易忽略的联动关系——过期数据的清理动作本身也会占用I/O资源。如果你的keep设得特别短比如7天那么每天都要清理大量数据文件清理时会产生额外的磁盘I/O。在高吞吐写入的同时做数据清理盘要是性能不够写入就会被拉下来。我建议keep不要设成“刚刚好”留出20%~30%的余量。数据清理时段尽量和写入高峰错开可以通过调度控制vnode的合并节奏。如果数据量确实大优先考虑分层存储把热数据放SSD、冷数据放HDD或者对象存储而不是让一套盘同时扛热写和冷清理。6.3 压缩策略和I/O的隐藏关系TDengine对时序数据有压缩能力压缩比通常在3~10倍之间。压缩的好处不仅是省空间更重要的是——数据文件变小了落盘和读取的I/O量也变小了。但压缩不是免费的它消耗CPU。这里就存在一个“CPU换I/O”的权衡CPU相对宽裕比如8核以上但磁盘一般保持默认压缩用压缩率换I/O带宽。CPU紧张比如2核小机器配NVMe可以适当降低压缩级别用I/O换CPU时间。TDengine的压缩配置在服务端是自动的但你可以通过调整compress参数控制压缩行为。注意这个参数针对的是数据块级压缩不是传输压缩传输压缩另有参数。7. 从单节点到集群存储配置要考虑的新维度7.1 多节点写入的存储分布逻辑单机调好之后很多人天真地以为集群就是“多复制几份配置”其实不然。TDengine的集群模式下数据按vnode分布到不同dnode上每个dnode的存储配置可以不同但必须统一规划否则会出现某个节点成为写入热点拖累整体写入吞吐。在多节点部署时你需要额外关注各节点的vnode数量要均衡避免某个节点vnode过多导致数据倾斜。副本数replica影响写入放大副本数为3时每条写入要在三个节点上落盘总I/O量变成3倍。如果磁盘性能不足写入性能会明显下降。跨节点数据同步也走网络I/O网络带宽和延迟同样会影响写入链路。7.2 热点节点的存储配置微调集群中偶尔会有某个节点的数据比其他节点多得多比如某些设备上报频率特别高。这种场景下别指望“所有节点一致”的配置能自愈。我的做法是监控各节点写入量通过taosMonitor或者接入PrometheusGrafana的监控体系找出热点节点。如果热点节点长期存在把热点表迁移到单独的vnode组或者提高热点节点的vnodeGroups数量让热点有更多并行落盘通道。如果热点集中在某几张超级表考虑表结构设计层面做分片比如按设备ID范围划分多个子表。7.3 扩容和缩容时的存储参数重估集群扩容不只是“加机器”这么简单。新增节点后旧节点的vnode要重新分配一部分出去这个迁移过程会带来额外的磁盘和网络I/O。迁移期间写入压力大容易出现性能抖动。实操建议扩容前先调低fsyncInterval降低WAL的压力比如从5000降到2000给迁移留出I/O余量。迁移完成后把参数调回高性能档位。数据均衡期间暂时关闭数据清理任务避免清理I/O和迁移I/O叠加。8. 实测记录一次I/O瓶颈的完整排查与解决过程8.1 现象描述写入延迟陡增磁盘利用率100%去年我接手过一套TDengine集群接入的设备大约12万台每台每5秒上报一条数据算下来峰值写入约2.4万条/秒。业务方反馈“最近一周每天下午写入延迟明显变大偶尔还报写入超时”。第一反应是看监控结果发现三个节点中有一个节点的磁盘%util长期在100%其他两个节点磁盘利用率只有40%。典型的热点节点I/O瓶颈。8.2 逐步排查从应用层到存储层排查思路分了四步第一步排除应用层。检查客户端写入是否均匀分布到三个节点——结果发现连接配置里写死了某个节点的地址所以这个节点接收的写入量天然比另外两个多。第二步查数据分布。用SQL查各vnode的数据量发现热点节点上的vnode数量比另外两个多了一倍原因是建库时指定了vnode数量和策略但没有考虑后续扩容。第三步查配置差异。热点节点用的还是默认WAL配置walLevel2而另外两个节点早就调成了walLevel1。也就是说热点节点不仅要承受更多的数据量还用了最耗I/O的WAL策略。第四步查磁盘老化情况。这块SSD已经用了两年多固件较老没有开启TRIM有效写入吞吐比新盘低了差不多30%。8.3 解决动作与效果对比调整动作更新客户端连接配置让写入均匀负载到三个节点。热点节点的walLevel改成1fsyncInterval设5000。单独给热点节点的WAL目录挂了一块NVMe盘。对SSD做了一次安全擦除后重新挂载并开启TRIM这一步操作风险较高务必有备份。调整前后对比指标调整前调整后热点节点磁盘%util100%62%P99写入延迟850ms120ms整体写入吞吐2.4万条/秒已到顶4.6万条/秒还有余量这个案例说明I/O瓶颈往往不是单个原因造成的而是应用层、配置层、硬件层三个层面的问题叠加。逐一排查比拍脑袋调一个参数靠谱得多。9. 监控I/O的日常工具和指标别等问题爆发才想起来9.1 必须盯住的几个I/O指标高吞吐写入环境里日常巡检I/O指标比出了问题再救火重要得多。我建议至少盯住这几项指标含义警戒线%util磁盘繁忙程度长期80%需要关注awaitI/O请求平均等待时间SSD10ms、HDD50ms要查iowaitCPU等待I/O时间占比持续20%说明I/O压力大svctmI/O服务时间和await差距大说明队列拥堵写入吞吐每秒写入的记录数下降趋势可能说明磁盘老化9.2 用iostat和taosMonitor组合排查排查I/O问题我的标配命令是iostat -x 1重点关注w_await写等待时间和w_util写利用率。如果w_util在写高峰期冲到90%以上基本可以确定磁盘是瓶颈。同时用taosMonitor看数据库内部的写入延迟和落盘频率。两者对照能快速判断瓶颈是“数据库在等磁盘”还是“数据库自身处理不过来”。9.3 磁盘寿命和写入放大的监控SSD的写入放大问题是隐藏杀手。正常的SSD写入放大比WAF在1~3之间如果超过5说明SSD的垃圾回收压力很大寿命在加速消耗。查看SSD的WAF需要借助smartctlsmartctl -x /dev/nvme0n1注意看nvm日志中的写入量total bytes written和主机写入量的比值。如果WAF异常高优先检查是否频繁小写落盘——这正是数据库配置不合理导致的比如buffer太小、落盘太频繁。10. 基于当前版本和生态的一些补充实践10.1 免费版和商业版的存储特性差异TDengine的免费版已经提供了相当完整的能力存储配置相关的核心参数没有做阉割这一点对大多数中小团队来说足够用。商业版在存储层增加的主要是更细粒度的多级存储策略和更完善的企业级监控告警。如果团队预算有限先用免费版把WAL、buffer、vnode这些基础配置调明白大概率能满足业务需求等数据量真正大到需要分层存储、冷热分离这一层时再考虑商业版的能力也不迟。10.2 使用TDengine Explorer做存储状态的日常观察新版本里TDengine Explorer提供了可视化的集群监控面板存储相关能看到每个dnode的数据量、vnode分布、磁盘使用率等。虽然不是性能调优的万能工具但它能让“数据分布是否均衡”“哪些vnode增长特别快”这类问题一目了然。建议运维团队的日常巡检流程里加一步每周看一次Explorer里的存储分布视图趁数据倾斜还没扩大之前处理掉。10.3 社区里关于存储配置的一些值得尝试的做法TDengine的社区讨论里关于存储配置有几种值得参考的思路有人把WAL文件放到tmpfs内存文件系统上写入完全不碰磁盘性能直接拉满。这招适合数据丢失容忍度极高的场景但机器重启等于丢WAL内存里的数据也会受影响风险很大不建议生产使用。有人建议对数据文件做周期性整理defrag降低碎片化。TDengine本身的merge机制能处理一部分但如果你的数据有大量乱序写入碎片化会更严重定期整理确实有效。还有人尝试用多块NVMe盘做vnode手动分片实现写入通道的硬隔离。这个方案配合vnodeGroups规划效果很好但对运维要求较高。我个人比较认可的做法是优先把WAL从数据盘上拆出去再考虑其他花活。这一步带来的收益最大操作风险也最低。11. 几个值得反复验证的细节单位、版本与参数作用域11.1 配置项单位在不同版本中的差异TDengine不同版本的配置单位并不完全一致这是踩坑高发区。比如buffer在2.x版本里单位是MB但早期1.x版本是KBwalBufferSize在不同小版本里也可能不同。建议每次升级后做一次全量配置备份并对照官方文档核对单位变化。另外配置项如果写错单位启动时不一定会报错但实际内存占用和预期相差很大这种问题最难排查。11.2 参数作用域全局参数与库级参数TDengine中部分存储参数是全局的比如walLevel、walBufferSize但也有库级别database可以覆盖的参数比如创建数据库时可以指定BUFFER、PAGES、DAYS等。实际项目中要做到全局和库级两层规划全局配置定基准保证所有库能跑。重要的业务库单独设置针对它的写入模型做精细化调整。比如同一实例下一个库是高频小记录采集需要大buffer、walLevel1另一个库是低频大包写入不需要那么大buffer就应该在两个库级别分别设置而不是全局一刀切。11.3 配置热更新与需要重启的参数TDengine部分参数支持在线修改但存储相关的参数大部分需要重启taosd才能生效。生产环境改配置前务必先备份原配置文件。在测试环境验证参数合法性和预期效果。安排维护窗口低峰期重启。重启后立刻检查日志和写入指标确认没有引入新问题。我见过不止一次“改一个参数不重启以为生效了结果性能没变”的情况。配置改完要确认日志里是否加载了新值别凭感觉判断。12. 关于这套实践我最后想说的存储配置调优这件事没有什么银弹。每个团队的数据量、写入模型、硬件条件都不一样直接抄别人的配置能跑但往往不是最优解。我这套实践的核心逻辑就三句话第一理解写入链路知道数据在哪个环节会和磁盘发生关系才知道要调什么。 第二WAL是写入性能的第一道关卡把它单独放高性能盘上收益最大。 第三任何配置调整都要用监控数据做验证不要凭感觉。如果你刚开始调TDengine存储配置可以从最简单的实验做起把walLevel从2改成1观察写入吞吐的变化。这个实验能让你直观地理解WAL对性能的钳制作用也是后续所有调优的基础。最后分享一个习惯每次调整完存储配置我都会在配置文档里记录“改了什么、为什么改、压测数据是多少、半个月后运行表现如何”。时间长了这份文档就是团队排查性能问题最宝贵的参考。调优不是一次性工作是随着数据量增长、硬件变化不断迭代的过程。

相关新闻

最新新闻

Triton语言tl.floor完全指南:从原理到实践

Triton语言tl.floor完全指南:从原理到实践

1. 为什么一个 floor 函数值得单独写一篇教程先交代一下背景。今年在给一个推理服务做算子优化,模型量化那一步需要把激活值映射到整数网格,常规做法是torch.floor,但换到 Triton kernel 里就发现事情没那么简单。Triton 的tl.floor不是torch…

2026/9/9 6:26:24
基于Simulink的冷热电三联供CCHP系统仿真建模与能量管理实践

基于Simulink的冷热电三联供CCHP系统仿真建模与能量管理实践

玩综合能源仿真这些年,我最大的感受是: 冷热电三联供(CCHP)系统是整个综合能源系统里最值得先啃的一块硬骨头。 原因很简单,它同时牵扯电网、天然气网、热网三个网络,包含燃气轮机/内燃机、余热锅炉、吸收…

2026/9/9 6:26:24
深度优先搜索与回溯算法:核心模板、剪枝技巧及数独实战

深度优先搜索与回溯算法:核心模板、剪枝技巧及数独实战

我第一次接触 DFS(深度优先搜索)是在做“全排列”这道题的时候。当时看到别人的解答只有短短十来行递归代码,我却完全看不懂为什么能输出所有排列。后来弄明白了,DFS 和回溯搜索并不是什么高深概念,它就是一个“走迷宫…

2026/9/9 6:26:24
CPO光引擎如何搞定32路加热控制与128路监控?高集成AFE实战解读

CPO光引擎如何搞定32路加热控制与128路监控?高集成AFE实战解读

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

2026/9/9 6:26:24
冷门好用AI软件怎么选?先按五类分清再安装

冷门好用AI软件怎么选?先按五类分清再安装

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

2026/9/9 6:26:24
Linux缓冲区体系全解析:从用户态到内核再到安全防护

Linux缓冲区体系全解析:从用户态到内核再到安全防护

聊到Linux,十个后端开发里有八个都在跟缓冲区打交道,但真能把它讲明白的人不多。平时排查线上问题的时候,“缓冲区”这三个字经常以各种身份出现:进程没输出日志,是标准I/O缓冲区没刷;服务器掉电丢数据&…

2026/9/9 6:21:24