Redis 大 key 问题总结

  1. 多大的 key 算大?

阿里云Redis 最佳实践中提到 合理的 Key 中 Value 的字节大小,推荐小于10 KB。过大的 Value 会引发数据倾斜、热点Key、实例流量或 CPU 性能被占满等问题,应从设计源头上避免此类问题带来的性能影响。那么 value Bytes >10kb 可以作为判断 大 key 的一个参考值。
2. 怎么发现大 Key ?

--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 上扫描。

[张松鹤 > Redis 大 key 问题总结 > image2021-8-25_11-29-50.png]

主要就是 summary 部分的信息:

该实例一共 有 52992key,总占用内存空间: bytes is 1470203
list 类型 有 15key,最大的 key 是 user_concurrency_260468,该 key153462 个元素; list 类型的 key 占了 00.03%,平均大小 10232.67 Bytes
hash 类型 有 11485key,最大的 key'account_source_node_group_rel_236129' ,这个 key 有三个字段
string 类型 最大的 key'cclive::dirtyword::accounts::join::6634678BEDA5BB7D' 占用内存空间 has 157374 bytes
set 类型 最大的 key 是 live_room_version' has 10 members
streams 类型是开源版本 5.0支持的新的数据类型,pub/sub 类型的增强版
# 备注:–-bigkeys 其实就是找出类型中最大的 key,最大的 key 不一定是大 key,最大的 key 都不超过 10kb 的话,说明不存在大 key。但某种类型如果存在较多的大key (>10kb),只会统计 top1 的那个 key,如果要统计所有大于 10kb 的 key,需要用第三方工具 扫描 rdb 持久化文件。

–-bigkeys 统计能直观的看出 string 类型 value 的大小,非 string 类型通常有以下两种方式统计:

(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 cclive::dirtyword::accounts::join::6634678BEDA5BB7D
(integer) 157481
127.0.0.1:6379> MEMORY USAGE user_concurrency_260468
(integer) 312583
# memory 命令统计的是一个预估值。从 string 类型的 user_concurrency_260468 结果看 : memory 命令统计的是 157481 , –-bigkeys summary 统计的是 157374 bytes

(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
redis-memory-for-key 单 key 统计工具:( –-bigkeys 统计结果里找到 list key top1: user_concurrency_260468 )
root@vm1:~# redis-memory-for-key -s 127.0.0.1 -p 6379 -a "password" user_concurrency_260468
[张松鹤 > Redis 大 key 问题总结 > image2021-8-25_14-30-16.png]
# list 类型 的 user_concurrency_260468 , 153490 个 items 占用 Bytes 309250, 300kb。数据结构:quicklist
Rdbtools 第三方开源工具包
从 dump.rdb 快照文件统计(bgsave): 将所有 > 10kb 的 key 输出到一个 csv 文件
root@vm1:~# rdb dump.rdb -c memory --bytes 10240 -f live_redis.csv
[张松鹤 > Redis 大 key 问题总结 > image2021-8-25_15-6-17.png]
  1. 如何优雅的删除 大 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 的方式清除。但是参数默认是关闭的。

补充:Redis key 淘汰策略 和 key 清除策略 (被动删除场景)

Redis 内存不够时 key 的淘汰策略 ,即超过了 maxmemory 的配置:

配置参数 maxmemory-policy =volatile-lru
noeviction:当内存不足以容纳新写入数据时,新写入操作会报错。
allkeys-lru:当内存不足以容纳新写入数据时,移除最近最少使用的key
allkeys-random:当内存不足以容纳新写入数据时,随机移除某个key。用数据丢失的风险。
volatile-lru:当内存不足以容纳新写入数据时,在设置了过期时间的 key 中,移除最近最少使用的 key。 建议配置的策略
volatile-random:当内存不足以容纳新写入数据时,在设置了过期时间的 key 中,随机移除某个 key。 不管你过期不过期。
volatile-ttl:当内存不足以容纳新写入数据时,在设置了过期时间的 key 中,有更早过期时间的 key 优先移除。
Redis key 淘汰时的 清除策略:(淘汰策略 和 淘汰清除策略是两码事:淘汰策略决定了要淘汰谁,清除策略是我要如何清除淘汰的 key )

(1)惰性删除:(建议开启惰性清除策略 )

ttl 过期的 key,不会立刻被清除,而是等下次访问时,判断过期了再自动清除。惰性删除避免了 cpu 要不停去轮询去主动发现哪个key 过期了节省了一定的 cpu 资源。配置 Lazyfree 机制惰性清除过期 key: lazyfree-lazy-expire on (淘汰数据时,是否启用 Lazyfree)
redis 内存使用达到maxmeory时,并设置了淘汰策略,在被动淘汰 key 时,开启 lazyfree异步清除机制: lazyfree-lazy-eviction on (驱逐数据时,是否启用 Lazyfree)
服务端被动清除某个 key 时,开启lazyfree异步清除机制: lazyfree-lazy-server-del on (隐式删除服务器数据时,是否启用 Lazyfree)

(2)定时删除:( redis 默认策略 )

redis 默认是每隔 100ms 就随机抽取一些设置了过期时间的 key,检查其是否过期,如果过期就删除。之所以是随机抽取,是为了避免Key过多,如果全量检查,会影响性能。redis不可能是扫描所有的 key去检查过期时间。

总结:

使用 Redis 4.0 以上的版本
–-bigkeys 、memory 命令 和 Rdbtools 工具 分析统计实例存在的 大 key
key 问题,主动删除无条件使用 UNLINK 异步,被动删除时配置 lazyfree 惰性删除

参考文档:

浅析Redis 4.0新特性之LazyFree: https://zhuanlan.zhihu.com/p/88024764

云数据库Redis开发运维规范 : https://help.aliyun.com/document_detail/251467.html

posted @   梦里花。  阅读(845)  评论(0编辑  收藏  举报
相关博文:
阅读排行:
· TypeScript + Deepseek 打造卜卦网站:技术与玄学的结合
· Manus的开源复刻OpenManus初探
· 三行代码完成国际化适配,妙~啊~
· .NET Core 中如何实现缓存的预热?
· 如何调用 DeepSeek 的自然语言处理 API 接口并集成到在线客服系统
点击右上角即可分享
微信分享提示