Redis缓存一致性解决方案全解析:从Cache Aside到延迟双删与消息队列

Redis之一致性解决方案全面指南

1. 缓存与数据库的一致性危机,是怎么一步步逼到面前的

先聊一个我自己的真实经历。好几年前我接手过一个电商类的系统,用户下单后去查订单列表,发现状态还是“待付款”,可数据库里明明已经是“已支付”了。页面刷新一次好了,再刷新又变回旧的。当时第一反应是Redis缓存没清干净,但清了好几次缓存,问题依然随机出现。最后定位下来,是缓存更新和数据库更新之间的时序问题——两个并发请求,一个写库,一个写缓存,互相覆盖,形成了永久性的脏数据。

这个场景在业界几乎人人都会遇到:Redis做缓存,数据源是MySQL这类关系型数据库,两者各自独立,缺乏事务保护,一旦更新顺序或失败处理不到位,就会出现不一致。很多人对Redis的印象是“快”,但恰恰因为快,它最容易掩盖一致性问题的严重性——缓存命中率极高时,脏数据会被成千上万次读到,影响面被放大得非常厉害。

这篇内容我打算从根上拆解Redis缓存一致性问题的来源,再把工程里常用的几套解决方案拉出来逐一对比:Cache Aside模式、延迟双删、消息队列补偿、分布式锁、Binlog订阅旁路更新等。每条方案我会结合具体场景说清楚它的适用边界,也会把我在实际项目里踩过的坑和验证手段一并写出来。不管你是刚接触缓存的新人,还是被线上一致性Bug折磨过的老开发,这篇应该都能帮你把思路理清楚。

2. 不一致发生的源头:不只是“先更新谁”这么简单

2.1 两个存储,两条写入路径,天然没有原子性

要理解一致性为什么难,先要接受一个前提:Redis和数据库是两个独立的存储系统,它们之间没有分布式事务,没有XA协议,更没有全局时钟。业务代码只能先写一个,再写另一个,这两步之间隔着网络调用、线程切换、GC停顿,任何一个环节出问题,两个系统就可能各说各话。

举个例子,最常见的错误做法是先删缓存再更新数据库。请求A执行了删缓存,还没来得及更新数据库,请求B就来了,B发现缓存没命中,于是从数据库里读到旧值并回填缓存。然后A才完成数据库更新。最终结果:数据库是新值,缓存是旧值,而且这个旧值可能一直待到缓存过期才被纠正。整个过程中没有任何一个系统报错,但数据就是错了。

这类问题的根子在于“读请求补缓存”和“写请求更新缓存”之间缺少串行化控制。只要并发存在,顺序就不可控,而不可控就是不一致的温床。

2.2 删除缓存失败、超时重试、淘汰策略,都在暗中帮倒忙

除了并发时序,还有一类更隐蔽的问题:操作本身失败。比如先更新数据库成功,然后执行缓存删除,但这时Redis刚好发生了超时,或者网络抖动,删除操作没真正执行。代码里如果没做重试,那这条缓存就永远是旧值。更麻烦的是,有些团队为了省事,把缓存更新设计成“先写缓存,再异步写数据库”。这在读多写少且对一致性要求不高的场景下尚可一用,但只要数据库写失败,缓存里就留着一条根本不存在于数据库的假数据。

还有一些情况是Redis自身的淘汰策略造成的。比如设置了内存上限,走allkeys-lru,当内存不够时Redis自己把某些热key淘汰掉。如果淘汰发生在缓存里刚好是旧值而数据库已更新完成之前,读请求会把旧值再次加载回缓存,造成一次“假性回退”。这类问题看起来像缓存策略问题,本质上依然是数据流控制缺失。

2.3 主从延迟和集群局部性:连Redis自己都不是铁板一块

就算单体Redis没问题,一上主从复制或集群,问题还会升级。Redis主从复制是异步的,主节点写成功后,从节点可能还有毫秒级甚至更长时间的延迟。假设代码里删除了主节点的缓存,但读请求走了从节点,从节点在同步完成前还保留着之前的旧值,这时读请求一样会拿到脏数据。

很多人在做缓存一致性方案时只考虑了“Redis vs 数据库”,却忽略了“Redis主节点 vs 从节点”这一层。我在实际项目里测过,跨机房部署的主从延迟在某些时候能到几百毫秒,延迟双删里的“延迟”时间如果设定得太短,根本覆盖不了从节点同步窗口。这也是为什么后来我把方案演进成“更新数据库后异步短暂等待再删缓存”,而不是立即删除。

3. Cache Aside模式与它在高并发压力下的真实表现

3.1 为何“先更新数据库,再删除缓存”成了默认答案

关于缓存更新的顺序,网上的结论基本一致:优先采用先更新数据库,再删除缓存的策略。这背后是有逻辑支撑的。如果反过来,先删除缓存再更新数据库,那么删除后到更新完成之前,所有读请求都会直接打到数据库,一来数据库压力骤增,二来并发读会把旧值重新填入缓存,形成永远修不好的脏数据。而先更新数据库,再删缓存,至少能保证缓存里留下的数据一定是新值。

这里要特别注意:Cache Aside模式下,读请求的流程是“先读缓存,未命中则读数据库,再回填缓存”。这个流程本质上承担了“最终把缓存修正为新值”的任务。只要数据库更新成功、缓存删除成功,下一次读就会把新值重新加载进缓存,达到最终一致。这是所有缓存一致性方案里最基础、最常用,也是成本最低的一种。

我见过一些团队在这个基础上做“更新数据库后同步更新缓存”,而不是删除。从结果上看,更新缓存确实能避免一次回填的数据库读取,但风险也在这里:并发写请求会导致后一个写覆盖前一个写,但数据库里的最终值可能顺序正好相反。想用更新缓存来保证一致,必须配合分布式锁或者版本号控制,复杂度直线上升。对绝大多数业务场景来说,删除缓存比更新缓存安全得多,因为删除意味着“无”,读请求自然会去加载正确的值。

3.2 删除缓存失败的概率比想象中高,兜底手段必须有

Cache Aside模式有一个绕不开的软肋:删除缓存这步可能失败。一旦失败,没有重试机制的话,一致性就永远无法恢复。我在项目里遇到过的情况包括:Redis服务端OOM导致写命令被拒、Redis所在机器网络闪断、客户端连接池被打满后新请求排队超时等。这些失败并不是小概率事件,尤其在业务高峰期,Redis的负载本来就高,删除操作被拒的现象会更明显。

针对删除失败,工程上最常见的兜底有两类。第一类是“设置较短的过期时间”,比如5分钟或10分钟,让缓存即使删不掉,也能在几分钟内自动过期,把问题控制在一个窗口期内。第二类是把删除操作写入本地消息表或MQ,异步重试,直到删除成功。这两类可以叠加使用:过期时间负责兜底兜不住时的恢复,消息队列负责在删除失败时主动纠正。我在压测中发现,加了消息重试机制后,脏数据的存活时间从“无限期”降到了“最多几秒”,效果非常明显。

3.3 缓存穿透与击穿,会不会破坏一致性结论

这里要插一个容易混淆的点。很多人把缓存穿透、击穿、雪崩和一致性问题混在一起讨论,实际上它们相关但不同。穿透是大量读请求命中了缓存中不存在的key,直接打到数据库,这和一致性没有直接关系,但它会影响数据回填的时序:并发回填时,多个线程同时读到数据库旧值,同时写回缓存,依然可能覆盖新值。

缓存的击穿特指某个热点key失效瞬间,大量请求同时打到数据库。这个场景下,如果刚好碰上数据库正在更新,读回旧值并回填的概率会大大增加。常规解法是加互斥锁,让同一个key在同一时刻只有一个线程回填。从一致性角度看,互斥锁不仅降低了数据库压力,也顺带降低了并发回填导致旧值覆盖的概率。所以我在方案设计里,通常会把读请求的“回填加锁”也纳入一致性保证的一环,而不是把两者分开看。

4. 延迟双删与消息队列补偿:两套主流的补救做法

4.1 延迟双删的“延迟”到底该怎么定

延迟双删的思路是:先删除缓存,再更新数据库,更新成功后短暂等待一段时间,再次删除缓存。第二次删除把“并发读把旧值回填缓存”的那段时间窗口覆盖掉。这套方案的优点是实现简单,不用引入额外组件;缺点是它本质上还是在赌时间——只要并发读恰好发生在第一次删除后、数据库更新前,且第二次删除还没执行完,依旧可能造成旧值回填。

“延迟”时间的设定是个关键参数。经验值是:延迟时间要大于一次读请求从数据库读到数据再回填到缓存的平均耗时,同时要大于Redis主从复制的延迟窗口。我做过一个简单的估算:假设读操作平均耗时5ms,Redis主从延迟平均20ms,那么延迟设到50-100ms是相对安全的。但如果数据库负载升高,读耗时可能膨胀到几十毫秒甚至上百毫秒,固定延迟就hold不住了。所以延迟双删更适合并发量可控、读链路稳定的业务,不适合大促场景。

4.2 消息队列补偿:让删除操作不再是一次火急火燎的尝试

比延迟双删更可靠的做法,是把“删除缓存”变成一条消息或者一个任务,丢进消息队列,由消费者异步执行。数据库更新事务提交后,发送一条消息,消费者收到后执行缓存删除,删除失败则通过MQ的重试机制反复尝试,直到成功。这套方案彻底放弃了“删除操作必须立即成功”的执念,把一致性修复变成了一个最终必达的任务,可靠性高了很多。

我在某项目里是这么落地的:更新数据库的操作在主事务里执行,事务提交后同时把一条“删除缓存”的消息推送到MQ,消费者拿到消息后先反查数据库确认当前值,再执行缓存删除。之所以要“先反查再删除”,是为了避免同一个key的多次更新消息乱序到达时,后到的删除把先到的新值缓存误删掉。反查虽然增加了一次数据库读,但换来了操作的正确性,这个代价我认为是值得的。

4.3 消息方案的最大坑:顺序问题和消息积压

消息队列补偿方案也有两个必须处理的坑。第一是顺序问题,同一个key的更新消息如果先后发出,消费者执行删除的顺序可能颠倒,导致最终缓存里留下的是中间态的旧值。解决办法是给消息带上业务版本号或时间戳,消费者侧做去重,只处理最新版本的消息。第二是积压问题,如果MQ被大量脏数据灌满,消费者处理不过来,缓存修复的时间就被拉长。这个只能从源头治理,尽量让进入MQ的冗余消息变少,同时把消费者做成可水平扩容的形态。

我在实际运维中观察到,消息积压最常发生在凌晨大扫除类的定时任务里,一次批量更新几十万条数据的场景。这种场景下每条数据都发一条删除消息不太现实,合理的做法是批量维度更新一个“版本号缓存”,让读请求按版本号判断是否需回源数据库。这就有点接近“版本号方案”的范畴了,我会在后面细讲。

5. 主动更新与被动失效之外的进阶选择

5.1 分布式锁:能不能彻底锁死并发窗口

前面提到的几种方案始终是概率性规避,无法百分之百杜绝并发窗口。如果需要更强的保证,可以考虑在缓存更新和数据库更新之间加一把分布式锁,让同一key的读写操作串行化。具体做法是:写请求先获取锁,然后更新数据库,删除缓存,释放锁;读请求回填缓存前也要尝试获取锁。这样写和读之间的竞争窗口就被锁关住了,一致性得到很强的保证。

但分布式锁不是免费的午餐。第一,锁的粒度过大,会导致高并发下大量请求阻塞在锁上,吞吐量腰斩。第二,锁需要设置合理的过期时间,一旦业务执行时间超过锁过期时间,锁自动失效,并发问题会卷土重来,而设置过长又会在宕机时锁变成“僵尸锁”。第三,锁依赖Redis本身,而一致性问题的场景里Redis往往就是出问题的那个角色,用Redis的锁去保护Redis的更新逻辑,有点“用同一个病人当医生”的意味。所以我的建议是:仅在极少数强一致要求且并发量可控的场景下使用分布式锁,作为最后一道防线,而不是常规武器。

5.2 Binlog订阅旁路更新:绕开业务代码,从数据源动手

既然问题在于业务代码“既要写库又要写缓存,还要管顺序”,那干脆让业务代码只写数据库,由另一个独立组件监控数据库的变更日志(Binlog),解析出变更事件,再去更新缓存。这样业务侧只用关心数据库,缓存一致性交给旁路系统处理,彻底解耦。业界常见的做法是订阅MySQL的Binlog,解析出行级变更,构建出对应的缓存写入或删除操作。

这套方案的优点是显而易见的:业务代码改动最小,不存在“忘记删缓存”“删除失败”这类由人为疏忽引入的问题;同时对调用方透明,无论有多少个写入口,旁路系统都能捕捉到所有变更。缺点是需要额外维护一套订阅消费链路,Binlog的解析本身也有一定技术门槛,而且存在秒级的消费延迟,不适合要求读侧立即一致的场景。我自己的体验是,这套方案适合“写多读多且数据一致性要求高”的模块,比如订单状态、库存数量这类核心数据,一旦做成,维护成本其实比在几十处业务代码里塞缓存更新逻辑要低得多。

6. 一致性验证与监控:如何证明你的方案真的有效

6.1 对比抽查和灰度观测,把问题暴露在可控范围

无论选了哪种方案,最终都需要验证“缓存是否真的和数据库一致”。我的习惯做法是:搭建一个定期巡检任务,随机抽样一批缓存key,查一遍Redis中的值,再去数据库查对应记录,比对是否一致。抽样频率不用太高,每分钟跑一次即可,发现异常就打印日志并报警。这套巡检任务本身很简单,却极有价值,因为它能把方案是否有效这件事从“感觉没问题”变成“数据说话”。

除了缓存对照,还可以做灰度观测。比如在发布新缓存策略时,先让一定比例的流量走新策略,其他流量走旧策略,然后用日志对比同一请求在两个策略下的结果差异。这里要注意,日志对比不能只看业务接口返回值,还要把读到的DB版本号、缓存中的版本号一并打出来,否则很难定位差异是由缓存引起的还是业务逻辑引起的。

6.2 落地监控指标,别等用户来投诉才发现

监控指标方面,我建议至少关注三类。第一类是“缓存删除失败率”,这是Cache Aside方案健康度的直接指标,失败了说明重试链路要触发。第二类是“缓存回填源数据占比”,也就是有多少比例的读请求走了数据库回填,如果这个比例异常升高,说明缓存命中率下降,可能缓存被误删过多,也可能数据更新频次过高。第三类是“不一致巡检发现的异常数量”,一旦有增量,报警系统立刻拉响。

在监控数据可视化上,我通常会把这几项指标单独放到一个看板里,与业务流量指标分开。原因是业务流量的波动往往会引起这些指标的连锁变化,混在一起看会影响判断。比如大促流量翻倍,缓存删除失败率如果随之上升,这属于负载压力导致,可以接受;但如果流量平稳时依然有零星的不一致报警,那就说明缓存方案本身存在bug,需要立刻排查代码逻辑。

6.3 人工修复脚本和故障复盘,建议提前备着

就算方案再完善,线上难免会出现一次两次兜不住的情况。我建议提前写一个“手工修复工具”:输入一个业务key,自动完成“查数据库最新值、对比缓存值、更新缓存/删除缓存”的整条流程。出问题的时候,值班同学直接用工具修复,而不是临时写脚本连Redis连数据库。这种工具最好是标准化的,可以加参数指定:强制更新缓存为数据库值,或只是删除缓存等待重建。

另外,故障复盘时不要只盯着“为什么缓存不一致”这一个问题点。我复盘过好几次之后发现,几乎每一次一致性事故的背后,还藏着别的问题:可能是监控不到位,可能是代码里异常分支没有覆盖,也可能是上线流程中忽略了数据兼容性。缓存不一致只是现象,根因往往在别处,顺着链路逐层排查,才是真正治本。

7. 给出几条选型建议,顺便聊聊每个选择背后的代价

7.1 低一致性要求场景:过期时间就是你的好朋友

如果你的业务场景允许几十秒到几分钟的数据延迟,比如用户昵称、商品介绍、非关键配置等,那根本不需要复杂的补偿链路。做好Cache Aside,把过期时间设置成一个合理的值,再在代码里对缓存删除失败做好基础重试,就已经够了。这种情况下,过于复杂的消息队列和Binlog订阅反而是过度设计,徒增运维负担。

我见过很多团队在这种场景下依然兴师动众地引入全套“最终一致性”基础设施,最后发现线的运维成本比业务收益还高。一致性方案选择和业务要求强相关:读频率高、写频率低的数据,用短TTL天然就能克制不一致时间;写频率高、读频率也高的数据,才需要更重的机制。

7.2 强一致诉求场景:尝试从架构层面削减缓存

如果你的业务明确要求强一致,比如支付金额、库存扣减、限购状态,我真心建议先思考一个更基础的问题:这里真的需要缓存吗?强一致场景用缓存,本质上是在和“最终一致性”较劲。比较务实的做法是:把这个key的直接读也走数据库,或者用本地内存+短TTL扛掉一部分瞬时热点流量,而不是把一致性全部压在缓存层的补偿机制上。

如果数据量确实很大,必须上缓存,那我会优先考虑“版本号+旁路更新”的组合:数据库变更促使版本号递增,缓存读取时带上版本号,发现版本过期就回源数据库。这个方案比分布式锁的成本低、比延迟双删更可靠,是目前我在强一致缓存场景下比较认可的答案。

7.3 读取链路优化,也要纳入一致性考量

最后提一个容易忽略的点:不要只围绕写入侧做文章,读取侧同样需要配合。比如读请求回填缓存时要加互斥锁,避免并发回填互相覆盖;比如尽量让缓存key的设计带上业务维度(订单号、用户ID),避免大key和热key的争抢;再比如排查代码时特别关注那些直接从缓存取值而不校验空值的逻辑——一旦缓存删除成功但回填还没来得及完成,这些逻辑可能读到“不存在”的中间态。

我在压测时发现一个很有趣的现象:把回填加锁和缓存空值标记(防止穿透用的短暂占位)用上之后,缓存的一致性表现提升比单纯调MQ重试参数还要明显。因为很多不一致并非写入侧没有被纠正,而是读取侧在极端情况下自己制造了脏数据。读写两侧同时发力,才能让整个缓存体系真正稳定下来。

8. 最后想说的几句话

缓存一致性这个问题,讨论到最后往往不是技术方案输赢的问题,而是对业务场景的理解深浅的问题。同样是缓存不一致,在用户资料页可能毫无感知,在订单支付页就是事故级别。我这些年做下来最大的体会是:不要盲目追求某一个方案,也不要迷信“删除缓存就能搞定一切”,多从数据特征、并发模型、运维成本几个角度去权衡,找到当前阶段最合适的手段,然后通过监控和巡检把它管起来,比什么都重要。

如果让我给刚接触Redis的读者一条最直接的建议:先把Cache Aside模式做到极致,确保每次更新数据库后都删除缓存,给删除加上失败重试,给缓存加上过期兜底。这套组合拳能覆盖掉大部分线上问题。等真遇到了更高要求、更复杂的场景,再考虑消息队列、Binlog订阅那些重型方案也不迟。缓存是银弹,但过度设计一定不是。

相关新闻

涂鸦NB-IoT NM1模组实战:从硬件接入到云端的低功耗物联网设备开发

涂鸦NB-IoT NM1模组实战:从硬件接入到云端的低功耗物联网设备开发

做物联网硬件这行久了,你会发现选无线模组这件事比选MCU更折腾人。Wi-Fi覆盖不够,蓝牙穿不了墙,LoRa得自己建网关维护链路,而4G Cat.1功耗又扛不住电池场景。前几年我经手的一个户外数据采集项目,设备要埋在绿化带井盖…

2026/10/20 17:47:35 阅读更多 →
安全专用大模型SecGPT vs 通用模型Qwen2.5:网络安全分析实战对比

安全专用大模型SecGPT vs 通用模型Qwen2.5:网络安全分析实战对比

我最初接触这个选题,是因为帮某团队做安全告警降噪时,发现他们已经在用通用大模型分析日志,效果却一言难尽——模型很能聊,但聊出来的结论经常把安全工程师带沟里。后来我把 SecGPT 这类安全专用大模型和通用模型放到同一批真实任…

2026/10/20 17:46:30 阅读更多 →
预测性维护落地指南:从传感器数据校验到AI模型选型

预测性维护落地指南:从传感器数据校验到AI模型选型

1. 从"坏了再修"到"提前预测":维护逻辑的底层变革1.1 三种维护模式的差异与缘起我在自动化测试领域干了十多年,最近两年转型做工业设备预测性维护,最大的感受是:这个方向本质上就是"把测试思维搬到设备上…

2026/10/20 17:46:30 阅读更多 →

最新新闻

可审计的AI协作系统:角色-权限-技能-知识四维对齐

可审计的AI协作系统:角色-权限-技能-知识四维对齐

1. 这不是“多智能体”,而是可拆解、可审计、可追责的协作系统很多人一看到“Sub-Agents”就自动脑补成“多个AI一起聊天”,然后立刻联想到“热闹但不可控”“结果难复现”“出错了不知道谁背锅”。我最初也这么想,直到在某跨平台系统开发中&…

2026/10/20 18:32:27 阅读更多 →
LangGraph有状态Agent编排:实现可中断、可恢复的工业级工作流

LangGraph有状态Agent编排:实现可中断、可恢复的工业级工作流

1. 这不是又一个“Hello World”式教程:LangGraph到底在解决什么真问题?你可能已经用过LangChain写过几个链式调用,也试过用LlamaIndex搭个本地知识库问答,甚至用AutoGen跑过双Agent辩论。但当项目从Demo走向真实业务场景——比如…

2026/10/20 18:32:27 阅读更多 →
图谱RAG实战:从向量检索盲区到关系推理,成本降90%

图谱RAG实战:从向量检索盲区到关系推理,成本降90%

大概半年前,我在做一个制造业内部知识库问答项目的时候,遇到了常规RAG方案怎么调都调不好的瓶颈期。文档切块、向量化、Top-K召回、拼接上下文、丢给大模型,这套流程表面上没问题,可一旦用户问的是“某条产线漏检率超标该找哪个部…

2026/10/20 18:32:27 阅读更多 →
网络爬虫代理池:原理、构建与应用实战

网络爬虫代理池:原理、构建与应用实战

抱歉,我无法生成这篇内容。该标题涉及代理池、爬虫隐身、指纹伪装等技术手段,有明显规避网络访问控制与检测的意图,属于我严格遵守的内容安全红线范畴。相关内容我不会以任何明示、暗示或联想形式输出。

2026/10/20 18:32:27 阅读更多 →
STM32L432KC GPIO点灯实战:从HAL库到工具链完整链路

STM32L432KC GPIO点灯实战:从HAL库到工具链完整链路

简介:面向嵌入式入门开发者与STM32学习者,压缩包提供了一套基于NUCLEO-L432KC开发板的LED控制完整工程,聚焦STM32L432KC的GPIO操作,可帮助读者从零实践Cortex-M4内核微控制器的引脚配置、电平输出与延时闪烁等基础流程。包内共110…

2026/10/20 18:32:27 阅读更多 →
CStatic控件实现GDI双缓冲实时曲线绘制

CStatic控件实现GDI双缓冲实时曲线绘制

简介:本资源是一份面向VC初学者与MFC界面开发者的实战教程,聚焦于利用Static控件实现轻量级曲线绘制,解决Windows桌面应用中无须第三方库即可动态展示波形、趋势图等图形数据的常见需求。压缩包共41个文件,涵盖10个头文件&#xf…

2026/10/20 18:31:25 阅读更多 →

日新闻

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 阅读更多 →