reids缓存设计

mac2024-05-30  44

11.1 缓存更新策略

分别从使用场景、一致性、开发维护成本三个角度分析三种缓存更新策略。

1 LRU/LFU/FIFO 淘汰策略

使用场景:当缓存的大小超过了设置的内存最大值时,需要根据淘汰策略对多出的数据进行清除; 一致性: 一致性较差, 清除的数据是由淘汰策略算法决定; 开发成本:开发成本较低,只需要设置maxmemory和淘汰策略算法即可,不需要额外的开发工作。

2 超时剔除

使用场景:业务上允许缓存层和数据层在一段时间可以不同, 可以使用此方式。 对缓存的数据设置过期 时间,当超过了过期时间缓存会自动清除掉, 下次在访问时,会从数据库从获取最新的数据到缓存中; 一致性: 一致性差, 一段时间缓存层和数据层属于不一致; 开发成本: 开发成本低,只需要设置缓存的过期时间即可。

3 主动更新

使用场景: 当需要缓存层的数据和数据库层数据一致性要求高,当数据更新时,需要实时更新到缓存层; 一致性:一致性较高; 开发成本:开发成本高,当数据更新时需要同步维护缓存数据。

三种缓存策略实际使用总结: 1)对缓存数据一致性要求不高, 可以设置最大内存和选择淘汰策略这种方式; 2)对缓存数据要求实时性高,需要用主动更新加超时剔除一起使用,避免主动更新出问题后,能及时清除掉 失效的缓存。

4 内存回收策略

在redis.conf 里面有个配置策略 maxmemory-policy ,它有几个可选值: noeviction: 默认的策略,即当内存使用达到阈值的时候,所有引起申请内存的命令都会报错; allkeys-lru:从数据集(server.db[i].dict)中挑选最近最少使用的数据淘汰 。 适用场景: 如果我们的应用对缓存的访问都是相对热点数据,就可以选择这个策略; allkeys-random:随机移除某个key。 适合的场景:如果我们的应用对于缓存key的访问概率相等,则可以使用这个策略。

从已经设置了过期时间的key中去选择 volatile-random:从已设置过期时间的数据集(server.db[i].expires)中任意选择数据淘汰。 volatile-lru:从已设置过期时间的数据集(server.db[i].expires)中挑选最近最少使用的数据淘汰。 volatile-ttl:从已设置过期时间的数据集(server.db[i].expires)中挑选将要过期的数据淘汰;适合场景:这种策略使我们可以向Redis提示哪些key更适合被淘汰,可以自己控制 。

策略选择好后, 需要设置内存的最大值,当超过内存最大值时,redis才会使用设置的回收策略。

11.2 缓存的粒度

在实际使用缓存的时候,缓存所有属性还是部分属性, 需要从通用性、空间占用、代码维护三个维度分析。

通用性: 缓存所有属性通用性好,但是实际工作上,在很长的一段时间只是维护几个属性字段; 空间占用: 缓存所有属性会占用更多的内存,数据在序列化和反序列化会占用更多cpu资源; 代码维护: 缓存所有属性维护成本低, 而部分属性如果有变动需要经常更新代码。 总结: 实际使用过程, 要根据实际情况, 从通用性、空间占用、代码维护三个维度取舍。

11.3 缓存击穿

1. 击穿的过程

1) 缓存层中没有查询到数据 2) 存储层也没有查询到数据, 不将空结果返回给缓存; 3) 直接返回空结果

2. 原因

1)程序问题; 2)恶意攻击导致大批量查询不命中缓存。

3. 解决方案

1) 缓存空对象

从存储层未查询到数据,会先把空对象缓存起来, 之后在返回给客户端空值。

存在的问题: 当空对象存储的越来越多,会占用大量内存, 解决方式, 可以用为这些空对象的key设置极端超时时间, 过期后自动清除。

2) 布隆过滤器

在缓存层和存储层之前增加一个布隆过滤器, 专门存储key值存在的key,如果查询的数据不存在key, 会被过滤器直接过滤掉, 从而实现了第一层过滤。

两种方案的对比: 实际使用中, 需要根据适用场景、维护成本去权衡使用哪种方式。

11.4 缓存雪崩

1. 原因

当缓存层出现故障,导致所有请求都直接访问存储层,造成存储层负载过重,严重会把存储层搞崩溃。

2. 解决方案

1) 高可用设置 redis的哨兵、集群都能保证缓存的高可用

2)依赖隔离组件为后端限流并降级

最新回复(0)