开发:这种Redis大key问题,你一个DBA怎么解决?

刘华阳 2025-09-29 14:44:08
作者介绍

刘华阳,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版本](https://files.mdnice.com/user/47359/dd0add99-8c83-4825-aa1b-83a63966bf40.png)

 

所以要使用更新版本的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 bytes
0 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 -10485760 < /dev/zero | tr '\0' 'a' | redis-cli -set bigstringOK[root@redis8 ~]# head -10485760 < /dev/zero | tr '\0' 'a' | redis-cli -set bigstri1OK[root@redis8 ~]# head -10485760 < /dev/zero | tr '\0' 'a' | redis-cli -set bigstr2OK[root@redis8 ~]# head -10485760 < /dev/zero | tr '\0' 'a' | redis-cli -set bigst3OK[root@redis8 ~]# head -10485760 < /dev/zero | tr '\0' 'a' | redis-cli -set bigs4OK[root@redis8 ~]# sh big_keys.sh 开始扫描 Redis (127.0.0.1:6379) 大 Key ...前 20 个大 key:----------------------------------------------12582928     bigstring 12582928     bigstri1  12582928     bigstr2   12582928     bigst3    12582928     bigs4     ----------------------------------------------单位:字节(可以除以 1048576 得到 MB)[root@redis8 ~]# 

 

linux shell 脚本,可以在本地执行,在脚本后带上IP和端口号,如果redis有密码,则最后带上密码即可。

 

  •  
  •  
  •  
  •  
  •  
  •  
  •  
  •  
  •  
  •  
  •  
  •  
  •  
  •  
  •  
  •  
  •  
  •  
  •  
  •  
  •  
  •  
  •  
  •  
  •  
  •  
  •  
  •  
  •  
  •  
  •  
  •  
  •  
  •  
  •  
  •  
  •  
  •  
  •  
  •  
  •  
  •  
  •  
  •  
  •  
  •  
  •  
#!/bin/bash# 用 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=$3
if [ -n "$AUTH" ]; then  AUTH_OPT="-a $AUTH"else  AUTH_OPT=""fi
echo"开始扫描 Redis ($HOST:$PORT) 大 Key ..."
cursor=0tmpfile=$(mktemp)
while :do# SCAN 每次取 1000 个 key  result=$($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$keysdo    size=$($REDIS_CLI -h $HOST -p $PORT$AUTH_OPT MEMORY USAGE "$k" 2>/dev/null)    if [ -n "$size" ]; then      echo -e "$size\t$k" >> $tmpfile    fidone
# cursor 回到 0 就说明扫描结束if [ "$cursor" == "0" ]; then    breakfidone
echo"前 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

最新评论
访客 2024年04月08日

如果字段的最大可能长度超过255字节,那么长度值可能…

访客 2024年03月04日

只能说作者太用心了,优秀

访客 2024年02月23日

感谢详解

访客 2024年02月20日

一般干个7-8年(即30岁左右),能做到年入40w-50w;有…

访客 2023年08月20日

230721

活动预告