分佈式鎖,分佈式事務

一、分佈式鎖

1、什麼是分佈式鎖?
場景1:常規的我們多線程訪問同一代碼塊的時候,爲了保證同一時間只能 由一個線程訪問,保證數據安全一致性,通常我們使用synchronized關鍵字來對方法加鎖,以達到保證數據安全性。

場景2:現在越來越多的項目,爲了追求性能與高併發,採用了soa架構,微服務架構,於是就會出現多個模塊單獨的服務。這個時候呢就會有一個問題,如何保證多個節點的現場同步執行呢? 這種情況呢,就會用到了分佈式鎖。

2、分佈式鎖的解決方案與實現有哪些呢?
1、數據庫解決方案思路:

        a.數據庫建一張表,字段方法名並且作爲唯一性,當一個方法執行時插入,則相當於獲得鎖,其他線程將無法訪問,方法執行完則釋放鎖。

但是上面這種存在問題:

1、數據庫單點,出現故障則將導致系統不可用。

2、沒有失效時間,一旦操作方法異常,導致一直沒有解鎖,也將導致其他不可用用。

        b.使用select * from user u where username = '' for update 來對記錄加上排他鎖。操作完成後使用commit命令釋放鎖。

2、基於緩存實現:  通常有Memcached、Redis實現等,以下以Redis實現分佈式鎖爲例

思路:主要用到的redis函數是setnx(),這個應該是實現分佈式鎖最主要的函數。首先是將某一任務標識名(這裏用Lock:order作爲標識名的例子)作爲鍵存到redis裏,併爲其設個過期時間,如果是還有Lock:order請求過來,先是通過setnx()看看是否能將Lock:order插入到redis裏,可以的話就返回true,不可以就返回false

具體實現參照:https://www.cnblogs.com/austinspark-jessylu/p/8043726.html

3.Zookeeper分佈式鎖

大致思路:每個客戶端對某個方法加鎖時,在zookeeper上的與該方法對應的指定節點的目錄下,生成一個唯一的瞬時有序節點。 判斷是否獲取鎖的方式很簡單,只需要判斷有序節點中序號最小的一個。 當釋放鎖的時候,只需將這個瞬時節點刪除即可。同時,其可以避免服務宕機導致的鎖無法釋放,而產生的死鎖問題。

ZK中創建和刪除節點只能通過Leader服務器來執行,然後將數據同不到所有的Follower機器上,所以性能上不如基於緩存實現。

 

二、分佈式事務:

舉個栗子吧:比如從支付寶轉100元到餘額寶,我們又兩個方法1、支付寶減掉100,2、餘額寶加上100。傳統的在一個模塊,一個服務,或者一個方法裏面,我們就很好解決了,只需要註解一個事務就行了,是吧。

@Transactional(rollbackFor=Exception.class) 這樣我們就可以保證兩個方法數據的一致性了。

但是顯然,現在我們的項目中,爲了滿足性能要求,不可能還這樣傳統單機實現。我們做成了兩個服務,在兩個不同的模塊 1、支付寶,2、餘額寶 這樣就存在了我們提到的問題,分佈式事務,這個時候如何解決呢?

通常來說呢 實現方式有如下幾種:

1、兩階段提交協議(Two-phase Commit,2PC):架構圖如下

簡單來說,協調器先給A/B各發一條,準備的命令,等到都返回準備好了的命令的時候,在發起事務提交。這樣來保證事務一致性,但是存在很多問題,就是通信上中斷的情況,會導致事務一致無法提交,而可能使系統崩潰。這就可以使用第二種方案。

2、TCC補償性,分爲三個階段TRYING-CONFIRMING-CANCELING(使用消息隊列實現,比如mq)
 

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章