前言
bigkey和hotkey是Redis生产中两个比较常见的问题,本文从它们的概念、危害、发现、解决的角度,来分析一下这两个问题。
bigkey
概念
通俗易懂的讲,Big Key就是某个key对应的value很大,占用的redis空间很大,本质上是大value问题。key往往是程序可以自行设置的,value往往不受程序控制,因此可能导致value很大。
redis中这些Big Key对应的value值很大,在序列化/反序列化过程中花费的时间很大,因此当我们操作Big Key时,通常比较耗时,这就可能导致redis发生阻塞,从而降低redis性能。
用几个实际的例子对大Key的特征进行描述:
- 一个String类型的Key,它的值为5MB(数据过大)
- 一个List类型的Key,它的列表数量为20000个(列表数量过多)
- 一个ZSet类型的Key,它的成员数量为10000个(成员数量过多)
- 一个Hash格式的Key,它的成员数量虽然只有1000个但这些成员的value总大小为10MB(成员体积过大)
一般业界(参考阿里、快手Redis开发规范)对于key的规范如下:
string类型控制在10KB以内,hash、list、set、zset元素个数不要超过5000。
危害
- 慢查询:由于bigkey包含的数据量很大,导致一次请求的执行时间可能会很长,导致慢查询问题
- 集群内存分布不均衡:集群模式下,bigkey较多的节点内存占用偏高,影响集群稳定性
- 过期阻塞:当bigkey过期(删除)时,由于Redis单线程,会导致Redis阻塞从而影响客户端命令执行
- 网卡超负荷:试想一个string类型的key数据量为10mb,这时10000个用户请求该key,那么会需要约100G的网卡带宽,影响服务器的正常运转
发现
主要思路为扫描Redis的所有Key,判断Key的长度即可。
-
Redis 4.0以后的客户端提供了bigkeys命令,可以找出每种数据类型占用内存最多的Key。
删除
主要有两个办法1.遍历删除 2.Redis 异步删除命令
循环遍历删除
- Hash删除: hscan + hdel
public void delBigHash(String host, int port, String password, String bigHashKey) {
Jedis jedis = new Jedis(host, port);
if (password != null && !"".equals(password)) {
jedis.auth(password);
}
ScanParams scanParams = new ScanParams().count(100);
String cursor = "0";
do {
ScanResult<Entry<String, String>> scanResult = jedis.hscan(bigHashKey, cursor, scanParams);
List<Entry<String, String>> entryList = scanResult.getResult();
if (entryList != null && !entryList.isEmpty()) {
for (Entry<String, String>