概述

本文主要介绍如何搜索云数据库Redis中过大的Key。

 

详细信息

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

 

对于Redis主从版本可以通过SCAN命令进行扫描,对于集群版本阿里云提供了ISCAN命令进行扫描,命令规则如下。

1
iscan [$DB_Idx] cursor [MATCH pattern] [COUNT count]

注:[$DB_Idx]为节点的ID,从0开始,可以通过info命令来获取。16到64GB的集群实例为8个节点,故[$DB_Idx]为0到7,128GB和256GB的为16个节点,以此类推。

 

为了便于搜索过大的Key,本文提供Python版的扫描脚本,使用方法如下。也可使用redis-cli的“--bigkeys”选项查找大Key

  1. 执行如下命令,下载Python版本的Redis客户端。
  2. 依次执行如下命令,安装Python版本的Redis客户端。
    1
    tar -xvf redis-2.10.5.tar.gz<br>cd redis-2.10.5<br>sudo python setup.py install
  3. 参考如下代码,创建名为“find_bigkey”的扫描脚本。
    1
    import sys<br>import redis<br>def check_big_key(r, k):<br>  bigKey = False<br>  length = 0 <br>  try:<br>    type = r.type(k)<br>    if type == "string":<br>      length = r.strlen(k)<br>    elif type == "hash":<br>      length = r.hlen(k)<br>    elif type == "list":<br>      length = r.llen(k)<br>    elif type == "set":<br>      length = r.scard(k)<br>    elif type == "zset":<br>      length = r.zcard(k)<br>  except:<br>    return<br>  if length > 10240:<br>    bigKey = True<br>  if bigKey :<br>    print db,k,type,length<br>def find_big_key_normal(db_host, db_port, db_password, db_num):<br>  r = redis.StrictRedis(host=db_host, port=db_port, password=db_password, db=db_num)<br>  for k in r.scan_iter(count=1000):<br>    check_big_key(r, k)<br>def find_big_key_sharding(db_host, db_port, db_password, db_num, nodecount):<br>  r = redis.StrictRedis(host=db_host, port=db_port, password=db_password, db=db_num)<br>  cursor = 0<br>  for node in range(0, nodecount) :<br>    while True:<br>      iscan = r.execute_command("iscan",str(node), str(cursor), "count", "1000")<br>      for k in iscan[1]:<br>        check_big_key(r, k)<br>      cursor = iscan[0]<br>      print cursor, db, node, len(iscan[1])<br>      if cursor == "0":<br>        break;<br>if __name__ == '__main__':<br>  if len(sys.argv) != 4:<br>     print 'Usage: python ', sys.argv[0], ' host port password '<br>     exit(1)<br>  db_host = sys.argv[1]<br>  db_port = sys.argv[2]<br>  db_password = sys.argv[3]<br>  r = redis.StrictRedis(host=db_host, port=int(db_port), password=db_password)<br>  nodecount = r.info()['nodecount']<br>  keyspace_info = r.info("keyspace")<br>  for db in keyspace_info:<br>    print 'check ', db, ' ', keyspace_info[db]<br>    if nodecount > 1:<br>      find_big_key_sharding(db_host, db_port, db_password, db.replace("db",""), nodecount)<br>    else:<br>      find_big_key_normal(db_host, db_port, db_password, db.replace("db", "")) 
  4. 参考如下命令,查找较大的Key。
    1
    python find_bigkey [$DB_Host] [$DB_Port] [$DB_Pass]
    注:
    • [$DB_Host]:Redis数据库的主机名或IP地址。
    • [$DB_Port]:Redis数据库的端口号,默认为“6379”。
    • [$DB_Pass]:Redis数据库的密码。
    • 该命令支持查找Redis主从版本和Redis集群版本中的大Key。此处的大Key阈值为“10240”,比如:String类型的Value大于10240的是大Key,List长度大于10240认为是大Key,Hash Field的数目大于10240认为是大Key。
    • 该脚本默认每次搜索1000个Key,对业务的影响比较低,不过最好在业务低峰期进行操作,避免scan命令对业务造成影响。
    系统显示类似如下。