





















Redis 是我们常见的缓存解决方案,但是使用不当的 Redis 同样会造成系统瓶颈。
要启用慢日志分析,首先先要对慢查询记录进行设置:
1# 命令执行耗时超过 5 毫秒,记录慢日志
2CONFIG SET slowlog-log-slower-than 5000
3# 只保留最近 500 条慢日志
4CONFIG SET slowlog-max-len 500
5
设置成功后通过下面的命令就能查到慢日志:
1127.0.0.1:6379> SLOWLOG get 5
21) 1) (integer) 32693 # 慢日志ID
3 2) (integer) 1593763337 # 执行时间戳
4 3) (integer) 5299 # 执行耗时(微秒)
5 4) 1) "LRANGE" # 具体执行的命令和参数
6 2) "user_list:2000"
7 3) "0"
8 4) "-1"
92) 1) (integer) 32692
10 2) (integer) 1593763337
11 3) (integer) 5044
12 4) 1) "GET"
13 2) "user_info:1000"
14
主要可能的原因无非也就是:
而要避免这种慢查询发生,就需要我们尽可能的避免复杂的查询和大 key 的产生。
而今天我们要说的重点就是关于 Redis 中的大 key 要怎么解决。
大 key 意味着 value 特别大(而不是 key 特别大),大 key 会导致的问题显而易见:
因此如果没有特殊情况,我们要尽量避免大 key。
要发现大 key 也很简单,可以直接通过下面的命令发现大 key:
1> redis-cli --bigkeys
2
3# Scanning the entire keyspace to find biggest keys as well as
4# average sizes per key type. You can use -i 0.1 to sleep 0.1 sec
5# per 100 SCAN commands (not usually needed).
6
7100.00% ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
8Keys sampled: 18
9
10-------- summary -------
11
12Total key length in bytes is 155 (avg len 8.61)
13
14Biggest string found "rand_16_0" has 4 bytes
15Biggest zset found "job:delayed" has 4 members
16
170 lists with 0 items (00.00% of keys, avg size 0.00)
180 hashs with 0 fields (00.00% of keys, avg size 0.00)
190 streams with 0 entries (00.00% of keys, avg size 0.00)
2017 strings with 67 bytes (94.44% of keys, avg size 3.94)
210 sets with 0 members (00.00% of keys, avg size 0.00)
221 zsets with 4 members (05.56% of keys, avg size 4.00)
23
当然,这种方法只能显示最大的那个 key,他不一定实际就是大 key,可能本身占用的内存并不多。
此外,如果在主节点执行,同样会阻塞运行,所以建议在从节点执行。
另外,也可以通过 SCAN来扫描 Redis,得到每个 key 的内存占用情况,从而感知到大 key 的存在:
1redis-cli --scan | while read key; do
2 echo "$(redis-cli memory usage $key) $key";
3done | sort -nr | head
4
使用 SCAN 命令不会阻塞 Redis,比较安全。
但是缺点是效率较低,对大量 key 的 Redis 数据库扫描时间较长。
也可以使用一些第三方软件来完成这一动作,比如 Redis RDB Tools。
实际上不仅读写会造成瓶颈,前面我们说过删除大 key 也会有性能问题。因为删除时不仅仅是删除一个操作,还会涉及到资源的回收和再分配,而 DEL是在主线程中执行的,Redis 中的执行命令是单线程的,这意味着直接影响了整个 Redis 的吞吐。
因此我们不能直接 DEL 大 key,更好的实践是使用 UNLINK代替 DEL,这样会分配另一个线程去回收,而不会阻塞主线程。
另一方面,如果 Redis 开启了 Lasy Free:lazyfree-lazy-user-del = yes,此时就不用 UNLINK,DEL 也会由其他线程执行了,从而不阻塞主线程。
站在业务的角度,有时候可能不可避免的会产生一些大 key,但原则上我们依旧要尽可能的避免这种情况的出现。
拿我们上一篇缓存文章中微博的例子为例,如果一个微博大 V 有非常多的粉丝(假设有一千万),这些数据量即使我们只存储 user_id,也会有不小的数据。此时我们就可以将大 V 的粉丝拆分成多个子列表来进行查询,一个子列表放 5000 个粉丝 id,避免单 key 过大。
在上一篇文章中,我们也说过热 key 的问题,热 key 对 Redis 主要造成的影响是:
说白了核心关键点就是网络实在不够用了。
而对于热 key 来说,除了加机器,还可以配合「发现-解决」的套路来减少热 key 带来的影响。
redis-cli --hotkeys -i 0.1来获取,但是相当于全 key 扫描,key 较多时成本会比较高,而且全量扫描的耗时导致它的实时性较差。对于热 key 来说,其实也没什么特别好的解决方案,主要也就是两个套路:
在发现热 key 的前提下构造多级缓存是一个比较正常的解决方案,这样有效降低了 Redis 的访问量,多级缓存的问题和解决方案在上一篇文章中也有提到。
大 key 和 热 key 不仅仅是一个技术问题,同时也要站在业务的角度来选择一个合适的解决方案。
此内容由惯性聚合(RSS阅读器)自动聚合整理,仅供阅读参考。 原文来自 — 版权归原作者所有。