談談使用Redis緩存時批量刪除的幾種實現
前言
在使用緩存的時候,我們時不時會遇到這樣一個需求,根據緩存鍵的規則去批量刪除這些數據,比較常見的就是按前綴去刪除。
舉個簡單的例子,Redis中現在有幾百個商品的數據,這些數據的key值是有一定規律的,都是以product:id
的形式存在的。
現在由於不得以為的原因要刪除這幾百個商品的數據,這個時候我們肯定就要把緩存鍵以product:
開頭的給全部刪除掉。
其實這個需求在Redis中是可以很容易去實現的。
來看看幾種常見的做法。
常見的幾種做法
- 用Keys命令找到key之後執行刪除操作
- 用Scan命令找到key之後執行刪除操作(2.8.0版本之後)
- 添加緩存數據的時候,可以同時將key存放到一個SET中,然後依據這個SET來執行刪除操作
對於Keys命令,網上有不少血的教訓,對於生產環境還是要謹慎謹慎再謹慎!能不用就別用。
Scan命令的話是大部分人推薦的做法,是增量式叠代的一個命令。
存到SET中就相對繁瑣一點,而且額外占用了一部分內存。而且在進行刪除的時候還要從這裏讀取出相應的key,同時也要移除這部分key的數據。
下面來看看如何在.NET Core中來處理,主要還是針對SCAN的做法。
示例操作Redis用的是StackExchange.Redis。
使用IServer.Keys
可能有人會有疑惑,不是說Keys命令盡量不要用嗎?怎麽你還用?
這個還真的要解釋一下!
可能從方法上,我們找遍所有IServer和IDataBase接口都找不到純粹的SCAN命令(SetScan,HashScan等除外)。
但是如果看過裏面的實現,你就會知道是為什麽了!
傳送門:Keys
可以看看下圖高亮的兩行代碼:
大致意思就是,如果你用的Redis的版本支持SCAN命令,走的就是SCAN,反之只能是KEYS了。
下面定義一個查找RedisKey的方法。
private static RedisKey[] SearchRedisKeys(IServer server, string pattern) { var keys = server.Keys(pattern: pattern).ToArray(); Console.WriteLine("Search Count-{0}",keys.Length); return keys; }
知道那些Key要刪除,剩下的就比較簡單了!
private static void KeysOrScanSolution(IServer server,IDatabase db, string pattern)
{
db.KeyDelete(SearchRedisKeys(server, pattern));
}
使用IDatabase.Execute
IServer.Keys可以說是隱式的調用了SCAN命令,那麽我們自然也可以顯式的去調用這個命令來完成這些。
private static RedisKey[] SearchRedisKeys(IDatabase db,string pattern)
{
var keys = new HashSet<RedisKey>();
int nextCursor = 0;
do
{
RedisResult redisResult = db.Execute("SCAN", nextCursor.ToString(), "MATCH", pattern, "COUNT", "1000");
var innerResult = (RedisResult[])redisResult;
nextCursor = int.Parse((string)innerResult[0]);
List<RedisKey> resultLines = ((RedisKey[])innerResult[1]).ToList();
keys.UnionWith(resultLines);
}
while (nextCursor != 0);
return keys.ToArray();
}
刪除的代碼。
private static void ExecuteSolution(IDatabase db, string pattern)
{
db.KeyDelete(SearchRedisKeys(db, pattern));
}
當然還有一種做法是調用lua腳本去完成,這裏就不細說了。
總結
雖然上面幾種做法能比較簡單的處理這個問題,但是在拿出這些Keys的時候,客戶端的內存占用可能會比較大,尤其是有大量符合條件的緩存項的時候。
涉及緩存的諸多操作(包含根據前綴去刪除緩存項),我也在EasyCaching中實現了相應的操作,後面也會不斷的抽時間來完善這一項目,有興趣的朋友可以關註一下。
文中的示例代碼 RedisBatchRemoveSolution
談談使用Redis緩存時批量刪除的幾種實現