刘华阳,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 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 -c 10485760 < /dev/zero | tr '\0' 'a' | redis-cli -x set bigstring
OK
[root@redis8 ~]# head -c 10485760 < /dev/zero | tr '\0' 'a' | redis-cli -x set bigstri1
OK
[root@redis8 ~]# head -c 10485760 < /dev/zero | tr '\0' 'a' | redis-cli -x set bigstr2
OK
[root@redis8 ~]# head -c 10485760 < /dev/zero | tr '\0' 'a' | redis-cli -x set bigst3
OK
[root@redis8 ~]# head -c 10485760 < /dev/zero | tr '\0' 'a' | redis-cli -x set bigs4
OK
[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有密码,则最后带上密码即可。
# 用 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=0
tmpfile=$(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$keys; do
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
fi
done
# cursor 回到 0 就说明扫描结束
if [ "$cursor" == "0" ]; then
break
fi
done
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
如果字段的最大可能长度超过255字节,那么长度值可能…
只能说作者太用心了,优秀
感谢详解
一般干个7-8年(即30岁左右),能做到年入40w-50w;有…
230721