Redis技术评审要点
Posted sysu_lluozh
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了Redis技术评审要点相关的知识,希望对你有一定的参考价值。
针对redis在技术方案评审或测试方案设计时的一些注意要点
一、大key
1.1 定义
- 单个简单的key存储的value很大
- hash、set、list中存储过多的元素
1.2 场景
- 热门话题下评论、答案排序场景
- 大V的粉丝列表
- 使用不恰当,或者对业务预估不准确、不及时进行处理垃圾数据等
1.3 风险:
- 单个size太大,并发高容易把redis带宽打满
- 读写大key会导致超时严重,甚至阻塞服务
- 如果删除大key或者自动过期,DEL命令可能阻塞Redis进程数十秒,使得其他请求阻塞
redis是单线程,操作bigkey比较耗时,那么阻塞 redis的可能性增大
1.4 应对
- 单个简单的key存储的value很大
- 对象需要每次都整存整取
将对象分拆成几个key-value, 使用multiGet获取值,这样分拆的意义在于分拆单次操作的压力,将操作压力平摊到多个redis实例中,降低对单个redis的IO影响
- 该对象每次只需要存取部分数据
可以将对象分拆成几个key-value, 也可以将这个存储在一个hash中,每个field代表一个具体的属性,使用hget、hmget来获取部分的value,使用hset、hmset来更新部分属性
- hash、set、list 中存储过多的元素
可以对存储元素按一定规则进行分类,分散存储到多个redis实例中
比如:一个缓存原来按游戏类别下的所有游戏名称以及开发商信息,单个key大于1M,可以拆分成按照游戏类别+开发商单独缓存,每次根据游戏类别+开发商信息来取游戏名称
二、Hot key
2.1 定义
Hot key,即热点key
指的是在一段时间内,该key的访问量远远高于其他的redis key,导致大部分的访问流量在经过 proxy分片之后,都集中访问到某一个redis 实例上
2.2 场景
hot key 通常在不同业务中,存储着不同的热点信息
- 新闻应用中的热点新闻内容
- 活动系统中某个用户疯狂参与的活动的活动配置
- 商城秒杀系统中,最吸引用户眼球,性价比最高的商品信息
2.3 风险
瞬间有几十万的请求去访问redis上某个固定的key,导致某个redis机器负载很高,从而压垮缓存服务的情况
2.4 应对
- 使用本地缓存
应用服务加本地缓存,从而降低了redis集群对hot key的访问量
但是同时带来的问题
- 本地缓存要能存放完该key的所有业务数据,本地缓存是否会过大
- 如果对可能成为hot key的key都进行本地缓存,本地缓存是否会过大,从而影响应用程序本身所需的缓存开销
- 如何保证本地缓存和redis集群数据的有效期的一致性
- 主动识别hot key
在proxy加额外功能,实现主动发现及识别hot key,并主动缓存其值
- 打散hot key处理
利用分片算法的特性,对key进行打散处理
hot key之所以是hot key,因为它只有一个key,落地到一个实例上
所以可以给hot key加上前缀或者后缀,把一个hot key的数量变成redis实例个数N的倍数M,从而由访问一个redis key变成访问N * M个redis key,N*M个redis key经过分片分布到不同的实例上,将访问量均摊到所有实例
三、缓存击穿
3.1 定义
缓存中没有但数据库中有的数据(一般是缓存时间到期)
由于高并发导致同时读缓存没读到数据需同时回源到DB,引起数据库压力瞬间增大,造成过大压力
3.2 风险
db瞬间被拖垮,影响其他业务
3.3 应对
-
设置热点数据永远不过期
-
接口限流与熔断、降级
-
加互斥锁实现串行回源db
public String get(key) {
String value = redis.get(key);
if (value == null) { //代表缓存值过期
//设置3min的超时,防止del操作失败的时候,下次缓存过期一直不能load db
if (redis.setnx(key_mutex, 1, 3 * 60) == 1) { //代表设置成功
value = db.get(key);
redis.set(key, value, expire_secs);
redis.del(key_mutex);
} else { //这个时候代表同时候的其他线程已经load db并回设到缓存了,这时候重试获取缓存值即可
sleep(100);
get(key); //重试
}
} else {
return value;
}
}
- 缓存中有数据,直接返回缓存的数据
- 缓存中没有数据,第1个进入的线程,获取锁并从数据库去取数据,没释放锁之前,其他并行进入的线程会等待100ms,再重新去缓存取数据(这样就防止都去数据库重复取数据,重复往缓存中更新数据情况出现)
加互斥锁实现串行回源db,保证同一个key只能单个线程回到db取查询串行回源
四、缓存雪崩
4.1 定义
指缓存中某个时间节点,大量key到过期时间,而同时查询数据量巨大,从缓存获取不到数据回源引起db压力过大甚至down机
与缓存击穿不同的是,缓存击穿指并发查同一条数据,缓存雪崩是不同数据都过期了,很多数据都查不到从而查数据库
4.2 风险
db瞬间被拖垮,影响其他业务
4.3 应对
- 缓存数据的过期时间增加设置随机因子,防止同一时间大量数据过期现象发生
- 如果缓存数据库是分布式部署,将热点数据均匀分布在不同缓存数据库中
- 设置热点数据永远不过期
- 同缓存击穿中的加互斥锁实现串行回源db,保证同一个key只能单个线程回到db去查询
五、缓存穿透
5.1 定义
指查询一个一不存在的数据
例如:从缓存redis没有命中,需要从mysql数据库查询,查不到数据则不写入缓存,这将导致这个不存在的数据每次请求都要到数据库去查询,造成缓存穿透
5.2 风险
增加db负载,高并发可能搞挂db
5.3 应对
- 缓存空对象,将null变成一个值
如果一个查询返回的数据为空(不管是数据不存在,还是系统故障),仍然把这个空结果进行缓存,但它的过期时间会很短,最长不超过五分钟
这样设置可能有两个问题:
- 空值做了缓存导致缓存层中存了更多的键
需要更多的内存空间(如果是攻击,问题更严重),比较有效的方法是针对这类数据设置一个较短的过期时间,让其自动剔除
- 缓存层和存储层的数据会有一段时间窗口的不一致
可能会对业务有一定影响,例如过期时间设置为5分钟,如果此时存储层添加了这个数据,那此段时间就会出现缓存层和存储层数据的不一致,此时可以利用消息系统或者其他方式清除掉缓存层中的空对象
- 布隆过滤器
将所有可能存在的数据哈希到一个足够大的bitmap中,一个一定不存在的数据会被这个bitmap拦截掉因此不需要回源,从而避免了对底层存储系统的查询压力
六、超时时间
key的超时时间设置是否合理
七、数据一致性
主要考虑内存值更新的入口考虑是否全面,要保证每个触发db变更的入口都有更新缓存
DB和缓存更新的顺序的合理性
八、冷数据
8.1 风险
上线新功能时大量冷数据读取都需要先回DB查询再反写redis,响应时间长,db负载高
8.2 应对
缓存预热
九、缓存故障
9.1 定义
缓存如果出现故障的兜底策略
9.2 风险
当出现上述任何一个故障导致缓存及DB短时间无法恢复时,如果没有兜底方案,则业务影响范围扩大,可能引起整个系统的雪崩效应
9.3 应对
制定明确的业务熔断降级策略
十、持久化
AOF:
日志回放
RDB:
内存快照
十一、LRU策略
定义:
从时间维度,把最近被访问到到key保留,把最近最少使用到的key剔除(其核心思想是如果数据被访问过,那么将来被访问的几率也更高)
算法类别:
- volatile-lru:设置了过期时间的key使用LRU算法淘汰
- volatile-ttl:设置了过期时间的key根据过期时间淘汰,越早过期越早淘汰
配置项:
- maxmenory:配置Redis存储数据时指定限制的内存大小,比如100M,当缓存消耗的内存超过这个值时将出发数据淘汰
以上是关于Redis技术评审要点的主要内容,如果未能解决你的问题,请参考以下文章