Redis big key

Redis中的big key指的是超过一定大小的键值对,可能导致性能下降、内存不均匀分配和网络拥塞等问题。常见的产生场景包括配置存储、用作队列和数据库。通过redis-cli的--bigkeys命令、离线分析RDB文件或使用SCAN命令可以发现big key。优化策略包括数据结构的合理设计、压缩处理、拆分集合和选择其他存储技术。删除big key时,推荐使用UNLINK命令以避免阻塞。

1、什么是 big key?

对于不同的数据类型,big key 定义不同:

  • 字符串类型:它的big体现在单个value值很大,一般认为超过10KB就是bigkey。
  • 非字符串类型:哈希、列表、集合、有序集合,它们的big体现在元素个数太多。建议把集合类型的元素个数控制在1万个以下。

2、 big key 的危害:

  • 影响性能,容易产生阻塞。
    • 在 Redis 基本 IO 模型中,主要是主线程在执行操作,任何耗时的操作,例如 bigkey、全量返回等操作,都是潜在的性能瓶颈。
    • AOF 重写过程中:主进程 fork 出后台的子进程会阻塞住子进程,阻塞时间取决于整个实例的内存大小。当主线程收到新写或修改的操作时,主线程会申请新的内存空间,用来保存新写或修改的数据,如果操作的是 bigkey,也就是数据量大的集合类型数据,那么主线程会因为申请大空间而面临阻塞风险。因为操作系统在分配内存空间时,有查找和锁的开销,这就会导致阻塞。
  • 造成网络拥塞:读取 bigkey 意味着需要消耗更多的网络流量,可能会对 Redis 服务器造成影响。
  • 过期删除:过期删除时,容易产生阻塞。
  • 迁移困难
  • 内存空间不均匀:比如在 Redis cluster 或者 codis 中,会造成节点的内存使用不均匀。

总结就是:bigkey 的读写操作会阻塞线程,降低 Redis 的处理效率 ​

阿里云建议:

当一个简单Key的Value过大或List、Hash等类型的数据中存储了大量的元素时,读取、删除这些数据的操作可能会花费过多的时间,阻塞单线程的Redis服务。此时您需要对内存结构进行优化,找出大Key并进行调整。

3、哪些场景下容易产生big key?

生产环境中遇到的几种不设置过期时间的情况:

  • 多个服务共享相同的配置,把配置存储到Redis中。
  • 把 Redis 当做队列,处理任务。消费没及时将导致队列越来越大。
  • 把 Redis 当做数据库,存储信息,不设置过期时间。List, hash 表越来越大。

4、如何发现 Big key

  • 使用 redis-cli 客户端的命令 --bigkeys
  • 生成 rdb 文件,离线分析 rdb 文件。比如:redis-rdb-cli,rdbtools;
  • 通过 scan 命令,对扫描出来的key进行类型判断,例如:string长度大于10K,list长度大于10240认为是big bigkeys

例子:寻找 big key 的 python 脚本:使用scan命令,每次扫描1000个key。 长度大于10240的key,则为big key。其中 string 类型,长度为10240,占用内存大约 10240 * 1 字节 = 10 kb

import sys
import redis
# 根据key的类型判断是否为big key
def check_big_key(r, k):
  bigKey = False
  length = 0 
  # 判断key的类型
  try:
    type = r.type(k)
    if type == "string":
      length = r.strlen(k)
    elif type == "hash":
      length = r.hlen(k)
    elif type == "list":
      length = r.llen(k)
    elif type == "set":
      length = r.scard(k)
    elif type == "zset":
      length = r.zcard(k)
  except:
    return
  # 长度大于10240,则为 big key
  if length > 10240:
    bigKey = True
  if bigKey :
    print db,k,type,length
    
# 用scan命令寻找 big key
def find_big_key_normal(db_host, db_port, db_password, db_num):
  r = redis.StrictRedis(host=db_host, port=db_port, password=db_password, db=db_num)
  for k in r.scan_iter(count=1000):
    check_big_key(r, k)
    
# 检查数据库分片是否有big key
def find_big_key_sharding(db_host, db_port, db_password, db_num, nodecount):
  r = redis.StrictRedis(host=db_host, port=db_port, password=db_password, db=db_num)
  cursor = 0
  for node in range(0, nodecount) :
    while True:
      iscan = r.execute_command("iscan",str(node), str(cursor), "count""1000")
      for k in iscan[1]:
        check_big_key(r, k)
      cursor = iscan[0]
      print cursor, db, node, len(iscan[1])
      if cursor == "0":
        break;
if __name__ == '__main__':
  if len(sys.argv) != 4:
     print 'Usage: python ', sys.argv[0], ' host port password '
     exit(1)
  db_host = sys.argv[1]
  db_port = sys.argv[2]
  db_password = sys.argv[3]
  r = redis.StrictRedis(host=db_host, port=int(db_port), password=db_password)
  # 节点数
  nodecount = r.info()['nodecount']
  keyspace_info = r.info("keyspace")
  for db in keyspace_info:
    print 'check ', db, ' ', keyspace_info[db]
    if nodecount > 1:
      # 有多个节点时
      find_big_key_sharding(db_host, db_port, db_password, db.replace("db",""), nodecount)
    else:
      # 只有单个节点
      find_big_key_normal(db_host, db_port, db_password, db.replace("db""")) 

5、如何优化 big key?

从两个方面来解决:

  • 合理优化数据结构:

1、对较大的数据进行压缩处理。 2、拆分集合:将大的集合拆分成小集合(如以时间进行分片)或者单个的数据。

  • 选择其他的技术来存储 big key:

3、或者使用其他的存储形式,考虑使用 cdn 或者文档性数据库 MongoDB。

6、如何删除 big key

直接使用 DEL 命令会发生什么?危险:同步删除 bigkey 会阻塞 Redis 其他命令,造成 Redis 阻塞。

  • 推荐使用 UNLINK 命令,异步删除 bigkey,不影响主线程执行其他命令。
  • 在业务的低峰期使用 scan 命令查找 big key,对于类型为集合的key,可以使用脚本逐一删除里面的元素。

[1] Redis中如何发现并优化big key? [2] Redis Big key 介绍 [3] Redis运维实战 [4] https://github.com/leonchen83/redis-rdb-cli [5] sripathikrishnan/redis-rdb-tools

评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
红包 添加红包
表情包 插入表情
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值