Mysql和Redis是一样的吗?数据如何一致?
先澄清一下Mysql和Redis的关系:Mysql是一个数据库,用来持久化数据,一定程度上保证数据的可靠性; Redis作为缓存,提高数据访问性能。
这是一个非常经典的问题,关于Mysql和Redis中如何保证数据一致性(即缓存一致性问题)。
使用过缓存的人都应该知道,在实际应用场景中很难保证缓存始终与数据库中的数据相同。
基本上,他们在大多数时间都试图保持数据一致,并确保最终是一致的。
缓存不一致是如何发生的
如果数据没有改变,就不会出现缓存不一致问题。
通常在数据发生变化时会出现缓存不一致的情况。因为每次数据发生变化,你都要同时操作数据库和缓存,而且它们分属不同的系统。不可能同时成功或失败。总会有时间差。同时读写时会出现缓存不一致的问题(理论上可以通过分布式事务来保证,但实践中很少有人这样做)。
虽然无法保证数据变化时缓存与数据库的强一致性,但是缓存更新还是有一定的设计方法的。遵循这些设计方法可以最大限度地减少这种不一致的影响时间和程度。
多种缓存刷新设计
缓存刷新设计方式大概有四种:
- 先清除缓存,再刷新数据库(这种方式在并发时最容易产生脏数据,而且不能
- 先更新数据库,删除缓存(Cache Aside Pattern)
- 只更新缓存,缓存本身同步更新数据库(Read/Write Through Pattern)
- 只更新缓存,缓存本身异步更新数据库(write Behind cache模式)
接下来详细介绍这四种设计方法中的一些
先删除缓存,再更新数据库
这种方法是同时读写容易出现缓存不一致问题
如上图所示,可能的执行流程顺序为:
- 客户1触发更新数据逻辑 客户2触发查询数据逻辑A
- 客户 1 删除了缓存中的数据 A
- 客户 2 在缓存中查询数据 A 并错过了
- 客户 2 从数据库中查询数据 A 并更新到缓存中
- 客户端1更新数据库中的数据A
。可以看到,缓存中最新的数据A与数据库中的数据A不一致。缓存中的数据A是旧的脏数据。
因此,通常不推荐这种方法。
先更新数据库,再使缓存失效
该方法在并发读写的情况下也可能会造成临时缓存不一致
如上图所示,其可能的执行流程顺序为:
- 客户 1 触发更新数据 A 的逻辑
- 客户 2 触发查询数据 A 的逻辑
- 客户 3 触发查询数据 A 的逻辑
- 数据更新
- 客户 2 查询数据 A
- 客户 1 使缓存中的数据 A 失效
- 客户 3 查询缓存中的数据 A,未命中
- 客户 3 查询数据库中的数据 A 并更新到缓存
可以看到,最终缓存中的数据A与数据库中的数据A是匹配的。理论上,数据不一致可能会在短时间内出现,但这种概率比较低。 ,大多数公司不会出现大问题。
只更新缓存,缓存本身同步更新数据库(Read/Write Through Pattern)
该方式对应业务只更新缓存,然后缓存同步更新数据库。 Write Through 的示例如下:
如上图所示,可能的执行流程顺序为:
- 客户端 1 触发更新数据 A 的逻辑
- 通过查询触发客户端 2数据 A
- 客户端 1 更新缓存中的数据 A,缓存同步更新数据库中的数据 A,然后返回结果
- 客户端 2 查询缓存中的数据 A,返回
Read Through 和 WriteThrough 流程类似,只是当客户端查询数据A时,如果缓存中的数据A无效(过期或者抛出),缓存会与数据库中的查询数据A同步,缓存起来,然后返回给客户端
这种方法与缓存不一致。概率极低,但必须专门修改缓存。
只更新缓存,缓存本身异步更新数据库(Write Behind Cache Pattern)
这种方式比较具体,所以业务操作只更新缓存,然后缓存异步更新数据库,例如:
如上图所示,可能的执行流程顺序是:
- 客户1触发更新数据A的逻辑
- 客户端2触发查询数据A的逻辑
- 客户端1更新缓存中的数据A并返回
- 客户端2查询缓存中的数据A并返回
- 缓存将数据A异步更新到数据库 优点这种方法的优点是读写性能非常好。基本上,只要内存被服务,它就会返回给客户端。但是,它的一致性不高,可能会导致数据丢失。
如果缓存异步更新数据到数据库时缓存服务崩溃,则未更新到数据库的数据将会丢失。
总结
上面提到的很多缓存更新设计方法都是前人总结的经验。这些方法或多或少都有缺点,并不完美。事实上,做到完美是很难的。的设计。在进行系统设计时,不应该追求完美。你应该做出一些权衡,找到最适合你业务场景的方法
作者:追光者
版权声明
本文仅代表作者观点,不代表Code前端网立场。
本文系作者Code前端网发表,如需转载,请注明页面地址。
发表评论:
◎欢迎参与讨论,请在这里发表您的看法、交流您的观点。