大家好,最近一直忙于工作,文章鸽了一段时间,后续会慢慢填坑。今天,给大家分享篇我们团队小伙伴的总结 《Redis 大key问题处理总结》,可谓干货满满。
Redis 大 key 问题处理总结
通过文章你能获得:
目录
在日常Redis的使用中,我们都遇到过因为key存储了过大的数据而造成请求缓慢甚至阻塞的情况,这个时候就需要排查Redis的大key去优化业务了,下面提供一些排查方案总结,仅供参考。
多大的 key 算大
阿里云Redis 最佳实践中提到:
合理的 Key 中 Value 的字节大小,推荐小于10 KB。过大的 Value 会引发数据倾斜、热点Key、实例流量或 CPU 性能被占满等问题,应从设计源头上避免此类问题带来的性能影响。
那么 value Bytes >10kb 可以作为判断 大 key 的一个参考值。
怎么发现大 key
1、string类型可使用命令 --bigkeys
--bigkeys
是 redis 自带的命令,对整个 Key 进行扫描,统计 string,list,set,zset,hash 这几个常见数据类型中每种类型里的最大的 key。string 类型统计的是value 的字节数;另外 4 种复杂结构的类型统计的是元素个数,不能直观的看出 value 占用字节数,所以 --bigkeys
对分析 string 类型的大 key 是有用的,而复杂结构的类型还需要一些第三方工具。( 元素个数少,不一定 value 不大;元素个数多,也不一定 value 就大)
root@vm1:~# redis-cli -h 127.0.0.1 -p 6379 -a "password" --bigkeys
--bigkeys
是以 scan 延迟计算的方式扫描所有 key,因此执行过程中不会阻塞 redis,但实例存在大量的 keys 时,命令执行的时间会很长,这种情况建议在 slave 上扫描。
image
主要就是 summary 部分的信息,分析可知:
该实例一共 有 52992 个 key,总占用内存空间:bytes is 1470203;
list 类型 有 15 个 key,最大的 key 有 153462 个元素;list 类型的 key 占了 00.03%,平均大小 10232.67 Bytes。
hash 类型 有 11485 个 key,最大的 key 是有三个字段。
string 类型 最大的 key 占用内存空间 157374 bytes。
set 类型 最大的 key 有 10 个元素。
streams 类型是开源版本 5.0 支持的新的数据类型,pub/sub 类型的增强版。
–-bigkeys
其实就是找出类型中最大的 key,最大的 key 不一定是大 key,最大的 key 都不超过 10kb 的话,说明不存在大 key。但某种类型如果存在较多的大key (>10kb),只会统计 top1 的那个 key,如果要统计所有大于 10kb 的 key,需要用第三方工具 扫描rdb持久化文件。
2/ 非 string 类型通常有以下两种方式统计:
- 2.1/ Redis 4.0 以后的版本:支持 了 memory 命令查看 key 的大小
root@vm1:~# redis-cli -h 127.0.0.1 -p 6379 -a "password"
127.0.0.1:6379> MEMORY USAGE keyname1
(integer) 157481
127.0.0.1:6379> MEMORY USAGE keyname2
(integer) 312583
memory 命令统计的是一个预估值。与 –-bigkeys
summary 统计的略有出入。
- 2.2/ Rdbtools 工具包:Rdbtools 是 python写的 一个第三方开源工具,用来解析 Redis 快照文件。除了解析 rdb 文件,还提供了 统计单个 key 大小的工具。
# 如下安装
git clone https://github.com/sripathikrishnan/redis-rdb-tools
cd redis-rdb-tools sudo && python setup.py install
Rdbtools 第三方开源工具包, 从 dump.rdb 快照文件统计(bgsave), 将所有 > 10kb 的 key 输出到一个 csv 文件
root@vm1:~# rdb dump.rdb -c memory --bytes 10240 -f live_redis.csv
如何优雅的删除大 key
4.0 以前 string,list,set,hash 不同数据类型的大 key,删除方式有所不同。一般有两种情况:del 命令删除单个很大的 key 和 del 批量删除 大 key。直接 del 命令粗暴的删大 key 容易造成 redis 线程阻塞。4.0 以前要优雅的删除就是针对不同的类型 写脚本,拆分链表,hash 表,分批删除。
4.0 版本以后官方对 删 大key 有了特别优化,支持了 lazy free 功能, 通常不需要开发脚本就可以删。
4.0 以后如何优雅的删除大 key 呢?
1/ 主动删除大 key
127.0.0.1:6379> UNLINK mykey
unlink 命令是 del 的异步版本,由 Lazyfree 机制实现。Lazyfree 机制的原理是在删除的时候只进行逻辑删除,把 key 释放操作放在 bio (Background I/O)单独的子线程中惰性处理,减少删除大 key 对 redis 主线程的阻塞,有效地避免因删除大key带来的性能问题。unlink 即使在批量删除 大 key 时,也不会对阻塞造成阻塞。
2/ 被动删除大 key
被动删除是指 Redis 自身的 key 清除策略,一个 大 key 过期或者被淘汰时,如何被清除,会不会导致阻塞?4.0 以前自动清除是有可能阻塞主线程的。
4.0 以后的版本,被动删除策略是可选的配置参数,允许 以 Lazyfree 的方式清除。但是参数默认是关闭的,可配置如下参数开启。
lazyfree-lazy-expire on # 过期惰性删除
lazyfree-lazy-eviction on # 超过最大内存惰性删除
lazyfree-lazy-server-del on # 服务端被动惰性删除
总结
- 使用 Redis 4.0 以上的版本
-
–-bigkeys
、memory
命令 和 Rdbtools 工具 分析统计实例存在的 大 key - 大 key 问题,主动删除无条件使用 UNLINK 异步,被动删除时配置 lazyfree 惰性删除。
最后,根本上解决大 key 问题要从开始时就避免使用大 key。
参考文档
- 浅析Redis 4.0新特性之LazyFree
- 云数据库Redis开发运维规范