fescar鎖設計和隔離級別的理解

Fescar全局鎖的理解

前幾天夜裏,我老大發我一篇文章說阿里的GTS開源了.
由於一直對分佈式事務比較感興趣。立馬pull了代碼,進行閱讀。
基本的原理,實現方案我就不一一細化了,詳細見官方文檔(寫的很棒,點贊)。 

在fescar的社區,你們比較關注的是經過fescar回滾到before快照前,別的線程假如更新了數據,且業務走完了,那麼恢復的這個快照不就是髒數據了麼。
很顯然,這種狀況在fescar中是不被容許的。

那麼fescar是如何作的呢?

咱們先簡單瞭解一下fescar的設計原理git

那些一上來就喜歡看源碼的同窗,必定不要錯過這麼官方的圖文介紹,看完再讀源碼事半功倍.

Fescar官方介紹github

瞭解完Fescar的基本原理,咱們重點關注下Fescar的全局排他鎖sql

Fescar設計了一個**全局的排他鎖**,來保證事務間的 **寫隔離**。

關於隔離性:(這是Fescar官方給的一段話)數據庫

全局事務的隔離性是創建在分支事務的本地隔離級別基礎之上的。

在數據庫本地隔離級別  **讀已提交或以上** 的前提下,Fescar 設計了由事務協調器維護的 全局寫排他鎖,來保證事務間的 寫隔離,將 **全局事務默認定義在 讀未提交 的隔離級別上**。

咱們對隔離級別的共識是:絕大部分應用在讀已提交的隔離級別下工做是沒有問題的。而實際上,這當中又有絕大多數的應用場景,實際上工做在讀未提交的隔離級別下一樣沒有問題。

在極端場景下,應用若是須要達到全局的讀已提交,Fescar也提供了相應的機制來達到目的。
默認,Fescar 是工做在 讀無提交 的隔離級別下,保證絕大多數場景的高效性。

個人解讀api

本地事務【讀已提交】,fescar全局事務【讀未提交】。這是這段話的核心。
我理解的這段話中fescar全局事務讀未提交,並非說本地事務的db數據沒有正常提交,而是指全局事務二階段commit|rollback未真正處理完(即未釋放全局鎖)。

總結來講:全局未提交可是本地已提交的數據,對其餘全局事務是可見的【固然在本地事務提交後,本地事務提交前,隔離級別是本地事務的管轄範圍】

for example
產品份額有5W,A用戶購買了2萬,份額branch一階段完畢(本地事務份額已經扣除commit),可是在下單的時候異常了。
由於本地事務讀已提交,這時候fescar容許業務訪問該條數據,3W,在A用戶的份額branch未回滾成功前,對其餘用戶可見。
可是其餘用戶並不能買該產品,必須等到產品份額回滾到5萬,其餘用戶才能夠操做產品數據。

因此看了這個例子 真的有必要作到全局事務讀已提交麼?

咱們先來看一下Fescar的全局鎖的作法異步

Fescar一階段分佈式

1. 本地(Branch)在向TC註冊的時候,把本地事務須要修改的數據table+pks提交到server端申請鎖,拿到全局鎖後,才能提交本地事務
2. 全局鎖的結構:resourceId + table + pks
3. 鎖是存在server端 branchSession中

Fescar二階段性能

一階段本地事務提交,db的鎖釋放了(for update鎖),可是全局鎖繼續保持,
直到二階段決議(注意釋放鎖的順序):
1. 提交:TC 釋放鎖,通知branch提交後 (rm端異步處理)
2. 回滾:TC 通知branch回滾後,釋放鎖(rm端同步處理 執行undo_log)

Fescar如何保障鎖的高效?spa

你們本身先思考下,最後給你們仔細解讀官方的demo,並分析fescar的性能問題

Fescar目前開源版本全局鎖的實現線程

你們有興趣本身閱讀:com.alibaba.fescar.server.lock.DefaultLockManagerImpl

官方的圖實在是作的太漂亮了,clone一份解讀 TC TM RM 以及全局鎖的獲取和釋放動做發生點

分支事務如何工做?關注全局鎖的獲取和釋放 特別是二階段commit和rollback全局鎖釋放的順序

 

ATBranch.png

Fescar中 RM TM TC如何工做的?

 

AT distribute transaction.png

看了這兩張圖,你們應該對fescar是如何工做的應該有一個大體的瞭解了。☺
一、全局鎖的獲取
二、tm tc rm之間如何通訊工做
三、隔離級別問題的思考

最後咱們來解讀一遍官方的demo

  • branch1:update storage_tbl set count = count - ? where commodity_code = ?
  • branch2:update account_tbl set money = money - ? where user_id = ?
  • branch3:insert into order_tbl (user_id, commodity_code, count, money) values (?, ?, ?, ?)
  1. 線程A:執行branch1(pk:55),執行branch2的時候發現沒錢了,扔了一個異常,那麼勢必須要回滾branch1的份額。

    • TM通知TC開始回滾branch1份額中
  2. 線程B:執行branch1(pk:55)

    • 若是線程A中branch1(pk:55)已經回滾成功了,那麼B線程能夠正常拿到鎖走下去
    • 若是線程A中branch1還未回滾(resourceId+table+pk鎖未釋放)。當線程B發起branch1向server發起申請鎖,會直接失敗。

Fescar全局鎖簡單總結:操做一條記錄的分支事務,必須等待這條記錄的前一個分支事務執行結束(具體commit rollback狀況分析以下),才能持有鎖。

其實相比XA的鎖,fescar在每一個分支事務的一階段結束後都釋放了db的鎖,因此fescar的性能瓶頸應該在於二階段的執行速度(釋放鎖的快慢)

由於分佈式事務在執行事務編排前,通常會校驗業務的正確性,因此發生回滾的機率相對較低,因此先考慮二階段commit操做。

  1. Commit場景分析:

    TM通知server進行commit,server立馬釋 branch的鎖,而後再逐個通知RM提交
     消耗:1 rpc操做,(branch刪除undo_log放在異步隊列裏面作)
  2. Rollback場景分析:

    TM通知server進行rollback,server通知RM回滾後立馬釋放 branch的鎖。
     消耗:1 + N的rpc操做 + N的回滾sql操做

因此總的來看fescar在commit的釋放全局鎖仍是很是高效的。

思考

1. server支持多臺機器部署,應該如何改造?

    全局鎖的問題,鎖改造;
    全局事務向server0申請的,Branch1發到server1,branch2發到server2的問題,多機器恢復的狀況,TC的改造

2. 全局鎖在Fescar中更新確實是沒有問題的,可是若是就是業務方須要手動調整DB數據呢?

    大膽猜想,依賴Fescar寫了一個管理平臺 用來執行sql的。哈哈

3. 隔離級別的思考
    Fescar默認工做在,本地事務讀已提交,全局事務讀未提交。
    是否存在全局事務必須工做在【讀已提交】級別而不能工做在【讀未提交】的業務場景呢?
    你們大膽腦洞 這個問題值得探討。

4. Fescar的文檔中說,是支持全局事務讀已提交的,那麼fescar是如何實現的呢?

   感興趣的同窗能夠試着讀一下com.alibaba.fescar.rm.datasource.exec.SelectForUpdateExecutor

源碼核心類

你們想讀源碼的話,能夠重點關注一下幾個類。有問題一塊兒探討。

TM相關
com.alibaba.fescar.tm.api.TransactionalTemplate

RM相關
com.alibaba.fescar.rm.datasource.exec.SelectForUpdateExecutor
com.alibaba.fescar.rm.datasource.ConnectionProxy
com.alibaba.fescar.rm.datasource.exec.AbstractDMLBaseExecutor
com.alibaba.fescar.rm.RMHandlerAT

TC相關
com.alibaba.fescar.server.coordinator.DefaultCoordinator
com.alibaba.fescar.server.coordinator.DefaultCore
com.alibaba.fescar.server.lock.DefaultLockManagerImpl

 

每一個本地操做多這幾步驟

1.select pk 2.lock local data 3.獲取設置全局pk鎖 rpc 4.釋放 lock local data

相關文章
相關標籤/搜索