硬件DMA和物理復(fù)制實現(xiàn)的數(shù)據(jù)庫多副本
大家都知道關(guān)系型數(shù)據(jù)庫的重要特性歸納起來是“ACID”,其中A是原子性,C是約束,I是隔離性,D是持久性。
POLARDB將從兩個維度出發(fā),從根本上改進多副本復(fù)制。一個是保證數(shù)據(jù)庫ACID中的D(Durable),把網(wǎng)絡(luò)、存儲硬件提供的DMA能力串起,用硬件通道高性能的把主庫的日志數(shù)據(jù)持久化到三個存儲節(jié)點的磁盤中;另一個是實現(xiàn)了高效的只讀節(jié)點,在主庫和只讀節(jié)點之間通過物理復(fù)制同步數(shù)據(jù),直接更新到只讀節(jié)點的內(nèi)存里。如何實現(xiàn)?
POLARDB實現(xiàn)日志數(shù)據(jù)持久化到三個存儲節(jié)點的磁盤中。主庫通過RDMA將日志數(shù)據(jù)發(fā)送到存儲節(jié)點的內(nèi)存中,存儲節(jié)點之間再通過RDMA互相復(fù)制,每個存儲節(jié)點用SPDK將數(shù)據(jù)寫入NVMe接口的存儲介質(zhì)里,整個過程CPU不用訪問被同步的數(shù)據(jù)塊(Payload),實現(xiàn)數(shù)據(jù)零拷貝。
同時由RDMA網(wǎng)卡和NVMe控制器完成數(shù)據(jù)傳輸和持久化,CPU僅做狀態(tài)機的維護,在一致性協(xié)議的協(xié)調(diào)下,把網(wǎng)卡和存儲卡兩塊硬件串起來,存儲節(jié)點之間數(shù)據(jù)同步采用并發(fā)Raft(ParallelRaft)協(xié)議,和Raft協(xié)議一樣,決議在leader節(jié)點上是串行生成和提交的,但并發(fā)Raft協(xié)議可以允許主從之間亂序同步,簡單的說,允許follower節(jié)點在漏掉若干條日志的情況先commit并apply后面過來的日志,并異步的去補之前漏掉的日志,數(shù)據(jù)同步的性能和穩(wěn)定性都顯著優(yōu)于Raft協(xié)議。
POLARDB在主庫和只讀實例之間的數(shù)據(jù)流上,放棄了基于binlog的邏輯復(fù)制,而是基于innodb的redolog實現(xiàn)了物理復(fù)制,從邏輯復(fù)制到物理復(fù)制對主庫和從庫性能帶來的提升都非常明顯。
在主庫上,原本引擎需要和binlog做XA事務(wù),事務(wù)要等到binlog和redolog同時寫盤后才能返回,去掉binlog后,XA事務(wù)可以去掉,事務(wù)的執(zhí)行路徑更短,IO開銷也更小。在從庫上,redolog由于是物理復(fù)制,僅需比對頁面的LSN就可以決定是否回放,天然可以多線程執(zhí)行,數(shù)據(jù)的正確性也更有保證,此外,POLARDB的從庫收到redolog后只需要更新緩存里的頁面,并不需要寫盤和IO操作,開銷遠低于傳統(tǒng)多副本復(fù)制里的從庫。
針對數(shù)據(jù)庫加速的Smart Storage
POLARDB的存儲節(jié)點針對數(shù)據(jù)庫的IO workload進行了一些針對性的優(yōu)化。
IO優(yōu)先級優(yōu)化:POLARDB在文件系統(tǒng)和存儲節(jié)點兩層都開了綠色通道,對redolog文件的更新進行優(yōu)待處理,減少排隊,提高IO的優(yōu)先級。redolog也從512對齊調(diào)整為4k對齊,對SSD性能更加友好。
double write優(yōu)化:POLARDB存儲節(jié)點原生支持1MB的原子寫,因此可以安全關(guān)閉doublewrite,從而節(jié)省了近一倍的IO開銷。
group commit優(yōu)化:POLARDB里一次group commit可以產(chǎn)生寫入幾百KB的單個大IO。對于單個SSD,延遲和IO的大小是呈線性的,而POLARDB從文件系統(tǒng)到存儲節(jié)點都進行一系列優(yōu)化來保證這種類型的IO能盡快刷下去,針對redolog文件進行條帶化,將一個上百KB的大IO切割為一批16KB的較小IO,分發(fā)到多個存儲節(jié)點和不同的磁盤上去執(zhí)行,進一步的降低關(guān)鍵IO路徑的延遲。
2. POLARDB的計算引擎性能優(yōu)化
使用共享存儲物理復(fù)制
由于POLARDB使用共享存儲和物理復(fù)制,實例的備份恢復(fù)也做到完全依賴redolog,因此去掉了binlog。使得單個事務(wù)對io的消耗減少,有效減少語句響應(yīng)時間,提升吞吐量。同時避免了引擎需要與binlog做的XA事務(wù)邏輯,事務(wù)語句的執(zhí)行路徑更短。
鎖優(yōu)化
POLARDB針對高并發(fā)場景,對引擎內(nèi)部鎖做了大量優(yōu)化,比如把latch分解成粒度更小的鎖,或者把latch改成引用計數(shù)的方式從而避免鎖競爭,例如Undo segment mutex, log system mutex等等。PolarDB還把部分熱點的數(shù)據(jù)結(jié)構(gòu)改成了Lock Free的結(jié)構(gòu),例如Server層的MDL鎖。
日志提交優(yōu)化
Redolog的順序?qū)懶阅軐?shù)據(jù)庫性能的影響很大,為了減少Redolog切換時對性能的影響,我們后臺采用類似Fallocate的方式預(yù)先分配日志文件,此外,現(xiàn)代的SSD硬盤很多都是4K對齊,而MySQL代碼還是按照早期磁盤512字節(jié)對齊的方式刷日志的,這樣會導(dǎo)致磁盤做很多不必要的讀操作,不能發(fā)揮出SSD盤的性能,我們在這方面也做了優(yōu)化。我們對日志提交時Group Commit進行優(yōu)化,同時采用Double RedoLog Buffer提升并行度。