8

这4大神操作,专治Redis缓存大key引起的事故 - Redis - dbaplus社群:围绕Data、Block...

 1 year ago
source link: https://dbaplus.cn/news-158-4888-1.html
Go to the source link to view the article. You can view the picture content, updated content and better typesetting reading experience. If the link is broken, please click the button below to view the snapshot at that time.
neoserver,ios ssh client

这4大神操作,专治Redis缓存大key引起的事故

树洞君 2022-10-19 09:44:18

问题描述

线上业务接口服务瞬间开始超时报警,上游调用方端口可用率下降至80%,属于P0级别事故,具体过程如下:

  • 19:44 接到报警,接口tp99超过300ms(正常情况下8ms);

  • 19:50 查看机器监控发现部分机器超时,问题机器随机不固定;

  • 19:55 此接口依赖缓存,有降级开关,查询db(确认开关关闭);

  • 19:58 查看缓存集群监控,整体未发现缓存客户端问题;

  • 20:03 运维协助查看集群,确认缓存服务端没有问题;

  • 20:10 扫描缓存副本 发现有单个大key超过5M,并且持续请求;

  • 20:13 删除大key,集群恢复 【故障原因】 缓存大key问题!

随着高并发流量的持续冲击,各种分布式框架、分布式缓存已经成为各大互联网公司的常用技术栈,其中就有redis缓存,作为一个分布式缓存技术栈,在应对高并发频次的请求,以及快速的响应成为缓存中的佼佼者。

我们在平时的面试中,也会经常被问到缓存大key如何处理的问题,接下来,我们借鉴中医学的望闻问切来分析如何发现缓存大key,如果判断缓存大key,如果解决缓存大key。

在一个接口服务里,如果我们的服务所在的客户端,只连接了缓存集群,我们如何快速的根据指标确认是否是缓存大key问题。

首先排除redis服务端集群硬件问题。我们先通过集群指标,判断是否有缓存服务端机器异常,引起的响应超时,观察redis服务端机器的各项指标,cpu、内存、网络等,排除redis服务端硬件的问题。

接下来找下客户端连接超时中断的现象,以及为什么客户端服务器会和redis服务连接中断。

  • 表象1:redis分片入流量不大,出流量巨大。



  • 表象2:每次都是指定redis分片相应超时,出流量巨大;而其余分片出流量正常。

我们先要清楚一个知识点,就是缓存的数据路由,Redis Cluster采用虚拟哈希槽分区而非一致性hash算法,预先分配16384(2^14)个卡槽,所有的键根据哈希函数映射到 0 ~ 16383整数槽内,每一个分区内的master节点负责维护一部分槽以及槽所映射的键值数据。

所以我们存入redis的每一条数据,在分片不变的情况下,始终存储在一个分片上。我们根据这个特点,结合监控集群的指标反应,可以快速定位是否是缓存大key。

正常情况下出流量各个分片出流量监控:

20221019094635785.png

缓存大key导致的固定分片出流量大:

20221019094646738.png

这种基本就可以确定是缓存大key的问题了,我们继续下一步,如何快速找到这些缓存大key,并且删掉。

找到问题的缓存分片,针对缓存分片进行大key扫描,网上方法有很多,感兴趣的话可以自己搜索,在此只介绍集中比较热门的方式。建议公司运维同事提前搭好类似的基础服务工具。

  • redis-rdb-tools工具。redis实例上执行bgsave,然后对dump出来的rdb文件进行分析,找到其中的大KEY。基本命令:rdb -c memory dump.rdb (dump.rdb为Redis实例的rdb文件,可通过bgsave生成)。



  • redis-cli --bigkeys命令。可以找到某个实例5种数据类型(String、hash、list、set、zset)的最大key。



  • 自定义的扫描脚本,以Python脚本居多,方法与redis-cli --bigkeys类似。

自此可以找出缓存的中的大key。执行 del 命令删除大key即可。

我们如何预防,才是重点。

  • redis本身定位就是一个内存缓存,而不是一个数据库,所以我们如果涉及到复杂的数据结构,建议设计之初就应该进行拆分。



  • 在所有set缓存方法前,增加切面校验,设定阈值,校验存储的缓存key-value的大小,如果超过的话,阻止录入并且计入报警。

最后我们解释下,为什么缓存大key会导致服务端链接缓存超时链接中断的现象。

先了解一个概念,redis缓冲区一共有三个,客户端缓冲区、复制及压缓冲区、AOF缓冲区,大key问题导致客户端-服务端链接中断的原因就在于第一个:客户端缓冲区。

Redis为每个客户端分配了输入缓冲区, 它的作用是将客户端发送的命令临时保存, 同时Redis从会输入缓冲区拉取命令并执行, 输入缓冲区为客户端发送命令到Redis 执行命令提供了缓冲功能, 如图所示。

20221019094659324.png

Redis 为每个客户端设置的输出缓冲区也包括两部分:一部分,是一个大小为 16KB 的固定缓冲空间,用来暂存 OK 响应和出错信息;另一部分,是一个可以动态增加的缓冲空间,用来暂存大小可变的响应结果。造成输出缓冲区溢出的原因:

  • 大key请求返回的结果

  • 执行了Monitor命令

  • 缓冲区设置大小不合理

限制输出缓冲区的配置:

  • client-output-buffer-limit normal 0 0 0 普通客户端不做限制,请求是阻塞式的。

  • client-output-buffer-limit pubsub 8mb 2mb 60 发布订阅式 总量8mb 60s内超过2mb就会自动关闭连接 。

避免溢出的方式显而易见:

  • 避免bigkey

  • 生产不使用Monitor操作

  • 合理设置client-output-buffer-limit

这也是我们的服务接口所在的客户端服务器,和redis服务端中断的根本原因,中断之后,客户端的检测狗会重新和redis服务端建立新的链接。 

至于redis服务端为什么每次中断的客户端服务器链接都是随机的呢?答案就在于我们的dubbo负载均衡策略,默认是随机请求。

作者丨树洞君 来源丨网址:https://juejin.cn/post/7084904769579384863 dbaplus社群欢迎广大技术人员投稿,投稿邮箱:[email protected]
20221019094508440.jpg

About Joyk


Aggregate valuable and interesting links.
Joyk means Joy of geeK