最新国产好看的视频,伊人天堂AV在线,国产Aaaaaa视频,蜜臀视频在线观看一区,人妻av色图,密臀久久久精品影片,青青视频免费观看毛片,久草在线观看视,国产三级精品色情在线

C# 實(shí)現(xiàn)Zookeeper分布式鎖的參考示例

 更新時(shí)間:2021年06月24日 10:43:28   作者:沒有星星的夏季  
Zookeeper分布式鎖的原理是巧妙的是使用了znode臨時(shí)節(jié)點(diǎn)的特點(diǎn)和監(jiān)聽(watcher)機(jī)制,監(jiān)聽機(jī)制很簡(jiǎn)單,就是我們可以給znode添加一個(gè)監(jiān)聽器,當(dāng)znode節(jié)點(diǎn)狀態(tài)發(fā)生改變時(shí)(如:數(shù)據(jù)內(nèi)容改變,節(jié)點(diǎn)被刪除),會(huì)通知到監(jiān)聽器。本文講解使用c#實(shí)現(xiàn)該功能

  分布式鎖 

  互聯(lián)網(wǎng)初期,我們系統(tǒng)一般都是單點(diǎn)部署,也就是在一臺(tái)服務(wù)器完成系統(tǒng)的部署,后期隨著用戶量的增加,服務(wù)器的壓力也越來越大,響應(yīng)速度越來越慢,甚至出現(xiàn)服務(wù)器崩潰的情況。

  為解決服務(wù)器壓力太大,響應(yīng)慢的特點(diǎn),分布式系統(tǒng)部署出現(xiàn)了。

  簡(jiǎn)單的說,就是我們將系統(tǒng)資源部署到多臺(tái)服務(wù)器中,然后使用一臺(tái)服務(wù)器做入口代理,根據(jù)一些決策將接收到的請(qǐng)求轉(zhuǎn)發(fā)到資源服務(wù)器,這也就是我們常說的 反向代理(一般就是使用nginx)

   雖然分布式解決了服務(wù)器壓力的問題,但也帶來了新的問題。

  比如,我們有一個(gè)下單統(tǒng)計(jì)的功能,當(dāng)完成下單后,需要執(zhí)行統(tǒng)計(jì)功能,而在高訪問的情況下,可能有兩個(gè)下單請(qǐng)求(A和B)同時(shí)完成,然后一起執(zhí)行了統(tǒng)計(jì)功能,這樣可能導(dǎo)致的結(jié)果就是A請(qǐng)求未將B請(qǐng)求數(shù)據(jù)統(tǒng)計(jì)在內(nèi),而B請(qǐng)求可能也未將A請(qǐng)求數(shù)據(jù)統(tǒng)計(jì)在內(nèi),這樣就造成了數(shù)據(jù)的統(tǒng)計(jì)錯(cuò),這個(gè)問題的產(chǎn)生的根本原因就是統(tǒng)計(jì)功能的并發(fā)導(dǎo)致的,如果是單點(diǎn)部署的系統(tǒng),我們簡(jiǎn)單的使用一個(gè)鎖操作就能完成了,但是在分布式環(huán)境下,A和B請(qǐng)求可能同時(shí)運(yùn)行在兩個(gè)服務(wù)器中,普通的鎖就不能起到效果了,這個(gè)時(shí)候就要使用分布式鎖了。 

  Zookeeper分布式鎖原理

  分布式鎖的實(shí)現(xiàn)發(fā)放有多種,簡(jiǎn)單的,我們可以使用數(shù)據(jù)庫表去實(shí)現(xiàn)它,也可以使用redis去實(shí)現(xiàn)它,這里要使用的Zookeeper去實(shí)現(xiàn)分布式鎖

  Zookeeper分布式鎖的原理是巧妙的是使用了znode臨時(shí)節(jié)點(diǎn)的特點(diǎn)和監(jiān)聽(watcher)機(jī)制,監(jiān)聽機(jī)制很簡(jiǎn)單,就是我們可以給znode添加一個(gè)監(jiān)聽器,當(dāng)znode節(jié)點(diǎn)狀態(tài)發(fā)生改變時(shí)(如:數(shù)據(jù)內(nèi)容改變,節(jié)點(diǎn)被刪除),會(huì)通知到監(jiān)聽器。

  前面幾節(jié)介紹過znode有三種類型  

  PERSISTENT:持久節(jié)點(diǎn),即使在創(chuàng)建該特定znode的客戶端斷開連接后,持久節(jié)點(diǎn)仍然存在。默認(rèn)情況下,除非另有說明,否則所有znode都是持久的。
  EPHEMERAL:臨時(shí)節(jié)點(diǎn),客戶端是連接狀態(tài)時(shí),臨時(shí)節(jié)點(diǎn)就是有效的。當(dāng)客戶端與ZooKeeper集合斷開連接時(shí),臨時(shí)節(jié)點(diǎn)會(huì)自動(dòng)刪除。臨時(shí)節(jié)點(diǎn)不允許有子節(jié)點(diǎn)。臨時(shí)節(jié)點(diǎn)在leader選舉中起著重要作用。
  SEQUENTIAL:順序節(jié)點(diǎn),可以是持久的或臨時(shí)的。當(dāng)一個(gè)新的znode被創(chuàng)建為一個(gè)順序節(jié)點(diǎn)時(shí),ZooKeeper通過將10位的序列號(hào)附加到原始名稱來設(shè)置znode的路徑,順序節(jié)點(diǎn)在鎖定和同步中起重要作用。

  其中,順序節(jié)點(diǎn),可以是持久的或臨時(shí)的,而臨時(shí)節(jié)點(diǎn)有個(gè)特點(diǎn),就是它屬于創(chuàng)建它的那個(gè)會(huì)話,當(dāng)會(huì)話斷開,臨時(shí)節(jié)點(diǎn)就會(huì)自動(dòng)刪除,如果在臨時(shí)節(jié)點(diǎn)上注冊(cè)了監(jiān)聽器,那么監(jiān)聽器就會(huì)收到通知,如果臨時(shí)節(jié)點(diǎn)有了時(shí)間順序,那我們?yōu)閷?shí)現(xiàn)分布式鎖就又有一個(gè)想法:

  假如在Zookeeper中有一個(gè)znode節(jié)點(diǎn)/Locker

  1、當(dāng)client1連接Zookeeper時(shí),先判斷/Locker節(jié)點(diǎn)是否存在子節(jié)點(diǎn),如果沒有子節(jié)點(diǎn),那么會(huì)在/Locker節(jié)點(diǎn)下創(chuàng)建一個(gè)臨時(shí)順序的znode節(jié)點(diǎn),假如是/client1,表示client1獲取了鎖狀態(tài),client1可以繼續(xù)執(zhí)行。

  2、當(dāng)client2連接Zookeeper時(shí),先判斷/Locker節(jié)點(diǎn)是否存在子節(jié)點(diǎn),發(fā)現(xiàn)已經(jīng)存在子節(jié)點(diǎn)了,然后獲取/Locker下的所有子節(jié)點(diǎn),同時(shí)按時(shí)間順序排序,在最后一個(gè)節(jié)點(diǎn),也就是/client1節(jié)點(diǎn)上注冊(cè)一個(gè)監(jiān)聽器(watcher1),同時(shí)在/Locker節(jié)點(diǎn)下創(chuàng)建一個(gè)臨時(shí)順序的znode節(jié)點(diǎn),假如是/client2。同時(shí)client2將被阻塞,而阻塞狀態(tài)的釋放是在監(jiān)聽器(watcher1)中的。

  3、當(dāng)client3連接Zookeeper時(shí),先判斷/Locker節(jié)點(diǎn)是否存在子節(jié)點(diǎn),發(fā)現(xiàn)已經(jīng)存在子節(jié)點(diǎn)了,然后獲取/Locker下的所有子節(jié)點(diǎn),同時(shí)按時(shí)間順序排序,在最后一個(gè)節(jié)點(diǎn),也就是/client2節(jié)點(diǎn)上注冊(cè)一個(gè)監(jiān)聽器(watcher2),同時(shí)在/Locker節(jié)點(diǎn)下創(chuàng)建一個(gè)臨時(shí)順序的znode節(jié)點(diǎn),假如是/client3。同時(shí)client2將被阻塞,而阻塞狀態(tài)的釋放是在監(jiān)聽器(watcher2)中的。

  以此類推。

  4、當(dāng)client1執(zhí)行完操作了,斷開Zookeeper的連接,因?yàn)?client1是臨時(shí)順序節(jié)點(diǎn),于是將會(huì)自動(dòng)刪除,而client2已經(jīng)往/client1節(jié)點(diǎn)中注冊(cè)了一個(gè)監(jiān)聽器(watcher1),于是watcher1將會(huì)受到通知,而watcher1又會(huì)釋放client2的阻塞狀態(tài)。于是client2獲取鎖狀態(tài),繼續(xù)執(zhí)行。

  5、當(dāng)client2執(zhí)行完操作了,斷開Zookeeper的連接,因?yàn)?client2是臨時(shí)順序節(jié)點(diǎn),于是將會(huì)自動(dòng)刪除,而client3已經(jīng)往/client2節(jié)點(diǎn)中注冊(cè)了一個(gè)監(jiān)聽器(watcher2),于是watcher2將會(huì)受到通知,而watcher2又會(huì)釋放client3的阻塞狀態(tài)。于是client3獲取鎖狀態(tài),繼續(xù)執(zhí)行。

  以此類推。

  這樣,不管分布式環(huán)境中有幾臺(tái)服務(wù)器,都可以保證程序的排隊(duì)似的執(zhí)行了。

  C#實(shí)現(xiàn)Zookeeper分布式鎖

  上一節(jié)有封裝過一個(gè)ZookeeperHelper的輔助類(Zookeeper基礎(chǔ)教程(四):C#連接使用Zookeeper),使用這個(gè)輔助類實(shí)現(xiàn)了一個(gè)ZookeeperLocker類: 

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading;
using System.Threading.Tasks;

namespace AspNetCore.ZookeeperConsole
{
    /// <summary>
    /// 基于Zookeeper的分布式鎖
    /// </summary>
    public class ZookeeperLocker : IDisposable
    {
        /// <summary>
        /// 單點(diǎn)鎖
        /// </summary>
        static object locker = new object();
        /// <summary>
        /// Zookeeper集群地址
        /// </summary>
        string[] address;
        /// <summary>
        /// Zookeeper操作輔助類
        /// </summary>
        ZookeeperHelper zookeeperHelper;

        /// <summary>
        /// 構(gòu)造函數(shù)
        /// </summary>
        /// <param name="lockerPath">分布式鎖的根路徑</param>
        /// <param name="address">集群地址</param>
        public ZookeeperLocker(string lockerPath, params string[] address) : this(lockerPath, 0, address)
        {
        }
        /// <summary>
        /// 構(gòu)造函數(shù)
        /// </summary>
        /// <param name="lockerPath">分布式鎖的根路徑</param>
        /// <param name="sessionTimeout">回話過期時(shí)間</param>
        /// <param name="address">集群地址</param>
        public ZookeeperLocker(string lockerPath, int sessionTimeout, params string[] address)
        {
            this.address = address.ToArray();

            zookeeperHelper = new ZookeeperHelper(address, lockerPath);
            if (sessionTimeout > 0)
            {
                zookeeperHelper.SessionTimeout = sessionTimeout;
            }
            if (!zookeeperHelper.Connect())
            {
                throw new Exception("connect failed:" + string.Join(",", address));
            }
            lock (locker)
            {
                if (!zookeeperHelper.Exists())//根節(jié)點(diǎn)不存在則創(chuàng)建
                {
                    zookeeperHelper.SetData("", "", true);
                }
            }
        }
        /// <summary>
        /// 生成一個(gè)鎖
        /// </summary>
        /// <returns>返回鎖名</returns>
        public string CreateLock()
        {
            var path = Guid.NewGuid().ToString().Replace("-", "");
            while (zookeeperHelper.Exists(path))
            {
                path = Guid.NewGuid().ToString().Replace("-", "");
            }
            return CreateLock(path);
        }
        /// <summary>
        /// 使用指定的路徑名稱設(shè)置鎖
        /// </summary>
        /// <param name="path">鎖名,不能包含路徑分隔符(/)</param>
        /// <returns>返回鎖名</returns>
        public string CreateLock(string path)
        {
            if (path.Contains("/"))
            {
                throw new ArgumentException("invalid path");
            }
            return zookeeperHelper.SetData(path, "", false, true);
        }
        /// <summary>
        /// 獲取鎖
        /// </summary>
        /// <param name="path">鎖名</param>
        /// <returns>如果獲得鎖返回true,否則一直等待</returns>
        public bool Lock(string path)
        {
            return LockAsync(path).GetAwaiter().GetResult();
        }
        /// <summary>
        /// 獲取鎖
        /// </summary>
        /// <param name="path">鎖名</param>
        /// <param name="millisecondsTimeout">超時(shí)時(shí)間,單位:毫秒</param>
        /// <returns>如果獲得鎖返回true,否則等待指定時(shí)間后返回false</returns>
        public bool Lock(string path, int millisecondsTimeout)
        {
            return LockAsync(path, millisecondsTimeout).GetAwaiter().GetResult();
        }
        /// <summary>
        /// 異步獲取鎖等等
        /// </summary>
        /// <param name="path">鎖名</param>
        /// <returns>如果獲得鎖返回true,否則一直等待</returns>
        public async Task<bool> LockAsync(string path)
        {
            return await LockAsync(path, System.Threading.Timeout.Infinite);
        }
        /// <summary>
        /// 異步獲取鎖等等
        /// </summary>
        /// <param name="path">鎖名</param>
        /// <param name="millisecondsTimeout">超時(shí)時(shí)間,單位:毫秒</param>
        /// <returns>如果獲得鎖返回true,否則等待指定時(shí)間后返回false</returns>
        public async Task<bool> LockAsync(string path, int millisecondsTimeout)
        {
            var array = await zookeeperHelper.GetChildrenAsync("", true);
            if (array != null && array.Length > 0)
            {
                var first = array.FirstOrDefault();
                if (first == path)//正好是優(yōu)先級(jí)最高的,則獲得鎖
                {
                    return true;
                }

                var index = array.ToList().IndexOf(path);
                if (index > 0)
                {
                    //否則添加監(jiān)聽
                    var are = new AutoResetEvent(false);
                    var watcher = new NodeWatcher();
                    watcher.NodeDeleted += (ze) =>
                    {
                        are.Set();
                    };
                    if (await zookeeperHelper.WatchAsync(array[index - 1], watcher))//監(jiān)聽順序節(jié)點(diǎn)中的前一個(gè)節(jié)點(diǎn)
                    {
                        if (!are.WaitOne(millisecondsTimeout))
                        {
                            return false;
                        }
                    }

                    are.Dispose();
                }
                else
                {
                    throw new InvalidOperationException($"no locker found in path:{zookeeperHelper.CurrentPath}");
                }
            }
            return true;
        }
        /// <summary>
        /// 釋放資源
        /// </summary>
        public void Dispose()
        {
            zookeeperHelper.Dispose();
        }
    }
}

  現(xiàn)在寫個(gè)程序可以模擬一下

using System;
using System.Collections.Generic;
using System.Text;
using System.Threading;

namespace AspNetCore.ZookeeperConsole
{
    class Program
    {
        static void Main(string[] args)
        {
            //Zookeeper連接字符串,采用host:port格式,多個(gè)地址之間使用逗號(hào)(,)隔開
            string[] address = new string[] { "192.168.209.133:2181", "192.168.209.133:2181", "192.168.209.133:2181" };
            //會(huì)話超時(shí)時(shí)間,單位毫秒
            int sessionTimeOut = 10000;
            //鎖節(jié)點(diǎn)根路徑
            string lockerPath = "/Locker";

            for (var i = 0; i < 10; i++)
            {
                string client = "client" + i;
                //多線程模擬并發(fā)
                new Thread(() =>
                {
                    using (ZookeeperLocker zookeeperLocker = new ZookeeperLocker(lockerPath, sessionTimeOut, address))
                    {
                        string path = zookeeperLocker.CreateLock();
                        if (zookeeperLocker.Lock(path))
                        {
                            //模擬處理過程
                            Console.WriteLine($"【{client}】獲得鎖:{DateTime.Now}");
                            Thread.Sleep(3000);
                            Console.WriteLine($"【{client}】處理完成:{DateTime.Now}");
                        }
                        else
                        {
                            Console.WriteLine($"【{client}】獲得鎖失敗:{DateTime.Now}");
                        }
                    }
                }).Start();
            }
                        
            Console.ReadKey();
        }
    }
}

  運(yùn)行結(jié)果如下:

   

   可以發(fā)現(xiàn),鎖功能是實(shí)現(xiàn)了的

  如果程序運(yùn)行中打印日志:Client session timed out, have not heard from server in 8853ms for sessionid 0x1000000ec5500b2

  或者直接拋出異常:org.apache.zookeeper.KeeperException.ConnectionLossException:“Exception_WasThrown”

  只需要適當(dāng)調(diào)整sessionTimeOut時(shí)間即可

以上就是C# 實(shí)現(xiàn)Zookeeper分布式鎖的參考示例的詳細(xì)內(nèi)容,更多關(guān)于C# 實(shí)現(xiàn)Zookeeper分布式鎖的資料請(qǐng)關(guān)注腳本之家其它相關(guān)文章!

您可能感興趣的文章:

相關(guān)文章

  • 如何使用C#代碼創(chuàng)建快捷方式文件詳解

    如何使用C#代碼創(chuàng)建快捷方式文件詳解

    在Windows中創(chuàng)建快捷方式很簡(jiǎn)單,如果想用C#代碼的方式創(chuàng)建,就沒有那么方便了,因?yàn)?NET框架沒有提供直接創(chuàng)建快捷方式的方法。這篇文章主要給大家介紹了關(guān)于如何使用C#代碼創(chuàng)建快捷方式文件的相關(guān)資料,需要的朋友可以參考下
    2018-08-08
  • C#實(shí)現(xiàn)基于Base64的加密解密類實(shí)例

    C#實(shí)現(xiàn)基于Base64的加密解密類實(shí)例

    這篇文章主要介紹了C#實(shí)現(xiàn)基于Base64的加密解密類,實(shí)例分析了C#基于Base64的加密解密實(shí)現(xiàn)技巧,具有一定參考借鑒價(jià)值,需要的朋友可以參考下
    2015-03-03
  • C# WinForm調(diào)用net core實(shí)現(xiàn)文件上傳接口

    C# WinForm調(diào)用net core實(shí)現(xiàn)文件上傳接口

    這篇文章主要為大家詳細(xì)介紹了C# WinForm如何調(diào)用net core實(shí)現(xiàn)文件上傳接口,文中的示例代碼講解詳細(xì),感興趣的小伙伴可以跟隨小編一起學(xué)習(xí)一下
    2024-04-04
  • C#中常用的運(yùn)算符總結(jié)

    C#中常用的運(yùn)算符總結(jié)

    在本篇文章里小編給大家分享了關(guān)于C#中常用的運(yùn)算符的知識(shí)點(diǎn)總結(jié),需要的朋友們跟著學(xué)習(xí)下。
    2019-03-03
  • C# Resources資源詳解

    C# Resources資源詳解

    這篇文章主要為大家詳細(xì)介紹了C# Resources資源,包括Resource Basics、Strongly Typed Resources等,具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下
    2017-01-01
  • C#實(shí)現(xiàn)順序隊(duì)列和鏈隊(duì)列的代碼實(shí)例

    C#實(shí)現(xiàn)順序隊(duì)列和鏈隊(duì)列的代碼實(shí)例

    今天小編就為大家分享一篇關(guān)于C#實(shí)現(xiàn)順序隊(duì)列和鏈隊(duì)列的代碼實(shí)例,小編覺得內(nèi)容挺不錯(cuò)的,現(xiàn)在分享給大家,具有很好的參考價(jià)值,需要的朋友一起跟隨小編來看看吧
    2018-10-10
  • 聊一聊C# 8.0中的await foreach使用

    聊一聊C# 8.0中的await foreach使用

    這篇文章主要介紹了聊一聊C# 8.0中的await foreach使用,小編覺得挺不錯(cuò)的,現(xiàn)在分享給大家,也給大家做個(gè)參考。一起跟隨小編過來看看吧
    2019-06-06
  • silverlight實(shí)現(xiàn)圖片局部放大效果的方法

    silverlight實(shí)現(xiàn)圖片局部放大效果的方法

    這篇文章主要介紹了silverlight實(shí)現(xiàn)圖片局部放大效果的方法,結(jié)合實(shí)例形式分析了silverlight針對(duì)圖片屬性的相關(guān)操作技巧,需要的朋友可以參考下
    2017-03-03
  • c#中利用委托反射將DataTable轉(zhuǎn)換為實(shí)體集的代碼

    c#中利用委托反射將DataTable轉(zhuǎn)換為實(shí)體集的代碼

    c#中利用委托反射將DataTable轉(zhuǎn)換為實(shí)體集的代碼,需要的朋友可以參考下
    2012-10-10
  • C#線程隊(duì)列用法實(shí)例分析

    C#線程隊(duì)列用法實(shí)例分析

    這篇文章主要介紹了C#線程隊(duì)列用法,以實(shí)例形式分析了C#線程隊(duì)列的創(chuàng)建、運(yùn)行、等待、結(jié)束等操作技巧,具有一定參考借鑒價(jià)值,需要的朋友可以參考下
    2015-09-09

最新評(píng)論

忻州市| 遵义市| 浦县| 清流县| 菏泽市| 开化县| 济南市| 蓝山县| 晴隆县| 焦作市| 嫩江县| 江口县| 岱山县| 宜州市| 义乌市| 龙井市| 城固县| 磴口县| 醴陵市| 深水埗区| 南皮县| 綦江县| 密山市| 衡南县| 康定县| 南郑县| 敖汉旗| 龙山县| 洪泽县| 阿拉善左旗| 闸北区| 逊克县| 大丰市| 乌拉特前旗| 罗城| 富裕县| 舟曲县| 苗栗市| 祥云县| 庄河市| 县级市|