MySQL源碼學習(三) Group Commit
承接Mysql源碼學習(一) 從一次insert開始,本文會詳細展開說明其中流程之一——Group Commit
Group Commit是Mysql 5.6版本加入的特性,目的是為了提高事務的并發度,并以此提高MySQL的性能。
Group Commit的原理
在多線程并發中,如果必須對資源的操作進行加鎖,開發者最先想到的流程就是在資源操作前獲取鎖,操作完以后釋放鎖。比如修改一個臨界區或者互斥區的內存空間,如果不修改整體的業務邏輯,幾乎無法對其進行優化。在MySQL中,事務提交時,為保證日志的順序化寫入,如果只是簡單的:寫日志->提交事務邏輯,幾乎無法進行優化。為了繼續提高性能,寫MySQL的大牛們想出了兩階段事務提交的邏輯(兩階段事務不僅僅能提高性能,還能解決分布式事務的一致性,redo log和binlog的一致性等問題),即在事務提交的第一階段,把日志先寫到redo log緩沖區,第二階段時,再把日志刷到存儲介質中,然后提交事務。而組提交在其中發揮的作用是:在第一階段時,多個并發線程可以把日志都寫到一個緩沖中,這些等待刷到磁盤的日志組成一個group;第二階段時,只要group中的任意一個事務的日志要刷新時,便會把整個緩沖區中的日志都刷新到磁盤上。這樣就實現了將多次磁盤的順序IO操作變為了1次磁盤IO,寫性能上得到了質的飛躍。
Group Commit能大幅提升性能的核心原因
往往電影和小說會把這類巨大的技術突破,表現為科學家、工程師們一覺睡醒后的靈光一現,或者遭遇了重大挫折后的神來之筆。這樣才能讓我們這些吃瓜觀眾們感受到成功原來距離我們如此之近,從而達到勵志效果。然而事實往往相反,這樣的設計,其實是通過工程師們長時間的分析嘗試,和孜孜不倦的辛苦測試得來的。
MySQL 5.6版本之前采取的是傳統的加鎖邏輯,性能瓶頸在于為保證事務的一致性,redo log只能順序io,而不能隨機io。那么在一個線程完成之前,其他線程只能等待。基于這樣的背景,我們會自然而然地想到是否可以把多次IO變為1次IO,如果需要多次變1次,那么自然就需要一個緩沖區。因此,Group Commit能夠提升性能的核心原因其實就是:磁盤的寫緩沖。一個樸實的功能,實際上經歷了多年時間,從5.0一直到5.6才得以真正實現。
Group Commit的代碼
log_write_up_to函數中,可以看到一段及其不自然的代碼,如圖1所示。這很像是后面才加進去的代碼,其中1303?行~1347行便是group的處理邏輯。
圖1 group commit在log_write_up_to函數中的處理
log_sys是redo log的日志管理對象。其中:
buf_next_to_write: ulint類型,還沒有寫入文件的緩存的偏移量。例如,當日志文件分割時,可能有的緩存就要寫到下一個文件中。
buf_free: ulint類型,存放了可寫緩沖區的偏移量。表征了可寫緩沖區的頭部。既然是緩沖區,里面必然可能存在還沒有刷新的數據。
write_lsn:當前日志緩沖區中的lsn
write_buf:要寫入的緩沖區
沖代碼的1332行至1340行可以看出,并非可有多少內容就寫多少內容。緩沖內容是要按照文件系統的塊大小類分配的。OS_FILE_LOG_BLOCK_SIZE為512,因此是要按照512字節來對齊的。
最后,log_mutex_exit。log mutext是整個redo log日志的鎖,鎖流程中,只包含了日志偏移的計算,并沒有日志的寫入過程,對整個日志的。整體速度大大加快。
再看buf和磁盤刷入的流程,如圖2所示:
圖2 日志緩沖的寫入和寫磁盤
這里可以看到,日志被寫入緩沖后,日志的寫鎖就被釋放。最終寫入磁盤時(寫入磁盤是事務提交的第二階段執行,也就是說事務提交的兩個階段都會進入到log_write_up_to函數),日志管理系統便沒有鎖,當一個group在寫時,另一個group的日志又被并行的寫入了緩沖,以此循環,實現了緩沖和刷盤的并行,大大減少了等待的時間。這便是group commit的精妙之處。
RDS-MYSQL 云數據庫 MySQL RDS MySQL MySQL
版權聲明:本文內容由網絡用戶投稿,版權歸原作者所有,本站不擁有其著作權,亦不承擔相應法律責任。如果您發現本站中有涉嫌抄襲或描述失實的內容,請聯系我們jiasou666@gmail.com 處理,核實后本網站將在24小時內刪除侵權內容。
版權聲明:本文內容由網絡用戶投稿,版權歸原作者所有,本站不擁有其著作權,亦不承擔相應法律責任。如果您發現本站中有涉嫌抄襲或描述失實的內容,請聯系我們jiasou666@gmail.com 處理,核實后本網站將在24小時內刪除侵權內容。