刘华阳,20年经历风霜雨打的 DBA,5年的 DBA 架构和团队管理经验,只要是数据库都喜欢学习。PostgreSQL ACE,MongoDB 狂热者,10年的 MYSQL 工作经验,现在在玩 POLARDB 与时俱进。
Redis最近在看大KEY的问题,想研究一下原理和解决的方案,在安装的过程中,发现现在的Redis和之前的5.0安装有一些区别。甚至越来越不认识Redis了,一些模块后续还的学习,今天主要针对大KEY的问题。
在安装中官方建议为安装Redis要安装Python?
之前5.0的时候我下载开源包很简单,下载编译,但现在登录官网后,我发现一个问题,安装开源的REDIS 文档上让我安装一堆依赖,包含python。
我研究了一下,第一个问题为什么要装Redis还要装python。
Redis 本身并不需要python而需要python的是Redis自带测试套件中的/test里面的东西,里面有很多python写的CI test,同时做Cmake的时候,有一些模块构建部分依赖管理也是有glue code,所以建议在安装高版本的时候可以安装python 按照官网的文档来。
同时Redis中的 RedisJson , RedisSearch, Redis Tiemseries等模块都依赖python生成器构建系统,需要的版本避免和原有系统的版本冲突,所以需要安装指定的python版本。

Redis install ptyhon
sudo dnf install -y --nobest --skip-broken \pkg-config \wget \gcc-toolset-13-gcc \gcc-toolset-13-gcc-c++ \git \make \openssl \openssl-devel \python3.11 \python3.11-pip \python3.11-devel \unzip \rsync \clang \curl \libtool \automake \autoconf \jq \systemd-devel```
所以要使用更新版本的redis的以及新功能的情况下是需要进行安装python和pip的。回到进行的问题,大key。
我们在安装好的Redis灌入一个大key:
head -c 10485760 < /dev/zero | tr '\0' 'a' | redis-cli -x set bigstring
怎么找到大key,redis有一些命令和工具可以进行分析和处理,通过 redis-cli --bigkeys可以对当前的redis进行scan,给出当前系统中每种数据类型中最大的key的名字和大小统计。这里注意 --bigkeys 是采样扫描,并不是全量扫描,如果要找出更多的大keys 并进行排行可以通过脚本来进行。
[root@redis8 ~]# redis-cli --bigkeys# Scanning the entire keyspace to find biggest keys as well as# average sizes per key type. You can use -i 0.1 to sleep 0.1 sec# per 100 SCAN commands (not usually needed).100.00% ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||Keys sampled: 1-------- summary -------Total key length in bytes is 9 (avg len 9.00)Biggest string found "bigstring" has 10485760 bytes0 hashs with 0 fields (00.00% of keys, avg size 0.00)0 lists with 0 items (00.00% of keys, avg size 0.00)0 streams with 0 entries (00.00% of keys, avg size 0.00)1 strings with 10485760 bytes (100.00% of keys, avg size 10485760.00)0 sets with 0 members (00.00% of keys, avg size 0.00)0 zsets with 0 members (00.00% of keys, avg size 0.00)[root@redis8 ~]#
[root@redis8 ~]# sh big_keys.sh开始扫描 Redis (127.0.0.1:6379) 大 Key ...前 20 个大 key:----------------------------------------------12582928 bigstring----------------------------------------------单位:字节(可以除以 1048576 得到 MB)[root@redis8 ~]# head -c 10485760 < /dev/zero | tr '\0' 'a' | redis-cli -x set bigstringOK[root@redis8 ~]# head -c 10485760 < /dev/zero | tr '\0' 'a' | redis-cli -x set bigstri1OK[root@redis8 ~]# head -c 10485760 < /dev/zero | tr '\0' 'a' | redis-cli -x set bigstr2OK[root@redis8 ~]# head -c 10485760 < /dev/zero | tr '\0' 'a' | redis-cli -x set bigst3OK[root@redis8 ~]# head -c 10485760 < /dev/zero | tr '\0' 'a' | redis-cli -x set bigs4OK[root@redis8 ~]# sh big_keys.sh开始扫描 Redis (127.0.0.1:6379) 大 Key ...前 20 个大 key:----------------------------------------------12582928 bigstring12582928 bigstri112582928 bigstr212582928 bigst312582928 bigs4----------------------------------------------单位:字节(可以除以 1048576 得到 MB)[root@redis8 ~]#
linux shell 脚本,可以在本地执行,在脚本后带上IP和端口号,如果redis有密码,则最后带上密码即可。
# 用 redis-cli 扫描 redis,找出占用内存最大的 20 个 key# 使用方法: ./find_bigkeys.sh [host] [port] [password]REDIS_CLI="redis-cli"HOST=${1:-127.0.0.1}PORT=${2:-6379}AUTH=$3if [ -n "$AUTH" ]; thenAUTH_OPT="-a $AUTH"elseAUTH_OPT=""fiecho"开始扫描 Redis ($HOST:$PORT) 大 Key ..."cursor=0tmpfile=$(mktemp)while :do# SCAN 每次取 1000 个 keyresult=$($REDIS_CLI -h $HOST -p $PORT$AUTH_OPT --raw SCAN $cursor COUNT 1000)cursor=$(echo"$result" | head -1)keys=$(echo"$result" | tail -n +2)for k in$keys; dosize=$($REDIS_CLI -h $HOST -p $PORT$AUTH_OPT MEMORY USAGE "$k" 2>/dev/null)if [ -n "$size" ]; thenecho -e "$size\t$k" >> $tmpfilefidone# cursor 回到 0 就说明扫描结束if [ "$cursor" == "0" ]; thenbreakfidoneecho"前 20 个大 key:"echo"----------------------------------------------"sort -nr $tmpfile | head -20 | awk '{printf "%-12s %-10s\n", $1, $2}'echo"----------------------------------------------"echo"单位:字节(可以除以 1048576 得到 MB)"rm -f $tmpfile
这里大keys有什么风险和问题:
通过访问大keys 如get ,hgetall 等会占用单线程,在访问中租塞其他的访问的请求。尤其在进行del命令删除的时候,会有卡顿的情况。
会造成内存碎片的问题,RDB/AOF文件也会变大,尤其在内存刷新的情况下,会耗时。
网络的传输压力也很大,会拖慢导致客户端超时等问题。
DBA 也会问为什么会产生大keys的问题,这里从开放的角度,大部分还是设计不合理:
日志存储,将一次请求的LOG 都塞入到一个KEY中
一客户ID为数据存储的情况,有的客户数据量小,有的很大,大的产生了大KEY
省事进行数据缓存,比如把一个配置表都缓存到一个KEY 中
解决方案也很多:
比如,写入数据按照时间分片,杜绝一直往一个KEY里面写,尤其日志信息。同时DBA也应该经常运行上面的脚本,来发现大KEYS并通知开发进行解决。且删除的时候用unlink的异步方式进行,二不要用del的方式来删除大keys.
作者丨 liuaustin3
来源丨公众号:AustinDatabases(ID:AustinDatabases)
dbaplus社群欢迎广大技术人员投稿,投稿邮箱:editor@dbaplus.cn
如果字段的最大可能长度超过255字节,那么长度值可能…
只能说作者太用心了,优秀
感谢详解
一般干个7-8年(即30岁左右),能做到年入40w-50w;有…
230721