行鎖功過:怎麼減少行鎖對性能的影響?&&閱讀筆記

MyISAM引擎不支持行鎖,MySQL的行鎖是由具體引擎所實現。InnoDB支持行鎖,併發控制比MyISAM更好

兩階段鎖

事務B的update語句執行時會是什麼現象呢?假設字段id是表t的主鍵。
在這裏插入圖片描述
事務B的update語句會被阻塞,直到事務A執行commit之後,事務B才能繼續執行。

在InnoDB事務中,行鎖是在需要的時候才加上的,但並不是不需要了就立刻釋放,而是要等到事務結束時才釋放。這個就是兩階段鎖協議

因此,如果事務中需要鎖多行,儘可能把最可能造成鎖衝突、最可能影響併發度的鎖儘量往後放。

eg:
現在你負責實現一個電影票在線交易業務,顧客A要在影院B購買電影票。這個業務需要涉及到以下操作:

  1. 從顧客A賬戶餘額中扣除電影票價;
  2. 給影院B的賬戶餘額增加這張電影票價;
  3. 記錄一條交易日誌。

如果這個時候有很多人來買票,那麼衝突的部分就是2了,因爲更新的是同一個數據 。

由於兩階段鎖協議,行鎖都是在事務提交的時候才釋放。所以當我們把語句2放到最後,就最大程度地減少了事務之間的鎖等待,提升了併發度。

死鎖和死鎖檢測

當併發系統中不同線程出現循環資源依賴,涉及的線程都在等待別的線程釋放資源時,就會導致這幾個線程都進入無限等待的狀態,稱爲死鎖
eg:
在這裏插入圖片描述
事務A在等待事務B釋放id=2的行鎖,而事務B在等待事務A釋放id=1的行鎖。 A、B在互相等待對方的資源釋放,進入了死鎖狀態。當出現死鎖以後,有兩種策略:

  • 直接進入等待,直到超時。超時時間可通過參數innodb_lock_wait_timeout來設置。
  • 發起死鎖檢測,發現死鎖後,主動回滾死鎖鏈條中的某一個事務,讓其他事務得以繼續執行。將參數innodb_deadlock_detect設置爲on,表示開啓這個邏輯。

在InnoDB中,innodb_lock_wait_timeout默認是50s,對於在線服務,這個時間太長,但是也不能太短,如果不是死鎖,而是簡單的鎖等待,那這樣就是誤傷了。

所以還要是採取主動死鎖檢測。innodb_deadlock_detect默認值就是on。在發生死鎖的時候,能夠快速發現並處理,但是它也有額外負擔。

每個新來的被堵住的線程,都要判斷會不會由於自己的加入導致了死鎖,這是一個時間複雜度是O(n)的操作。這樣的死鎖檢測耗費大量CPU資源

如果確保不會發生死鎖,可以臨時把死鎖檢測關掉,但是這樣又會出現大量的超時…

控制併發度吧!

基本思路就是,對於相同行的更新,在進入引擎之前排隊。這樣在InnoDB內部就不會有大量的死鎖檢測工作了(可以通過中間件,或者修改MySQL源碼)

也可以把一行改成邏輯上的多行來減少鎖衝突。我們可以把影院賬戶餘額分割爲十條記錄之和,每次修改影院金額的時候,隨機選取其中一條,這樣衝突概率就變成原來的1/10

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