Redis 缓存

Redis 缓存

Redis 可作为关系型数据库的缓存,存储热点数据加快访问速度

服务端缓存:在访问 DB 后将请求参数作为 key,回包内容作为 value 进行缓存
客户端缓存:对服务端 RPC 调用后,将结果存储在客户端

缓存模式

数据库和缓存如何保证一致性? | 小林coding (xiaolincoding.com)

Cache Aside 旁路缓存

最常见的策略

读策略:
应用服务查询数据是否在缓存上,在则直接返回缓存数据,否则从数据库查询并放到缓存中

除了查库后加载这种模式,如果业务有需要,还可以预加载数据到缓存

写策略:

  1. 先更新数据库
  2. 后删除缓存

Read/Write Through 读/写穿透

读穿透:
应用服务不和缓存直接交互,而是访问数据服务,数据服务查询数据是否在缓存上,不在则从数据库查询

写穿透:
所有的写操作都经过缓存,每次向缓存中写数据的时候,缓存会把数据持久化到对应的数据库中去,且这两个操作都在一个事务中完成
因此,只有两次都写成功了才是最终写成功了

Write Behind

Write Through 的异步更新版本,在写入一段时间后将数据一起写入数据库

缓存一致性

Redis 缓存更新一致性 - -Finley- - 博客园 (cnblogs.com)

缓存一致性指缓存和数据库中数据的一致性

完全避免缓存不一致只有使用锁,包括 CAS 乐观锁,分布式锁(悲观锁),分布式事务
实践过程中也可以使用延时双删极大的降低不一致概率
订阅 binglog 可以避免写线程相互竞争, 但避免不了读写线程竞争

不完全解决

过期依赖

更新时仅更新数据库不处理缓存,等待 Redis 缓存过期失效后从 Mysql 拉取新数据

优点:

删除缓存

删除缓存可以保证缓存中不因为更新出现错误数据,但可能因为删除失败而使得旧数据长时间保留

弥补方式

为什么是删除缓存,而不是更新缓存呢?

删除一个数据,相比更新一个数据更加轻量级,出问题的概率更小
在实际业务中,缓存的数据可能不是直接来自数据库表,也许来自多张底层数据表的聚合。比如商品详情信息,在底层可能会关联商品表、价格表、库存表等,如果更新了一个价格字段,那么就要更新整个数据库,还要关联的去查询和汇总各个周边业务系统的数据,这个操作会非常耗时
从另外一个角度,不是所有的缓存数据都是频繁访问的,更新后的缓存可能会长时间不被访问,所以说,从计算资源和整体性能的考虑,更新的时候删除缓存,等到下次查询命中再填充缓存,是一个更好的方案
系统设计中有一个思想叫 Lazy Loading,适用于那些加载代价大的操作,删除缓存而不是更新缓存,就是懒加载思想的一个应用

订阅 binlog

将搭建的消费服务作为 Mysql 的一个从服务器,订阅 Mysql 的 binlog 日志,解析日志内容后更新至 redis

CAS

CAS 乐观锁当且仅当客户端最后一次取值后该 key 没有被其他客户端修改的情况下,才允许当前客户端将新值写入

分布式锁

在每次更新前获取分布式排他锁保证一致性

缓存异常

什么是缓存雪崩、击穿、穿透? | 小林coding

缓存异常的三个常见问题分别是缓存雪崩、缓存击穿、缓存穿透

通常会给缓存数据设置过期时间,缓存过期后重新从数据库中取数据并更新至缓存

缓存雪崩

缓存雪崩指同一时间发生大量缓存数据的过期或 Redis 故障宕机时,大量请求直接访问数据库导致数据库压力过大崩溃

解决方法

缓存击穿

缓存击穿指缓存中某个热点数据过期后被大量的请求访问,高并发请求直接访问数据库导致数据库崩溃

解决方案:

缓存穿透

缓存穿透指大量请求访问不存在的数据导致数据库压力骤增

解决方案:

布隆过滤器基于哈希实现,存在 hash 冲突的可能
布隆过滤器说数据存在,并不一定证明数据库中存在这个数据,但是查询到数据不存在,数据库中一定就不存在这个数据

布隆过滤器

布隆过滤器是一个 bit 向量或者说 bit 数组
一个值被映射到布隆过滤器的方式是使用多个不同的哈希函数生成多个哈希值,并将 bit 数组中对应的位置置 1
多个值之间会产生覆盖(哈希值对应的位置相同),因此不能判断一个值一定存在
如果一个值对应的位置上为 0,则其一定不存在

特殊 Key

Hot Key

原因: Hot key 引发缓存系统异常,主要是因为突发热门事件发生时,超大量的请求访问热点事件对应的 key,流量集中打在一个缓存节点机器,这个缓存机器很容易被打到物理网卡、带宽、CPU 的极限,从而导致缓存访问变慢、卡顿

解决方案:
首先找到 Hot Key

Big Key

大 key,是指在缓存访问时,部分 Key 的 Value 过大,进而引发的读写、加载易超时的现象

原因:

解决方案: