天天看點

【C#|.NET】分布式鎖服務

背景

  分布式鎖服務在大家的項目中或許用的不多,因為大家都把排他放在資料庫那一層來擋。當大量的行鎖、表鎖、事務充斥着資料庫的時候,不如換個角度思考問題。一般web應用很多的瓶頸都在資料庫上,這裡給大家介紹的是減輕資料庫鎖負擔的一種方案。

簡介

  如果我們的需求很簡單,例如對于使用者的賬戶資金,要保證原子性操作。并且不同的用戶端在同一時間内隻能送出一個對象操作。lock、單例?!在單台上還可以,但是大型web項目上,負載均衡是常用的技術手段手段,同一意義的對象可能存在不同的副本,這時我們又如何保證排他操作。資料庫的事務!除了這個,接下來我們引出本章的主題、分布式鎖服務。  

  一個簡單的鎖服務實作起來并不難,甚至利用memcache很快就能構造一套分布式鎖系統。我們隻需要在操作對象時寫入kv鍵值對,操作完畢時釋放kv,在讀取對象時判斷kv中是否有資料就可以了,我們甚至還可以給它一個預設的釋放時間。

  這是一種解決方案,但是如果我們的要求更高一點,我們需要權限認證(例如隻能來自xxx域名的請求)、需要上下級節點關聯(例如一個使用者的資金賬戶被鎖住,同時鎖住他的購物車、積分等)、需要螢幕回調、甚至需要考慮單點故障問題。那麼,蟲子在這裡推薦另一套方案----zookeeper。

zookeeper

  Zookeeper是Hadoop中的一個子產品。是一個分布式的,開源的分布式應用程式協調服務,用它可以來現同步服務,配置維護。

  更多的内容大家看文檔吧或者直接網上搜一下,理論性的内容寫多了讓人困。我們直接看實踐。

性能篇

  伺服器ubuntu (虛拟機一台)

  用戶端window2003

  服務端安裝好java環境 然後跟着官方的介紹部署

  

  啟動zkserver

  我們測試下鎖服務相關的操作

  ps:試下本機的windows2003  因為是本地環境 不于上面做對比 僅看看zookeeper本身的資料處理效率

功能篇

  一張圖就可以介紹完普通功能

  再看下watcher  

<a href="http://blog.51cto.com/dubing/791464#">?</a>

<code>public</code> <code>class</code> <code>MyWatch : IWatcher</code>

<code>    </code><code>{</code>

<code>        </code><code>public</code> <code>void</code> <code>Process(WatchedEvent qevent)</code>

<code>        </code><code>{</code>

<code>            </code><code>Console.WriteLine(</code><code>"this is MyWatch"</code><code>);</code>

<code>        </code><code>}    </code>

<code>    </code><code>}</code>

<code>public</code> <code>class</code> <code>MyWatch2 : IWatcher</code>

<code>            </code><code>Console.WriteLine(</code><code>"this is MyWatch2"</code><code>);</code>

<code>        </code><code>}  </code>

 建立連接配接時 new ZooKeeper("192.168.206.129:2181", new TimeSpan(0, 0, 0, 4000), new MyWatch());

檢查是否存在時zk.Exists(Dir, new MyWatch2());

擷取資料時zk.GetData(Dir, new MyWatch2(), stat);

我們再運作一遍之前的demo  去掉delete操作

加上delete操作

 淺析

  建立連接配接:

  1.擷取服務主機清單

  2.設定逾時時間

  3.注冊用戶端事件

  4.以線程安全的方式建立請求連接配接(啟動用戶端請求隊列,循環隊列基于socket通信、根據請求類型執行不同的請求動作)

  請求流程:

  構造請求頭、構造request,reponse、構造響應頭、構造Packet對象,packet對象準備好後,把整個對象放入一個outgoingQueue 

packet被放入outgoingQueue中,等待SendThread把packet對應的内容發送給server。server處理分3步在doio方法中ReadLength ReadConnectResult ReadResponse,直到ReadResponse方法中确定packet請求結束。

  響應流程:

  針對心跳的ping請求的resp,針對auth請求的resp,一般接口請求的resp,如果接口請求要求了watcher,當watcher關注的内容有變化時的notification

  鎖相關部分API方法:

  建立節點:create

  demo:zk.Create(Dir, severname.GetBytes(), Ids.OPEN_ACL_UNSAFE, CreateMode.Persistent);

  其中CreateMode分為4類Persistent、PersistentSequential、Ephemeral、EphemeralSequential

  PERSISTENT 建立持久化節點,對應機器關閉連接配接後節點/資料不會消失

  PERSISTENT_SEQUENTIAL 如果PATH是以’/’結尾則以這個PATH作為父節點,建立一個子節點,其子節點名字是一個按先後順序排列的數值;否則建立一個名字是‘/’後面字元加上先後順序排列的數值字元串的節點,同樣建立持久節點

  EPHEMERAL 建立瞬時節點,Zookeeper在感覺連接配接機器當機後會清除它建立的瞬時節點

  EPHEMERAL_SEQUENTIAL 穿件瞬時順序節點,和PERSISTENT_SEQUENTIAL一樣,差別在于它是瞬時的

  删除節點 delete

  demo :zk.Delete(Dir, -1);

  前一個參數代表節點名稱(一般用作路徑),後一個是版本号 -1表示全比對

  檢視節點 exists

  demo : zk.Exists(Dir, new MyWatch2());

  擷取資料 getData 

  demo :zk.GetData(Dir, new MyWatch2(), stat);

  擷取一個節點的資料,可注入watcher   

  設定資料 setData 

  demo : zk.SetData(Dir, new byte[1], 1);

  擷取下級節點集合 GetChildren

  demo :zk.GetChildren(Dir, true);

  存儲

  znodes類似檔案和目錄。但它不是一個典型的檔案系統,zookeeper資料儲存在記憶體中,這意味着zookeeper可以實作高吞吐量和低延遲。

  watcher

  Zookeeper有兩種watches,一種是data watches,另一種是child watches。其中,getData()和exists()以及create()等會添加data watches,getChildren()會添加child watches。而delete()涉及到删除資料和子節點,會同時觸發data watches和child watches。

  算法

  Paoxs算法 本篇中僅用單台server做demo 改個時間詳細介紹下Paoxs  

 本篇先到此 希望對大家有幫助

本文轉自 熬夜的蟲子  51CTO部落格,原文連結:http://blog.51cto.com/dubing/791464