MySQL数据库和Redis缓存一致性的更新策略

MySQL数据库和Redis缓存一致性的更新策略
最新回答
默看〆这一切

2022-07-10 16:03:55

MySQL数据库和Redis缓存一致性的更新策略主要包括同步直写、异步缓写、双检加锁、延时双删、先更新数据库再删除缓存等方案,推荐采用“先更新数据库再删除缓存”结合消息中间件的方式实现最终一致性。 以下是具体策略的详细说明:

一、读写缓存策略
  • 同步直写策略写入数据库时同步更新Redis缓存,确保两者数据实时一致。适用于对一致性要求极高的场景(如金融交易),但可能因同步操作增加响应延迟。

  • 异步缓写策略允许数据库更新后延迟更新Redis(如物流系统),通过消息队列(RabbitMQ/Kafka)补偿失败操作。适用于容忍短期不一致的场景,可提升系统吞吐量。

二、双检加锁策略

通过双重检查和互斥锁避免缓存穿透和并发问题:

  1. 首次检查:线程从Redis读取数据,若存在直接返回。
  2. 加锁检查:未命中时获取互斥锁,再次检查Redis(防止其他线程已写入)。
  3. 数据库查询:若仍未命中,从MySQL查询并写入Redis。
  4. 释放锁:后续线程直接使用缓存,避免重复查询。代码示例
public String get(String key) { String value = redisTemplate.get(key); if (value != null) return value; synchronized (RedisTest.class) { value = redisTemplate.get(key); if (value != null) return value; value = studentDao.get(key); redisTemplate.setnx(key, value, time); return value; }}三、数据库与缓存更新策略对比
  1. 先更新数据库,再更新Redis

    问题:若Redis更新失败,导致数据不一致。

    适用场景:无高并发写入的简单系统。

  2. 先更新Redis,再更新数据库

    问题:多线程下可能导致Redis与数据库数据永久不一致(如线程1更新Redis后崩溃,未更新数据库)。

    风险:高并发场景下极易出现数据错乱。

  3. 先删除缓存,再更新数据库

    问题:删除缓存后,线程可能读取旧数据库值并回写到Redis,导致不一致。

    改进方案:延时双删。

  4. 延时双删

    流程

    删除Redis缓存;

    更新MySQL;

    延迟一段时间(如2秒)后再次删除Redis。

    问题:延迟时间难以精准控制,且sleep操作降低系统性能。

    代码示例

public void deleteRedisData(Student stu) { jedis.del(stu); // 第一次删除 studentDao.update(stu); // 更新数据库 TimeUnit.SECONDS.sleep(2); // 延迟 jedis.del(stu); // 第二次删除}
  1. 先更新数据库,再删除缓存(推荐)

    流程

    更新MySQL;

    删除Redis缓存;

    若删除失败,通过消息中间件重试。

    优势:避免延时操作,结合消息队列实现最终一致性。

    完整方案

    更新数据库;

    数据库binlog触发订阅程序;

    订阅程序提取key并尝试删除Redis;

    失败时将数据发送至消息队列;

    消费者从队列获取数据并重试删除。

四、MySQL主从复制对一致性的影响
  • 原理

    Master写入数据变更到二进制日志(binlog);

    Slave通过I/O线程拉取binlog并保存为中继日志(relay log);

    SQL线程重放relay log以同步数据。

  • 问题:主从同步存在延迟(毫秒级),可能导致缓存删除后Slave未同步完成,此时查询Slave会得到旧数据。
  • 解决方案

    强制读主库(牺牲高可用性);

    延迟缓存删除时间(需评估业务容忍度);

    使用中间件(如Canal)监听binlog并触发缓存更新。

五、策略选择建议
  • 强一致性场景:同步直写或“先更新数据库再删除缓存”+消息队列。
  • 最终一致性场景:异步缓写或延时双删(需权衡延迟与性能)。
  • 高并发场景:双检加锁或分布式锁(如Redlock)避免缓存击穿。
  • 避免方案:单独使用“先删除缓存再更新数据库”或“先更新缓存再更新数据库”。

总结:推荐采用“先更新数据库,再删除缓存”结合消息中间件的方式,通过异步补偿机制实现最终一致性,兼顾性能与可靠性。对于极端场景,可结合业务特点选择同步直写或分布式锁强化一致性。