一区二区三区在线-一区二区三区亚洲视频-一区二区三区亚洲-一区二区三区午夜-一区二区三区四区在线视频-一区二区三区四区在线免费观看

服務器之家:專注于服務器技術及軟件下載分享
分類導航

PHP教程|ASP.NET教程|Java教程|ASP教程|編程技術|正則表達式|C/C++|IOS|C#|Swift|Android|VB|R語言|JavaScript|易語言|vb.net|

服務器之家 - 編程語言 - ASP.NET教程 - 詳解ASP.Net Core 中如何借助CSRedis實現一個安全高效的分布式鎖

詳解ASP.Net Core 中如何借助CSRedis實現一個安全高效的分布式鎖

2020-06-11 17:29菠蘿吹雪—Code ASP.NET教程

這篇文章主要介紹了ASP.Net Core 中如何借助CSRedis實現一個安全高效的分布式鎖,文中通過示例代碼介紹的非常詳細,對大家的學習或者工作具有一定的參考學習價值,需要的朋友們下面隨著小編來一起學習學習吧

引言:最近回頭看了看開發的.Net Core 2.1項目的復盤總結,其中在多處用到Redis實現的分布式鎖,雖然在OnResultExecuting方法中做了防止死鎖的處理,但在某些場景下還是會發生死鎖的問題,下面我只展示部分代碼:

詳解ASP.Net Core 中如何借助CSRedis實現一個安全高效的分布式鎖

問題:

(1)這里setnx設置的值“1”,我想問,你最后del的這個值一定是你自己創建的嗎?

(2)圖中標注的步驟1和步驟2不是原子操作,會有死鎖的概率嗎?

大家可以思考一下先,下面讓我們帶著這兩個問題往下看,下面介紹一下使用Redis實現分布式鎖常用的幾個命令。

一、使用Redis實現分布式鎖常見的幾個命令

? Setnx

命令:SETNX key value
說明:將 key 的值設為 value ,當且僅當 key 不存在。若給定的 key 已經存在,則 SETNX 不做任何動作。SETNX 是『SET if Not eXists』(如果不存在,則 SET)的簡寫。
時間復雜度:O(1)
返回值:設置成功,返回1 ; 設置失敗,返回 0

? Getset

命令:GETSET key value
說明:將給定 key 的值設為 value ,并返回 key 的舊值(old value)。當 key 存在但不是字符串類型時,返回一個錯誤。
時間復雜度:O(1)
返回值:返回給定 key 的舊值; 當 key 沒有舊值時,也即是, key 不存在時,返回 nil 。

? Expire

命令:EXPIRE key seconds
說明:為給定 key 設置生存時間,當 key 過期時(生存時間為 0 ),它會被自動刪除。
時間復雜度:O(1)
返回值:設置成功返回 1 ;當 key 不存在或者不能為 key 設置生存時間時(比如在低于 2.1.3 版本的 Redis 中你嘗試更新 key 的生存時間),返回 0 。

? Del

命令:DEL key [key ...]
說明:刪除給定的一個或多個 key 。不存在的 key 會被忽略。
時間復雜度:O(N); N 為被刪除的 key 的數量。
刪除單個字符串類型的 key ,時間復雜度為O(1)。
刪除單個列表、集合、有序集合或哈希表類型的 key ,時間復雜度為O(M), M 為以上數據結構內的元素數量。
返回值:被刪除 key 的數量。

好了,命令熟悉之后,下面我們就開始一步一步實現分布式鎖。

二、使用Redis實現分布式鎖版本一:與時間戳的結合

對于上面的setnx設置的默認值1,我們采用時間戳來防止問題一,下面先讓我們來看下想當然寫法流程圖。

流程圖:

詳解ASP.Net Core 中如何借助CSRedis實現一個安全高效的分布式鎖

C#代碼實現:

?
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
static void Main(string[] args)
    {
      var lockTimeout = 5000;//單位是毫秒
      var currentTime = DateTime.Now.ToUnixTime(true);
      if (SetNx("lockkey", currentTime+ lockTimeout,lockTimeout))
      {
        //TODO:一些業務邏輯代碼
        //.....
        //.....
        //最后釋放鎖
        Remove("lockkey");
      }
      else
      {
        Console.WriteLine("沒有獲得分布式鎖");
      }
      Console.ReadKey();
    }
 
    public static bool SetNx(string key,long time ,double expireMS)
    {
      if (redisClient.SetNx(key, time))
      {
        if (expireMS > 0)
          redisClient.Expire(key, TimeSpan.FromMilliseconds(expireMS));
        return true;
      }
      return false;
    }
 
    public static bool Remove(string key)
    {
      return redisClient.Del(key) > 0;
    }

上面的代碼中value的值我們使用時間戳,不是一個固定的值了,至少能保證你刪除的key確實是你自己的,所以,建議大家在設value的值時,不要設置一個固定的值,最好是隨機的。但是這樣寫雖然解決了問題一,但是這種寫法還是存在一定的風險,雖然Redis是單線程的并且setnx、expire是原子操作,但是先setnx再expire就不是原子操作了!!!我們要考慮多線程環境和容器部署時多實例環境等等,那這樣的寫法就會出現問題。

比如:現在有A、B兩臺服務器在跑這個應用,當A臺應用跑到:setnx成功但是還沒有設置過期時間的時候,突然重啟服務,這個時候在分布式環境中就會發生死鎖的問題,因為你沒有設置過期時間。

下面我們通過調試來展示死鎖的場景:

A應用:在執行到setnx成功但是在執行expire之前宕機了,此時的Redis已經有數據了,但是沒有過期時間

詳解ASP.Net Core 中如何借助CSRedis實現一個安全高效的分布式鎖

B應用:運行正常

但是B應用就會一直獲取不到鎖,導致死鎖。

詳解ASP.Net Core 中如何借助CSRedis實現一個安全高效的分布式鎖

所以上面在獲取鎖的邏輯還是有問題的,為了解決這個問題,我們采用下面的方式來處理。

三、使用Redis實現分布式鎖版本二:雙重防死鎖

流程圖:

詳解ASP.Net Core 中如何借助CSRedis實現一個安全高效的分布式鎖

C#代碼實現:

?
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
public static void RedisLockV2()
    {
      var lockTimeout = 5000;//單位是毫秒
      var currentTime = DateTime.Now.ToUnixTime(true);
 
      if (SetNxV2("lockkey",DateTime.Now.ToUnixTime(true)+lockTimeout))
      {
        //設置過期時間
        redisClient.Expire("lockkey", TimeSpan.FromMilliseconds(5000));
        //TODO:一些業務邏輯代碼
        
        Console.WriteLine("處理業務ing");
        Thread.Sleep(100000);
 
        Console.WriteLine("處理業務ed");
        //最后釋放鎖
        Remove("lockkey");
      }
      else
      {
        //未獲取到鎖,繼續判斷,判斷時間戳看看是否可以重置并獲取鎖
        var lockValue = redisClient.Get("lockkey");
        var time = DateTime.Now.ToUnixTime(true);
 
        if (!string.IsNullOrEmpty(lockValue) && time> lockValue.ToInt64())
        {
          //再次用當前時間戳getset
          //返回固定key的舊值,舊值判斷是否可以獲取鎖
          var getsetResult = redisClient.GetSet("lockkey", time);
          if (getsetResult == null || (getsetResult != null && getsetResult == lockValue))
          {
            Console.WriteLine("獲取到Redis鎖了");
            //真正獲取到鎖
            redisClient.Expire("lockkey", TimeSpan.FromMilliseconds(5000));
            //TODO:一些業務邏輯代碼
            //.....
            //.....
            Console.WriteLine("處理業務");
            //最后釋放鎖
            Remove("lockkey");
          }
          else
          {
            Console.WriteLine("沒有獲取到鎖");
          }
 
        }
        else
        {
          Console.WriteLine("沒有獲取到鎖");
        }
      }
      
    }

現在,Redis中的情況如下:

詳解ASP.Net Core 中如何借助CSRedis實現一個安全高效的分布式鎖

我們運行上面的代碼,結果如下:

詳解ASP.Net Core 中如何借助CSRedis實現一個安全高效的分布式鎖

副本.exe中添加一行代碼。來模擬這種場景:有A、B兩臺服務器在跑這個應用,當A臺應用跑到:setnx成功但是還沒有設置過期時間的時候,突然重啟服務,這個時候在分布式環境中就會發生死鎖的問題,因為你沒有設置過期時間

詳解ASP.Net Core 中如何借助CSRedis實現一個安全高效的分布式鎖

我們先執行Lottery.ThriftRpc - 副本.exe,等Redis里面有值了,并且這個key是沒有過期時間,再關閉掉該程序:

詳解ASP.Net Core 中如何借助CSRedis實現一個安全高效的分布式鎖

然后,再執行Lottery.ThriftRpc.exe

詳解ASP.Net Core 中如何借助CSRedis實現一個安全高效的分布式鎖

詳解ASP.Net Core 中如何借助CSRedis實現一個安全高效的分布式鎖

看,我們是不是解決了該問題,至于過期時間設置為多少要結合你的具體業務處理時間來計算出一個合理的值,好了,聊到這里關于Redis的分布式鎖就講完了,希望對你有幫助,謝謝。

四、總結:

上面的示例中Redis的組件用的是CSRedisCore,這里只是自己的一點體會,如果你有更好的辦法,可以在評論區討論,關于Redis的理論講解有太多的文章了,大家可以參考,關于Redis的文章我只總結工作中遇到的一些問題,關于文章中的源碼,我就不提供了,太簡單了。后面我會不定期分享一些Redis的問題,希望大家多多支持。

以上所述是小編給大家介紹的ASP.Net Core 中如何借助CSRedis實現一個安全高效的分布式鎖詳解整合,希望對大家有所幫助,如果大家有任何疑問請給我留言,小編會及時回復大家的。在此也非常感謝大家對服務器之家網站的支持!

原文鏈接:https://www.cnblogs.com/runningsmallguo/p/10322315.html

延伸 · 閱讀

精彩推薦
主站蜘蛛池模板: 超高清欧美同性videos | 女主被当众调教虐np | 91影视永久福利免费观看 | 亚洲精品成人在线 | 午夜综合 | 国产精品99久久免费观看 | 窝窝午夜精品一区二区 | 久久全国免费久久青青小草 | 国产精品嫩草影院一二三区 | 男人爱看的网站 | 国产亚洲福利一区二区免费看 | 婷婷久久精品 | 国产精品久久久久a影院 | 午夜国产精品福利在线观看 | 福利三区 | 亚洲 欧美 日韩 国产 视频 | 久久国产精品无码视欧美 | 97在线资源站 | 日本性生活大片 | 成人资源影音先锋久久资源网 | 无码人妻视频又大又粗欧美 | 娇妻被朋友征服中文字幕 | 爱色综合v | 亚洲精品色图 | 毛片资源站| 我在厨房摸岳的乳HD在线观看 | 午夜精品久久久久久久99蜜桃i | 爽好舒服快想要免费看 | 无人影院在线播放视频 | 95视频免费看片 | 国产免费色视频 | 99热这里只有精品在线播放 | 天海翼黄色三级 | 97精品久久天干天天蜜 | 免费全看男女拍拍拍的视频 | 四虎影院在线免费 | 91大神第九部红酒气质女 | 久久国产精品二区99 | 亚洲10p | 福利片福利一区二区三区 | 邪恶肉肉全彩色无遮琉璃神社 |