Redis技术评审要点

Posted sysu_lluozh

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了Redis技术评审要点相关的知识,希望对你有一定的参考价值。

针对redis在技术方案评审或测试方案设计时的一些注意要点

一、大key

1.1 定义

  1. 单个简单的key存储的value很大
  2. hash、set、list中存储过多的元素

1.2 场景

  1. 热门话题下评论、答案排序场景
  2. 大V的粉丝列表
  3. 使用不恰当,或者对业务预估不准确、不及时进行处理垃圾数据等

1.3 风险:

  1. 单个size太大,并发高容易把redis带宽打满
  2. 读写大key会导致超时严重,甚至阻塞服务
  3. 如果删除大key或者自动过期,DEL命令可能阻塞Redis进程数十秒,使得其他请求阻塞

redis是单线程,操作bigkey比较耗时,那么阻塞 redis的可能性增大

1.4 应对

  1. 单个简单的key存储的value很大
  • 对象需要每次都整存整取

将对象分拆成几个key-value, 使用multiGet获取值,这样分拆的意义在于分拆单次操作的压力,将操作压力平摊到多个redis实例中,降低对单个redis的IO影响

  • 该对象每次只需要存取部分数据

可以将对象分拆成几个key-value, 也可以将这个存储在一个hash中,每个field代表一个具体的属性,使用hget、hmget来获取部分的value,使用hset、hmset来更新部分属性

  1. hash、set、list 中存储过多的元素

可以对存储元素按一定规则进行分类,分散存储到多个redis实例中
比如:一个缓存原来按游戏类别下的所有游戏名称以及开发商信息,单个key大于1M,可以拆分成按照游戏类别+开发商单独缓存,每次根据游戏类别+开发商信息来取游戏名称

二、Hot key

2.1 定义

Hot key,即热点key
指的是在一段时间内,该key的访问量远远高于其他的redis key,导致大部分的访问流量在经过 proxy分片之后,都集中访问到某一个redis 实例上

2.2 场景

hot key 通常在不同业务中,存储着不同的热点信息

  1. 新闻应用中的热点新闻内容
  2. 活动系统中某个用户疯狂参与的活动的活动配置
  3. 商城秒杀系统中,最吸引用户眼球,性价比最高的商品信息

2.3 风险

瞬间有几十万的请求去访问redis上某个固定的key,导致某个redis机器负载很高,从而压垮缓存服务的情况

2.4 应对

  1. 使用本地缓存

应用服务加本地缓存,从而降低了redis集群对hot key的访问量

但是同时带来的问题

  • 本地缓存要能存放完该key的所有业务数据,本地缓存是否会过大
  • 如果对可能成为hot key的key都进行本地缓存,本地缓存是否会过大,从而影响应用程序本身所需的缓存开销
  • 如何保证本地缓存和redis集群数据的有效期的一致性
  1. 主动识别hot key

在proxy加额外功能,实现主动发现及识别hot key,并主动缓存其值

  1. 打散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 应对

  1. 设置热点数据永远不过期

  2. 接口限流与熔断、降级

  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 应对

  1. 缓存数据的过期时间增加设置随机因子,防止同一时间大量数据过期现象发生
  2. 如果缓存数据库是分布式部署,将热点数据均匀分布在不同缓存数据库中
  3. 设置热点数据永远不过期
  4. 同缓存击穿中的加互斥锁实现串行回源db,保证同一个key只能单个线程回到db去查询

五、缓存穿透

5.1 定义

指查询一个一不存在的数据
例如:从缓存redis没有命中,需要从mysql数据库查询,查不到数据则不写入缓存,这将导致这个不存在的数据每次请求都要到数据库去查询,造成缓存穿透

5.2 风险

增加db负载,高并发可能搞挂db

5.3 应对

  1. 缓存空对象,将null变成一个值

如果一个查询返回的数据为空(不管是数据不存在,还是系统故障),仍然把这个空结果进行缓存,但它的过期时间会很短,最长不超过五分钟

这样设置可能有两个问题:

  • 空值做了缓存导致缓存层中存了更多的键

需要更多的内存空间(如果是攻击,问题更严重),比较有效的方法是针对这类数据设置一个较短的过期时间,让其自动剔除

  • 缓存层和存储层的数据会有一段时间窗口的不一致

可能会对业务有一定影响,例如过期时间设置为5分钟,如果此时存储层添加了这个数据,那此段时间就会出现缓存层和存储层数据的不一致,此时可以利用消息系统或者其他方式清除掉缓存层中的空对象

  1. 布隆过滤器

将所有可能存在的数据哈希到一个足够大的bitmap中,一个一定不存在的数据会被这个bitmap拦截掉因此不需要回源,从而避免了对底层存储系统的查询压力

六、超时时间

key的超时时间设置是否合理

七、数据一致性

主要考虑内存值更新的入口考虑是否全面,要保证每个触发db变更的入口都有更新缓存

DB和缓存更新的顺序的合理性

八、冷数据

8.1 风险

上线新功能时大量冷数据读取都需要先回DB查询再反写redis,响应时间长,db负载高

8.2 应对

缓存预热

九、缓存故障

9.1 定义

缓存如果出现故障的兜底策略

9.2 风险

当出现上述任何一个故障导致缓存及DB短时间无法恢复时,如果没有兜底方案,则业务影响范围扩大,可能引起整个系统的雪崩效应

9.3 应对

制定明确的业务熔断降级策略

十、持久化

AOF:
日志回放

RDB:
内存快照

十一、LRU策略

定义:
从时间维度,把最近被访问到到key保留,把最近最少使用到的key剔除(其核心思想是如果数据被访问过,那么将来被访问的几率也更高)

算法类别:

  1. volatile-lru:设置了过期时间的key使用LRU算法淘汰
  2. volatile-ttl:设置了过期时间的key根据过期时间淘汰,越早过期越早淘汰

配置项:

  1. maxmenory:配置Redis存储数据时指定限制的内存大小,比如100M,当缓存消耗的内存超过这个值时将出发数据淘汰

以上是关于Redis技术评审要点的主要内容,如果未能解决你的问题,请参考以下文章

让评审人爱上你的8个要点

软件开发技术基础复习要点

翻译-高质量JavaScript代码书写基本要点

html 这个要点包含使用RightCare品牌创建浮动框的片段。

测试要点

redis要点