【redis】BigKey

Bennie

Morekey 案列

面试题引入

  • 阿里广告平台,海量数据里查询某一固定的前缀的 key
  • 小红书,你如何生产上限制 keys */flushdb/flushall 等危险命令以防止误删误用?
  • 美团,MEMORY USAGE 命令你用过吗?
  • BigKey 问题,多大算 big?你如何发现?如何删除?如何处理?
  • BigKey 你做过调优吗?惰性释放 lazyfree。了解过吗?
  • Morekey 问题,生产上 redis 数据库有 1000W 记录,你如何遍历?key*可以吗?

批量插入数据

1
2
3
4
5
6
for((i=1;i<=100*10000;i++)); do echo "set k$i v$i" >> /tmp/redisTest.txt ;done;
cat /tmp/redisTest.txt | redis-cli --pipe

redis-cli
127.0.0.1:6379> DBSIZE
(integer) 1000000

当执行keys *的时候花费了

1
2
1000000) "k634210"
(7.01s)

生产环境限制 keys */ flushdb / flushall 等危险命令以防止误删除,修改 redis.conf

1
2
3
rename-command keys ""
rename-command flushdb ""
rename-command flushall ""

不用 keys,那用什么?

scan 命令,Redis 的 SCAN 命令是在大数据量的场景下优化对 Redis 键空间的遍历的命令,可以逐步地将所有的键迭代出来,它主要用来实现对 Redis 数据集的持续和渐进式的遍历。
常见的用法如下:

1
SCAN cursor [MATCH pattern] [COUNT count]

cursor:游标,初始值为 0,之后每次调用 SCAN 返回的新游标值,用于标识遍历的当前位置。
MATCH pattern:可选项,匹配符合指定模式的键。
COUNT count:可选项,每次返回的元素数量,Redis 默认为 10 个。

而当服务器向用户返回值为 0 的游标时, 表示迭代已结束。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
127.0.0.1:6379> SCAN 0  MATCH * COUNT 5
1) "458752"
2) 1) "k302634"
2) "k430755"
3) "k714111"
4) "k231894"
5) "k776289"
127.0.0.1:6379>
127.0.0.1:6379> SCAN 458752 MATCH * COUNT 5
1) "32768"
2) 1) "k313913"
2) "k142341"
3) "k549873"
4) "k78244"
5) "k598951"
6) "k413095"
127.0.0.1:6379> SCAN 32768 MATCH * COUNT 5
1) "163840"
2) 1) "k125427"
2) "k378551"
3) "k516756"
4) "k235141"
5) "k380212"

其他的还有:

  • SSCAN 命令用于迭代 SET 集合中的元素。
  • HSCAN 命令用于迭代 Hash 类型中的键值对。
  • ZSCAN 命令用于迭代 SortSet 集合中的元素和元素对应的分值

Bigkey 案列

多大算 big?

参考阿里云 redis 开发规范

  • string 是 value,最大 512MB,但是>=10KB 就是 bigkey
  • list\hash\set\zset,个数超过 5000 就是 bigkey

带来的危害?

  • 内存不均匀、集群迁移困难
  • 超时删除,大 key 删除作梗
  • 网络流量阻塞

如何产生的

  • 比如粉丝列表逐步上升

如何发现

  • redis-cli –bigkeys
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
# 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).

[00.00%] Biggest string found so far '"k302634"' with 7 bytes
[19.85%] Biggest string found so far '"k1000000"' with 8 bytes

[100.00%] Sampled 1000000 keys so far

-------- summary -------

Sampled 1000000 keys in the keyspace!
Total key length in bytes is 6888896 (avg len 6.89)

Biggest string found '"k1000000"' has 8 bytes

0 lists with 0 items (00.00% of keys, avg size 0.00)
0 hashs with 0 fields (00.00% of keys, avg size 0.00)
1000000 strings with 6888896 bytes (100.00% of keys, avg size 6.89)
0 streams with 0 entries (00.00% of keys, avg size 0.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)
  • memory usage [key]
1
2
127.0.0.1:6379> MEMORY USAGE k1000000
(integer) 72

如何删除?

  • String: 一般用 del,如果过于庞大用 unlink
  • Hash:使用 hscan 每次获取少量的 field-value,再使用 hdel 删除每个 field
  • List:使用 ltrim 渐进式删除,直到全部删除完成
  • Set: 使用 sscan 每次获取部分元素,再使用 srem 命令删除每个元素
  • Zset:使用 zscan 每次获取部分元素,再使用 ZREMRANGEBYRANK 删除每个元素

Bigkey 生产环境调优

在 redis.conf 配置文件中 LAZY FREEING 相关说明

1
2
3
lazyfree-lazy-server-del yes
replica-lazy-flush yes
lazyfree-lazy-user-del yes
  • 标题: 【redis】BigKey
  • 作者: Bennie
  • 创建于 : 2024-02-26 20:25:53
  • 更新于 : 2024-02-26 15:48:18
  • 链接: https://liubin.ink/2024/02/26/redis/【redis】BigKey/
  • 版权声明: 本文章采用 CC BY-NC-SA 4.0 进行许可。
 评论