redis 缓存
redis更新策略
内存淘汰:不用自己维护,利用Redis的内存淘汰机制,当内存不足时自动进行淘汰部分数据。下次查询时更新缓存。一致性较差。维护成本 基本无
超时剔除:给缓存数据进行添加TTL时间(具体是expire方法),到期后自己会自动进行删除缓存。下次查询时进行更新缓存。
内存淘汰 | 超时剔除 | 主动更新 | |
---|---|---|---|
说明 | 不用自己维护,利用Redis的内存淘汰说明机制,当内存不足时自动淘汰部分数据。下次查询时更新缓存 | 给缓存数据添加TTL时间,到期后自动删除缓存。下次查询时更新缓存。 | 编写业务逻辑,在修改数据库的同时,更新缓存。 |
一致性 | 差 | 一般 | 好 |
维护成本 | 无 | 低 | 高 |
主动更新策略
考虑的问题:
操作缓存和数据库时有三个问题需要考虑:
- 1.删除缓存还是更新缓存?
- 更新缓存:每次更新数据库都更新缓存,无效写操作较多
- 删除缓存:更新数据库时让缓存失效,查询时再更新缓存
- 2.如何保证缓存与数据库的操作的同时成功或失败?
- 单体系统,将缓存与数据库操作放在一个事务
- 分布式系统,利用TCC等分布式事务方案
- 3.先操作缓存还是先操作数据库?
- 先删除缓存,再操作数据库
- 先操作数据库,再删除缓存
TCC概念
分布式TCC(Try-Confirm-Cancel)是一种用于分布式系统中的事务管理模式,特别适用于分布式环境下的业务一致性控制。TCC事务模式通过将一个全局事务分为三个阶段来确保事务的原子性、一致性和可恢复性,避免在分布式环境中出现部分成功、部分失败的情况。
1.删除缓存还是更新缓存?
我们选择的是删除缓存,更新数据库时让缓存失效,查询时再更新缓存。
原因:
因为我们利用缓存,就是仅仅当我们对数据库进行查询时,利用缓存来代替直接查询数据库的操作。但是对于更新数据库数据的操作,我们本来就不经过缓存而是直接去进行数据库进行操作的,所以说同时更新缓存是无效的。使用的是延迟加载策略,当查询数据库数据的时候再进行更新缓存中的数据。
2.如何保证缓存与数据库的操作的同时成功或失败?
对于单体系统,将缓存与数据库操作放在一个事务
对于分布式系统,利用的是TCC等分布式事务方案
3.先操作缓存还是先操作数据库?
我们使用的是:先操作数据库再删除缓存,后面通过出现异常的概率来说明为什么
无论是先操作缓存还是先操作数据库,我们都要明白一个点:
对于缓存的操作的速率是远远大于操作数据库的速率的 。
当是正常情况时(无穿插):
当出现异常情况,穿插的情况时:我们分析这两种情况触发的概率:
(1)先操作数据库,再删除缓存:
先开启一个线程1,在查询的时候,缓存恰好失效。那么此时缓存显然未命中,那么要去进行查询数据库的数据。但是在查询的过程中,正好开启的线程2进行了更新数据库的操作v=20并且执行删除缓存操作。此时线程1查询数据库数据查询到了为v=10,并且把v=10写入缓存。但其实线程2已经把数据库数据更新为v=20了,所以此时出现异常。
分析概率大小:
我们知道查询缓存的速率是远远快于查询数据库数据的。
前提条件为:缓存恰好在查询缓存的时候失效。
在查询数据库并且写入缓存的时候,又更新数据库并且删除缓存的情况是极低的
(2)先删除缓存,再操作数据库:
这种出现异常的概率较大。因为更新数据库的操作这一时间段是远远大于操作缓存的时间的。所以说发生的可能性会大很大相比于上一个操作顺序
通过概率进行比较可以得出,我们选择发生异常概率小的情况1:先操作数据库,再删除缓存
缓存更新策略的最佳实践方案:
1.低一致性需求:使用Redis自带的内存淘汰机制
2.高一致性需求:主动更新,并以超时剔除作为兜底方案
- 2.1 读操作:缓存命中则直接返回,缓存未命中则查询数据库,并写入缓存,设定超时时间(即是expire方法),当超过超时时间还没有查询该缓存中的数据时,就会缓存自己死亡。这就是超时时间的意义。
- 2.2 写操作:先写数据库,然后再删除缓存,要确保数据库与缓存操作的原子性