Amazon在SIGMOD 2017發表了論文《Amazon Aurora: DesignConsiderations for High Throughput Cloud-Native Relational Databases》,第一次公開介紹了Aurora的設計理念和內部實現,下文是我對論文的解讀,如有理解不准確的地方,歡迎大家批評指正。
>>摘要
Aurora是亞馬遜雲服務AWS中的關系型數據庫服務,主要面向OLTP場景。本文會詳細介紹Aurora的架構以及設計背后的理念。 Aurora基本設計理念是在雲上環境下,數據庫的最大瓶頸不再是計算或者存儲資源,而是網絡,因此基於一套存儲計算分離架構,將日志處理下推到分布式存儲層,通過架構上的優化來解決網絡瓶頸。 下文首先會介紹Aurora如何做到不僅減少了網絡資源消耗,同時還能快速故障恢復且不丟失數據,接着會介紹Aurora如何做到異步模式下分布式存儲節點的一致性,最后會介紹Aurora在生產環境使用的經驗。
>>1. 概述
在雲上環境下,存儲計算分離作為解決系統彈性和伸縮性的方案越來越普遍。廣義來說,任何數據庫,底下文件系統掛一個分布式存儲,即可以認為做到了存儲計算分離。通過存儲計算分離,可以透明添加存儲節點,剔除故障節點,進行故障切換,擴展存儲空間等。在這個背景下,IO不再成為數據庫的瓶頸,因為IO壓力可以打散在多個存儲節點上,反而是網絡成為瓶頸,因為數據庫實例與所有存儲節點的交互都需要通過網絡,尤其是為了提升數據庫性能,數據庫實例與存儲節點可能是並行交互的,這進一步加重了網絡壓力。傳統數據庫中的IO操作是需要同步執行的,當需要進行IO等待時,這往往會導致線程上下文切換,影響數據庫性能。比如IO讀操作,當需要訪問一個數據頁時,如果在緩沖池沒有命中,則需要進行磁盤IO,那么讀線程需要等待IO完成才能繼續其它操作,同時這種動作可能會進一步引發刷臟頁等。另外一個我們熟悉場景是事務提交操作(IO寫操作),事務提交成功返回前一定要等待事務對應日志刷盤才能返回,由於事務是串行提交,因此其它事務也必須同步等待這個事務提交。 傳統數據庫中的兩階段事務尤其不適合與分布式雲環境,因為二階段提交協議對系統中參與的節點和網絡要求很高,自身容錯能力有限,這點與大規模分布式雲環境中,軟件和硬件故障是常態的特征是矛盾的。
本文介紹的Aurora是一個雲上環境全新的數據庫服務可以很好的解決上述傳統數據庫遇到的問題。 它基於存儲計算分離的架構,並將回放日志部分下推到分布式存儲層,存儲節點與數據庫實例(計算節點)松耦合,並包含部分計算功能。 Aurora體系下的數據庫實例仍然包含了大部分核心功能,比如查詢處理,事務,鎖,緩存管理,訪問接口和undo日志管理等;但redo日志相關的功能已經下推到存儲層,包括日志處理,故障恢復,備份還原等。Aurora相對於傳統數據庫有三大優勢,首先,底層數據庫存儲是一個分布式存儲服務,可以輕松應對故障;其次,數據庫實例往底層存儲層只寫redo日志,因此數據庫實例與存儲節點之間的網絡壓力大大減小,這為提升數據庫性能提供了保障;第三,將部分核心功能(故障恢復,備份還原)下推到存儲層,這些任務可以在后台不間歇地異步執行,並且不影響前台用戶任務。下文會詳細介紹Aurora如何實現這些功能,主要包括三大塊:
1.如何基於Quorum模型保證底層存儲的一致性
2.如何將redo日志相關的功能下推到存儲層
3.如何消除同步點,分布式存儲下如何做檢查點和故障恢復
>> 2. 可擴展高可用存儲
2.1復制和容錯處理
Aurora存儲層的復制基於Quorum協議,假設復制拓撲中有V個節點,每個節點有一個投票權,讀 或 寫 必須拿到Vr 或 Vw個投票才能返回。為了滿足一致性,需要滿足兩個條件,首先Vr + Vw > V,這個保證了每次讀都能讀到擁有最新數據的節點;第二,Vw > V/2,每次寫都要保證能獲取到上次寫的最新數據,避免寫沖突。比如V=3,那么為了滿足上述兩個條件,Vr=2,Vw=2。為了保證各種異常情況下的系統高可用,Aurora的數據庫實例部署在3個不同AZ(AvailablityZone),每個AZ包含了2個副本,總共6個副本,每個AZ相當於一個機房,是一個獨立的容錯單元,包含獨立的電源系統,網絡,軟件部署等。結合Quorum模型以及前面提到的兩條規則, V=6,Vw=4,Vr=3,Aurora可以容忍任何一個AZ出現故障,不會影響寫服務;任何一個AZ出現故障,以及另外一個AZ中的一個節點出現故障,不會影響讀服務且不會丟失數據。
2.2分片管理
通過Quorum協議,Aurora可以保證只要AZ級別的故障(火災,洪水,網絡故障)和節點故障(磁盤故障,掉電,機器損壞)不同時發生,就不會破壞協議本身,數據庫可用性和正確性就能得到保證。那么,如果想要數據庫“永久可用”,問題變成如何降低兩類故障同時發生的概率。由於特定故障發生的頻率(MTTF, Mean Time to Fail)是一定的,為了減少故障同時發生的概率,可以想辦法提高故障的修復時間(MTTR,Mean Time To Repair)。Aurora將存儲進行分片管理,每個分片10G,6個10G副本構成一個PGs(Protection Groups)。Aurora存儲由若干個PGs構成,這些PGs實際上是EC2(AmazonElastic Compute Cloud)服務器+本地SSD磁盤組成的存儲節點構成,目前Aurora最多支持64T的存儲空間。分片后,每個分片作為一個故障單位,在10Gbps網絡下,一個10G的分片可以在10s內恢復,因此當前僅當10s內同時出現大於2個的分片同時故障,才會影響數據庫服務的可用性,實際上這種情況基本不會出現。 通過分片管理,巧妙提高了數據庫服務的可用性。
2.3輕量級運維
基於分片管理,系統可以靈活應對故障和運維。比如,某個存儲節點的磁盤IO壓力比較大,可以人為將這個節點剔除,並快速新加一個節點到系統。另外,在進行軟件升級時,同樣可以臨時將存儲節點剔除,待升級完畢后再將節點加入到系統。所有這些故障和運維管理都是分片粒度滾動進行的,對於用戶完全透明。
>> 3. 存儲計算分離
3.1傳統數據庫寫放大問題
我們看看在傳統數據庫中寫的流程。以單機MySQL為例,執行寫操作會導致日志落盤,同時后台線程也會異步將臟頁刷盤,另外為了避免頁斷裂,進行刷臟頁的過程還需要將數據頁寫入double-write區域。如果考慮生產環境中的主備復制,如圖2所示,AZ1和AZ2分別部署一個MySQL實例做同步鏡像復制,底層存儲采用Elastic Block Store(EBS),並且每個EBS還有自己的一份鏡像,另外部署Simple Storage Service(S3)進行redo日志和binlog日志歸檔,以支持基於時間點的恢復。從流程上來看,每個步驟都需要傳遞5種類型的數據,包括redo,binlog,data-page,double-write和frm元數據。由於是基於鏡像的同步復制,這里我理解是Distributed Replicated Block Device(DRBD),因此圖中的1,3,5步驟是順序的,這種模型響應時間非常糟糕,因為要進行4次網絡IO,且其中3次是同步串行的。從存儲角度來看,數據在EBS上存了4份,需要4份都寫成功才能返回。 所以在這種架構下,無論是IO量還是串行化模型都會導致性能非常糟糕。
3.2日志處理下放到存儲層
傳統數據庫中,修改一個數據頁,會同步產生對應的redo日志,基於數據頁的前鏡像回放redo日志可以得到數據頁的后鏡像。事務提交時,需要事務對應的redo日志都寫盤成功后才能返回。在Aurora中,所有的寫類型只有一種,那就是redo日志,任何時候都不會寫數據頁。存儲節點接收redo日志,基於舊版本數據頁回放日志,可以得到新版本的數據頁。為了避免每次都從頭開始回放數據頁變更產生的redo日志,存儲節點會定期物化數據頁版本。如圖3所示, Aurora由跨AZ的一個主實例和多個副本實例組成,主實例與副本實例或者存儲節點間只傳遞redo日志和元信息。主實例並發向6個存儲節點和副本實例發送日志,當4/6的存儲節點應答后,則認為日志已經持久化,對於副本實例,則不依賴其應答時間點。 從sysbench測試(100G規模,只寫場景,壓測30分鍾)的數據來看,Aurora是基於鏡像MySQL吞吐能力的35倍,每個事務的日志量比基於鏡像MySQL日志量要少7.7倍。再來看看故障恢復速度,傳統數據庫宕機重啟后,恢復從最近的一個檢查點開始,讀取檢查點后的所有redo日志進行回放,確保已經提交的事務對應的數據頁得到更新。在Aurora中,redo日志相關的功能下推到存儲層,回放日志的工作可以一直在后台做。任何一次讀磁盤IO操作,如果數據頁不是最新版本,都會觸發存儲節點回放日志,得到新版本的數據頁。因此類似傳統數據庫的故障恢復操作實質在后台一直不斷地進行,而真正進行故障恢復時,需要做的事情很少,所以故障恢復的速度非常快。
3.3存儲服務設計關鍵點
Aurora存儲服務設計的一個關鍵原則是減少前台用戶寫的響應時間,因此將盡可能多的操作移到后台異步執行,並且存儲節點會根據前台的請求壓力,自適應分配資源做不同的工作。比如,當前台請求很繁忙時,存儲節點會減緩對舊版本數據頁的回收。傳統數據庫中,后台線程需要不斷地推進檢查點,避免故障恢復時間消耗的時間過長,但會影響前台用戶請求處理能力; 對於Aurora而言,分離的存儲服務層使得后台線程推進檢查點動作完全不影響數據庫實例,並且是推進地越快,越有利於前台的磁盤IO讀操作(減少了回放日志過程)。 Aurora寫基於Quorum模型,存儲分片后,按片達成多數派即可返回,由於分布足夠離散,少數的磁盤IO壓力大也不會影響到整體的寫性能。如圖4所示,圖中詳細介紹了主要的寫流程,1).存儲節點接收數據庫實例的日志,並追加到內存隊列;2).將日志在本地持久化成功后,給實例應答;3).按分片歸類日志,並確認丟失了哪些日志;4).與其它存儲節點交互,填充丟失的日志;5).回放日志生成新的數據頁;6).周期性地備份數據頁和日志到S3系統;7).周期性地回收過期的數據頁版本;8).周期性地對數據頁進行CRC校驗。上述所有寫相關的操作,只有第1)和第2)步是串行同步的,會直接影響前台請求的響應時間,其它操作都是異步的。
>> 4.一致性原理
這節主要介紹Aurora如何在不利用2PC協議的情況下,如何通過在讀副本,存儲節點間傳遞redo日志保證數據一致性。首先,我們會介紹如何做到在故障恢復時不需要回放redo日志;其次,我們會介紹常見的操作,比如讀,寫和事務提交操作,然后會介紹Aurora如何保證從數據庫副本實例讀取的數據處於一致的狀態;最后會詳細介紹故障恢復的流程。
4.1日志處理
目前市面上幾乎所有的數據庫都采用WAL(Write Ahead Logging)日志模型,任何數據頁的變更,都需要先寫修改數據頁對應的redo日志,Aurora基於MySQL改造當然也不例外。在實現中,每條redo日志擁有一個全局唯一的Log Sequence Number(LSN)。為了保證多節點數據的一致性,我們並沒有采用2PC協議,因為2PC對錯誤的容忍度太低,取而代之的是,我們基於Quorum協議來保證存儲節點的一致性。由於在生產環境中,各個節點可能會缺少部分日志,各個存儲節點利用gossip協議補全本地的redo日志。 在正常情況下,數據庫實例處於一致的狀態,進行磁盤IO讀時,只需要訪問redo日志全的存儲節點即可;但在故障恢復過程中,需要基於Quorum協議進行讀操作,重建數據庫運行時的一致狀態。 數據庫實例中活躍着很多事務,事務的開始順序與提交順序也不盡相同。當數據庫異常宕機重啟時,數據庫實例需要確定每個事務最終要提交還是回滾。這里介紹下Aurora中存儲服務層redo日志相關幾個關鍵的概念。Volumn Complete LSN(VCL),表示存儲服務擁有VCL之前的所有完整的日志。在故障恢復時,所有LSN大於VCL的日志都要被截斷。ConsistencyPoint LSNs(CPLs),對於MySQL(InnoDB)而言,如下圖所示, 每個事務在物理上由多個mini-transaction組成,而每個mini-transaction是最小原子操作單位,比如B樹分裂可能涉及到多個數據頁的修改,那么這些頁修改對應的對應一組日志就是原子的,重做日志時,也需要以mini-transaction為單位。 CPL表示一組日志中最后的一條日志的LSN,一個事務由多個CPL組成,所以稱之為CPLs。Volumn Durable LSN(VDL)表示已持久化的最大LSN,是所有CPLs中最大的LSN,VDL<=VCL,為了保證不破壞mini-transaction原子性,所有大於VDL的日志,都需要被截斷。比如,VCL是1007,LSN為900,1000,1100是CPLs,那么我們需要截斷1000以前的日志。 VDL表示了數據庫處於一致狀態的最新位點,在故障恢復時,數據庫實例以PG為單位確認VDL,截斷所有大於VDL的日志。
4.2基本操作
1).Writes
在Aurora中,數據庫實例向存儲節點傳遞redo日志,達成多數派后將事務標記為提交狀態,然后推進VDL,使數據庫進入一個新的一致狀態。 在任何時刻,數據庫中都會並發運行着成千上萬個事務,每個事務的每條redo日志都會分配一個唯一的LSN,這個LSN一定大於當前最新的VDL,為了避免前台事務並發執行太快,而存儲服務的VDL推進不及時,我們定義了LSN Allocation Limit(LAL),目前定義的是10,000,000,這個值表示新分配LSN與VDL的差值的最大閥值,設置這個值的目的是避免存儲服務成為瓶頸,進而影響后續的寫操作。由於底層存儲按segment分片,每個分片管理一部分頁面,當一個事務涉及的修改跨多個分片時,事務對應的日志被打散,每個分片只能看到這個事務的部分日志。 為了確保各個分片日志的完整性,每條日志都記錄前一條日志的鏈接,通過前向鏈接確保分片擁有了完整的日志。Segment Complete LSN(SCL)表示分片擁有完整日志的位點,存儲節點相互間通過gossip協議來彌補本地日志空洞,推進SCL 。
2).Commits
在Aurora中,事務提交是完全異步的。每個事務由若干個日志組成,並包含有一個唯一的“commit LSN”,工作線程處理事務提交請求時,將事務相關的日志提交到持久化隊列並將事務掛起,並繼續處理其它數據庫請求。 當VDL的位點大於事務的commit LSN時,表示這個事務redo日志都已經持久化,可以向客戶端回包,通知事務已經成功執行。在Aurora中,有一個獨立的線程處理事務成功執行的回包工作,因此,從整個提交流程來看,所有工作線程不會因為事務提交等待日志推進而堵塞 ,他們會繼續處理新的請求,通過這種異步提交方式,大大提高了系統的吞吐。這種異步化提交思想目前比較普遍,AliSQL也采用類似的方式。
3).Reads
在Aurora中,與大多數數據庫一樣,數據頁的請求一般都從緩沖池中獲得,當緩沖池中對應的數據頁不存在時,才會從磁盤中獲取。如果緩沖池滿了,根據特定的淘汰算法(比如LRU),系統會選擇將一個數據頁淘汰置換出去,如果被置換的數據頁被修改過,則首先需要將這個數據頁刷盤,確保下次訪問這個頁時,能讀到最新的數據。但是Aurora不一樣,淘汰出去的數據頁並不會刷盤寫出,而是直接丟棄。 這就要求Aurora緩沖池中的數據頁一定有最新數據,被淘汰的數據頁的page-LSN需要小於或等於VDL。(注意,這里論文中描述有問題,page-LSN<=VDL才能被淘汰,而不是大於等於) 這個約束保證了兩點:1.這個數據頁所有的修改都已經在日志中持久化,2.當緩存不命中時,通過數據頁和VDL總能得到最新的數據頁版本。
在正常情況下,進行讀操作時並不需要達成Quorum。當數據庫實例需要讀磁盤IO時,將當前最新的VDL作為一致性位點read-point,並選擇一個擁有所有VDL位點的日志的節點作為請求節點,這樣只需要訪問這一個節點即可得到數據頁的最新版本。 從實現上來看,因為所有數據頁通過分片管理,數據庫實例記錄了存儲節點管理的分片以及SCL信息,因此進行IO操作時,通過元信息可以知道具體哪個存儲節點有需要訪問的數據頁,並且SCL>read-point。數據庫實例接收客戶端的請求,以PG為單位計算Minimum Read Point LSN,在有讀副本實例的情況下,每個實例都都可以作類似的計算得到位點,實例之間通過gossip協議得到全局的per-Group MRPL,稱之為PGMRPL。PGMRPL是全局read-point的低水位,每個存儲節點根據PGMRPL,不斷推進數據頁版本,並回收不再使用的日志。
4).Replicas
在Aurora中,寫副本實例和至多15個讀副本實例共享一套分布式存儲服務,因此增加讀副本實例並不會消耗更多的磁盤IO寫資源和磁盤空間。這也是共享存儲的優勢,零存儲成本增加新的讀副本。讀副本和寫副本實例間通過日志同步。寫副本實例往存儲節點發送日志的同時向讀副本發送日志,讀副本按日志順序回放, 如果回放日志時,對應數據頁不在緩沖池中,則直接丟棄。可以丟棄的原因在於,存儲節點擁有所有日志,當下次需要訪問這個數據頁時,存儲節點根據read-point,可以構造出特定的數據頁版本 需要說明的是,寫副本實例向讀副本發送日志是異步的,寫副本執行提交操作並不受讀副本的影響。副本回放日志時需要遵守兩個基本原則,1).回放日志的LSN需要小於或等於VDL,2).回放日志時需要以MTR為單位,確保副本能看到一致性視圖。在實際場景下,讀副本與寫副本的延時不超過20ms。
4.3 故障恢復
大多數數據庫基於經典的ARIES協議處理故障恢復,通過WAL機制確保故障時已經提交的事務持久化,並回滾未提交的事務。這類系統通常會周期性地做檢查點,並將檢查點信息計入日志。故障時,數據頁中同時可能包含了提交和未提交的數據,因此,在故障恢復時,系統首先需要從上一個檢查點開始回放日志,將數據頁恢復到故障時的狀態,然后根據undo日志回滾未交事務。從故障恢復的過程來看, 故障恢復是一個比較耗時的操作,並且與檢查點操作頻率強相關。通過提高檢查點頻率,可以減少故障恢復時間,但是這直接會影響系統處理前台請求吞吐,所以需要在檢查點頻率和故障恢復時間做一個權衡,而在Aurora中不需要做這種權衡。
傳統數據庫中,故障恢復過程通過回放日志推進數據庫狀態,重做日志時整個數據庫處於離線狀態。Aurora也采用類似的方法,區別在於將回放日志邏輯下推到存儲節點,並且在數據庫在線提供服務時在后台常態運行。 因此,當出現故障重啟時,存儲服務能快速恢復,即使在10wTPS的壓力下,也能在10s以內恢復。數據庫實例宕機重啟后,需要故障恢復來獲得運行時的一致狀態,實例與Read Quorum個存儲節點通信,這樣確保能讀到最新的數據,並重新計算新的VDL,超過VDL部分的日志都可以被截斷丟棄。在Aurora中,對於新分配的LSN范圍做了限制,LSN與VDL差值的范圍不能超過10,000,000,這個主要是為了避免數據庫實例上堆積過多的未提交事務,因為數據庫回放完redo日志后還需要做undo recovery,將未提交的事務進行回滾。在Aurora中,收集完所有活躍事務后即可提供服務,整個undo recovery過程可以在數據庫online后再進行。
>> 5. 雲上Aurora體系
在社區InnoDB中,一個寫操作會修改緩沖池中數據頁內容,並將對應的redo日志按順序寫入WAL。事務提交時,WAL協議約定對應事務的日志需要持久化后才能返回。實際上,為了防止頁斷裂,緩沖池中修改的數據頁也會寫入double-write區域。數據頁的寫操作在后台進行,一般是在頁面置換或是做檢查點過程中發生。InnoDB除了IO子系統,還包括事務子系統,鎖管理系統,B+Tress實現以及MTR等。MTR約定了最小事務,MTR中的日志必需以原子的方式執行(比如B+Tree分裂或合並相關的數據頁)。
數據庫引擎基於社區版InnoDB引擎改進,將磁盤IO讀寫分離到存儲服務層。redo日志按照PG划分,每個MTR的最后一條日志是一致性位點。與社區的MySQL版本一樣,支持標准的隔離級別和快照讀。Aurora數副本實例不斷從寫副本實例獲取事務開始和提交信息,並利用該信息提供快照讀功能。 數據庫實例與存儲服務層相互獨立,存儲服務層向上為數據庫實例提供統一的數據視圖,數據庫實例從存儲服務層獲取數據與從本地讀取數據一樣。 下圖展示了雲上Aurora的部署架構,Aurora利用AmazonRelational Database Service (RDS)來管理元數據。RDS在每個實例部署一個agent,稱之為Host Manager(HM)。HM監控集群的健康狀況並確定是否需要做異常切換,或者是一個實例是否需要重建。每個集群由一個寫副本,0個或多個讀副本組成。所有實例在都一個物理Region(比如美國東部,美國西部),一般是跨AZ部署,並且分布式存儲服務層也在同一個Region。為了保證安全,我們在數據庫層,應用層和存儲層做了隔離。實際上,數據庫實例通過3類Amazon Virtual Private Cloud (VPC)網絡可以相互通信。通過應用層VPC,應用程序可以訪問數據庫;通過RDS VPC,數據庫可以和管控節點交互;通過存儲層VPC,數據庫可以和存儲服務節點交互。
存儲服務實際上是由一組EC2集群構成,這個集群橫跨至少3個AZ,對多個用戶提供存儲,讀寫IO,備份恢復等服務。存儲節點管理本地SSD並與數據庫實例和其它存儲節點交互,備份/還原服務不斷備份新數據到S3,在必要時從S3還原數據。存儲服務的管控系統借助Amazon DynamoDB服務作為持久化存儲,存儲內容包括配置,元數據信息,備份到S3數據的信息等。為了保證存儲服務高可用,整個系統需要在異常影響到用戶之前,主動快速發現問題。系統中的所有關鍵操作都被監控,一旦性能或者可用性方面出現問題,則立即會產生報警。
>> 6. 性能數據
性能數據我這里不一一展開了,具體數據大家可以參考原論文。
>> 7. 實踐經驗
我們發現越來越多的應用遷移到Aurora集群,他們有一些共通點,我們希望抽象出一些典型的場景,並總結經驗。
7.1多租戶
Aurora很多用戶都在做Software-as-a-Service(SaaS)服務,這些服務底層存儲模型一般比較穩定,通過多個用戶共享一個數據庫實例來減少成本。這種模式下,數據庫實例上會有大量的表,導致元數據暴增,這加大了字典管理的負擔。這種架構下,用戶一般會面臨解決三類問題:1).維持實例上較高的吞吐和並發,2).能夠靈活應對磁盤空間問題,提前評估磁盤空間並具備快速的擴展能力,3)不同租戶間的影響要控制在最小。Aurora能完美解決這三類問題。
7.2高並發處理能力
互聯網應用通常會因為各種原因導致壓力驟增,這需要系統有良好的擴展能力和處理高並發的能力。在Aurora中,由於底層的存儲服務和上層的計算節點可以方便地自動擴容,因此Aurora具備快速擴展能力,並且實際上Aurora有很多用戶連接數長期維持在8000以上。
7.3表結構升級
由於表結構升級往往伴隨着鎖表和拷表,持續時間也比較長,而DDL是一個日常操作,因此需要有一套高效的online DDL機制。主要包括2點,1).schema多版本,每個數據頁都存儲當時的schema信息,頁內數據可以通過schema信息解析,2).對於修改的page采用modify-on-write機制來減少影響。
7.4軟件升級
由於用戶使用Aurora實例通常只有一個主實例,因此發生任何問題都特別嚴重。Aurora中,所有的持久化數據都在存儲層,數據庫實例的狀態信息可以借助存儲層和元數據獲得,因此可以很方便的構造一個新的數據庫實例,為了提高軟件升級效率,我們通過Zero-Downtime Patch (ZDP)來滾動升級
>> 8. 總結
Aurora誕生的原因是在彈性伸縮的雲環境下,傳統的高吞吐OLTP數據庫既不能保證可用性,又不能保證持久性。 Aurora的關鍵點在於將傳統數據庫中的存儲與計算分離,具體而言,將日志部分下推到一個獨立的分布式存儲服務層。由於這種分離架構下,所有IO操作都是通過網絡,網絡將成為最大的瓶頸,因此Aurora集中精力優化網絡以便提高系統吞吐能力。Aurora依靠Quorum模型,在性能影響可控的前提下,解決雲環境下的各種異常錯誤。在Aurora中,日志處理技術減少了I/O寫放大,異步提交協議避免了同步等待,同時分離的存儲服務層還避免了離線故障恢復和檢查點操作。 Aurora的存儲計算分離方案使得系統整體架構非常簡單,而且方便未來的演進。
Q&A
1.一般了解到的Quorum算法只需要滿足Vr + Vw > N即可,為啥Aurora還需要滿足第2個條件?
從文中了解到Aurora中Quorum算法需要滿足兩個條件:
a).Vr + Vw > N,NWR算法,確保讀和寫有交集,能讀到最新寫入的數據。
b).Vw > N/2,避免更新沖突。
Quorum算法的基本含義是確保讀副本數與寫副本數有交集,能讀到最新寫入的數據。Aurora加入第二條約束主要是為了保證每次寫入集合都與上次寫入的節點集合有交集,確保能讀到最近一次的更新,這樣日志能夠以自增的方式追加,確保不會丟失更新。從另外一個角度來說,寫副本數設置為Vw > N/2也間接在讀寫性能做了均衡。假設N=5,W=1,R=5,滿足第一個條件,每次寫入一個節點即可返回成功,那么讀取時則需要讀取5個副本,才能拿到最新的數據。
2.每個segment分片是10G,如果事務跨多個segment分片如何處理?
每個事務實際是有若干個MTR(mini-transaction)構成,MTR是InnoDB中修改物理塊的最小原子操作單位,MTR的redo日志作為一個整體寫入到全局redo日志區。在Aurora中存儲按照segment分片管理,發送日志時,也按分片歸類后發送,那么就存在一種情況,一個MTR跨多個segement分片,MTR日志被打散的情況。本質上來說,這種情況也不存在問題,因為 事務提交時,如果事務跨多個segment分片,則會需要多個PG都滿足Quorum協議才返回,進而推進VDL。所以如果VDL超過了事務的commit-LSN,則表示事務涉及到的日志已經全部持久化,不會存在部分segment日志丟失的問題,所以能夠保證事務持久性。
3.Aurora讀副本如何實現MVCC?
在Aurora中,寫副本實例往存儲節點發送日志的同時會傳遞日志到讀副本實例,讀副本以MTR為單位回放日志;與此同時,寫副本還會將事務開始和提交的信息傳遞給讀副本,這樣在讀副本實例上也能構造出活躍的事務視圖。在讀副本上執行讀操作時,會依據活躍事務視圖作為記錄可見習判斷依據,進而能讀到合適版本的數據。當然,Aurora讀副本與寫副本之間是異步復制,至多有20ms的延遲,因此在Aurora讀副本上可能不能讀到最新的提交數據。
4.為什么Aurora有成本優勢?
Aurora中,多個數據庫實例(寫副本+多個讀副本)共享一個分布式存儲層。對於數據庫引擎而言,整個存儲服務一個大的資源池,用戶根據需求申請存儲空間,最小粒度是10G,相對於單個實例的本地存儲,存儲空間利用率大大提升,而且非常方便擴展。另一方面,所有數據庫引擎公用一份存儲,零存儲成本增加數據庫引擎,能大幅降低成本。
5.Aurora的優勢和缺陷?
優勢:
1). 存儲節點,計算節點彈性伸縮,按需配比
2). 一份存儲,對接多個計算節點,多租戶存儲服務,成本低。
3). 只傳遞日志,巧妙的解決寫放大問題。
4). 實例快速故障恢復
5). 架構簡單,通過多副本能快速擴展讀能力,單個寫副本則巧妙地避免了分布式事務等復雜實現。
缺陷:
1). 適合於讀多寫少的應用,寫水平擴展依賴於中間件方案。
2). SQL層與社區版MySQL一樣,復雜查詢能力(比如OLAP場景)較弱。
3). 單個寫副本,無分區多點寫能力(用戶維度+時間維度)
4). 總容量有上限,64TB
6.Aurora與Spanner的異同點?
從對比來看,Aurora與Spanner走的兩條不同的路線,Aurora以市場用戶為導向,所以選擇全面兼容MySQL/PostgreSQL,用戶可以無縫遷移到Aurora。另外就是,Aurora基於MySQL修改,並通過共享存儲方案避免了二階段提交,分布式事務等復雜的實現,因此開發周期相對較短,也更容易出成果。反觀Spanner,是一個重新設計的數據庫,無論是基於Paxos的強同步還是分布式事務的支持,以及利用TrueTime機制實現全局一致性讀等都是比較復雜的實現,功能非常強大,但是在SQL兼容性這塊確做地不夠好,這也可以解釋為什么Aurora廣泛用於雲上業務,而Spanner則更多地是在Google內部使用,相信即使Spanner現在開放了雲版本,其SQL兼容性也是一個很大的挑戰。當然Aurora本身的數據庫引擎就是MySQL,其對於復雜查詢的短板還需要持續改進和優化。
備注:本文在微信公眾號已經同步發布,感興趣的同學可以關注我們團隊的公眾號。