此篇部落格主要是講述mysql(僅限innodb)的兩階段加鎖(2pl)協議,而非兩階段提交(2pc)協議,區別如下:
2pl,兩階段加鎖協議:主要用於單機事務中的一致性與隔離性。
2pc,兩階段提交協議:主要用於分布式事務。
mysql本身針對性能,還有乙個mvcc(多版本控制)控制,本文不考慮此種技術,僅僅考慮mysql本身的加鎖協議。
在對記錄更新操作或者(select for update、lock in share model)時,會對記錄加鎖(有共享鎖、排它鎖、意向鎖、gap鎖、nextkey鎖等等),本文為了簡單考慮,不考慮鎖的種類。
在乙個事務裡面,分為加鎖(lock)階段和解鎖(unlock)階段,也即所有的lock操作都在unlock操作之前,如下圖所示:
引入2pl是為了保證事務的隔離性,即多個事務在併發的情況下等同於序列的執行。 在數學上證明了如下的封鎖定理:
如果事務是良構的且是兩階段的,那麼任何乙個合法的排程都是隔離的。
具體的數學推到過程可以參照《事務處理:概念與技術》這本書的7.5.8.2節.
此書乃是關於資料庫事務的聖經,無需解釋(中文翻譯雖然晦澀,也能堅持讀下去,強烈推薦)
在實際情況下,sql是千變萬化、條數不定的,資料庫很難在事務中判定什麼是加鎖階段,什麼是解鎖階段。於是引入了s2pl(strict-2pl),即:
如下圖所示:在事務中只有提交(commit)或者回滾(rollback)時才是解鎖階段,
其餘時間為加鎖階段。
這樣的話,在實際的資料庫中就很容易實現了。
上面很好的解釋了兩階段加鎖,現在我們分析下其對效能的影響。考慮下面兩種不同的扣減庫存的方案:
方案1:
begin;
// 扣減庫存
update t_inventory set
count=count
-5where
id=$ and
count >= 5;
// 鎖住使用者賬戶表
select * from t_user_account where user_id=123
forupdate;
// 插入訂單記錄
insert
into t_trans;
commit;
由於在同乙個事務之內,這幾條對資料庫的操作應該是等價的。但在兩階段加鎖下的效能確是有比較大的差距。兩者方案的時序如下圖所示:方案2:
begin;
// 鎖住使用者賬戶表
select * from t_user_account where user_id=123
forupdate;
// 插入訂單記錄
insert
into t_trans;
// 扣減庫存
update t_inventory set
count=count
-5where
id=$ and
count >= 5;
commit;
值得注意的是:由於庫存往往是最重要的熱點,是整個系統的瓶頸。那麼如果採用第二種方案的話,
tps應該理論上能夠提公升3rt/rt=3倍。這還僅僅是業務就只有三條sql的情況下,
多一條sql就多一次rt,就多一倍的時間。
如下圖所示:在更新到資料庫的那個時間點才算鎖成功
提交到資料庫的時候才算解鎖成功
這兩個round_trip的前半段是不會計算在內的
當前只考慮網路時延,不考慮資料庫和應用本身的時間消耗。
從上面的例子中,可以看出,需要把最熱點的記錄,
放到事務最後,這樣可以顯著的提高吞吐量。更進一步:
越熱點記錄離事務的終點越近(無論是commit還是rollback)
筆者認為,先後順序如下圖:
這也是任何sql加鎖不可避免的。上文提到了按照記錄key的熱度在事務中倒序排列。 那麼寫**的時候任何可能併發的sql都必須按照這種順序來處理,不然會造成死鎖。如下圖所示:
我們可以直接將一些簡單的判斷邏輯寫到update的謂詞裡面,以減少加鎖時間,考慮下面兩種方案:
方案1:
方案2:begin:
int count = select count
from t_inventory for update;
ifcount >= 5:
update t_inventory set
count=count-5
where id =123
commit
else
rollback
時延如下圖所示:begin:
int
rows = update t_inventory setcount=count
-5where
id =123
andcount >=5
if
rows > 0:
commit;
ele
rollback;
可以看到,通過在update中加謂詞計算,少了1rt的時間。
mysql採用兩階段加鎖協議實現隔離性和一致性,我們只有深入的去理解這種協議,才能更好的對我們的sql進行優化,增加系統的吞吐量。由於update在執行過程中對符合謂詞條件的記錄加的是和select
forupdate一致的排它鎖
(具體的鎖型別較為複雜,不在這裡描述),所以兩者效果一樣。
啟示:1.兩階段加鎖:事務鎖分為兩個階段:lock和unlock。
2.兩階段加鎖的意義:保證事務隔離性,即併發事務執行結果和序列化執行結果一樣,稱為可序列化。
3.熱點資料(系統的瓶頸)放到臨近commit時,這樣該資料加鎖的時間就變短,增大系統吞吐量。
4.避免死鎖:按同一的加鎖順序(按訪問熱度)進行加鎖,否則可能出現死鎖。
5.select for update和update where 謂詞計算,update where可以減少鎖時間,相當於壓縮了sql,兩條變一條。
MySql 兩階段加鎖協議
此篇部落格主要是講述mysql 僅限innodb 的兩階段加鎖 2pl 協議,而非兩階段提交 2pc 協議,區別如下 2pl,兩階段加鎖協議 主要用於單機事務中的一致性與隔離性。2pc,兩階段提交協議 主要用於分布式事務。mysql本身針對性能,還有乙個mvcc 多版本控制 控制,本文不考慮此種技術...
mysql5 7兩階段提交 mysql兩階段提交
1.兩階段提交 mysql中經常說的wal技術,wal的全稱是write ahead logging,它的關鍵點就是先寫日誌,再寫磁碟。即當有一條記錄需要更新時,innodb引擎就會先把記錄寫到redo log裡,並更新記憶體,這個時候更新就完成了。因為如果每一次的更新操作都需要寫進磁碟,然後磁碟也...
mysql兩階段鎖協議 MySql 兩階段加鎖協議
mysql 兩階段加鎖協議 前言此篇部落格主要是講述mysql 僅限innodb 的兩階段加鎖 2pl 協議,而非兩階段提交 2pc 協議,區別如下 2pl,兩階段加鎖協議 主要用於單機事務中的一致性與隔離性。2pc,兩階段提交協議 主要用於分布式事務。mysql本身針對性能,還有乙個mvcc 多版...