概述
本文主要介绍如何搜索云数据库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。
- 执行如下命令,下载Python版本的Redis客户端。 1
wget
"https://pypi.python.org/packages/68/44/5efe9e98ad83ef5b742ce62a15bea609ed5a0d1caf35b79257ddb324031a/redis-2.10.5.tar.gz#md5=3b26c2b9703b4b56b30a1ad508e31083"
- 依次执行如下命令,安装Python版本的Redis客户端。 1
tar -xvf redis-
2.10
.
5
.tar.gz<br>cd redis-
2.10
.
5
<br>sudo python setup.py install
- 参考如下代码,创建名为“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"
,
""
))
- 参考如下命令,查找较大的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
命令对业务造成影响。