背景
最近接到需求,要刪除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小時內完成清理。