衛(wèi)孝賢 劉文欣 蔡鵬
摘要:隨著云計(jì)算的盛行,用戶對云數(shù)據(jù)庫的需求越發(fā)復(fù)雜,而當(dāng)下基于共享存儲(chǔ)的一寫多讀的云數(shù)據(jù)庫系統(tǒng)并不能支持寫性能的動(dòng)態(tài)擴(kuò)展,多個(gè)主節(jié)點(diǎn)同時(shí)提供寫服務(wù),會(huì)引起跨節(jié)點(diǎn)的讀寫沖突,進(jìn)而導(dǎo)致多主節(jié)點(diǎn)緩存不一致,對于這個(gè)問題,基于全局有序的事務(wù)日志的樂觀沖突檢測可以檢測出跨節(jié)點(diǎn)事務(wù)沖突,并回滾沖突的事務(wù),維持整個(gè)系統(tǒng)的隔離級別與一致性,另外,通過廣播和回放全局有序的事務(wù)日志,可以將主節(jié)點(diǎn)的修改同步到其余節(jié)點(diǎn),保證每個(gè)節(jié)點(diǎn)的獨(dú)立服務(wù)能力,這一基于事務(wù)日志的多主緩存一致性解決方案已實(shí)現(xiàn)在開源數(shù)據(jù)庫MySQL上,并通過實(shí)驗(yàn)驗(yàn)證了該解決方案對系統(tǒng)性能的影響。
關(guān)鍵詞:云數(shù)據(jù)庫:多主緩存:事務(wù)日志
中圖分類號(hào):TP392 文獻(xiàn)標(biāo)志碼:A DOI:10.3969/j/i8811.1000-5641.202091002
0引言
時(shí)至今日,隨著大數(shù)據(jù)技術(shù)的發(fā)展,涌現(xiàn)出了多種多樣的新型數(shù)據(jù)庫,但是傳統(tǒng)的關(guān)系型數(shù)據(jù)庫仍然占據(jù)著主導(dǎo)地位,這是因?yàn)殛P(guān)系型數(shù)據(jù)庫采用了sQL(structured Query Language)標(biāo)準(zhǔn),這種高級的非過程化的數(shù)據(jù)庫編程語言將編程邏輯和關(guān)系型數(shù)據(jù)的管理方式完美地銜接起來,其普適性目前仍然難以超越。
如果說關(guān)系型數(shù)據(jù)庫是IT時(shí)代的產(chǎn)物,那么互聯(lián)網(wǎng)時(shí)代的產(chǎn)物就是云計(jì)算,在蓬勃發(fā)展的云計(jì)算2.0時(shí)代,關(guān)系型數(shù)據(jù)庫在云托管的環(huán)境下存在一些問題:①傳統(tǒng)數(shù)據(jù)庫的I(Input)/O(Output)“瓶頸”在云場景下發(fā)生了變化,在多租戶場景下I/O分布到多個(gè)節(jié)點(diǎn)和多個(gè)磁盤,單個(gè)磁盤的I/O壓力不會(huì)太大,性能的“瓶頸”轉(zhuǎn)移到了數(shù)據(jù)包的發(fā)送速度和網(wǎng)絡(luò)帶寬上;②事務(wù)的提交是另一個(gè)問題,例如某個(gè)客戶端提交的事務(wù)中包含了數(shù)據(jù)A的修改,要想將A的修改同步到其余的服務(wù)節(jié)點(diǎn),讓其余的客戶端可以讀到A的值,這需要多階段的同步協(xié)議,但這些協(xié)議會(huì)帶來較高的事務(wù)延遲;③多節(jié)點(diǎn)云數(shù)據(jù)庫的故障恢復(fù)與傳統(tǒng)的關(guān)系型數(shù)據(jù)庫的故障恢復(fù)也是有區(qū)別的,如何恢復(fù)整個(gè)系統(tǒng)的狀態(tài)或是故障后切換到?jīng)]有故障的節(jié)點(diǎn)需要另外設(shè)計(jì)一套解決方案。
作為云計(jì)算時(shí)代的先行者,亞馬遜在2014年發(fā)布了云托管的關(guān)系型數(shù)據(jù)庫Aurora,并在2017年發(fā)布了論文Amazon aurora:Design considerations for high throughput cloud native relationaldatabases,解釋了基于云環(huán)境的關(guān)系型數(shù)據(jù)庫應(yīng)該如何設(shè)計(jì),2018年,阿里巴巴緊隨其后發(fā)布了商用云數(shù)據(jù)庫PolarDB,隨后,2019年微軟發(fā)布了云數(shù)據(jù)庫Socrates,2020年華為發(fā)布了云數(shù)據(jù)庫Taurus,這些商業(yè)云數(shù)據(jù)庫無一例外地遵循了存儲(chǔ)計(jì)算分離的原則,存儲(chǔ)計(jì)算分離是將關(guān)系型數(shù)據(jù)庫的邏輯分為存儲(chǔ)和計(jì)算兩個(gè)部分:存儲(chǔ)部分負(fù)責(zé)數(shù)據(jù)的持久化;計(jì)算部分負(fù)責(zé)SQL的解析、事務(wù)處理等計(jì)算邏輯,存儲(chǔ)部分由多個(gè)存儲(chǔ)節(jié)點(diǎn)共同組成的共享存儲(chǔ)系統(tǒng)實(shí)現(xiàn),而計(jì)算節(jié)點(diǎn)則提供獨(dú)立的數(shù)據(jù)庫請求服務(wù)能力,在這一架構(gòu)下,云數(shù)據(jù)庫可以通過增減存儲(chǔ)節(jié)點(diǎn)或者計(jì)算節(jié)點(diǎn),動(dòng)態(tài)地?cái)U(kuò)展系統(tǒng)的存儲(chǔ)能力或計(jì)算能力,實(shí)現(xiàn)云場景下的按需分配、動(dòng)態(tài)擴(kuò)展。
到目前為止,除了Aurora之外,所有的商用云數(shù)據(jù)庫只提供了一寫多讀的計(jì)算節(jié)點(diǎn)配置,即計(jì)算節(jié)點(diǎn)中只有一個(gè)節(jié)點(diǎn)可以執(zhí)行寫操作,其余的節(jié)點(diǎn)只提供讀服務(wù),這種配置的云數(shù)據(jù)庫集群只能提供讀性能的擴(kuò)展,而整個(gè)系統(tǒng)的寫性能無法通過增減節(jié)點(diǎn)進(jìn)行擴(kuò)展。
云場景下,用戶的需求是復(fù)雜且難以預(yù)測的,僅僅是讀性能的擴(kuò)展并不能滿足用戶的所有需求,為了實(shí)現(xiàn)寫性能的擴(kuò)展,云數(shù)據(jù)庫系統(tǒng)需要增減具有寫能力的計(jì)算節(jié)點(diǎn),由于系統(tǒng)的存儲(chǔ)是眾多計(jì)算節(jié)點(diǎn)共享的,而每個(gè)計(jì)算節(jié)點(diǎn)有自己的緩存,寫操作首先作用于緩存,緩存滿時(shí)換出到共享存儲(chǔ)中,每個(gè)計(jì)算節(jié)點(diǎn)的緩存都包含該節(jié)點(diǎn)近一段時(shí)間內(nèi)讀寫的數(shù)據(jù),不同節(jié)點(diǎn)的緩存中可能包含相同的數(shù)據(jù),另外,每個(gè)計(jì)算節(jié)點(diǎn)都獨(dú)立地提供讀寫服務(wù),因此,在多主的場景下,不同主節(jié)點(diǎn)的緩存中相同數(shù)據(jù)可能會(huì)出現(xiàn)版本不一致的現(xiàn)象,這些不同版本的數(shù)據(jù)副本是不可控的,在換出到共享存儲(chǔ)時(shí)會(huì)產(chǎn)生讀寫沖突。
現(xiàn)今,主流的基于共享存儲(chǔ)的多主解決方案有兩種——Oracle RAC和DB2 pureScale,這兩種方案在實(shí)現(xiàn)方式上有所不同,但思路都是通過多節(jié)點(diǎn)協(xié)調(diào)的遠(yuǎn)程物理頁鎖保證頁的寫權(quán)限只會(huì)被一個(gè)節(jié)點(diǎn)擁有,因?yàn)槎喙?jié)點(diǎn)的讀寫會(huì)產(chǎn)生鎖沖突,擁有寫權(quán)限的節(jié)點(diǎn)完成寫操作后,將新版本的頁在集群中傳輸,更新其余節(jié)點(diǎn)緩存中頁的副本,這一方案會(huì)帶來較多的網(wǎng)絡(luò)通信用于申請鎖和傳輸頁,另外,跨節(jié)點(diǎn)死鎖的處理也較為復(fù)雜,需要多次的網(wǎng)絡(luò)通信,頻繁的網(wǎng)絡(luò)通信和粗粒度的鎖會(huì)限制整個(gè)系統(tǒng)的擴(kuò)展性和吞吐量。
綜上所述,為了在共享存儲(chǔ)的云數(shù)據(jù)庫系統(tǒng)中提供可動(dòng)態(tài)擴(kuò)展的寫性能,解決多主場景下緩存不一致的問題,本文基于MySQL設(shè)計(jì)并實(shí)現(xiàn)了多主緩存一致性維護(hù)插件,本文的主要貢獻(xiàn)如下,
(1)基于redo日志生成事務(wù)日志,并通過廣播和篩選回放事務(wù)日志更新其他節(jié)點(diǎn)的緩存,設(shè)計(jì)并實(shí)現(xiàn)了異步日志廣播機(jī)制,減少了事務(wù)延時(shí)中的網(wǎng)絡(luò)等待,
(2)通過全局有序的事務(wù)日志檢測跨節(jié)點(diǎn)的事務(wù)沖突,維護(hù)了整個(gè)系統(tǒng)的數(shù)據(jù)一致性。
(3)通過實(shí)驗(yàn)論證了Paxos提議和切片ID這兩種全局事務(wù)ID分配方式對多主數(shù)據(jù)庫系統(tǒng)性能的影響。
本文后續(xù)安排如下:第1章描述基于MySQL的多主數(shù)據(jù)庫架構(gòu);第2章描述事務(wù)日志的生成方式和優(yōu)缺點(diǎn);第3章介紹異步日志廣播和兩種全局事務(wù)ID分配方式,以及基于全局有序事務(wù)日志的沖突檢測方法;第4章通過實(shí)驗(yàn)驗(yàn)證本文方案對系統(tǒng)性能的影響;第5章總結(jié)全文。
1基于MySQL的多主數(shù)據(jù)庫架構(gòu)
為了減少應(yīng)用從傳統(tǒng)關(guān)系型數(shù)據(jù)庫向云數(shù)據(jù)庫遷移的代價(jià),當(dāng)下的云數(shù)據(jù)庫大多基于MySQL開發(fā),保證了與MySQL客戶端的兼容,如阿里巴巴的PolarDB,其計(jì)算節(jié)點(diǎn)是MySQL的服務(wù)層與部分存儲(chǔ)引擎,而存儲(chǔ)層則是自主研發(fā)的分布式文件系統(tǒng)PolarFS,通過遠(yuǎn)程文件I/O接口將日志和數(shù)據(jù)持久化到分布式存儲(chǔ)上。
仿照PolarDB的架構(gòu),本文設(shè)計(jì)了如圖1所示的多主數(shù)據(jù)庫原型:多個(gè)MySQL進(jìn)程組成計(jì)算節(jié)點(diǎn)集群,這些計(jì)算節(jié)點(diǎn)將日志和數(shù)據(jù)寫到共享的遠(yuǎn)程存儲(chǔ)上,以此組成基于共享存儲(chǔ)的多主數(shù)據(jù)庫架構(gòu),
由圖1可知,每個(gè)計(jì)算節(jié)點(diǎn)都可以獨(dú)立地提供讀寫能力,并通過多主插件協(xié)調(diào)不同節(jié)點(diǎn)的事務(wù),以維護(hù)各節(jié)點(diǎn)緩存中的緩沖池一致性,多主插件對于MySQL本身邏輯的影響較小,可以較便捷地變更實(shí)現(xiàn)方式,以此驗(yàn)證多種解決方案對于系統(tǒng)的影響,另外,MySQL成熟的事務(wù)機(jī)制和緩沖池機(jī)制為解決方案的設(shè)計(jì)提供了重要的研究背景參考,提高了解決方案的實(shí)用性,
2事務(wù)日志的生成
2.1全局事務(wù)日志的必要性
為了維護(hù)多主場景下的緩存一致性,本文設(shè)計(jì)了基于日志的解決方案,然而,在MySQL中存在著多種類型的日志,其中最為重要的就是binlog和redo log,這兩種日志維護(hù)了MySQL事務(wù)的持久性,binlog有更好的通用性,而redo log有更好的性能,但是在多主場景下,這兩種日志并不能符合跨節(jié)點(diǎn)沖突檢測和日志同步的需求,因此,本文基于性能更好的redo log生成了全局事務(wù)日志,用于維護(hù)多主緩存的一致性。
通常,數(shù)據(jù)庫的日志會(huì)被分為邏輯日志與物理日志:邏輯日志記錄的是數(shù)據(jù)庫的邏輯操作;而物理日志記錄的是數(shù)據(jù)庫的物理更改,在MySQL中,邏輯日志的體現(xiàn)是binlog,物理日志的體現(xiàn)是redolog。
MySQL的binlog是一種獨(dú)立于存儲(chǔ)引擎的日志,由MySQL服務(wù)層管理,主要應(yīng)用于數(shù)據(jù)庫的主從復(fù)制和故障恢復(fù),binlog中記錄了每一個(gè)數(shù)據(jù)庫操作(Insert、Update、Delete,不包括Select),相比于redo log,binlog有更好的可讀性,通過解析binlog可以在不同的存儲(chǔ)引擎或異構(gòu)數(shù)據(jù)庫中回放數(shù)據(jù),binlog的缺點(diǎn)是存在性能上的缺陷:①binlog記錄的是邏輯操作,回放過程中解析日志的代價(jià)更高;②開啟binlog時(shí),MySQL需要確認(rèn)binlog和redo log兩份日志都成功刷盤才能提交事務(wù),這會(huì)影響到事務(wù)的響應(yīng)時(shí)間和吞吐量,
redo log盡管沒有binlog那么高的通用性,但是卻有著性能上的優(yōu)勢,在跨節(jié)點(diǎn)場景下直接通過redo log檢測沖突時(shí),則會(huì)遇到一些問題:①redo log中僅能檢測出對于頁的更新,并無事務(wù)的信息,盡管可以檢測出頁級別的并行寫沖突,卻無法判斷是否存在事務(wù)級別沖突,可能會(huì)使本無沖突的事務(wù)回滾;②由于無法確定事務(wù)對應(yīng)的所有日志記錄,即使在redo log中檢測出了沖突,應(yīng)該回滾的事務(wù)日志依然需要回放,在緩沖池中回放出事務(wù)的數(shù)據(jù)頁和undo頁后,才可以執(zhí)行事務(wù)的回滾,這無疑是多余的回放。
若是日志能以事務(wù)為單位組織,將會(huì)為沖突檢測和日志回放帶來極大的便利。
2.2全局事務(wù)日志生成
InnoDB存儲(chǔ)引擎的redo log對于日志記錄來說是有序的,但是對于事務(wù)來說是無序的,由于日志記錄中并不包含事務(wù)信息,無法通過掃描和解析redo log直接獲取到事務(wù)對應(yīng)的所有日志記錄,事務(wù)提交時(shí)也僅僅會(huì)記錄最后一條日志記錄的日志序列號(hào),來確保之前產(chǎn)生的日志記錄已經(jīng)刷盤,因此,本文設(shè)計(jì)了如圖2所示的全局事務(wù)日志采集模塊。
MySQL默認(rèn)的事務(wù)模型是“一連接一線程”,即MySQL接收到連接請求時(shí),會(huì)分配一個(gè)線程專門服務(wù)該連接,接收該連接發(fā)來的SQL語句,并在解析后執(zhí)行,該線程接收到事務(wù)開始請求后,會(huì)啟動(dòng)一個(gè)事務(wù),事務(wù)提交后清空事務(wù)對象的狀態(tài),為接收下一個(gè)事務(wù)做準(zhǔn)備,事務(wù)的執(zhí)行在單個(gè)連接上是串行的,因此,本文可以通過線程ID唯一的標(biāo)識(shí)正在執(zhí)行的事務(wù),并據(jù)此收集以事務(wù)為單位產(chǎn)生的日志記錄,整個(gè)流程如下。
(1)當(dāng)事務(wù)開始時(shí),記錄下執(zhí)行事務(wù)的線程ID,并在線程ID-事務(wù)日志映射表上創(chuàng)建新的日志鏈表,標(biāo)志著該線程已啟動(dòng)一個(gè)事務(wù)。
(2)迷你事務(wù)執(zhí)行讀寫操作后會(huì)產(chǎn)生相應(yīng)的日志記錄,此時(shí)觸發(fā)日志生成事件,在日志被存入日志棧之前收集日志記錄和線程ID,在線程ID-事務(wù)日志映射表中找到對應(yīng)線程的日志鏈表,將日志記錄插入鏈表。
(3)當(dāng)事務(wù)提交時(shí),檢查當(dāng)前線程對應(yīng)的日志鏈表,若為空,則說明該事務(wù)屬于只讀事務(wù),
事務(wù)日志可以回避原生redo log在跨節(jié)點(diǎn)沖突檢測場景的問題:①日志以為事務(wù)為單位組織起來,執(zhí)行沖突檢測時(shí)可以檢測出事務(wù)之間的沖突,避免誤判;②當(dāng)判定某一事務(wù)由于沖突應(yīng)該回滾時(shí),可以丟棄其對應(yīng)的日志,不需要再做無效的回放和傳輸,加快了日志回放和傳輸?shù)乃俣取?/p>
2.3日志的提前解析
一般來說,MySQL日志回放的過程是,先掃描日志文件,解析每個(gè)日志塊的頭部信息,進(jìn)而在掃描分析出每條日志記錄的偏移量,解析每條日志記錄頭部記錄的頁號(hào)后,將其按照頁號(hào)存放到一個(gè)線程ID-事務(wù)日志映射表中,之后再從線程ID-事務(wù)日志映射表中以頁為單位提取對應(yīng)的日志記錄鏈表,再次解析日志記錄頭部,解析出日志的類型和一些輔助信息后,傳人對應(yīng)的函數(shù)中執(zhí)行回放。
多主日志同步的場景下,將內(nèi)存中的日志記錄傳輸?shù)蕉鄠€(gè)副本后,每個(gè)副本都需要經(jīng)過兩次解析才能獲取到真正需要回放的內(nèi)容,從系統(tǒng)的角度來看,這就產(chǎn)生了重復(fù)的解析,增加了整個(gè)系統(tǒng)的CPU占用,影響了日志回放的速度。
因此,應(yīng)該對日志進(jìn)行提前解析,在不增加日志記錄占用空間的情況下,將日志記錄中的有效信息提取出來,通過解析頭部信息,可以較為簡單地得出日志類型、頁號(hào)、頁中的偏移量和實(shí)際修改內(nèi)容,部分在回放中沒有意義的特殊類型的日志記錄可以在提前解析完成后舍棄。
日志的提前解析可以減少同步日志時(shí)的網(wǎng)絡(luò)傳輸數(shù)據(jù)量,減少整個(gè)系統(tǒng)的資源消耗,提高日志回放速度,在一寫多讀場景下,日志的提前解析會(huì)給唯一的主節(jié)點(diǎn)帶來額外的負(fù)擔(dān),從而降低整個(gè)系統(tǒng)的寫性能,但在多主場景下,日志由多個(gè)主節(jié)點(diǎn)分別產(chǎn)生,提前解析的壓力由多個(gè)主節(jié)點(diǎn)共同負(fù)擔(dān),故對系統(tǒng)的性能影響較小。
3基于全局事務(wù)日志的沖突檢測
3.1異步日志廣播
事務(wù)日志生成之后,需要將其廣播到集群中的其余節(jié)點(diǎn),通過回放事務(wù)日志中與緩存內(nèi)容有關(guān)的日志記錄,更新其余節(jié)點(diǎn)的緩存內(nèi)容,這一過程與MySQL的主從復(fù)制、組復(fù)制思路相似:通過日志更新數(shù)據(jù)庫內(nèi)容,實(shí)現(xiàn)多副本數(shù)據(jù)一致,MySQL的組復(fù)制采用了同步日志廣播的形式,在主節(jié)點(diǎn)提交事務(wù)時(shí)將binlog經(jīng)過一次Paxos提議確定全局順序,并確保binlog被大多數(shù)節(jié)點(diǎn)收到,收到binlog的節(jié)點(diǎn)依據(jù)之前收到的全局有序日志判斷是否存在跨節(jié)點(diǎn)沖突,然后將檢測結(jié)果返回給主節(jié)點(diǎn),主節(jié)點(diǎn)收到大多數(shù)節(jié)點(diǎn)無沖突的回復(fù)后才會(huì)提交本地事務(wù)。
在跨節(jié)點(diǎn)沖突檢測的場景下,日志的生命周期并不需要太長,沖突檢測只會(huì)利用到從事務(wù)啟動(dòng)到提交前這段時(shí)間提交的事務(wù)日志,因?yàn)閮H有這段時(shí)間提交的事務(wù)會(huì)改變數(shù)據(jù)庫的狀態(tài),可能與執(zhí)行沖突檢測的事務(wù)產(chǎn)生沖突,另外,由于所有節(jié)點(diǎn)的全局事務(wù)日志副本都是一致的,跨節(jié)點(diǎn)沖突檢測在所有節(jié)點(diǎn)執(zhí)行的結(jié)果都是一致的,因此,沒有必要所有節(jié)點(diǎn)都執(zhí)行沖突檢測,當(dāng)確定本地事務(wù)在全局事務(wù)序列中的位置后,只需要結(jié)合之前的事務(wù)日志執(zhí)行沖突檢測,即可確定事務(wù)是否可以提交,事務(wù)提交后,日志可以通過異步的方式發(fā)送到其余節(jié)點(diǎn),而不用等待日志成功發(fā)送到大多數(shù)節(jié)點(diǎn)后再提交事務(wù),同步日志廣播與異步日志廣播的時(shí)間軸分析如圖3所示。
異步日志廣播可以減少事務(wù)中的網(wǎng)絡(luò)等待時(shí)延,避免由于網(wǎng)絡(luò)阻塞帶來的事務(wù)提交長等待,另外,異步的日志廣播方案使得更新自身緩存的時(shí)機(jī)與本地事務(wù)的提交無關(guān),緩存更新的延遲會(huì)導(dǎo)致其余節(jié)點(diǎn)讀取的數(shù)據(jù)版本較舊,但這在分布式系統(tǒng)中是允許的。
3.2全局事務(wù)ID分配
前面多有提到“全局事務(wù)日志”的概念,但是目前為止,本文只討論了事務(wù)日志的生成和廣播,所有節(jié)點(diǎn)都擁有全局事務(wù)日志的副本,前提條件是所有節(jié)點(diǎn)對于任意一事務(wù)日志在這一全局事務(wù)序列中的順序達(dá)成共識(shí),實(shí)現(xiàn)全局有序,最直接的方法就是為每一個(gè)事務(wù)分配一個(gè)全局的事務(wù)ID,這個(gè)ID標(biāo)識(shí)了事務(wù)在全局事務(wù)序列中的順序,只要所有節(jié)點(diǎn)對該ID的分配達(dá)成共識(shí),即可保證全局事務(wù)序列的一致。
目標(biāo)是共識(shí),那么首先想到的就是共識(shí)協(xié)議Paxos或raft,本文在3.1節(jié)中也有提到過,組復(fù)制通過將binlog打包發(fā)送到一個(gè)Paxos組中來保證消息的全局有序,這種基于Paxos提議的全局有序協(xié)調(diào)機(jī)制可以保證系統(tǒng)的高可用,是一種簡單有效的方案,落實(shí)到多主場景中,基于Paxos提議的全局事務(wù)ID分配機(jī)制的實(shí)現(xiàn)方式如圖4所示,其使用了微信開源的PhxPxaos庫。
盡管簡單有效,但基于Paxos提議的全局事務(wù)ID分配機(jī)制在多主場景下還是存在一些問題:①每次事務(wù)提交都需要經(jīng)過一次Paxos提議才能確定全局事務(wù)ID,事務(wù)需要至少等待一次所有節(jié)點(diǎn)參與的協(xié)調(diào)結(jié)束后才能提交,網(wǎng)絡(luò)等待的時(shí)間過長;②高并發(fā)的數(shù)據(jù)庫會(huì)同時(shí)執(zhí)行多個(gè)事務(wù),事務(wù)提交時(shí)會(huì)發(fā)起Paxos提議,以線程為單位的Paxos提議發(fā)送會(huì)引起較為劇烈的提議沖突,協(xié)調(diào)提議沖突的網(wǎng)絡(luò)代價(jià)會(huì)降低整個(gè)系統(tǒng)的吞吐量;③Paxos協(xié)議適用于3節(jié)點(diǎn)到5節(jié)點(diǎn)的場景,隨著參與節(jié)點(diǎn)數(shù)量的增加,系統(tǒng)的吞吐量會(huì)急劇下降,無法支持良好的擴(kuò)展。
為了保證沖突檢測的有效性和日志回放的有序性,事務(wù)在提交前需要確認(rèn)自己擁有的全局事務(wù)ID,高并發(fā)環(huán)境下單節(jié)點(diǎn)上會(huì)有多個(gè)事務(wù)同時(shí)提交,以單個(gè)事務(wù)為單位申請全局事務(wù)ID并不是一個(gè)好的選擇,會(huì)導(dǎo)致頻繁地發(fā)出申請或是單節(jié)點(diǎn)上的多個(gè)申請排隊(duì),等待所有線程上的事務(wù)都進(jìn)入提交狀態(tài)后,再去做批量申請的操作,又可能會(huì)由于某一個(gè)或幾個(gè)線程上的長事務(wù)長時(shí)間執(zhí)行而導(dǎo)致整個(gè)節(jié)點(diǎn)的提交阻塞,更為糟糕的是,無法完成提交的事務(wù)不會(huì)釋放本地的行鎖,而其余線程上的事務(wù)可能在等待被持有的行鎖而無法進(jìn)入提交狀態(tài),這就導(dǎo)致了額外的死鎖。
比較好的選擇是提前為節(jié)點(diǎn)劃分一些事務(wù)ID,在事務(wù)提交時(shí)將這些ID分配給事務(wù),使得事務(wù)可以快速提交,而不會(huì)影響到同一節(jié)點(diǎn)其余線程上事務(wù)的提交。
為了減少事務(wù)提交過程中的網(wǎng)絡(luò)等待,本文提出了基于切片的全局事務(wù)ID分配機(jī)制,如圖5所示,全局事務(wù)ID是連續(xù)而單調(diào)遞增的自然數(shù)序列,但邏輯上可以劃分為多個(gè)切片,每個(gè)切片是一組與節(jié)點(diǎn)數(shù)量等量的全局事務(wù)ID集合,在切片中,按照節(jié)點(diǎn)的編號(hào)順序?qū)D分配給對應(yīng)的節(jié)點(diǎn),事務(wù)提交時(shí),節(jié)點(diǎn)可通過簡單的計(jì)算將切片ID和局部ID的組合轉(zhuǎn)換成可用的全局事務(wù)ID,之后即可執(zhí)行本地提交,廣播事務(wù)日志更新其余節(jié)點(diǎn)的緩存,當(dāng)節(jié)點(diǎn)增減時(shí),如同圖5中的節(jié)點(diǎn)3.需要將這一節(jié)點(diǎn)的變更信息發(fā)送到所有節(jié)點(diǎn)上,并收到確認(rèn)回復(fù),才能保證所有節(jié)點(diǎn)后續(xù)的切片中會(huì)增加新節(jié)點(diǎn)需要的槽位,
基于切片的全局事務(wù)ID分配機(jī)制不需要在提交時(shí)等待網(wǎng)絡(luò)傳輸,只要經(jīng)過本地的計(jì)算即可獲取全局有序的事務(wù)ID,相比基于Paxos提議的分配方式有著更好的擴(kuò)展性和更低的事務(wù)時(shí)延。
3.3沖突檢測
在每個(gè)節(jié)點(diǎn)都擁有一份全局事務(wù)日志的副本之后,還需要解決的一個(gè)問題是跨節(jié)點(diǎn)的事務(wù)沖突處理,每個(gè)節(jié)點(diǎn)都有獨(dú)立的服務(wù)讀寫請求的能力,本地多個(gè)線程執(zhí)行的事務(wù)由MySQL的事務(wù)鎖機(jī)制解決沖突,跨節(jié)點(diǎn)的事務(wù)由于不共享事務(wù)模塊而缺少處理沖突的手段,全局事務(wù)日志基于redo log生成,其中包含了對于數(shù)據(jù)頁的修改,分配了全局事務(wù)ID的事務(wù)日志形成的全局事務(wù)日志包含了所有節(jié)點(diǎn)上所有事務(wù)的提交順序和數(shù)據(jù)修改操作,通過掃描這一日志可以檢測出跨節(jié)點(diǎn)事務(wù)之間的寫沖突,但這樣是不夠的,僅檢測跨節(jié)點(diǎn)事務(wù)的寫沖突,可能會(huì)破壞節(jié)點(diǎn)本地的事務(wù)隔離級別,
所以,在事務(wù)執(zhí)行的過程中除了讀寫操作生成的日志記錄,還需要收集讀寫操作之前的數(shù)據(jù)版本,通過數(shù)據(jù)版本形成的讀集合與日志記錄組成的寫集合可以檢測出跨節(jié)點(diǎn)事務(wù)的讀寫沖突,沖突檢測的方案參考了分布式數(shù)據(jù)庫中的樂觀并發(fā)控制方法。
算法1是基于事務(wù)日志的跨節(jié)點(diǎn)沖突檢測算法,其中的輸入certification info是一個(gè)以頁號(hào)和頁中行偏移量為索引組織的版本集合,版本通過全局事務(wù)ID描述,驗(yàn)證數(shù)據(jù)庫記錄了全局已提交事務(wù)對于頁中行的修改,當(dāng)前事務(wù)的寫集合是基于事務(wù)日志解析出的事務(wù)修改的行集合,而快照版本集合是事務(wù)執(zhí)行讀寫操作前記錄的頁號(hào)、行偏移量和版本號(hào)。
4實(shí)驗(yàn)
4.1實(shí)驗(yàn)環(huán)境
本文基于開源數(shù)據(jù)庫MySQL實(shí)現(xiàn)了多主插件,實(shí)驗(yàn)服務(wù)器配置信息:Intel(R)Xeon(R)Silver 4 110CPU,168 GB內(nèi)存;10 GB/8網(wǎng)卡;CentOS Linux release 7.7.1908(core)操作系統(tǒng);實(shí)驗(yàn)選用TPC-c負(fù)載,倉庫數(shù)量為50.每個(gè)計(jì)算節(jié)點(diǎn)有16個(gè)客戶端連接,每個(gè)計(jì)算節(jié)點(diǎn)都作為主節(jié)點(diǎn)執(zhí)行寫事務(wù)。
4.2全局事務(wù)ID分配性能測試
第一組實(shí)驗(yàn)是,多個(gè)節(jié)點(diǎn)執(zhí)行TPC-C寫負(fù)載,測試不同的ID分配方式對于系統(tǒng)吞吐量的影響,如表1所示,表1中,縱坐標(biāo)是參與多主集群的節(jié)點(diǎn)數(shù)量,橫坐標(biāo)是整個(gè)事務(wù)的吞吐量,用每秒鐘傳輸?shù)膔equest/事務(wù)數(shù)量(Transactions Per Second,TPS)表示,單個(gè)寫節(jié)點(diǎn)時(shí),系統(tǒng)不需要網(wǎng)絡(luò)傳輸,本地生成的連續(xù)ID即可作為全局ID使用,此時(shí)兩種分配方式的吞吐量相同,這一數(shù)據(jù)可以作為擴(kuò)展性的參考。
基于Paxos提議的全局ID分配參考MySQL的組復(fù)制機(jī)制實(shí)現(xiàn),從表1可以看出,3個(gè)節(jié)點(diǎn)時(shí)系統(tǒng)的吞吐量是單節(jié)點(diǎn)的1.65倍左右,擴(kuò)展到3個(gè)節(jié)點(diǎn)時(shí)系統(tǒng)性能較低,但還在可接受的范圍;而擴(kuò)展到5個(gè)節(jié)點(diǎn)時(shí),系統(tǒng)的吞吐量下降至單節(jié)點(diǎn)的9.38%,這是不可接受的性能衰減,基于切片的全局ID分配按照預(yù)先分配的切片單位計(jì)算全局ID,無論是3個(gè)節(jié)點(diǎn)還是5個(gè)節(jié)點(diǎn),都可以保持接近線性擴(kuò)展的擴(kuò)展性,3個(gè)節(jié)點(diǎn)時(shí)吞吐量是單節(jié)點(diǎn)的3倍,5個(gè)節(jié)點(diǎn)時(shí)接近單節(jié)點(diǎn)的5倍。
4.3事務(wù)性能測試
從表1可以看出基于Paxos提議的全局ID分配擴(kuò)展性十分糟糕,第二組實(shí)驗(yàn)的目的是探究產(chǎn)生這一現(xiàn)象的原因,表2是不同的分配方式單次分配全局ID的平均分配時(shí)延,從表2可以看到,基于切片的全局ID分配方式表現(xiàn)十分穩(wěn)定,無論是3個(gè)節(jié)點(diǎn)還是5個(gè)節(jié)點(diǎn),單次分配只需要0.16us左右,對于事務(wù)執(zhí)行時(shí)延的影響較小,而基于Paxos提議的分配方式由于需要網(wǎng)絡(luò)溝通達(dá)成共識(shí),隨著節(jié)點(diǎn)數(shù)量的增加,單次提議的時(shí)延會(huì)越來越高,單個(gè)節(jié)點(diǎn)時(shí)并不需要通過Paxos提議生成ID,而是通過本地計(jì)算直接生成有序ID,故此時(shí)基于Pxaos提議的分配方案平均時(shí)延為0.在無沖突的情況下,5個(gè)節(jié)點(diǎn)單次提議所需的平均時(shí)延是3個(gè)節(jié)點(diǎn)的381倍,當(dāng)發(fā)生沖突時(shí),5個(gè)節(jié)點(diǎn)單次提議的平均時(shí)延是3個(gè)節(jié)點(diǎn)的1.4倍,看上去似乎擴(kuò)展性的表現(xiàn)好一些,但實(shí)際并不是這樣,3個(gè)節(jié)點(diǎn)的情況下,發(fā)生沖突的提議平均時(shí)延是無沖突時(shí)延的900倍;5個(gè)節(jié)點(diǎn)時(shí),沖突提議的平均時(shí)延是無沖突時(shí)延的3.4倍,產(chǎn)生這一現(xiàn)象的原因是,隨著節(jié)點(diǎn)數(shù)量的增加,達(dá)成共識(shí)需要的網(wǎng)絡(luò)代價(jià)越來越高,單位時(shí)間里可以發(fā)出的提議數(shù)量更少,產(chǎn)生的沖突也會(huì)更少;而3個(gè)節(jié)點(diǎn)時(shí)完成一次成功的提議可能需要經(jīng)過多次連續(xù)的沖突,無論如何,可以看出沖突對于提議的平均時(shí)延影響極大。
表3是兩種分配方式中單次事務(wù)執(zhí)行的平均時(shí)延,從表3可以看出,基于切片分配ID的事務(wù)執(zhí)行時(shí)延比較穩(wěn)定,隨著節(jié)點(diǎn)數(shù)量的增加,事務(wù)時(shí)延的變化很小,基于Paxos提議分配ID的事務(wù)隨著節(jié)點(diǎn)數(shù)量的增加,由于網(wǎng)絡(luò)代價(jià)的增加和沖突的影響,事務(wù)的時(shí)延變化很大,3個(gè)節(jié)點(diǎn)事務(wù)平均時(shí)延是單節(jié)點(diǎn)的1.88倍,5個(gè)節(jié)點(diǎn)事務(wù)平均時(shí)延是3個(gè)節(jié)點(diǎn)的29.75倍。
5結(jié)語
隨著云計(jì)算的發(fā)展,用戶對于云數(shù)據(jù)庫的需求越來越復(fù)雜,當(dāng)下一寫多讀的商業(yè)云數(shù)據(jù)庫產(chǎn)品并不能滿足用戶對于寫性能動(dòng)態(tài)擴(kuò)展的需求,在存儲(chǔ)計(jì)算分離的架構(gòu)下,動(dòng)態(tài)擴(kuò)展寫性能需要支持多個(gè)計(jì)算節(jié)點(diǎn)同時(shí)執(zhí)行寫操作,并且不破壞多個(gè)計(jì)算節(jié)點(diǎn)緩存中數(shù)據(jù)的一致性,本文基于開源數(shù)據(jù)庫MysQL設(shè)計(jì)了一種基于全局事務(wù)日志同步的緩存一致性維護(hù)機(jī)制,通過收集和提前解析redo日志生成以事務(wù)為單位的日志,為事務(wù)日志申請一個(gè)全局有序且連續(xù)的事務(wù)ID,以此全局有序的事務(wù)日志為基礎(chǔ)進(jìn)行跨節(jié)點(diǎn)事務(wù)的沖突檢測,回滾沖突的事務(wù),以此維護(hù)多主緩存的一致性,通過實(shí)驗(yàn)證明,基于Paxos提議的全局事務(wù)ID分配擴(kuò)展性較差,而切片ID的方案在理想情況下可達(dá)到線性擴(kuò)展。