全部产品
弹性计算 会员服务 网络 安全 移动云 数加·大数据分析及展现 数加·大数据应用 管理与监控 云通信 阿里云办公 培训与认证 更多
存储与CDN 数据库 域名与网站(万网) 应用服务 数加·人工智能 数加·大数据基础服务 互联网中间件 视频服务 开发者工具 解决方案 物联网 智能硬件
云数据库 Redis 版

如何搜索过大的 key

更新时间:2017-07-19 10:38:20

背景信息

Redis 提供了 list、hash、zset 等复杂类型的数据结构,业务在使用的时候可能由于 key 设计不合理导致某个 key 过大。由于 redis 简单的单线程模型,业务在获取或者删除大 key 的时候都会有一定的影响,另外在集群模式下由于大 key 的产生还很容易导致某个子节点的内存满。综上所述我们需要搜索工具来发现过大的 key。

对于 Redis 主从版本可以通过scan命令进行扫描,对于集群版本提供了ISCAN命令进行扫描,命令规则如下,其中节点个数 node 可以通过info命令来获取。

  1. ISCAN idx cursor [MATCH pattern] [COUNT count]

其中,idx 为节点的 id,从0开始,16到64 GB 的集群实例为8个节点故 idx 为0到7,128 GB 和256 GB 的为16个节点。

操作步骤

  1. 执行以下命令下载 python 客户端。

    1. wget "https://pypi.python.org/packages/68/44/5efe9e98ad83ef5b742ce62a15bea609ed5a0d1caf35b79257ddb324031a/redis-2.10.5.tar.gz#md5=3b26c2b9703b4b56b30a1ad508e31083"
  2. 解压安装 python 客户端。

    1. tar -xvf redis-2.10.5.tar.gz
    2. cd redis-2.10.5
    3. sudo python setup.py install
  3. 创建以下扫描脚本。

    1. import sys
    2. import redis
    3. def check_big_key(r, k):
    4. bigKey = False
    5. length = 0
    6. try:
    7. type = r.type(k)
    8. if type == "string":
    9. length = r.strlen(k)
    10. elif type == "hash":
    11. length = r.hlen(k)
    12. elif type == "list":
    13. length = r.llen(k)
    14. elif type == "set":
    15. length = r.scard(k)
    16. elif type == "zset":
    17. length = r.zcard(k)
    18. except:
    19. return
    20. if length > 10240:
    21. bigKey = True
    22. if bigKey :
    23. print db,k,type,length
    24. def find_big_key_normal(db_host, db_port, db_password, db_num):
    25. r = redis.StrictRedis(host=db_host, port=db_port, password=db_password, db=db_num)
    26. for k in r.scan_iter(count=1000):
    27. check_big_key(r, k)
    28. def find_big_key_sharding(db_host, db_port, db_password, db_num, nodecount):
    29. r = redis.StrictRedis(host=db_host, port=db_port, password=db_password, db=db_num)
    30. cursor = 0
    31. for node in range(0, nodecount) :
    32. while True:
    33. iscan = r.execute_command("iscan",str(node), str(cursor), "count", "1000")
    34. for k in iscan[1]:
    35. check_big_key(r, k)
    36. cursor = iscan[0]
    37. print cursor, db, node, len(iscan[1])
    38. if cursor == "0":
    39. break;
    40. if __name__ == '__main__':
    41. if len(sys.argv) != 4:
    42. print 'Usage: python ', sys.argv[0], ' host port password '
    43. exit(1)
    44. db_host = sys.argv[1]
    45. db_port = sys.argv[2]
    46. db_password = sys.argv[3]
    47. r = redis.StrictRedis(host=db_host, port=int(db_port), password=db_password)
    48. nodecount = r.info()['nodecount']
    49. keyspace_info = r.info("keyspace")
    50. for db in keyspace_info:
    51. print 'check ', db, ' ', keyspace_info[db]
    52. if nodecount > 1:
    53. find_big_key_sharding(db_host, db_port, db_password, db.replace("db",""), nodecount)
    54. else:
    55. find_big_key_normal(db_host, db_port, db_password, db.replace("db", ""))
  4. 执行python find_bigkey host 6379 password命令查找大 key。

    说明:该命令支持查找 Redis 主从版本和集群版本的大 key ,默认大 key 的阈值为10240。string 类型的 value 大于10240的是大 key,list 长度大于10240认为是大 key,hash field 的数目大于10240认为是大 key。

    另外默认该脚本每次搜索1000个 key,对业务的影响比较低,不过最好在业务低峰期进行操作,避免 scan 命令对业务的影响。

本文导读目录