目录

Redis和MySQL如何保持数据一致性

在高并发的场景下,大量的请求直接访问 MySQL 很容易造成性能问题。所以,我们都会用 Redis 来做数据的缓存,削减对数据库的请求。

但是,MySQL 和 Redis 是两种不同的数据库,如何保证不同数据库之间数据的一致性就非常关键了。

数据不一致的原因

  1. 在高并发的业务场景下,数据库大多数情况都是用户并发访问最薄弱的环节。
  2. 所以,就需要使用 redis 做一个缓冲操作,让请求先访问到 redis,而不是直接访问 MySQL 等数据库。
  3. 读取缓存步骤一般没有什么问题,但是一旦涉及到数据更新:数据库和缓存更新,就容易出现缓存(Redis)和数据库(MySQL)间的数据一致性问题。
  4. 这个业务场景,主要是解决读数据从 Redis 缓存,一般都是按照下图的流程来进行业务操作。

缓存先后删除问题

不管是先写 MySQL 数据库,再删除 Redis 缓存;还是先删除缓存,再写库,都有可能出现数据不一致的情况。

先删除缓存

  1. 如果先删除 Redis 缓存数据,然而还没有来得及写入 MySQL,另一个线程就来读取
  2. 这个时候发现缓存为空,则去 Mysql 数据库中读取旧数据写入缓存,此时缓存中为脏数据。
  3. 然后数据库更新后发现 Redis 和 Mysql 出现了数据不一致的问题

后删除缓存

  1. 如果先写了库,然后再删除缓存,不幸的写库的线程挂了,导致了缓存没有删除
  2. 这个时候就会直接读取旧缓存,最终也导致了数据不一致情况
  3. 因为写和读是并发的,没法保证顺序,就会出现缓存和数据库的数据不一致的问题

解决方案

  • 延时双删策略

    基本思路:

    在写库前后都进行 redis.del(key)操作,并且设定合理的超时时间。

    具体步骤:

    1. 先删除缓存
    2. 再写数据库
    3. 休眠 500 毫秒
    4. 再次删除缓存

    问题:这个 500 毫秒怎么确定的,具体该休眠多久时间呢?

    1. 需要评估自己的项目的读数据业务逻辑的耗时。
    2. 这么做的目的,就是确保读请求结束,写请求可以删除读请求造成的缓存脏数据。
    3. 当然这种策略还要考虑 redis 和数据库主从同步的耗时。
    4. 最后的的写数据的休眠时间:则在读数据业务逻辑的耗时基础上,加几百 ms 即可。

    比如:休眠 1 秒。

    设置缓存过期时间是关键点

    1. 从理论上来说,给缓存设置过期时间,是保证最终一致性的解决方案
    2. 所有的写操作以数据库为准,只要到达缓存过期时间,缓存删除
    3. 如果后面还有读请求的话,就会从数据库中读取新值然后回填缓存

    方案缺点

    结合双删策略+缓存超时设置,这样最差的情况就是:

    1. 在缓存过期时间内发生数据存在不一致
    2. 同时又增加了写请求的耗时。
  • 异步更新缓存(基于 Mysql binlog 的同步机制)

    整体思路:

    1. 涉及到更新的数据操作,利用 Mysql binlog 进行增量订阅消费
    2. 将消息发送到消息队列
    3. 通过消息队列消费将增量数据更新到 Redis 上
    4. 操作情况

    读取 Redis 缓存:热数据都在 Redis 上 写 Mysql:增删改都是在 Mysql 进行操作 更新 Redis 数据:Mysql 的数据操作都记录到 binlog,通过消息队列及时更新到 Redis 上

    Redis 更新过程

    数据操作主要分为两种:

    1. 一种是全量(将所有数据一次性写入 Redis)
    2. 一种是增量(实时更新)

    这里说的是增量,指的是 mysql 的 update、insert、delate 变更数据。

    读取 binlog 后分析 ,利用消息队列,推送更新各台的 redis 缓存数据。

    1. 这样一旦 MySQL 中产生了新的写入、更新、删除等操作,就可以把 binlog 相关的消息推送至 Redis
    2. Redis 再根据 binlog 中的记录,对 Redis 进行更新
    3. 其实这种机制,很类似 MySQL 的主从备份机制,因为 MySQL 的主备也是通过 binlog 来实现的数据一致性

    这里的消息推送工具你也可以采用别的第三方:kafka、rabbitMQ 等来实现推送更新 Redis!

总结

在高并发应用场景下,如果是对数据一致性要求高的情况下,要定位好导致数据和缓存不一致的原因。

解决高并发场景下数据一致性的方案有两种,分别是延时双删策略和异步更新缓存两种方案。

另外,设置缓存的过期时间是保证数据保持一致性的关键操作,需要结合业务进行合理的设置。

参考

https://mp.weixin.qq.com/s/OkVbgFwy6w_RPmWIycsAEw