Redis常见缓存问题及解决方案

缓存穿透

大量请求请求根本不存在的资源(DB本身就不存在,Redis更是不存在),就会将请求直接打在DB服务器上。

解决方案

  • 接口校验:对于id=-3872这些无效访问就直接拦截,不允许这些请求到达Redis、DB上。
  • 对空值进行缓存:虽然数据库中没有id=-3872的用户的数据,但是在redis中对他进行缓存(key=-3872,value=null),这样当请求到达redis的时候就会直接返回一个null的值给客户端,避免了大量无法访问的数据直接打在DB上。使用空值作为缓存的时候,key设置的过期时间不能太长,防止占用太多redis资源。
  • 使用布隆过滤器:存在的键值存在集合中,布隆过滤器可以用于检索一个元素是否在一个集合中。
  • 实时监控,设置白名单:对redis进行实时监控,当发现redis中的命中率下降的时候进行原因的排查,配合运维人员对访问对象和访问数据进行分析查询,从而进行黑名单的设置限制服务。

缓存击穿

redis中的某个热点key过期,但是此时有大量的用户访问该过期key,那么就会将请求直接打在DB服务器上,导致整个DB瘫痪。

解决方案

  • 使用setnx锁机制:只有一个请求可以获取到互斥锁,然后到DB中将数据查询并返回到Redis,之后所有请求就可以从Redis中得到响应
  • 提前对热点数据进行设置:对热点数据进行预先设置在redis中
  • 监控数据,适时调整key过期时间:监控哪些数据是热门数据,实时的调整key的过期时长

缓存雪崩

redis中大量的key集体过期,缓存服务故障或宕机

解决方案

  • 将失效时间分散开:常用且易于实现通过使用自动生成随机数使得key的过期时间TTL是随机的,防止集体过期。
  • 使用多级缓存架构
    使用nginx缓存 + redis缓存 + 其他缓存,不同层使用不同的缓存,可靠性更强。
  • 构建缓存高可用集群
    主要针对缓存服务故障的情景,使用Redis集群来提高服务的可用性。
  • 使用锁或者队列的方式
    如果查不到就加上排它锁,其他请求只能进行等待,但这种方式可能影响并发量。
  • 设置缓存标记
    热点数据可以不考虑失效,后台异步更新缓存,适用于不严格要求缓存一致性的情景。

热key

通常以其接收到的Key被请求频率来判定,例如:

  • QPS集中在特定的Key:Redis实例的总QPS(每秒查询率)为10,000,而其中一个Key的每秒访问量达到了7,000。
  • 带宽使用率集中在特定的Key:对一个拥有上千个成员且总大小为1 MB的HASH Key每秒发送大量的HGETALL操作请求。
  • CPU使用时间占比集中在特定的Key:对一个拥有数万个成员的Key(ZSET类型)每秒发送大量的ZRANGE操作请求。

引发的问题

  • 占用大量的CPU资源,影响其他请求并导致整体性能降低。
  • 集群架构下,产生访问倾斜,即某个数据分片被大量访问,而其他数据分片处于空闲状态,可能引起该数据分片的连接数被耗尽,新的连接建立请求被拒绝等问题。
  • 在抢购或秒杀场景下,可能因商品对应库存Key的请求量过大,超出Redis处理能力造成超卖。
  • 热Key的请求压力数量超出Redis的承受能力易造成缓存击穿,即大量请求将被直接指向后端的存储层,导致存储访问量激增甚至宕机,从而影响其他业务。

产生的原因

  • 预期外的访问量陡增,如突然出现的爆款商品、访问量暴涨的热点新闻、直播间某主播搞活动带来的大量刷屏点赞、游戏中某区域发生多个工会之间的战斗涉及大量玩家等。
  • 请求分片集中,超过单redis服务器的性能,比如固定名称key,hash落入同一台服务器,瞬间访问量极大,超过机器瓶颈,产生热点key问题。

如何监控发现

  • 凭借业务经验,进行预估哪些是热key
  • 业务侧自行监控和收集
  • 用redis自带命令
    (1)monitor命令:该命令可以实时抓取出redis服务器接收到的命令,然后写代码统计出热key是啥;当然,也有现成的分析工具可以给你使用,比如redis-faina;但是该命令在高并发的条件下,有内存增暴增的隐患,还会降低redis的性能。
    (2)hotkeys参数:redis 4.0.3提供了redis-cli的热点key发现功能,执行redis-cli时加上–hotkeys选项即可;但是该参数在执行的时候,如果key比较多,执行起来比较慢;

解决方案

  • 使用二级缓存
  • redis集群,,将热key分散到不同的服务器中
  • 热key拆分
  • 将核心/非核心业务做Redis的隔离

大key

通常以Key的大小和Key中成员的数量来综合判定,例如:

  • Key本身的数据量过大:一个String类型的Key,它的值为5 MB。
  • Key中的成员数过多:一个ZSET类型的Key,它的成员数量为10,000个。
  • Key中成员的数据量过大:一个Hash类型的Key,它的成员数量虽然只有1,000个但这些成员的Value(值)总大小为100 MB。

引发的问题

  • 客户端执行命令的时长变慢。
  • Redis内存达到maxmemory参数定义的上限引发操作阻塞或重要的Key被逐出,甚至引发内存溢出(Out Of Memory)。
  • 集群架构下,某个数据分片的内存使用率远超其他数据分片,无法使数据分片的内存资源达到均衡。
  • 对大Key执行读请求,会使Redis实例的带宽使用率被占满,导致自身服务变慢,同时易波及相关的服务。
  • 对大Key执行删除操作,易造成主库较长时间的阻塞,进而可能引发同步中断或主从切换。

产生的原因

  • 在不适用的场景下使用Redis,易造成Key的value过大,如使用String类型的Key存放大体积二进制文件型数据;
  • 业务上线前规划设计不足,没有对Key中的成员进行合理的拆分,造成个别Key中的成员数量过多;
  • 未定期清理无效数据,造成如HASH类型Key中的成员持续不断地增加;
  • 使用LIST类型Key的业务消费侧发生代码故障,造成对应Key的成员只增不减。

解决方案

  • 对大Key进行拆分
    例如将含有数万成员的一个HASH Key拆分为多个HASH Key,并确保每个Key的成员数量在合理范围。在Redis集群架构中,拆分大Key能对数据分片间的内存平衡起到显著作用。
  • 对大Key进行清理
    将不适用Redis能力的数据存至其它存储,并在Redis中删除此类数据。
  • 对过期数据进行定期清理
    堆积大量过期数据会造成大Key的产生,例如在HASH数据类型中以增量的形式不断写入大量数据而忽略了数据的时效性。可以通过定时任务的方式对失效数据进行清理。
  • 监控Redis的内存水位
    您可以通过监控系统设置合理的Redis内存报警阈值进行提醒,例如Redis内存使用率超过70%、Redis的内存在1小时内增长率超过20%等。通过此类监控手段,可以提前规避许多问题,例如LIST数据类型的消费程序故障造成对应Key的列表数量持续增长,将告警转变为预警从而避免故障的发生。

大key删除法

redis大key是让人比较头疼的问题,如果线上redis出现大key,断然不可立即执行del,因为大key的删除会造成阻塞。阻塞期间,所有请求都可能造成超时,当超时越来越多,新的请求不断进来,这样会造成redis连接池耗尽,尽而引发线上各种依赖redis的业务出现异常。

  • 低峰期删除
    在业务低峰期进行删除,造成的影响比较小,一般适用执行期间qps非常小的业务。
  • scan分批删除
    可以每次随机取一批数据,分批删除
  • 异步删除
    • unlink
      unlink命令只是将键与键空间断开连接。实际的删除将稍后异步进行。如果集合键的元素个数大于64个(详细后文),会把真正的内存释放操作,给单独的bio来操作

    • flushall、flushdb
      在执行flushall或者flushdb清空key的时候,增加了ASYNC选项 FLUSHALL [ASYNC],当用户没设置ASYNC的时候,此时的flush操作是阻塞的,当设置了ASYNC的时候,会建立一个新的空字典,然后指向它,老字典交给异步线程来慢慢删。

    • 被动删除
      被动删除指当一个key过期或者被淘汰,redis主动去删除。在4.0版本之前,自动删除也是需要阻塞线程的。在4.0 之后,可以选择被动删除策略,可以手动选择以 Lazy Free 的方法进行删除

      lazyfree-lazy-expire on    # 过期惰性删除
      replica-lazy-flush on    # slave 异步 flush 数据
      lazyfree-lazy-eviction on    # 超过最大内存惰性删除
      lazyfree-lazy-server-del on    # 服务端被动惰性删除
      
  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值