GaussDB(for MySQL)數據庫在寫入性能上,在業界同類產品中是最好的,這主要得益於GaussDB(for MySQL)在MySQL內核方面的諸多優化。其中有一項從「送快遞」得來靈感的優化——事務異步提交,值得咱們分析。數據庫
咱們先來看看MySQL 8.0的事務提交的大體流程segmentfault
圖1 MySQL 8.0事務執行流程服務器
以上流程,是MySQL8.0對WAL原則的一種實現,這個流程意味着,任何一個事務的提交,必定要完成write buffer和flush to disk流程。併發
然而那麼這個流程中,有一個問題:每一個服務器的CPU是有限的,服務器能處理的Thread也是有上限的,那麼當咱們的業務的併發數量,遠遠大於咱們服務器能並行處理的數量時,那麼後來的事務,只能等待前面的事務提交後才能被處理。在這以前,他們什麼也作不了。所以,在大併發場景下,如何進一步提高線程的使用率,是大併發事物寫入的一個關鍵。異步
一個優化,並非憑空想象出來的,有時候,每每來源於現實生活。下面,咱們先來看看咱們身邊,和事務提交流程很是相似的一個例子:快遞。post
如今的快遞配送,通常一個快遞員會負責一片區域,快遞剛開始興起時,數量很少,那麼一個快遞員基本上能夠在規定時間內完成配送。性能
圖2 過去的快遞配送測試
可是,隨着快遞數量愈來愈多,一個快遞員要在一個小區配送很長的時間,才能到下一個小區,經常致使了快遞員沒法準時的配送。在這個問題的催動下,隨後,一個新的行業開始出現 – 快遞驛站。優化
圖3 如今的快遞配送spa
接下來,讓咱們來看下,快遞驛站究竟解決了什麼問題。
快遞的配送過程當中,最耗時的,不是裝貨,不是卸貨,而是電話和等待。配送一個小區的時間,取決於這個最後一個來取快遞的人的時間,在最後一我的取完快遞錢,快遞員除了打電話,作不了其餘任何事情(也沒有辦法通知下一個小區的人,由於最後一我的來取得時間是沒法肯定的)。那麼這個等待的時間,對於快遞員來講,就是一種浪費。
快遞驛站能夠很大程度解決這個問題,快遞員到了之後,只須要將快遞卸貨,便可前往下一個小區,剩下的事情,就能夠由驛站的人員來完成,大大提高了快遞員的配送效率。
分析
回過頭來,咱們看看數據庫,若是把Transaction線程看作快遞員,存儲上的文件看作取快遞的人,那麼咱們會發現二者有很是大的類似性。那麼咱們能夠像快遞配送優化那樣去優化事務的處理流程嗎?答案是能夠的。
圖4 事務處理和快讀配送很是相似
根據快遞驛站的優化原理,咱們知道,快遞驛站幫快遞員免去了等待客戶取貨的時間,那麼事務處理過程當中,有沒有等待的過程呢?答案是有的,存儲的IO就是一個較長的等待。數據庫使用經驗豐富的開發人員來都知道,等待redo日誌寫入存儲的磁盤IO性能,很大程度上決定了數據庫的寫入性能。對於現代數據庫來講,尤爲對於GaussDB(for MySQL)這樣計算於存儲分離的數據庫,存儲的IO耗時,在事務處理的總耗時中,佔據了不小的比例,雖然有log buffer的合併寫入,提高併發狀況下的總體吞吐,可是若是在等待IO的這段時間中,這些線程可以去作別的事情(例如處理等待中的其餘事務)。那麼將會有進一步的性能提高。
既然找到了等待的點,那麼咱們就能夠像快遞配送的優化方法,爲數據庫,也創造一個「快遞驛站」,讓「快遞驛站」來作等待的事情,而事務線程就能夠去處理其餘等待中的事務,讓CPU不會「閒下來」。
圖5 GaussDB(for MySQL)的「快遞驛站」
如圖5所示,GaussDB(for MySQL)當redo日誌的flush to disk動做完成後,便可進行事務提交,可是此時並不該答客戶端,而是直接處理下一個事務。同時使用少許」post comit worker線程」,來批量等待日誌寫入完成(等待的過程其實並不佔用CPU),並應答客戶端,這就可讓「等待」和「下一個事務的處理」並行化,讓CPU「閒不下來」。
圖6 Sysbench write only 模型下寫入性能測試
根據實際測試,在標準的sysbench寫入模型下,沒有使用Post Commit時,極限性能是35萬QPS左右,而使用Post commit後,能夠到大42萬以上的QPS,提高了20%的寫入性能。