分散式鎖,分散式事務以及解決方案瞭解一下
一、分散式鎖
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
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)