MySQL鎖(一)全域性鎖:如何做全庫的邏輯備份?

大雜草發表於2020-12-15

資料庫鎖設計的初衷是處理併發問題,這也是資料庫與檔案系統的最大區別。

根據加鎖的範圍,MySQL裡大致可以分為三種鎖:全域性鎖、表鎖和行鎖。接下來我們會分三講來介紹這三種鎖,今天要講的是全域性鎖。

全域性鎖

全域性鎖,顧名思義,就是對整個資料庫加鎖。MySQL 提供了一個加全域性讀鎖的方法,命令是 Flush tables with read lock(FTWRL)。

全域性鎖典型的應用場景是做全庫的邏輯備份

通過FTWRL加全域性鎖

通過FTWRL確保不會有其他執行緒對資料庫做更新,然後對整個庫做備份。注意,在備份過程中整個庫完全處於只讀狀態。

  • 如果在主庫上備份。那麼在備份期間都不能執行更新。
  • 如果在從庫上備份。那麼在備份期間,從庫不能執行主庫同步過來的 binlog,從而造成主從延時。

在備份過程中資料庫無法寫,這對業務會有很大的影響,為什麼要加鎖呢,不加鎖行不行呢?

我們來看看不加鎖會怎樣。以銀行轉賬為例。

MySQL鎖(一)全域性鎖:如何做全庫的邏輯備份?
圖1 備份同時在轉賬

當使用者A轉100給使用者B,如果在使用者A賬戶扣除了100,但還沒給使用者B賬戶增加100時,對賬戶表完成了備份,那此時備份資料與生產環境的資料出現不一致性。

也就是說,不加鎖的話,備份得到的庫不是一個邏輯時間點,這個檢視是邏輯不一致的。當進行備份還原時,使用者B賬戶就少了100,這就出現很嚴重的問題了。

通過加全域性鎖會影響業務,那有更好的辦法嗎?

在事務隔離的實現原理那一篇文章裡,我們學習了事務隔離中的可重複讀隔離級別是能夠得到一致性檢視的。而一致性檢視能夠確保資料的邏輯一致性。

官方自帶的邏輯備份工具是 mysqldump。當 mysqldump 使用引數 -single-transaction 的時候,導資料之前就會啟動一個事務,來確保拿到一致性檢視。而由於MVCC的支援,這個過程中資料是可以正常更新的。檢視這篇文章,瞭解更多關於MVCC和一致性讀的內容。

有了一致性讀後,還需要 FTWRL 嗎?

一致性讀是好,但前提是引擎要支援這個隔離級別。比如,對於MyISAM這種不支援事務的引擎,如果備份過程中有更新,總是隻能取到最新的資料,那麼就破壞了備份的一致性。這時,我們就需要使用FTWRL命令了。

所以 -single-transaction 方法只適用於所有的表使用事務引擎的庫

既然要全庫只讀,為什麼不使用set global readonly=true的方式呢?

雖然 readonly 也能夠設定全庫為只讀狀態。但還是建議使用 FTWRL,原因有兩個:

  1. 在有些系統中,readonly的值會被用來做其他邏輯,比如用來判斷一個庫是主庫還是備庫。因此,修改global變數的方式影響面更大,不建議你使用。
  2. 在異常處理機制上有差異。如果執行FTWRL命令之後由於客戶端發生異常斷開,那麼MySQL會自動釋放這個全域性鎖,整個庫回到可以正常更新的狀態。而將整個庫設定為readonly之後,如果客戶端發生異常,則資料庫就會一直保持readonly狀態,這樣會導致整個庫長時間處於不可寫狀態,風險較高。

相關文章