Amazon Aurora:高吞吐量的雲原生關係數據庫的設計考量

譯者:Aceking,極數雲舟技術合夥人,數據庫內核研發專家,負責企業級雲原生數據庫ArkDB等核心數據庫產品,華中科技大學計算機係數據庫方向研究生畢業,原達夢數據庫產品研發工程師,負責達夢數據庫內核開發,長期致力於數據庫原理和源碼開發,精通C/C++,公司內部流傳有他的名言:之後不再敢說精通C++了。前端

摘要mysql

Amazon Aurora是亞馬遜網絡服務(AWS)的一個組成部分,對外提供一個OLTP負載類型的關係數據庫服務。本文描述這種架構設計考量。咱們確信,高吞吐量的數據處理的主要約束已經從計算、存儲轉移到網絡中來了。Aurora給出一個新穎的架構來解決這個約束,其最顯著的特色是把重作日誌(redo)處理下放到專門爲Aurora設計的存儲服務中。文章會介紹如何既能減小網絡流量,又能快速崩潰恢復(crash recovery), 還能實現複製失效不損失數據,以及存儲上的容錯,自愈。而後介紹Aurora在多存儲節點中的保持持久狀態的一致性的高效異步方案,避免了代價高昂繁複的恢復協議。最後,咱們分享了18個多月運營Aurora產品的經驗,這些經驗是從現代雲應用的客戶們對數據庫層的指望中總結的。web

關鍵字sql

數據庫; 分佈式系統; 日誌處理; 仲裁模型; 複製; 恢復; 性能; OLTP數據庫

01 導論緩存

愈來愈多的IT負載轉移到公有云中,這種全行業的轉變的重大緣由包括:公有云服務商可以彈性按需提供容量,以及只需支付運營費用而不用支付資產費用的模式。許多IT負載須要一個OLTP的關係型數據庫。所以,提供一種等效甚至超越的預置數據庫用以支持這種轉變顯得相當重要。安全

愈來愈多現代分佈式雲服務,經過解耦計算與存儲,以及跨越多節點複製的方式實現了彈性與可伸縮性。這樣作,可讓咱們進行某些操做,例如替換失誤或者不可達的主機,添加複製節點,寫入節點與複製節點的故障轉移,拓展或者收縮數據庫實例的大小等等。在這種環境下,傳統的數據庫系統所面臨的IO瓶頸發生改變。由於IO能夠分散到多租戶集羣中的多個節點和多個磁盤中,致使單個磁盤和節點不在是熱點。相反,瓶頸轉移到發起這些IO請求的數據庫層與執行這些IO請求的存儲層之間的網絡中。除了每秒包數(packets per second , PPS)以及帶寬這種基本瓶頸外,一個高性能的數據庫會向發起存儲機羣並行的寫入,從而放大了網絡流量。某個異常存儲節點的性能,磁盤或者網絡通路,都會嚴重影響響應時間。服務器

雖然數據庫大部分的操做能夠互相重疊執行,可是有一些狀況須要同步操做,這會致使停頓和上下文切換(多是線程上下文切換,也能夠是內核態與用戶態切換--譯者注)。狀況之一,數據庫因爲緩衝緩存(buffer cache)未命中,致使進行磁盤讀,讀線程沒法繼續只能等待磁盤讀取完成。將髒頁強制趕出而且刷盤,用以給新頁騰出空間。也會致使緩存(cache)不命中。雖而後臺處理,例如檢查點,髒頁寫入線程能減小這種強制行爲,可是仍然會致使停頓,上下文切換以及資源爭用。網絡

事務提交是另外一個干擾源。一個正在提交的事務的停頓,會阻止另外一個事務的進行。處理多節點同步協議的提交,如兩階段提交(2PC)對雲級規模(cloud-scale)的分佈式系統來講更是一個挑戰。這些協議不能容忍失敗。可是高規模(high-scale)老是充斥着軟硬件失效的「背景噪聲」。同時還有高延遲,由於高規模系統老是跨多個數據中心分佈的。架構

本文中,咱們介紹Amazon Aurora,一種新型的數據庫服務,經過大膽激進的使用高分佈性的雲環境中的日誌來解決上述問題。咱們給出了一種使用多租戶可伸縮的存儲面向服務的架構(圖1),這種存儲服務與數據庫實例集羣鬆耦合,而且從中提取虛擬的分段的重作日誌(redo log).雖然每一個數據庫實例仍然有大部分的傳統的數據庫內核(查詢處理,事務,鎖,緩衝緩存,訪問方法,回滾管理), 可是一些功能(重作日誌,持久存儲,崩潰恢復,備份恢復)已經剝離,放到存儲服務中。
Amazon Aurora:高吞吐量的雲原生關係數據庫的設計考量

咱們的架構與傳統方法相比,有三大明顯優點:首先,把存儲建爲一個容錯、自愈、跨多個數據中心的獨立服務,咱們能夠保護數據庫,使得網絡層或存儲層的性能差別,暫時或永久的失效,對數據庫再也不有影響。咱們觀察到持久存儲的失效能夠做爲一個長時-可用性事件(longlasting availability event)來建模, 而可用性事件能夠做爲一個長時性能變更來建模,長時性能變更已經有一個設計良好的系通通一處理。 其次,經過存儲寫日誌的方式,能夠把網絡的IOPS減小一個量級。一旦咱們移除了這個瓶頸,就能夠大膽的在大量的其餘爭用點上作優化,就能獲取比咱們基於的MySQL基線源碼更明顯的吞吐量的提高。第三,咱們把一些最重要最複雜的功能(如:備份、日誌恢復)從數據庫引擎中一次性代價高昂的操做轉變爲分攤到大型分佈式機羣的連續異步的操做。從而得到近乎瞬時的崩潰恢復,無需檢查點,同時,備份的代價也不高昂,不會影響前臺處理。

本文介紹了咱們的三點貢獻

如何分析雲級規模下的持久性,如何設計具備對相關失效具備彈性的仲裁系統。(段2)

如何使用靈巧的分離存儲,使獲得存儲的負載低於傳統的1/4。(段3)

如何在存儲分佈式系統中消除多階段同步,崩潰恢復,檢查點。(段4)

咱們把三個創意組合在一塊兒,設計出Auraro整體架構(段5),隨後(段 6)檢視咱們的性能結果,(段7)展現咱們的運營經驗,(段8)概述相關的工做,(段9)給出結束語。

02 可伸縮的持久性

若是數據庫不作其餘的事情,必須知足以下要求:一旦寫入,必須可讀。不是全部系統能夠作到這一點。在本段中咱們討論了aurora仲裁模型背後的原理,爲何咱們要將存儲分段,如何將持久性與可得到性結合在一塊兒,減小抖動,而且幫助解決大規模存儲機羣的運營問題。

2.1 複製與相關失效

實例的生命週期與存儲的生命週期並無太大的相關。實例失效,用戶會將其關閉,他們會根據負載狀況調整其大小。這些特色有助於咱們將計算層與存儲層解耦。

一旦你這樣作了,這些存儲節點和磁盤仍然會失效,所以須要某種形式的複製實現對失效的彈性。在規模大的雲環境下,存在持續的下層背景噪聲,如節點失效,磁盤、網絡路徑失效。每一種失效有不一樣的持續時間和破壞半徑。好比,某個節點暫時沒法網絡到達,重啓致使的臨時停機時間,磁盤,節點,機架,網關的葉節點或者主幹節點, 甚至整個數據中心的永久失效。

在存在複製的系統中,實現容錯使用一種[]基於仲裁的投票協議。若是一個複製數據項有V個副本,每一個副本能夠賦予一個投票,一次讀操做或者寫操做分別須要Vr個投票的讀仲裁,或者Vw個投票的寫仲裁。那麼要達到一致性,仲裁必須兩個規則,首先,每次讀操做必須能得到最新的修改。公式爲:

Vr+Vw > V,

這個規則,保證讀取的節點集與寫節點集有交集,讀仲裁至少能讀到一個最新版本的數據副本。其次,每次寫必須佔副本多數,用以免寫衝突。即公式:

Vw > V/2,

一個能容忍複製數據項(V=3)一個節點損失的通用的方法是,寫須要2/3的投票仲裁(Vw=2),讀也須要2/3投票仲裁(Vr=2)。

咱們確信2/3的投票仲裁數是不充分的,爲了解釋爲何,先了解AWS的一個概念,可用區(AZ,availability zone)是區域(region)的子集。一個可用區與其餘可用區能夠低延遲的鏈接,可是能夠隔離其餘可用區的故障,例如,電源,網絡,軟件部署,洪水等等。跨AZ的分佈複製數據能夠保證典型的大規模故障模式隻影響一個複製副本,這意味着,能夠簡單地放三個副本到在不一樣的可用區,就能夠支持大範圍的事件容錯,可是少許的個別失效事件除外。

然而,在一個大的存儲機羣,故障的背景噪聲意味着,任意給一個時刻,都會有一個節點或者磁盤的子集可能壞掉並修復。這些故障可能在可用區A、B、C中獨立分佈。然而,可用區C因爲火災、洪水、屋頂倒塌等等,與此同時,可用區A或者B也有故障(故障背景噪聲),就打破了任意一個副本的仲裁過程。在這一點上,2/3票數的讀取仲裁模型,已經失去了兩個副本,所以沒法肯定第三個副本是不是最新的。換一句話說,雖然,每一個可用區的個體複製節點故障互不相關,可是一個可用區的失效,則與可用區全部的節點和磁盤都相關。仲裁系統要能容忍故障背景噪聲類型的故障與整個可用區的故障同時發生的狀況。

在Aurora中,咱們選用一種能夠容兩種錯誤的設計:(a)在損失整個可用區外加一個節點(AZ+1)狀況下不損失數據。

(b)損失整個可用區不影響寫數據的能力。

在三個可用區的狀況下,咱們把一個數據項6路寫入到3個可用區,每一個可用區有2個副本。使用6個投票模型(V=6),一個寫仲裁要4/6票數(Vw=4),一個讀仲裁須要3/6票數(Vr=3),在這種模型下,像(a)那樣丟失整個可用區外加一個節點(總共3個節點失效),不會損失讀取可用性,像(b)那樣,損失2個節點,乃至整個可用區(2個節點),仍然保持寫的可用性。保證讀仲裁,使得咱們能夠經過添加額外的複製副原本重建寫仲裁。

2.2 分段的存儲

如今咱們考慮AZ+1狀況是否能提供足夠的持久性問題。在這個模型中要提供足夠的持久性,就必須保證兩次獨立故障發生的機率(平均故障時間,Mean Time to Failure, MTTF)足夠低於修復這些故障的時間(Mean Time to Repair, MTTR)。若是兩次故障的機率夠高,咱們可能看到可用區失效,打破了衝裁。減小獨立失效的MTTF,哪怕是一點點,都是很困難的。相反,咱們更關注減小MTTR,縮短兩次故障的脆弱的時間窗口。咱們是這樣作的:將數據庫卷切分紅小的固定大小的段,目前是10G大小。每份數據項以6路複製到保護組(protection Group,PG)中,每一個保護組由6個10GB的段組成,分散在3個可用區中。每一個可用區持有2個段。一個存儲卷是一組相連的PG集合,在物理上的實現是,採用亞馬遜彈性計算雲(ES2)提供的虛擬機附加SSD,組成的大型存儲節點機羣。組成存儲卷PG隨着卷的增加而分配。目前咱們支持的卷沒有開啓複製的狀況下可增加達64TB。

段是咱們進行背景噪聲失效和修復的獨立單元。咱們把監視和自動修復故障做爲咱們服務的一部分。在10Gbps的網絡鏈接狀況下,一個10GB的段能夠在10秒鐘修復。只有在同一個10秒窗口中,出現兩個段的失效,外加一個可用區的失效,而且該可用區不包含這兩個段,咱們才能夠看到仲裁失效。以咱們觀察的失效率來看,幾乎不可能,即便在爲咱們客戶管理的數據庫數量上,也是如此。

2.3 彈性的運營優點

一旦有人設計出一種能對長時失效天然可復原(彈性)的系統,天然也對短時失效也能作到可復原。一個能處理可用區長時失效的系統,固然也能處理像電源事故這樣的短時停頓,或者是因糟糕的軟件部署致使的回滾。能處理多秒的仲裁成員的可用性的損失的系統,也能處理短時的網絡的阻塞,單個存儲節點的過載。

因爲咱們系統有高容錯性,能夠利用這點,經過引發段不可用,作一些維護工做。好比 熱管理就直截了當,咱們直接把把熱點磁盤或節點的一個段標記爲壞段,而後仲裁系統經過在機羣中遷移到較冷的節點來修復。操做系統或者安全打補丁在打補丁時,也是一個短時不可用事件。甚至,軟件升級也能夠經過這個方式作。在某個時刻,咱們升級一個AZ,可是確保PG中不超過一個成員(段或者節點)也在進行補丁。所以,咱們的系統能夠用敏捷的方法論在咱們的存儲服務中進行快速部署。

03 日誌即數據庫

本段解釋爲何傳統的數據庫系統在採用段2所述的分段的複製存儲系統,仍難以承受網絡IO和同步停頓致使的性能負擔。咱們解釋了將日誌處理剝離到存儲服務的方法,以及實驗證明這種方法如何顯著的下降網絡IO,最後講述了最小化同步停頓和沒必要要寫操做的各類技術。

3.1 寫放大的負擔

咱們的存儲卷的分段存儲,以及6路寫入4/6仲裁票數的模型,具備高彈性。可是不幸的是,這種模型會讓傳統的數據庫如MYSQL沒法承受這種性能負擔,由於應用往存儲作一次寫入,會產生存儲中許多不一樣的真實IO。高量的IO又被複制操做放大,產生沉重的PPS(每秒包數,packets per second)負擔。同時,IO也會致使同步點流水線停滯,以及延遲放大。雖然鏈複製[8]以及其餘替代方案能減小網絡代價,可是仍然有同步停頓以及額外的延遲。讓咱們看看傳統的數據庫寫操做是怎麼進行的把。像Mysql這樣的系統,一邊要向已知對象(例如,heap文件,B-數等等)寫入頁,一邊要像先寫日誌系統(write-ahead log, WAL)寫入日誌。日誌要記錄頁的前像到後像的修改的差別。應用日誌,可讓頁由前像變爲後像。
而實際上,還有其餘的數據也要寫入。舉個例子,考慮一下如圖2所示以主從方式實現的同步鏡像mysql配置, 用以實現跨數據中心的高可用性。AZ1是主mysql實例,使用亞馬遜彈性塊存儲(EBS),AZ2是從Mysql實例,也用EBS存儲,往主EBS的寫入,均要經過軟件鏡像的方法同步到從EBS卷中。

Amazon Aurora:高吞吐量的雲原生關係數據庫的設計考量

圖2所示,引擎須要寫入的數據類型:重作日誌,binlog日誌,修改過數據頁,double-write寫,還有元數據FRM文件。圖中給了以下的實際IO順序:

步驟1步驟2,像EBS發起寫操做,而且會像本地可用區的EBS鏡像寫入,以及操做完成的響應消息。

步驟3,使用塊級鏡像軟件將寫入轉入到從節點。

步驟4和5從節點將傳入的寫入操做執行到從節點的EBS和它的EBS鏡像中。

上述MySQL的鏡像模型不可取,不只僅由於它如何寫入的,也由於它寫進了什麼數據。首先,1,3,5步驟是順序同步的過程,因爲有許多順序寫入,產生了額外的延遲。抖動也被放大,哪怕是在異步寫的時候,由於它必須等待最慢的操做,讓系統任憑異常節點的擺佈。按照分佈式視角來看,這個模型能夠視做4/4的寫仲裁,在失效或者異常節點的異常性能面前,顯得十分脆弱。其次,OLTP應用產生的用戶操做,能夠產生許多不一樣類型的寫入,而這些數據寫入方式雖然都不一樣,可是卻表示一樣的信息。例如,往雙寫緩衝的寫入,主要是爲了防止存儲層頁的損壞,(可是內容與頁的普通寫入是同樣的)

3.2 日誌處理分離到存儲

傳統數據庫修改一個頁,就會產生日誌記錄。調用日誌應用器,應用日誌到內存中該頁數據的前像,獲得該頁的後像。事務提交前日誌必須已經寫入,而數據頁則可推後寫入。在Aurora中,經過網絡的寫入只有重作日誌。數據庫層不寫入數據頁,也沒有後臺寫入,沒有檢查點,沒有Cache替換。相反,日誌應用器已經放置到存儲層,存儲層在後臺生成,或者按需生成數據庫的數據頁。固然,從頭開始應用全部修改的,代價讓人難以承受,所以,咱們在後臺持續生成數據頁以免每次抓取時在從新生成這些頁。從正確性的角度來看,後臺生成是徹底可選的:就引擎而言,日誌即數據庫 ,存儲全部具體化出來的頁,均可以視做日誌應用的緩存。與檢查點不一樣,只有那些很長修改鏈的頁纔會要從新具化 ,檢查點由整個日誌鏈長度控制,而Aurora由給定頁的日誌鏈長度來控制。

儘管複製會致使的寫放大,咱們的方法明顯能減小網絡負載,並且保證性能與持久性。在使人尷尬的並行寫入,存儲能超載IO而不影響數據庫引擎的寫吞吐能力。舉個例子,圖3所示,是一個一主多從Aurora集羣,部署在多個可用區中。在這個模型中,主庫往存儲寫入日誌,而且把這些日誌與元數據更新發送給從節點。基於公共存儲目標(一個邏輯段,好比,PG)的一批批日誌都是徹底有序的。把每一個批次以6路傳輸給複製節點,存儲引擎等待4個或4個多的迴應,用以知足寫仲裁條件,來判斷日誌在持久上或硬化上是否有問題。複製節點應用這些日誌記錄來更新自身的緩存緩衝。

Amazon Aurora:高吞吐量的雲原生關係數據庫的設計考量

爲了測量網絡IO的情況,咱們在以上所述的兩種mysql配置下,進行了100GB的數據集只寫負載的sysbench[9]測試:一種是跨多個可用區的mysql鏡像配置,另外一個是Aurora的RDS,在r3.8large EC2的實例中運行了30分鐘。

實驗結果如表1所示。在30分鐘的時間裏,在事務上,Aurora比mysql鏡像多35倍,雖然Aurora的寫放大了6倍,可是每一個事務寫IO仍然比mysql鏡像小7.7倍。這裏並無記錄EBS的鏈式複製與mysql跨可用區的寫。每一個存儲節點,只是6個複製節點中的一個,所以看不到寫放大。這裏的IO數量減小了46倍。寫入了更少的數據,省下的網絡能力,能夠激進地經過複製實現持久性與可用性,並在發起並行請求時,最小化抖動的影響。
Amazon Aurora:高吞吐量的雲原生關係數據庫的設計考量

把日誌處理放到存儲服務中,也能夠最小化崩潰恢復的時間,來提升可用性,而且消除檢查點、後臺寫、備份等後臺處理所帶來的抖動。咱們再看崩潰恢復。傳統數據庫在崩潰以後,必須從最近的檢查點開始,將日誌重演並要報保證全部的保存的日誌都被應用。在Aurora中,持續的日誌應用發生在存儲中,而且它是持續的,異步的,分散在機羣中的。任何一次讀頁請求,若是該頁不是當前版本,則要應用一些重作日誌。所以,崩潰恢復過程已經分散到全部的正常的前臺處理中,不須要在數據庫啓動的時候執行。

3.3 存儲服務的設計點

咱們的存儲服務設計的核心原則是最小化前臺寫請求的延遲。咱們把大部分的存儲處理移到了後臺。鑑於存儲層前臺的請求峯值與平均值之間的天然變更,咱們有足夠的時間在前臺請求以外進行這些處理。並且咱們也有機會用cpu換磁盤。好比說,當存儲節點忙於前端請求處理,就沒有必要進行舊頁的垃圾回收(GC),除非該磁盤快滿了。Aurora中,後臺處理與前臺處理負相關。與傳統的數據庫不同,傳統數據庫的後臺寫頁、檢查點處理與系統的的前臺的請求量正相關。若是系統中有積壓請求,咱們會抑制前端請求,避免造成長隊列。由於系統中的段以高熵的形式(高混亂程度)分佈在不一樣的存儲節點中,限制一個存儲節點在4/6仲裁系統中天然的做爲慢節點處理。

如今以更多的細節來觀察存儲節點各類活動。如圖4所示,包含了以下若干步驟:

一、接收日誌記錄而且放入內存隊列中。

二、保存到磁盤而且返回應答。

三、組織日誌記錄,而且識別日誌中的空白,由於有些批次的日誌會丟失。

四、與對等節點交流(gossip)填住空白。

五、合入日誌到新的數據頁。

六、週期地將新數據頁和日誌備份到S3。

七、週期的回收舊版本。

八、校驗頁中的CRC編碼。

注意,以上各個步驟不全是異步的,1 和 2 在前臺路徑中有潛在的延遲影響。

Amazon Aurora:高吞吐量的雲原生關係數據庫的設計考量

04 日誌前行

本段中,咱們介紹數據庫引擎生成的日誌如何在持久狀態,運行狀態,複製狀態始終保持一致。特別是,如何不須要2PC協議高效地實現一致性。首先,咱們展現瞭如何在崩潰恢復中避免使用高昂的重作處理。咱們解釋正常操做中如何維護運行狀態與複製狀態。最後,咱們披露崩潰恢復的細節。

4.1 解決方案草圖:異步處理

由於咱們把數據庫建模爲一個日誌流,事實上日誌做爲有序的修改序列,這點咱們也要利用。實際上,每一個日誌都有與之關聯的日誌序列號(Log Sequence Number, LSN), LSN是由數據庫產生的單調遞增的值。

這就可使咱們簡化共識協議,咱們採用異步方式協議而不是2PC協議。2PC協議交互繁複而且不容錯。在高層次上,咱們維護一致性與持久化的點,在接收還未完成的存儲請求的響應時推動這些點,而且是持續的推動。因爲單獨的存儲節點可能會丟失一個或者多個日誌記錄,它們能夠與同PG的其餘成員進行交流,尋找空白並填補空洞。運行狀態是由數據庫維護的,咱們能夠直接從存儲段讀取而不須要讀仲裁。但在崩潰恢復時候,運行狀態已丟失須要重建的時候除外,這時候仍須要讀仲裁。

數據庫可能有不少獨立的未完成的事務,這些事務能夠與發起時順序徹底不一樣的順序完成(達到持久化的結束狀態)。假設數據庫奔潰或重啓,這些獨立事務是否回滾的決策是分開的。則跟蹤並撤銷部分完成事務的邏輯保留在數據庫引擎中,就像寫入簡單磁盤同樣。在重啓過程當中,在容許數據庫訪問存儲卷以前,存儲進行自身的崩潰恢復,而不關心用戶層的事務。固然,要保證數據庫看到的存儲系統是單一的視圖,儘管實際上存儲是分佈式的。

存儲服務決定一個最高的LSN,保證在在這個LSN以前的日誌記錄都是能夠讀取的。(VCL,volume Complete LSN)。在恢復過程當中,對應LSN任何高於VCL的重作日誌都要丟棄。可是,數據庫還能夠進一步約束條件,取其子集,用以標記哪些日誌能夠丟棄。這個子集就是CPL集(Consistency Point LSNs)。所以,咱們還能夠定義一個VDL(volume durable LSN)爲小與VCL的最大CPL。舉個例子,雖然數據完成到LSN爲1007,可是數據庫標記的CPL集爲900,1000,1100。在這種狀況下,咱們丟棄的位置爲1000(1000之後的都要丟棄),也就是咱們完成到1007(VCL),可是持久到1000(VDL)。

所以,完成性與持久性是不一樣的。CPL能夠看做存儲事務必須有序接受的某種限制形式。若是客戶端沒有對此加以區別,咱們把每一個日誌記錄標記爲一個CPL。實際上,數據庫與存儲以以下方式交互:

每一個數據庫層面的事務,都被打斷爲多個迷你事務(mini-transactions,MTRs),迷你事務是有序的,並且是原子的方式執行(就是不可分割地執行)。

一個迷你事務由多條連續的日誌記錄組成(要多少有多少)。

迷你事務的最後一條日誌記錄就是一個CPL

在崩潰恢復過程當中,數據庫告訴存儲層爲每一個PG創建一個持久點,用來創建一個VDL,而後發起丟棄高於VDL日誌的命令。

4.2 正常操做

咱們如今描述數據庫的「正常操做」, 依次關注寫、讀、提交與複製。

4.2.1 寫

在Aurora中,數據庫不停地與存儲服務交互,而且維護狀態以創建仲裁,推動卷持久性(volume durablity),而且在提交時註冊事務。舉個例子,在正常/前轉路徑中,當數據庫接收到響應消息爲每批日誌創建寫仲裁,則推動當前VDL。在任意給定時刻,數據庫可能有大量的併發事務活動。每一個事務均產生日誌,數據庫又爲每條日誌分配惟一的有序的LSN,可是分配受限於一條原則,LSN不能大於當前VDL與一個常量值的和。這個常量稱爲LSN分配限值(LAL, LSN Allocation limit)(目前設置爲一千萬)。這個限值保證數據庫的LSN不超出存儲系統太遠,在存儲或者網絡跟不上時,提供一個反壓,用以調節來入的寫請求。

注意,每一個PG的每一個段僅僅能看到存儲卷日誌記錄的子集,該子集的日誌僅僅影響駐留於該段的頁。每一個日誌記錄包含一個指向PG中前一個日誌記錄的反向連接。這些反向連接能夠跟蹤達到每一個段的日誌記錄的完成點,用以創建段完成LSN(Segment Complete LSN, SCL), SCL是表示一個最大LSN,在該LSN之下全部的日誌記錄均已經被該PG接收到。存儲節點使用SCL相互交流,用來查找並交換得到本身確實的那部分日誌。

4.2.2 提交

在Aurora中,事務提交是異步完成的。當客戶端提交一個事務,處理事務提交的線程記錄一個「提交LSN」(commit lsn)到一個單獨的等待提交的事務列表中,而後將事務擱置去處理其餘任務。這至關於WAL協議是基於事務提交的完成,也即當且僅當最新的VDL大於或等於事務的提交LSN的時候。隨着VDL的推動,數據庫在正在等待提交事務識別符合條件的,由專有線程向正在等待的客戶端發送提交響應消息。工做線程不會由於提交事務而暫停,它們僅是把其餘的掛起的請求拉起繼續處理。

4.2.3 讀

在Aurora中,和大部分的數據庫同樣,頁由buf和cache提供。只有頁是否在Cache中還存疑的時候,纔會致使存儲IO請求。

若是buf cache已滿,系統找出受害頁,將其趕出cache。在傳統數據庫中,若是受害頁是「髒頁「,替換前要刷盤。這就保證後續的頁的提取,老是最新數據。然而Aurora在驅逐頁的時候並無將頁寫出,但它強制執行一個保證:在buff或cache中的頁始終是最新的版本。實現這一保證的措施是,僅僅將「頁LSN(Page LSN)「(與頁相關最新的日誌LSN)大於或者等於VDL。這個協議保證了:(a)頁的全部修改在日誌中都已硬化, (b)在cache沒命中的時候,得到最近的持久化版本的頁,請求當前VDL版本頁就足夠了。

數據庫在正常狀況下不須要使用讀仲裁來創建一致性。當從磁盤讀取一個頁,數據庫創建一個讀取點(read-point)

表示讀取發起時候的VDL。數據庫能夠選擇一個相對於讀取點數據完整存儲節點,從而取獲得最新版本的數據。存儲節點返回的數據頁必定與數據庫的迷你事務(mtr)的預期語義一致。由於,數據庫管理着往存儲節點日誌的饋送,跟蹤這個過程(好比,每一個端的SCL),所以它知道那些段知足讀取要求(那些SCL大與讀取點的段)。而後直接向有足額數據的段發起讀請求。

考慮到數據庫知道那些讀操做沒有完成,能夠在任什麼時候間在每一個PG的基礎上計算出最小的讀取點LSN(Minimum Read Point LSN). 若是有存儲節點交流寫的可讀副本,用來創建全部節點每一個PG的最小讀取點,那麼這個值就叫作保護組最小讀取點LSN(Protection Group Min Read Point LSN, PGMRPL). PGMRPL用來標識「低位水線」,低於這個「低位水線」的PG日誌記錄都是沒必要要的。換句話說,每一個存儲段必須保證沒有低於PGMRPL的讀取點的頁讀請求。每一個存儲節點能夠從數據庫瞭解到PGMRPL,所以,能夠收集舊日誌,物化這些頁到磁盤中,再安全回收日誌垃圾。

實際上,在數據庫執行的併發控制協議,其數據庫頁和回滾段組織方式,與使用本地存儲的傳統數據庫的組織方式並沒有二致。

4.2.4 複製節點(replicas)

在Aurora中,在同一個存儲卷中,一次單獨的寫最多有15個讀複製。所以,讀複製在消耗存儲方面,並無增長額外的代價,也沒有增長額外的磁盤寫。爲了最小化延遲,寫生成的日誌流除了發送給存儲節點,也發送全部的讀複製節點。在讀節點中,數據庫依次檢查日誌流的每一天日誌記錄。若是日誌引用的頁在讀節點的緩衝緩存中,則日誌應用器應用指定的日誌記錄到緩存中的頁。不然,簡單丟棄日誌記錄。注意從寫節點的視角來看,複製節點是異步消費日誌流的,而寫節點獨立於複製節點響應用戶的提交。複製節點在應用日誌的時候必須聽從以下兩個重要規則:(a)只有LSN小於或等於VDL的日誌記錄才能應用。(b)只有屬於單個迷你事務(MTR)的日誌記錄才能被應用(mtr不完整的日誌記錄不能應用),用以保證複製節點看到的是全部數據庫對象的一致視圖。實際上,每一個複製節點僅僅在寫節點後面延遲一個很短的時間(20ms甚至更少)。

4.3 恢復

大部分數據庫(如ARIES)採用的恢復協議,取決因而否採用了能表示提交事務全部的精確的內容的先寫日誌(write ahead log,WAL)。這些系統週期的作數據庫檢查點,經過刷髒頁到磁盤,並在日誌中寫入檢查點記錄,粗粒度地創建持久點。在重啓的時候,任何指定的頁均可能丟失數據,丟失的數據多是已經提交了的,也可能包含未提交的。所以,在崩潰恢復的過程當中,系統從最近的檢查點開始處理日誌,使用日誌應用器將這些日誌應用日誌到相關數據庫頁中。經過執行相應的回滾日誌記錄,能夠回滾崩潰時正在運行的事務,這個過程給數據庫帶來了故障點時候的一致性狀態。崩潰恢復是一個代價高昂的操做,減小檢查點間隔能夠減小代價,可是這會帶來影響前端事務的代價。傳統數據庫須要在二者作權衡,而Aurora則不須要這樣的權衡。

傳統數據庫有一個重要的簡化原則是,使用同一個日誌應用器,推動數據庫狀態與進行同步的日誌恢復。而且此時從前端看來,數據庫庫是脫機的。Aurora設計也遵循一樣的原則。可是日誌應用器已經從數據庫中解耦出來,直接在存儲服務中在老是在後臺並行運行。一旦數據庫開始執行卷恢復,它會與存儲服務合做來進行。結果是,Aurora數據庫恢復速度很是快(一般在10秒如下),哪怕是每秒運行100,000條語句時候崩潰後狀況下作恢復。

Aurora數據庫不須要在崩潰以後重建運行狀態。在崩潰的狀況下,它會聯繫每一個PG,只要數據知足了寫仲裁的條件,段的讀仲裁徹底能夠保證能發現這些數據。一旦數據庫爲每一個PG創建了讀仲裁,則能夠從新計算VDL,生成高於該VDL的丟棄範圍(truncation range),保證這個範圍後的日誌都要丟棄,丟棄範圍是這是數據庫能能夠證實的最大可能保證未完成的日誌(不是完整MTR的日誌)可見的結束LSN。而後,數據庫能夠推斷出LSN分配的上限,即LSN的上限能超過VDL多少(前面描述的一千萬)。丟棄範圍使用時間數字(epoch number)做爲版本,寫在存儲服務中,不管崩潰恢復仍是重啓,都不會弄混丟棄日誌的持久化。

數據庫仍然須要作undo恢復,用來回滾崩潰時正在進行的事務。可是,回滾事務能夠在數據庫聯機的時候進行,在此以前,數據庫已經經過回滾段的信息,創建了未完成事務列表。

05 放在一塊兒

本段中,咱們描述如圖5所示Aurora的各個模塊。

Aurora庫是從社區版的mysql/innodb數據庫fork出來的分支,與之不一樣的主要在讀寫磁盤數據這塊。在社區版的Innodb中,數據的寫操做修改buffer中的頁,相應的日誌也按LSN順序寫入WAL的緩存中。在事務提交的時候,WAL協議只要求事務的日誌記錄寫入到磁盤。最終,這個被修改的緩存頁使用雙寫技術寫入到磁盤中,使用雙寫的目的是爲了不不完整的頁寫(partial page writes)。這些寫操做在後臺執行,或者從cache驅逐頁出去時候執行,或者在檢查點時候執行。除IO子系統外,innodb還包含事務子系統,鎖管理器,B+樹的實現,以及「迷你事務」(MTR)。innodb的將一組不可分割執行(executed atomically)的操做稱爲一個迷你事務(例如,分裂/合併B+樹頁)。

Amazon Aurora:高吞吐量的雲原生關係數據庫的設計考量

在Aurora的Innodb變種中,mtr中原先那些不可分割執行日誌,按照批次組織,分片並寫入到其所屬的PG中,將mtr最後一個日誌記錄標記爲一致點(consistency point), Aurora在寫方面支持與社區mysql同樣的隔離等級(ANSI標準級別,Snapshot 隔離級,一致性讀)。Aurora讀複製節點能夠從寫節點獲取事務開始和提交的持續信息,利用這些信息支持本地只讀事務的snapshot隔離級。注意,併發控制是徹底有數據庫實現的,對存儲服務沒有任何影響。存儲服務爲下層數據提供了展示了一個統一視圖,與社區版本innodb往本地存儲寫數據的方式,在邏輯上徹底等效。

Aurora使用亞馬遜關係數據庫服務(RDS)做爲控制平臺。RDS包含一個數據庫實例上的代理,監控集羣的健康狀況,用以決定是否進行故障切換,或者是否進行實例替換。而實例能夠是集羣中的一個,集羣則由一個寫節點,0個或者多個讀複製節點組成。集羣中全部的示例,均在同一個地理區域內(例如,us-east-1,us-west-2等)。可是放置在不一樣的可用區內。鏈接同一個區域的存儲機羣。爲了安全起見,數據庫、應用、存儲之間的鏈接都被隔離。實際上,每一個數據庫實例均可以經過三個亞馬遜虛擬私有云(VPC)進行通訊:用戶VPC,用戶應用程序能夠經過它與數據庫實例進行交互。RDS VPC,經過它數據庫節點之間,數據庫與控制平臺之間進行交互。存儲VPC,用以進行數據庫與存儲之間的交互。

存儲服務部署在EC2虛擬機集羣中。這些虛擬機在一個區域內至少跨三個可用區,共同負責多用戶提供存儲卷、以及這些卷的讀寫、備份、恢復。存儲節點負責操做本地SSD,與對等節點或數據庫實例進行交互,以及備份恢復服務。備份恢復服務持續的將數據的改變備份到S3,而且依據需求從S3恢復。存儲控制平臺使用亞馬遜DynamoDB服務存儲集羣的永久數據、存儲卷配置、卷的元數據、備份到S3的數據的描述信息。爲了協調長時間的操做,如數據庫卷恢復操做,修復(從新複製)存儲節點失效等,存儲控制平臺使用亞馬遜簡單工做流服務(Amazon Simple Workflow Service)。維持高可用性,須要在影響用戶以前,主動地、自動地、儘早地檢測出真正的或潛在的問題。存儲操做各個關鍵的方面都要經過metric收集服務進行持續監控,metric會在關鍵性能、可用性參數值指示出現異常進行報警。

06 性能結果

在本段中,咱們分享了自2015五月Aurora達到「GA」(基本可用)以後的運營經驗。咱們給出工業標準的基準測試結果,以及從咱們客戶得到的性能結果。

標準基準測試結果

這裏展現了在不一樣的試驗下,Aurora與mysql的性能對比結果。實驗使用的是工業標準的基準測試,如sysbench和TPC-C的變種。咱們運行的mysql實例,附加的存儲是有30K IPOS的EBS存儲卷,除非另有說明,這些mysql運行在有32 vCPU和244G內存的r3.8xlarge EC2實例中,配備了Intel Xeon E5-2670 v2 (Ivy Bridge) 處理器,r3.8xlarge的緩存緩衝設置到170GB。

07 學到的經驗

咱們能夠看到客戶運行的大量的各類應用,客戶有小型的互聯網公司,也有運行大量Aurora集羣的複雜組織。然而許多應用的都是標準的用例,咱們關注於這些雲服務應用中共同的場景和指望,以引領咱們走向新方向。

7.1 多租戶與數據庫整合

咱們許多客戶運營軟件即服務(SaaS)的業務,有專有云業務客戶,也有將企業部署的遺留系統轉向SaaS的客戶。咱們發現這些客戶每每依賴於一種不能輕易修改應用。所以,他們一般把他們本身的不一樣用戶經過一個租戶一個庫或模式的方式整合到一個單實例中。這種風格能夠減小成本:他們避免爲每一個用戶購買一個專有實例,由於他們的用戶不可能同時活躍。舉個例子,有些SaaS的客戶說他們有50,000多用戶。

這種模式與咱們衆所周知的多租戶應用如Saleforce.com不一樣,saleFore.com採用的多租戶模式是,全部用戶都在同一模式統一的表中,在行級記錄中標記租戶。結果是,咱們看到進行數據庫整合的用戶擁有巨量的表。生產實例中擁有超過150,000個表的小數據庫很是的廣泛。這就給管理如字典緩存等元數據的組件帶來了壓力。這些用戶須要(a)維持高水平的吞吐量以及併發的多用戶鏈接,(b)用多少數據就購買提供多少的模式,很難進一步預測使用多少存儲空間,(c)減小抖動,最小化單個用戶負載尖峯對其餘租戶的影響。Aurora支持這些屬性,對這些SaaS的應用適配得很好。

7.2 高併發自動伸縮負載

互聯網負載須要處理由於突發事件致使的尖峯流量。咱們的主要客戶之一,在一次高度受歡迎的全國性電視節目中出現特殊情況,經歷了遠高於正常吞吐量峯值的尖峯,可是並無給數據庫帶來壓力。要支持這樣的尖峯,數據庫處理大量併發用戶鏈接顯得十分的重要。這在Aurora是可行的,由於下層存儲系統伸縮性如此之好。咱們有些用戶運行時都達到了每秒8000個鏈接。

7.3 模式升級

現代web應用框架,如Ruby on Rails,都整合了ORM(object-relational mapping, 對象-關係映射)。致使對於應用開發人員來講,數據庫模式改變很是容易,可是對DBA來講,如何升級數據庫模式就成爲一種挑戰。在Rail應用中,咱們有關於DBA的第一手資料:「數據庫遷移「,對於DBA來講是"一週作大把的遷移「,或者是採用一些迴避策略,用以保證未來遷移的不那麼痛苦。而Mysql提供了自由的模式升級語義,大部分的修改的實現方式是全表複製。頻繁的DDL操做是一個務實的現實,咱們實現了一種高效的在線DDL,使用(a)基於每頁的數據庫版本化模式,使用模式歷史信息,按需對單獨頁進行解碼。(b)使用寫時修改(modify-on-write)原語,實現對單頁的最新模式懶更新。

7.4 可用性與軟件升級

咱們的客戶對雲原生數據庫如何解決運行機羣和對服務器的補丁升級的矛盾,有着強烈的指望。客戶持有某種應用,而這些應用有主要使用Aurora做爲OLTP服務支持。對這些客戶來講,任何中斷都是痛苦的。因此,咱們許多客戶對數據庫軟件的更新的容忍度很低,哪怕是至關於6周30秒的停機時間。所以,咱們最近發佈了零停機補丁(zero downtime patch)特性。這個特性容許給用戶補丁可是不影響運行的數據庫鏈接。

如圖5所示,ZDP經過尋找沒有活動事務的瞬間,在這瞬間將應用假脫機到本地臨時存儲,給數據庫引擎打補丁而後更新應用狀態。在這個過程當中,用戶會話仍然是活動的,並不知道數據庫引擎已經發生了改變。
Amazon Aurora:高吞吐量的雲原生關係數據庫的設計考量

08 相關工做

在本段中,咱們討論其餘人的貢獻,這些貢獻與Aurora採用的方法相關。

存儲與引擎解耦雖然傳統的數據都被設計成單內核的守護進程。可是仍有相關的工做,將數據庫內核解耦成不一樣的組成部分,例如,Deuteronomy就是這樣的系統,將系統分爲事務組件(Tranascation Component, TC)和數據組件(Data Componet ,DC).事務組件提供併發控制功能已經從DC中作崩潰恢復的功能,DC提供了一個LLAMA之上的訪問方法。LLAMA是一個無閂鎖的基於日誌結構的緩存和存儲管理系統。Sinfonia 和 Hyder則從可拓展的服務抽出了事務性訪問方法,實現了能夠抽象使用這些方法的數據庫系統。Yesquel系統實現了一個多版本分佈式平衡樹,而且把將併發控制從查詢處理中獨立出來。Aurora解耦存儲比Deuteronomy、Hyder、Sinfonia更爲底層。在Aurora中,查詢處理,事務,併發,緩存緩衝以及訪問方法都和日誌存儲解耦,而且崩潰恢復做爲一個可拓展的服務實現的。

分佈式系統 在分區面前,正確性與可用性的權衡早已爲人所知,在網絡分區去狀況下,一個副本的可串行化是不可能的,最近Brewer的CAP理論已經證實了在高可用系統在網絡分區的狀況下,不可能提供「強」一致性。這些結果以及咱們在雲級規模的經驗,激發了咱們的一致性目標,即便在AZ失效引發分區的狀況下也要一致性。

Brailis等人研究了高可用事務系統(Highly Available Transactions, HATs)的問題。他們已經證實分區或者高網絡延遲,並不會致使不可用性。可串行化、snapshot隔離級、可重複讀隔離級與HAT不兼容。然而其餘的隔離級能夠達到高可用性。Aurora提供了全部的隔離級,它給了一個簡單的假設,即任什麼時候候都只有一個寫節點產生日誌,日誌更新的LSN,是在單個有序域中分配的。

Google的Spanner提供了讀和寫的外部一致性,而且提供了跨數據在同一個時間戳上全球一致性讀。這些特性使得spanner能夠一致性備份,一致性分佈式查詢處理以及原子模式更新,這些特性都是全球規模的,哪怕是正在運行的事務的時候,也支持。正如Bailis解釋的同樣,Spanner是爲google的重-讀(read-heavy)負載高度定製的。採用兩階段提交,讀/寫事務採用兩階段鎖。

併發控制弱一致性與弱隔離級模型在分佈式數據庫中已爲人所知。由此產生了樂觀複製技術以及最終一致性系統在中心化的系統中,採用的其餘的方法,有基於鎖的悲觀模式(),採用如多版本併發控制樂觀模式,如Hekaton,如VoltDB採用分片方法,Deuteronomy和Hyper採用時間戳排序的方法。而Aurora給數據庫系統提供了一個持久存在的抽象的本地磁盤,容許引擎本身處理隔離級與併發控制。

日誌結構存儲1992年LFS就引入了日誌結構存儲系統。最近Deuteronomy和LLMA的相關工做,以及Bw-tree以多種方式在存儲引擎棧中採用日誌結構技術,和Aurora同樣,經過寫入差量而不是寫整頁減小寫放大。Aurora與Deuteronomy都實現了純重作日誌系統,而且跟蹤最高持久化的LSN,用以確認提交。

崩潰恢復 傳統數據庫依賴於ARIES的恢復協議,如今有些數據庫爲了性能而採用了其餘途徑。例如,Hekaton與VoltDB採用某種形式的更新日誌來重建崩潰後的內存狀態。像Sinfonia系統採用如進程對以及複製狀態機的技術來避免崩潰恢復。Graefe描述一種使用每頁日誌記錄鏈的系統,能夠按需逐頁重作。能夠提升崩潰恢復的速度。Aurora與Deuteronomy不須要重作崩潰恢復的過程。這是由於Deuteronomy會將事務延遲,以便只有提交的事務的修改纔會寫入到持久存儲中。於是,與Aurora不一樣,Deuteronomy能處理的事務大小必然受到限制。

09 結論

咱們設計出了高吞吐量的OLTP數據庫Aurora,在雲級規模環境下,並無損失其可用性與持久性。主要思想是,沒有采用傳統數據庫的單核架構,而是從計算節點中把存儲解耦出來。實際上,咱們只從數據庫內核中移走了低於1/4的部分到獨立的彈性伸縮的分佈式服務中,用以管理日誌與存儲。因爲全部的IO寫都要經過網絡,如今咱們的基本的約束就在於網絡。因此咱們關注於能緩解網絡壓力並能提升吞吐量的技術。咱們使用仲裁模型來處理大規模的雲環境下的相關的複雜失效。而且避免了特殊節點帶來的性能懲罰。使用日誌處理減小總的IO負擔。採用異步共識方法消除多階段提交同步協議的繁複交互與高昂的代價,以及離線的崩潰恢復,和分佈式存儲的檢查點。咱們的方法致使了簡化系統架構,能下降複雜性,易於伸縮能爲將來的發展打下基礎。

文章我的解讀

圖1中所示的Data Plane中,數據庫引擎那個框包住了Caching,而存儲服務那個框,也包住了Caching。回味無窮。能夠猜想,Cache是共享內存,數據庫引擎和存儲服務均可以訪問。並且Cache不光是數據庫引擎的一部分,並且也是存儲服務的一部分。全文大部分篇幅講如何優化寫請求帶來的網絡負擔,而隻字未提讀請求是否帶來網絡負擔。所以,能夠大膽猜想,一次寫操做,不光是把日誌應用到磁盤存儲中,同時也把已經在cache的頁也應用了,所以大部分的讀請求不須要真實的存儲IO,除非該頁在cache中沒有命中。從段6的Aurora測試能夠看到,Aurora實例擁有的緩存至關大,通常的應用軟件的數據庫數據都能放在內存中。從圖3也能夠看到,AZ1主實例,也會向AZ2,AZ3數據庫從實例發送日誌與元數據,既然已經將日誌處理從數據庫引擎解耦出來了,發送的日誌由誰應用呢?我的認爲,AZ2與AZ3接收到日誌,仍然是有存儲服務應用的,只不過Cache是存儲服務與數據庫引擎共享的。

並且有這個猜想,咱們進一步解讀零停機補丁的實現方式。ZDP如何保持用戶鏈接實現假脫機?我的認爲,應用到數據庫之間有proxy。使用proxy來保持應用程序的鏈接,並從新與更新後數據庫實例創建鏈接,並且要作到用戶會話無感受,Cache是共享內存是必要的。由於Cache保存了大部分數據庫運行狀態,重啓後的數據庫實例仍然繼續進行用戶會話的查詢。這個和使用共享內存的postgre有點像,你隨意殺死postgre某些進程,並不影響用戶會話的查詢。

此外,我的認爲,Aurora的計算節點,有可能也是存儲節點。雖然邏輯上是存儲與計算分離的,可是也能夠享受不分離帶來的好處,好比,存儲服務能夠直接往Cache應用日誌,使得數據庫引擎在大部分讀請求不須要真實的IO。

Aurora有沒有checkpoint?

Aurora的PGMRPL能夠認爲是檢查點。LSN小於這個點的數據頁已經刷盤,而大於這個點的頁能夠刷盤,也能夠不刷盤,LSN小於這個點的日誌均可以丟棄。PGMRPL在邏輯上與存儲引擎的檢查點是等效的。能夠認爲是PG上的檢查點。

Aurora與polardb

Aurora與Polardb都是存儲與計算分離、一些多讀、共享分佈式存儲的架構。很顯然,polardb在寫放大上面沒有作優化。從節點須要同步主庫的髒頁,共享的存儲,私有的髒頁,是個很難解決的矛盾。所以polardb的讀節點會影響寫節點。而Aurora能夠認爲沒有髒頁。日誌即數據庫,能夠把日誌應用器看做更慢的存儲,存儲服務與緩存均可以認爲是日誌應用器的Cache。

從節點與主節點之間有延遲,而aurora存儲的數據頁有多版本,文中明確指出存儲有舊頁回收處理。從節點依據讀取點LSN讀取到指定版本的頁,文中段4.2.4指出,寫節點到讀複製節點之間的延遲小於20ms,所以,不可回收的舊版本頁應該不會太多。

臨時表

每一個讀節點雖然只有查詢操做,可是查詢操做會生成臨時表用以保存查詢的中間結果。生成臨時表數據是不會產生日誌的。可是這裏仍有寫IO,我的認爲,Aurora有可能直接寫在本地存儲,這樣不會產生網絡上的負擔。

相關文章
相關標籤/搜索