《高效能MySQL》筆記-併發控制

一任天然發表於2018-01-31

讀寫鎖

在處理併發讀或者寫時,可以通過實現一個由兩種型別的鎖組成的鎖系統來解決問題。這兩種型別的鎖通常被稱為共享鎖(shared lock)和排他鎖(exclusive lock),也叫讀鎖(read lock)和寫鎖(write lock)。
讀鎖是共享的,或者說相互不阻塞的。多個客戶在同一時刻可以同時讀取同一個資源,而互不干擾。寫鎖則是排他的,也就是說一個寫鎖會阻塞其他的寫鎖和讀鎖,這就是出於安全策略的考慮,只有這樣,才能確保在給定的時間裡,只有一個使用者能執行寫入,並防止其他使用者讀取正在寫入的同一資源。
在實際的資料庫系統中,每時每刻都在發生鎖定,當某個使用者在修改某一部分資料時,MySQL會通過鎖定防止其他使用者讀取同一資料。大多數時候,MySQL鎖的內部管理都是透明的。

鎖粒度

一種提高共享資源併發性的方式就是讓鎖定物件更有選擇性。儘量只鎖定需要修改的部分資料,而不是所有的資源。更理想的方式是,只對會修改資料片進行精確的鎖定。任何時候,在給定的資源上,鎖定的資料量越少,則系統的併發成都越高,只要互相之間不發生衝突即可。
問題是加鎖也需要消耗資源。鎖的各種操作,包括獲得鎖、檢查鎖是否已經解除、釋放鎖等,都會增加系統的開銷。如果系統花費大量的時間來管理鎖,而不是存取資料,那麼系統的效能可能會因此受到影響。
所謂的鎖策略,就是在鎖的開銷和資料的安全性之間尋求平衡,這種平衡當然也會影響到效能。大多數商業資料庫系統沒有提供更多的選擇,一般都是在表上施加行級鎖(row-level lock),並以各種複雜的方式來實現,以便在鎖比較多的情況下儘可能提供更好的效能。
而MySQL則提供了多種選擇。每種MySQL儲存引擎都可以實現自己的鎖策略和鎖粒度。在儲存引擎的設計中,鎖管理是個非常重要的決定。將鎖粒度固定在某個級別,可以為某些特定的應用場景提供更好的效能,但同時卻會失去對另外一些應用場景的良好支援。好在MySQL支援多個儲存引擎的架構,所以不需要單一的通用解決方案。下面將介紹兩種最重要的鎖策略。

表鎖(table lock)

表鎖是MySQL中最基本的鎖策略,並且是開銷最小的策略。表鎖會鎖定整張表。一個使用者在對錶進行寫操作(插入、刪除、更新等)前,需要先獲得寫鎖,這會阻塞其他使用者對該表的所有讀寫操作。當沒有寫鎖時,其他讀取的使用者才能獲得讀鎖,讀鎖之間是不相互阻塞的。
在特定的場景中,表鎖也可能有良好的效能。例如,READ LOCAL表鎖支援某些型別的併發寫操作。另外,寫鎖也比讀鎖有更高的優先順序,因此一個寫鎖請求可能會被插入到讀鎖佇列的前面(寫鎖可以插入到鎖佇列中讀鎖的前面,反之讀鎖則不能插入到寫鎖的前面)。
儘管儲存引擎可以管理自己的鎖,MySQL本身還是會使用各種有效的表鎖來實現不同的目的。例如,伺服器會為諸如ALTER TABLE之類的語句使用表鎖,而忽略儲存引擎的鎖機制。

行級鎖(row lock)

行級鎖可以最大程度地支援併發處理(同時也帶來了最大的鎖開銷)。在InnoDB和XtraDB,以及其他一些儲存引擎中實現了行級鎖。行級鎖只在儲存引擎層實現,而MySQL伺服器層沒有實現。伺服器層完全不瞭解儲存引擎中的鎖實現。

相關文章