Redis SETNX實現分散式鎖

来源:https://www.cnblogs.com/rohmeng/archive/2019/08/22/11397476.html
-Advertisement-
Play Games

1、某進程1執行 SETNX lock 以嘗試獲取鎖 2、由於某進程2已獲得了鎖,所以進程1執行 SETNX lock 返回0,即獲取鎖失敗 3、進程1執行 GET lock 來檢測鎖是否已超時,如果沒超時,則線程等待一段時間,再次檢測 4、如果進程1檢測到鎖已超時,即當前的時間大於鍵 lock 的 ...


1、某進程1執行 SETNX lock 以嘗試獲取鎖

2、由於某進程2已獲得了鎖,所以進程1執行 SETNX lock 返回0,即獲取鎖失敗

3、進程1執行 GET lock 來檢測鎖是否已超時,如果沒超時,則線程等待一段時間,再次檢測

4、如果進程1檢測到鎖已超時,即當前的時間大於鍵 lock 的值,進程1會執行以下操作

GETSET lock <current Unix timestamp + lock timeout + 1>

5、由於 GETSET 操作在設置鍵的值的同時,還會返回鍵的舊值,通過比較鍵 lock 的舊值是否小於當前時間,可以判斷進程是否已獲得鎖

6、假如另一個進程3也檢測到鎖已超時,併在進程1之前執行了 GETSET 操作,那麼進程1的 GETSET 操作返回的是一個大於當前時間的時間戳,這樣進程1就不會獲得鎖而繼續等待。註意到,即使進程1接下來將鍵 lock 的值設置了比進程3設置的更大的值也沒影響。

另外,值得註意的是,在進程釋放鎖,即執行 DEL lock 操作前,需要先判斷鎖是否已超時。如果鎖已超時,那麼鎖可能已由其他進程獲得,這時直接執行 DEL lock 操作會導致把其他進程已獲得的鎖釋放掉。

C# Code

using System;
using System.Threading;
using System.Threading.Tasks;
using CSRedis;

namespace RedisLockDemo
{
    public class CsRedisLock
    {
        private static readonly int _lock_timeout = 40;
        private static readonly string _lock_key = "lock";
        public static void Test()
        {
            var rds = new CSRedisClient("127.0.0.1:6379,password=123456,defaultDatabase=13,poolsize=50,ssl=false");
            RedisHelper.Initialization(rds);

            Parallel.For(0, 13, x =>
            {
                if (GetLock(_lock_key))
                {
                    Console.WriteLine($"person:{x},線程ID:{Thread.CurrentThread.ManagedThreadId},獲得鎖 woking");

                    if (DateTimeOffset.Now.ToUnixTimeMilliseconds() < RedisHelper.Get<long>(_lock_key))
                    {
                        //釋放鎖
                        RedisHelper.Del(_lock_key);
                    }
                }
                else
                {
                    Console.WriteLine($"person:{x},線程ID:{Thread.CurrentThread.ManagedThreadId},獲取鎖異常");
                }
            });
            Console.WriteLine();
        }

        private static bool GetLock(string key)
        {
            bool getLocked = false;
            try
            {
                while (!getLocked)
                {
                    var now = DateTimeOffset.Now.ToUnixTimeMilliseconds();
                    var lock_time = now + _lock_timeout + 1;
                    getLocked = RedisHelper.SetNx(key, lock_time);
                    //判斷是否獲取鎖,
                    if (getLocked || now > RedisHelper.Get<long>(key) && now > RedisHelper.GetSet<long>(key, lock_time))
                    {
                        getLocked = true;
                    }
                    else
                    {
                        Thread.Sleep(30);
                    }
                }
            }
            catch (Exception ex)
            {
                Console.WriteLine(ex.Message);
            }
            return getLocked;
        }
    }
}

相關文檔:https://redis.io/commands/setnx


您的分享是我們最大的動力!

-Advertisement-
Play Games
更多相關文章
  • 創建定時任務的目的就是擺脫人為對程式重覆性地運行。 0. 首先用下麵的指令檢查你是否安裝crontab, 如果沒有的話按下麵的方式進行安裝 minute: 表示分鐘,可以是從0到59之間的任何整數。 hour:表示小時,可以是從0到23之間的任何整數。 day:表示日期,可以是從1到31之間的任何整 ...
  • tree命令,是大小寫敏感的。常用的是:1.tree -C 顏色顯示 2.tree -f 顯示文件全路徑ls -R也可以顯示樹結構,但沒上面 清晰 3.tree -L n n 是數字,表示顯示幾層 4.tree -P *.pl 只顯示文件目錄和*.pl的perl文件。 5.tree -F 顯示目錄後 ...
  • 安裝: yum install -y httpd php 查看版本:、 rpm -qa httpd php httpd-2.2.15-54.el6.centos.x86_64 php-5.3.3-48.el6_8.x86_64 修改apache配置文件: vim /etc/httpd/conf/ht ...
  • 需求1:新建除了root之外的新用戶,並且新用戶具有root用戶的相關功能 1.首先修改/etc/sudoers文件具有寫入的許可權 chmod 777 /etc/sudoers 2.修改/etc/sudoers vim /etc/sudoers,定位到如下行: ## Allow root to ru ...
  • 備份資料庫/usr/local/mysql5.5/bin/mysqldump -uroot -p1234abcd wordpress >~/wordpress_20151206.sql59 23 * * * /usr/local/mysql5.5/bin/mysqldump -uroot -p123 ...
  • 1.進程管理 psps --help 列印當前的進程信息ps -a 列印所有進程信息ps -e 列印所有進程信息 用的最多ps -eu 列印所有進程信息(更便捷的顯示方式)2.需要在進程中挑出我們需要管理的進程ps -e | grep mysqld3.kill進程典型需要kill關閉進程kill:向 ...
  • 0. 基本概念 一個【傳輸】(控制、批量、中斷、等時):由多個【事務】組成; 一個【事務】(IN、OUT、SETUP):由一多個【Packet】組成。 USB數據在【主機軟體】與【USB設備特定的端點】間被傳輸。【主機軟體】與【USB設備特定的端點】間的關聯叫做【pipes】。一個USB設備可以有多 ...
  • 轉自Clement-Xu的csdn博客 http://blog.csdn.net/clementad/article/details/41620631 Apache在Linux系統中,其實叫“httpd”,可以使用yum來安裝。 1、查看httpd包是否可用: # yum list | grep h ...
一周排行
    -Advertisement-
    Play Games
  • 概述:在C#中,++i和i++都是自增運算符,其中++i先增加值再返回,而i++先返回值再增加。應用場景根據需求選擇,首碼適合先增後用,尾碼適合先用後增。詳細示例提供清晰的代碼演示這兩者的操作時機和實際應用。 在C#中,++i 和 i++ 都是自增運算符,但它們在操作上有細微的差異,主要體現在操作的 ...
  • 上次發佈了:Taurus.MVC 性能壓力測試(ap 壓測 和 linux 下wrk 壓測):.NET Core 版本,今天計劃準備壓測一下 .NET 版本,來測試並記錄一下 Taurus.MVC 框架在 .NET 版本的性能,以便後續持續優化改進。 為了方便對比,本文章的電腦環境和測試思路,儘量和... ...
  • .NET WebAPI作為一種構建RESTful服務的強大工具,為開發者提供了便捷的方式來定義、處理HTTP請求並返迴響應。在設計API介面時,正確地接收和解析客戶端發送的數據至關重要。.NET WebAPI提供了一系列特性,如[FromRoute]、[FromQuery]和[FromBody],用 ...
  • 原因:我之所以想做這個項目,是因為在之前查找關於C#/WPF相關資料時,我發現講解圖像濾鏡的資源非常稀缺。此外,我註意到許多現有的開源庫主要基於CPU進行圖像渲染。這種方式在處理大量圖像時,會導致CPU的渲染負擔過重。因此,我將在下文中介紹如何通過GPU渲染來有效實現圖像的各種濾鏡效果。 生成的效果 ...
  • 引言 上一章我們介紹了在xUnit單元測試中用xUnit.DependencyInject來使用依賴註入,上一章我們的Sample.Repository倉儲層有一個批量註入的介面沒有做單元測試,今天用這個示例來演示一下如何用Bogus創建模擬數據 ,和 EFCore 的種子數據生成 Bogus 的優 ...
  • 一、前言 在自己的項目中,涉及到實時心率曲線的繪製,項目上的曲線繪製,一般很難找到能直接用的第三方庫,而且有些還是定製化的功能,所以還是自己繪製比較方便。很多人一聽到自己畫就害怕,感覺很難,今天就分享一個完整的實時心率數據繪製心率曲線圖的例子;之前的博客也分享給DrawingVisual繪製曲線的方 ...
  • 如果你在自定義的 Main 方法中直接使用 App 類並啟動應用程式,但發現 App.xaml 中定義的資源沒有被正確載入,那麼問題可能在於如何正確配置 App.xaml 與你的 App 類的交互。 確保 App.xaml 文件中的 x:Class 屬性正確指向你的 App 類。這樣,當你創建 Ap ...
  • 一:背景 1. 講故事 上個月有個朋友在微信上找到我,說他們的軟體在客戶那邊隔幾天就要崩潰一次,一直都沒有找到原因,讓我幫忙看下怎麼回事,確實工控類的軟體環境複雜難搞,朋友手上有一個崩潰的dump,剛好丟給我來分析一下。 二:WinDbg分析 1. 程式為什麼會崩潰 windbg 有一個厲害之處在於 ...
  • 前言 .NET生態中有許多依賴註入容器。在大多數情況下,微軟提供的內置容器在易用性和性能方面都非常優秀。外加ASP.NET Core預設使用內置容器,使用很方便。 但是筆者在使用中一直有一個頭疼的問題:服務工廠無法提供請求的服務類型相關的信息。這在一般情況下並沒有影響,但是內置容器支持註冊開放泛型服 ...
  • 一、前言 在項目開發過程中,DataGrid是經常使用到的一個數據展示控制項,而通常表格的最後一列是作為操作列存在,比如會有編輯、刪除等功能按鈕。但WPF的原始DataGrid中,預設只支持固定左側列,這跟大家習慣性操作列放最後不符,今天就來介紹一種簡單的方式實現固定右側列。(這裡的實現方式參考的大佬 ...