【Redis】大key的处理
文章目录
- 什么是Redis的大key?
- 如何发现大key
- 如何删除大key?
什么是Redis的大key?
- String类型的值大于10kb
- hash、list、set、zset的元素个数超过5000个
只要满足上面二者之一,我们都称这个key为大key(big key)
如何发现大key
- redis-cli --bigkeys
利用redis-cli提供的–bigkeys参数,可以遍历分析所有的key,并返回key的整体统计信息与每个数据的最大的那个大key
redis-cli -h 127.0.0.1 -p 6379 -a “password” --bigkeys
- 第三方工具
使用Redis-Rdb-Tools分析RDB快照文件,全面分析内存使用情况
rdb dump.rdb -c memory --bytes 10240 -f redis.csv
- scan扫描
自己编写代码,使用scan扫描Redis中的所有key,利用strlen、hlen等命令判断key的长度(此处不建议使用MEMORY USAGE)
private Jedis jedis;
@BeforeEach
void setUp() {
// 1.建立连接
// jedis = new Jedis("192.168.150.101", 6379);
jedis = JedisConnectionFactory.getJedis();
// 2.设置密码
jedis.auth("123321");
// 3.选择库
jedis.select(0);
}
final static int STR_MAX_LEN = 10 * 1024;
final static int HASH_MAX_LEN = 500;
@Test
void testScan() {
int maxLen = 0;
long len = 0;
String cursor = "0";
do {
// 扫描并获取一部分key
ScanResult<String> result = jedis.scan(cursor);
// 记录cursor
cursor = result.getCursor();
List<String> list = result.getResult();
if (list == null || list.isEmpty()) {
break;
}
// 遍历
for (String key : list) {
// 判断key的类型
String type = jedis.type(key);
switch (type) {
case "string":
len = jedis.strlen(key);
maxLen = STR_MAX_LEN;
break;
case "hash":
len = jedis.hlen(key);
maxLen = HASH_MAX_LEN;
break;
case "list":
len = jedis.llen(key);
maxLen = HASH_MAX_LEN;
break;
case "set":
len = jedis.scard(key);
maxLen = HASH_MAX_LEN;
break;
case "zset":
len = jedis.zcard(key);
maxLen = HASH_MAX_LEN;
break;
default:
break;
}
if (len >= maxLen) {
System.out.printf("Found big key : %s, type: %s, length or size: %d %n", key, type, len);
}
}
} while (!cursor.equals("0"));
}
如何删除大key?
直接删除大key会造成阻塞,因为redis是单线程执行,阻塞期间,其他所有请求可能都会超时。超时越来越多,会造成redis连接耗尽,产生各种异常。
- 低峰期删除:凌晨,观察QPS(每秒查询量Query Per Second),选择低的时候,无法彻底解决阻塞,不过损失将会降低
- 分批吹删除:对于hash,使用hscan扫描法,对于集台采用srandmember每次随机取数据进行删除。对于有序集台可以使用zremrangebyrank直接删除,对于列表直接pop即可。
- 异步删除法:在Redis4.0之后,产生了一个unlink方法,用unlink代替del来删除,这样redis会将这个key放入到一个异步线程中,进行删除,这样不会阻塞主线程。