談談使用Redis緩存時批量刪除的幾種實現

前言

在使用緩存的時候,咱們時不時會遇到這樣一個需求,根據緩存鍵的規則去批量刪除這些數據,比較常見的就是按前綴去刪除。git

舉個簡單的例子,Redis中如今有幾百個商品的數據,這些數據的key值是有必定規律的,都是以product:id的形式存在的。github

如今因爲不得覺得的緣由要刪除這幾百個商品的數據,這個時候咱們確定就要把緩存鍵以product:開頭的給所有刪除掉。redis

其實這個需求在Redis中是能夠很容易去實現的。緩存

來看看幾種常見的作法。lua

常見的幾種作法

  1. 用Keys命令找到key以後執行刪除操做
  2. 用Scan命令找到key以後執行刪除操做(2.8.0版本以後)
  3. 添加緩存數據的時候,能夠同時將key存放到一個SET中,而後依據這個SET來執行刪除操做

對於Keys命令,網上有很多血的教訓,對於生產環境仍是要謹慎謹慎再謹慎!能不用就別用。code

Scan命令的話是大部分人推薦的作法,是增量式迭代的一個命令。server

存到SET中就相對繁瑣一點,並且額外佔用了一部份內存。並且在進行刪除的時候還要從這裏讀取出相應的key,同時也要移除這部分key的數據。blog

下面來看看如何在.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

相關文章
相關標籤/搜索