背景
最近接到需求,要删除ssdb中一个8000+w个member的zset。
该SSDB架构为双主模式+Keepalived构建的高可用。
处理时长要求在一天内完成。
相关SSDB-API
-
zrange:zrange name offset limit,根据下标索引区间 [offset, offset + limit) 获取 key-score 对, 下标从 0 开始. zrrange 是反向顺序获取.(注意! 本方法在 offset 越来越大时, 会越慢!)
-
zkeys:zkeys name key_start score_start score_end limit,列出 zset 中的 key 列表
-
zscan:zscan name key_start score_start score_end limit,列出 zset 中处于区间 (key_start+score_start, score_end] 的 key-score 列表. 如果 key_start 为空, 那么对应权重值大于或者等于 score_start 的 key 将被返回. 如果 key_start 不为空, 那么对应权重值大于 score_start 的 key, 或者大于 key_start 且对应权重值等于 score_start 的 key 将被返回.也就是说, 返回的 key 在 (key.score == score_start && key > key_start || key.score > score_start), 并且key.score <= score_end 区间. 先判断 score_start, score_end, 然后判断 key_start._,("", “”] 表示整个区间.
-
zclear:zclear name,删除 zset 中的所有 key.
-
zremrangebyscore:zremrangebyscore name start end,删除权重处于区间 [start,end] 的元素.
-
zremrangebyrank:zremrangebyrank name start end,删除位置处于区间 [start,end] 的元素.
-
zdel:zdel name key,获取 zset 中的指定 key.
-
multi_zdel :multi_zdel name key1 key2 …,批量删除 zset 中的 key.
Redis与SSDB命令映射表
解决思路
-
思路1:通过zclear直接删key
-
思路2:遍历zset的member(zkeys、zrange、zscan),然后删除member(zdel)
-
思路3:通过删除排名的方式进行删除(zremrangebyrank)
最终方案
使用思路3,但是为了记录删除数据,使用了zrange+zdel+pipeline的方法,具体实现如下。
在从库中进行操作。
demo
#encoding: utf-8
import redis
def del_big_zset(rip, rport, passwd, key)
rpool = redis.ConnectionPool(host = rip, port = rport, db = 0, password = passwd)
r = redis.Redis(connection_pool=rpool)
pipeline = r.pipeline(transaction=False)
count = 0
key_size = r.zcard(key)
start = 0
end = 1000
while(key_size > 1):
member_list = r.zrange(name=key,start=start,end=end)
for member in member_list:
print "%s" % (member)
pipeline.zrem(key, member)
result = pipeline.execute()
key_size = r.zcard(key)
效果
每秒清除速度是5k左右,最终预计5小时内完成清理。