1. 尊龙凯时(中国)人生就是搏!

      新闻
      首页 >  尊龙人生就是博中国区新闻 >  数字中国·星火文集 | Redis大Key分析和解决最佳实践

      数字中国·星火文集 | Redis大Key分析和解决最佳实践

      • 发布时间:2022-06-08
      • 来源:
      •   
      • 打印

      Redis大Key分析和解决最佳实践

      尊龙人生就是博中国区

      刘彬

      1.

      概述

      我们先假定有如下场景:某税务局一线运维收到客户反馈通知,说系统查询某机构对申报信息极为缓慢。于是开发人员找到一个出问题的机构A,通过搜索日志系统找到系统操作Redis时间比较久,并且从日志系统搜到一些Redis 含询超时的异常。最后我们定位到的原因如下:

      在申报接口的时候系统通过Redis做了一个级存,记录机构的申报信息,Redis数据结构:key=机构、IDvalue=申报列表,而Redis查询发现多了许多大key,体现在一个机构ID一天有上万甚至几十万的申报信息。我们通常将此类问题称为Redis大Key问题。

      2.

      Redis大Key基本概念及场景

      所谓的大key问题是某个key对应的value比较大,所以本质上是大value问题,key往往是开发过程中可以自行设置,可以控制大小,value往往不受程序控制跟业务场景有关系,因此可能导致value较大。

      2.1基本概念

      在Redis中,大key指的是key对应的value值所占的内存空间比较大:

      ● value是string类型,大小建议控制在10kb以内。

      ● valve是hash、list、set、zset等集合类型,元素个数建议不要超过 5000(或者1万、几万)。上述的定义并不绝对,主要是根据value的大小和元索个数来确定,业务也可以很据自己的场景确定标淮。

      2.2常见场景

      大key的产生往往是业务方设计不合理,没有预见vaule的动态增长问题。

      通常有几类此较经典的场录:

      ● 一直往value存放数据,没有删除及过期机制。

      ● 数据没有合理做分片,将大key变成以一个个小key。

      3.

      Redis大Key带来的影响

      ● 客户端超时阻塞。由于Redis单线程的特性,操作大key的通常比较耗时,也就意味着阻塞Redis可能性越大,这样会造成容户瑞阻塞或者引起故障切换,会出现各种Redis慢查询。

      ● 内存空间不均匀。集群模式在slot分片均匀情况下,会出现数据和查询倾斜情况,部分有大key的Redis节点占用内行多、QPS高。

      ● 引发网络阻塞。每次获取大key产生的网络流量按大,如果一个key的大小为1MB每秒访问量为1000,那么行秒会产生1000MB的流量。这对于普通千兆网卡的服务器说是灾难性的。

      ● 阻塞工作线程。执行大key删除时,在低版本Redis中可能阻塞线程。

      4.

      Redis大Key如何检测

      ● 改写Redis客户端,在sdk中加入埋点,实时上报数据给Redis大key 检测平台、监控告警。

      ● scan+debug object bigkey命令,循环遍历Redis key序列化后的长度。debug object bigkey可能会比较慢,它存在阻塞Redis的可能,建议在从节点执行该命令,官方不推荐。

      ● scan+memory usage。该命令是在Redis 4.0+以后提供的,可以循环遍历统计计算每个键值的字节数。

      ● 通过python脚本迭代的scan key。对每次scan的内容进行判断是否为大key。

      ● Redis-cli --bigkeys。可以找到某个Redis 实例5种数据类型(string、hash、list、set、zset)的最大key。但如果Redis key 比较多,执行该命令会比较慢,建议在从节点执行该命令。

      ● rdbtools开源工具包。rdbtools是python写的一个第三方开源工具,用来解析Redis快照文件,Redis实例上执行bgsave,然后对dump出;来的rdb文件进行分析,找到其中的大key。

      例如:rdb dump.rdb -c memory --byes 10240 -f Redis.csv

      从dump.rdb 快照文件统计 (bgsave),将所有>10kb的key输出到一个csv文件。

      5.

      Redis大Key如何删除

      如果对这类大key直接使用del命今进行删除,会导致长时间阻塞,甚至崩溃,因为del命令在删除集合类型数据时,时间复杂度为O(M),M是集合中元素的个数。Redis是单线程的,单个命令执行时间过长就会阻塞其他命令,容易引起雪崩,稳妥的建议如下:

      主动删除大Key

      一、分批次渐近删除

      一般来说,对于string数据类型使用del命令不会产生阻塞。其它数据类型分批删除,通过scan命令遍历大key,每次取得少部分元素进行删除,然后再获取和删除下一批元素.对Hash,Sorted Set, List. Set 分别处理、思路相同,先对key改名进行逻辑删除,使客户端无法使用原key,然后使用批量小步删除。

      ● 删除大Hash

      步骤:(1)key改名,相当于逻辑上删除key,任何Redis命令都访问不了该key。(2)小步多批次删除。

      伪代码:

      ● 删除大List

      伪代码:

      ● 删除大Set

      伪代码:

      ● 删除大Sorted Set

      伪代码:

      二、采用unlink+bigkey异步非阻塞删除,这个命令是在Redis 4.0+提供的代替del命令,不会阻塞主线程。

      被动删除大Key

      被动删除是指利用Redis自身的key消除策略,配置lazyfree情性删除。但是参数默认是关闭的。可配置如下参数开启:

      6.

      Redis大Key如何设计与优化

      主要针对以下两种经典场景进行优化:

      单个key 存储的 value 很大(超过 10kb)

      1)从业务角度评估,value中只存储有用的字段,尽量去掉无用的字段。

      2)可以考点在应用层先对value进行压缩,比如采用LZ4/Snappy之类的压缩算法,配合Redis客户端序列化配置,可以无侵入完成value的压缩。.

      3)value设计的时候越小越好,关联的数据分不同的key进行存儲。

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

      5)对Redis集群进行扩容。

      集合数据类型hash. list, set. sorted set等存储过多的元素(超过5000个)

      类似于场景一中的第一个做法,可以将这些元素分拆:

      以hash为例,原先的正常存取流程是hget(hashKey,field) ;hset(hashkey,field,value)现在,我们可以分拆构建一个新的 newHashkey,具体做法:固定一个桶的数量,比如10000每次存取的时候,先在本地计算field的hash值,取模10000,确定了该field落在哪个newHashkey上。

      set、sorted、list也可以采用类似做法。

      联系我们
      友情链接: