Redis学习——高级篇②
- = = = = = = = = = = Redis7高级之BigKey(二) = = = = = = = = = =
- 1.MoreKey案例
- 2.BigKey案例
- 2.1 多大算 BigKey以及它的危害
- 2.2 如何产生、发现、删除
- 3. bigKey生产调优
= = = = = = = = = = Redis7高级之BigKey(二) = = = = = = = = = =
1.MoreKey案例
来个小问题 打底:Morekey问题,生产上redis数据库有1000W记录,你如何遍历? key *可以吗?
来启用一下!
matthew@matthew-virtual-machine:~/redis-7.2.4/myredis$ redis-server redis6379.conf
matthew@matthew-virtual-machine:~/redis-7.2.4/myredis$ redis-cli -a 123456 -p 6379
Warning: Using a password with '-a' or '-u' option on the command line interface may not be safe.
127.0.0.1:6379> keys *
1) "k3"
2) "zset1"
3) "set1"
4) "list"
5) "hset2"
6) "set2"
7) "hset1"
127.0.0.1:6379> flushall
OK
127.0.0.1:6379> flushall
OK
127.0.0.1:6379> keys *
(empty array)
127.0.0.1:6379> DBSIZE
(integer) 0
-
往redis里面插入大量测试数据key
- 生成100W条redis批量设置kv的语句保存在
redisTest.txt
- 生成100W条redis批量设置kv的语句保存在
for((i=1;i<=100*10000;i++)); do echo "set k$i v$i" >> /tmp/redisTest.txt ;done;
# 生成100W条redis批量设置kv的语句(key=kn,value=vn)写入到/tmp目录下的redisTest.txt文件中
matthew@matthew-virtual-machine:~/redis-7.2.4/myredis$ for((i=1;i<=100*10000;i++)); do echo "set k$i v$i" >> /tmp/redisTest.txt ;done;matthew@matthew-virtual-machine:~/redis-7.2.4/myredis$ # 生成100W条redis批量设置kv的语句(key=kn,value=vn)写入到/tmp目录下的redisTest.txt文件中
matthew@matthew-virtual-machine:~/redis-7.2.4/myredis$ more /tmp/redisTest.txt
set k1 v1
set k2 v2
set k3 v3
set k4 v4
set k5 v5
...
- 通过redis管道的
--pipe
命令插入100W大批量数据
cat /tmp/redisTest.txt | redis-cli -h 127.0.0.1 -p 6379 -a 123456 --pipe
通过redis-cli登录查看是否成功
-
keys * / flushall / flushdb 危险命令
-
keys * / flushall / flushdb 严禁 在线上使用
-
keys * / flushall / flushdb 会造成阻塞,会导致Redis其他的读写都被延后甚至是超时报错,可能会引起缓存雪崩甚至数据库宕机
-
通过配置禁用危险命令
-
scan 命令代替 keys *,避免卡顿
一句话,类似mysql的 limit的但不完全相同
- 语法
SCAN cursor [MATCH pattern] [COUNT count]
基于游标的迭代器,需要基于上一次的游标延续之前的迭代过程以0作为游标开始一次新的迭代,直到命令返回游标0完成一次遍历不保证每次执行都返回某个给定数量的元素,支持模糊查询一次返回的数量不可控,只能是大概率符合count参数。
-
特点
cursor
-游标。pattern
-匹配的模式。count
-指定从数据集里返回多少元素,默认值为10
- SCAN 命令是一个基于游标的迭代器,每次被调用之后, 都会向用户返回一个新的游标, 用户在下次迭代时需要使用这个新游标作为 SCAN 命令的游标参数, 以此来延续之前的迭代过程。
- SCAN 返回一个包含两个元素的数组
- 第一个元素是用于进行下一次迭代的新游标
- 第二个元素则是一个数组, 这个数组中包含了所有被迭代的元素。如果新游标返回零表示迭代已结束。
- SCAN的遍历顺序,非常特别,它不是从第一维数组的第0位一直遍历到末尾,而是采用了高位进位加法来遍历。之所以使用这样特殊的方式进行遍历,是考虑到字典的扩容和缩容时避免槽位的遍历重复和遗漏。
-
使用
2.BigKey案例
2.1 多大算 BigKey以及它的危害
参考 《阿里云Redis开发规范》
- string 是value,最大512MB但是 >= 10KB 就是bigkey
- list、hash、set和zset,个数超过5000就是bigkey
危害
- 内存不均,集群迁移困难
- 超时删除,大key导致阻塞
- 网络流量阻塞
2.2 如何产生、发现、删除
产生
发现
-
redis-cli --bigkeys
-
redis-cli -h 127.0.0.1 -p 6379 -a 111111 --bigkeys//每隔 100 条 scan 指令就会休眠 0.1s,ops 就不会剧烈抬升,但是扫描的时间会变长redis-cli -h 127.0.0.1 -p 7001 –-bigkeys -i 0.1
-
好处
- 给出每种数据结构Top 1 bigkey,同时给出每种数据类型的键值个数+平均大小
-
不足
- 想查询大于10kb的所有key,
--bigkeys
参数就无能为力了,需要用到memory usage
来计算每个键值的字节数
- 想查询大于10kb的所有key,
-
-
memory usage
- 计算每个键值的字节数
MEMORY USAGE
命令给出一个key和它的值在RAM中所占用的字节数。返回的结果是key的值以及为管理该key分配的内存总字节数。对于嵌套数据类型,可以使用选项SAMPLES
,其中count 表示抽样的元素个数,默认值为5。当需要抽样所有元素时,使用SAMPLES 0
。
删除bigkey
- 参考 《阿里云Redis开发规范》
-
普通命令
-
String
- 一般用del,过于庞大 unlink
-
hash
-
使用hscan每次获取少量
field-value
,再使用hdel
删除每个field
-
语法
-
阿里手册
先用hdel把hash的field降下来,再用del
-
-
list
-
使用 ltrim 渐进式逐步删除,直到全部删除
-
命令
-
阿里手册
-
-
set
-
使用sscan 每次获取部分元素,再使用 srem 命令删除每个元素
-
命令
-
阿里手册
-
-
zset
-
使用zscan每次获取部分元素,再使用ZREMRANGEBYRANK 命令删除每个元素
-
命令
- 阿里手册
-
-
3. bigKey生产调优
- 阻塞和非阻塞删除命令
Redis有两个原语来删除键。
- 一种称为 DEL,是对象的阻塞删除。
- 这意味着服务器停止处理新命令,以便以同步方式回收与对象关联的所有内存。如果删除的键与一个小对象相关联, 则执行DEL命令所需的时间非常短,可与大多数其他命令相媲美
- Redis中的O(1)或O( l o g N log_N logN)命令。但是,如果键与包含数百万个元素的聚合值相关联,则服务器可能会阻塞很长时间(甚至几秒钟)才能完成操作。
以上也是为什么删大key困难的原因
- Redis 还提供了非阻塞删除原语
- 例如
UNLINK
(非阻塞DEL)以及FLUSHALL
和FLUSHDB
命令的ASYNC选项,以便在后台回收内存。这些命令在恒定时间内执行。另一个线程将尽可能快地逐步释放后台中的对象。FLUSHALL
和FLUSHDB
的DEL
、UNLINK
和ASYNC
选项是用户控制的。这取决于应用程序的设计,以了解何时使用其中一个是个好主意。然而,作为其他操作的副作用,Redis 服务器有时不得不删除键或刷新整个数据库。具体而言,Redis 在以下场景中独立于用户调用删除对象:
在上述所有情况下,默认情况是以阻塞的方式删除对象,就像调用DEL一样。但是,您可以使用以下配置指令专门配置每种情况,以便以非阻塞的方式释放内存,就像调用UNLINK一样。
-
优化配置