Redis缓存与数据库一致性实战:延迟双删与binlog订阅方案

数据库与Redis缓存的一致性,是数据库运维和架构设计里的经典难题。读写缓存没有事务保证,缓存更新失败就会让旧数据留在线上。本文对比Cache Aside、延迟双删、binlog订阅(Canal)三种主流方案,给出不同业务场景下的取舍结论和实现细节。

先确认需求:一致性与性能的边界

业务对一致性的要求分两类。容忍秒级不一致:商品浏览数、推荐列表,用Cache Aside加过期时间即可。要求强一致:库存、账户余额、订单状态,必须把缓存更新做成数据库驱动的确定性流程。先把需求分清楚,方案才能对症下药。

方案一:Cache Aside + 过期时间(基础盘)

标准读写流程:读缓存,未命中则读库并回填;写操作先更新数据库,再删除缓存。删除缓存而不是更新缓存,因为更新缓存要和DB操作保持原子性,删除则天然幂等,下次读再回填。注意点:缓存必须设置过期时间作为兜底,防止删除失败导致永久脏读。

// 写:先更新DB,再删缓存
public void update(Goods goods) {
    goodsMapper.updateById(goods);
    redisTemplate.delete("goods:" + goods.getId());  // 延迟删除见方案二
}
// 读:缓存未命中回源
public Goods get(Long id) {
    Goods g = redisTemplate.opsForValue().get("goods:" + id);
    if (g == null) {
        g = goodsMapper.selectById(id);
        redisTemplate.opsForValue().set("goods:" + id, g, 30, TimeUnit.MINUTES);
    }
    return g;
}

方案二:延迟双删(Cache Aside的补丁)

删缓存与更新数据库之间存在时间窗:请求A读旧值回填缓存,请求B更新库删缓存,A的回填把旧值又写进去了。延迟双删就是在更新库后延迟几百毫秒再删一次缓存,把A回填的脏值清掉。实现要点:延迟删除用异步任务,第二次删除要保证执行成功并做补偿。

// 写路径:更新DB -> 删缓存 -> 延迟再删一次
public void updateWithDelay(Goods goods) {
    goodsMapper.updateById(goods);
    redisTemplate.delete("goods:" + goods.getId());
    // 延迟500ms再删一次,覆盖读回填的脏值
    executor.schedule(() -> redisTemplate.delete("goods:" + goods.getId()),
                      500, TimeUnit.MILLISECONDS);
}

延迟双删能覆盖多数场景,但不是严格正确:延迟窗口内的读取仍可能脏。要求极高的业务不适合。

方案三:binlog订阅(Canal)解耦更新

业务写入MySQL,Canal监听binlog变更,异步把最新数据推送到Redis。缓存更新完全由数据变更驱动,业务代码不需要管缓存,适合读多写少、要求最终一致的场景。关键实现:先改DB,Canal解析后写缓存;写缓存失败要重试或回源。

// Canal监听变更,解析后更新缓存
public void onBinlogChange(BinlogEntry entry) {
    if (entry.getTable().equals("t_goods")) {
        Long id = entry.getRowId();
        // 直接查库拿最新值,或从binlog行数据组装
        Goods g = goodsMapper.selectById(id);
        redisTemplate.opsForValue().set("goods:" + id, g, 30, TimeUnit.MINUTES);
        // 失败重试交给MQS,保证最终一致
    }
}

Canal方案引入了消息中间件和消费组件,运维复杂度上升,但对业务侵入最小,适合订单、库存这类强一致业务。

三个方案的选型结论

方案一致性复杂度适用

Cache Aside+过期 秒级 列表页、详情页
延迟双删 毫秒级 中低并发
binlog订阅 最终一致 中高 库存、订单

选型要点:并发不高用延迟双删足够;写入频繁且要求最终一致的用Canal;无论哪种方案,缓存过期时间都是最后的防线,不能省。上线前模拟并发读写压测,用数据说话。

原创文章,作者:小编,如若转载,请注明出处:https://www.yunthe.com/redis-huan-cun-yu-shu-ju-ku-yi-zhi-xing-shi-zhan-yan-chi/

(0)
小编小编
上一篇 2小时前
下一篇 2小时前

相关推荐