本文由 網易雲 發布。
作者:郭憶
本篇文章僅限內部分享,如需轉載,請聯系網易獲取授權。
在2017年5月芝加哥舉辦的世界頂級數據庫會議SIGMOD/PODS上,作為全球最大的公有雲服務提供商,Amazon首次系統的總結了新一代雲端關系數據庫Aurora的設計實現。Aurora是Amazon在2014 AWS re:Invent大會上推出的一款全新關系數據庫,提供商業級的服務可用性和數據可靠性,相比MySQL有5倍的性能提升,並基於RDS 提供自動化運維和管理;
經過2年時間發展,Aurora已經成長為AWS 客戶增長最快的雲服務之一,包括全球知名的在線游戲網站Expedia、社交游戲公司
Zynga都在使用Aurora。Aurora的推出一時引起了國內數據庫研究人員的熱烈討論,大家關注的一個焦點就是Aurora是否是基於MySQL推出的一個新的存儲引擎?下面我們就根據會議發布的論文,一起走進Aurora。
為什么要有Aurora?
在理解Aurora設計的初衷之前,我們首先來了解一下AWS RDS MySQL的高可用部署架構設計。與我們之前的猜測是一致的, AWS RDS是基於EC2、EBS這樣的雲基礎設施構建的,數據庫實例部署在EC2內,數據盤由一組通過鏡像實現的兩副本EBS提供。
為了實現跨數據中心的高可用,Primary和Replica分別部署在兩個可用域內,數據同步采用類似DRBD的方式在操作系統內核通過塊設備級別的同步復制實現,所以AWS RDS的Replica平時是不能被讀取的,只能用於跨可用域的故障恢復。Replica與Primary是完全對稱的,通過內核復制到replica的數據同樣存放在一組鏡像實現的兩副本EBS中。從圖中可以看到,這樣的一個部署架構,數據庫發起的一次寫IO需要同步復制5次,其中3次還是串行的,網絡延遲對數據庫的性能影響非常嚴重。
MySQL的InnoDB存儲引擎遵從WAL協議,所有對數據頁的更新都必須首先記錄事務日志。此外,MySQL在事務提交時,還會生 成binlog;為了保證被修改的數據頁在刷新到硬盤的過程中保證原子性,Innodb設計了double-write的機制,每個數據頁會在硬盤上寫兩遍。此外,MySQL還有元數據文件(frm)。在AWS RDS的高可用架構中,所有的這些日志文件、數據文件都要經過網絡的傳輸5次,對網絡帶寬也是巨大的考驗。
這樣的一個架構由於不涉及具體數據庫內核的改動,滿足了AWS發展初期可以快速支持多種類型的關系數據庫的需求,但是顯然隨着規模的增長,這樣的架構的缺陷也越來越明顯。當我們還在考慮如何優化我們的網絡性能和IO路徑時,AWS的注意力已經轉移到如何來減少數據在網絡上的傳輸,這就有了后來Aurora的架構。
Aurora的系統架構
Aurora與傳統關系數據庫相比,最大的一個架構上的創新就是將數據和日志的管理交由底層的存儲系統來完成,數據庫實例只負責向存儲系統中寫入redo log。由於底層存儲節點掛載的是本地硬盤,日志的持久化和數據頁的更新並不需要跨網絡完成,所以只有redo log需要通過網絡傳輸。由於MySQL的redo log中包含了對某個數據頁的某行記錄的更新,通過redo log以及先前的數據頁可以構造出更新后的完整頁面,所以Aurora選擇通過redo log建立起數據庫實例和底層存儲系統之間的關系。
在Aurora中,數據庫實例負責處理SQL查詢,事務管理,緩沖池管理,鎖管理,權限管理,undo管理,對用戶而言,Aurora與MySQL 5.6完全兼容。底層的存儲系統負責redo log持久化,數據頁的更新和垃圾日志記錄的回收,同時底層存儲系統會對數據進行定期備份,上傳到S3中。底層存儲系統的元數據存儲在Amazon DynamoDB中,基於Amazon SWF提供的工作流實現對Aurora 的自動化管理。
存儲系統的設計
Amazon為Aurora實現了一個高可用、高可靠、可擴展、多租戶共享的存儲系統。
多副本
為了實現數據的可靠性,Aurora在多個可用域內部署了多個數據副本,基於Quorum原則確保多個副本數據的最終一致性。
Quorum原則要求V個數據副本,一次讀操作必須要讀取Vr個數據副本,一次寫操作必須要同時寫入Vw個數據副本,Vw和Vr需要滿足:Vw + Vr > V,且 Vw > V/2。Quorum原則可以確保一份數據不能被同時讀寫,同時也確保了兩個寫操作必須串行化,后一個寫操作可以基於前一個的結果進行更新。
一般最小的Quorum要求最少3個數據副本,Vr = 2 ,Vw =2,在雲環境中,就是3個可用域,每個可用域一個數據副本,一個可用域不可用,不影響數據的讀寫。但是在真實的場景中,一個可用域不可用的同時,另外一個可用域很有可能也出現故障,為了解決上述問題,Aurora采用了6副本數據,每個可用域2個數據副本,一次寫操作需要4個數據副本,一次讀操作需要3個數據副本。這 樣的設計可以實現:
1. 在一個可用域內兩個數據副本同時失效,同時另外一個可用域內的一個數據副本失效,不影響整個系統的讀;
2. 任意兩個數據副本同時失效,不影響系統的寫;
分段存儲系統設計
任何一個高可用系統設計的前提假設都是在一段時間內,連續兩次發生故障的概率足夠的低。對於Aurora基於Quorum的多副本設計而言,如果一個AZ的副本失效,在修復過程中,同時再有一個副本失效,則整個系統將不可寫;如果在AZ+1的副本失效的同時,又有一個副本再失效,則系統將不可讀。我們沒有辦法去阻止連續故障的發生,但是我們可以通過縮短前一次故障的修復時間,從而降低連續兩次故障出現的概率,這就是分段存儲設計的思想來源。
Aurora將一個數據庫實例的數據卷划分為10G固定大小的存儲單元,這樣可以確保每個單元數據可以快速的恢復。每個存儲單元有6個副本,每個可用域內2個副本,6個副本組成了一個PG(Protection Groups)。物理上,由一組掛載本地SSD的EC2雲主機充當存儲節點,每個存儲節點上分布了很多存儲單元。一組PG構成了一個Aurora實例的數據卷,通過分配更多的PG,可以線性擴展數據卷的容量,最大支持64TB。
Segment是存儲系統故障恢復的最小單元,之所以選擇10G大小,如果太小,可能造成元數據過於龐大,如果太大,又可能造成單個Segment的修復時間過長,經過Aurora測試,10G大小的Segment數據恢復時間在10Gbps的網絡傳輸速度下,只需要10秒時間,這樣就確保了存儲系統可以在較短的時間內完成故障修復。Segment的元數據由一個DynamoDB來負責存儲。
基於Segment和Quorum的設計,Aurora可以通過人工標記一些Segment下線,來完成數據遷移,對於熱點均衡、存儲節點操作系統升級更新都非常有幫助。
以日志核心的數據庫
事務日志的寫入
在MySQL數據庫InnoDB存儲引擎中,所有數據記錄都存儲在16K大小的數據頁中,所有對行記錄的修改操作,都首先必須對數據頁進行加鎖,然后在內存中完成對數據頁行記錄修改操作,同時生成redo log和undo log,在事務提交時,確保修改操作對應的redo log持久化到硬盤中,最終被更新的數據頁通過異步方式刷新到硬盤中。redo log確保了數據頁更新的持久化,每個redo logrecord都有一個唯一標識,LSN(log sequence number),標識該記錄在redo log文件中的相對位置。為了確保一個更新操作對多個數據頁,或者一個數據頁內部多條記錄的修改原子性,一個事務會被切分成多個Mini-transaction(MTR),MTR是MySQL內部最小執行單元,在Aurora中,MTR的最后一個redo log record對應的LSN,稱為CPL(Consistency Point LSN),是redo log中一致點。
在每個MTR提交時,會將MTR生成的redo log 刷新到公共的log buffer中,在MySQL內部,一般log buffer空間滿,或者wait 超時,再或者事務提交時,log buffer中的redo log會被刷新到硬盤中。在Aurora中,每個PG都保存了一部分數據頁,每個redo logrecord在被刷新到硬盤之前,會按照redo log record更新的數據頁所在的PG,划分成多個batch,然后將batch發送到PG涉及的6 個存儲節點,只有等到6個節點中的4個的ACK,這個batch內的redo log record才算寫入成功。最新寫入成功的MTR的最后一個記錄對應的LSN,我們成為VDL( Volume Durable LSN ),這個點之前的MTR對數據頁的修改,都相當於已經持久化到存儲系統中。
存儲節點對事務日志的處理
每個存儲節點在接收到redo log record batch之后,首先會將其加入到一個內存隊列中,然后將redo log record持久化到硬盤后,返回ACK 給寫入實例(Primary)。接下來,由於每個存儲節點可能保存的batch不完整(由於Quorum 4/6機制),所以需要通過與同一個PG下的其他存儲節點進行詢問,索要缺失的batch。

Aurora中存儲節點對數據的管理采用了log-structured storage方式,每個PG的redo log record首先按照page進行歸類,同一個page的redo log record在寫入時,直接append在該頁面之后,頁面中的已有記錄會有一個連接指針,指向最新的記錄版本。
除此之外,每個PG內的每個segment上的redo log record都包含一個指針,指向他的前一個log record,通過這個指針,我們很容易判斷每個Segment上的log record完整性,如果缺失,則可已通過與其他的存儲節點進行詢問,補齊缺失redo log record。
數據頁的合並和舊版本記錄的回收
類似HBase、Cassandra采用LSM Tree的NoSQL系統,Aurora也需要有一個垃圾回收和數據頁合並的過程。在MySQL中,臟頁的刷新是通過Check point的機制來完成的,redo log的空間是有限的,必須要將redo log涉及的數據頁持久化到硬盤中,redo log 空間才能釋放,新的redo log 才能寫入,所以MySQL的臟頁刷新與客戶端的事務提交是密切相關的,如果臟頁刷新過慢,可能導致系統必須等待臟頁刷新,事務無法提交。另外,Check point機制也決定了臟頁是否刷新是根據整個redo log大小來決定的,即使一個頁面只是偶爾一次更新,整個數據頁在check point推進過程中,都必須重新寫入,同時為了確保一個數據頁的完整性, MySQL還有double write機制,頁面被寫兩次,代價非常昂貴,顯然是不合理的。
Aurora的設計更加巧妙,因為數據是有熱點的,不同的數據頁的更新頻率是不一樣的,根據每個Page待更新的redo log record數量,來決定page是否進行合並。
縱觀Aurora的設計,一個核心的設計原則就是將數據頁看成是日志的一個緩存,通過犧牲一定的讀,換取了很好的寫性能,這是所有基於log-structured system 共性。
對數據庫的操作
寫操作
在Aurora中,同時會存在很多寫事務,這些事務會產生大量的redo log record,因為所有的事務在提交時,都必須確保該事務產生的redo log已經寫入到底層至少4個存儲節點中,考慮到網絡和存儲節點的IO性能,Aurora中會對寫事務進行限制,如果當前分配的LSN大於VDL加上LAL(LSN Allocation limit),則不再分配新的LSN。
提交事務
在MySQL中,雖然在事務執行過程中,各個事務是並發執行的,但是在提交時,都是串行的,雖然MySQL 5.6推出了Group Commit,可以批量提交,但是在前一個group提交過程中,其他線程也不得不sleep等待喚醒,這樣無疑造成了資源浪費。
在Aurora中,事務的提交完全是異步的,每個事務執行完成以后,提交的過程只是將該事務加入到一個內部維護的列表中,然后該線程就被釋放了。當VDL大於該列表中等待提交事務commit對應的lsn時,則由一個線程,向各個客戶端發送事務提交確認。
讀操作
在MySQL中,所有的讀請求都是首先讀buffer cache的,只有當buffer cache未命中的情況下,才會讀取硬盤。Buffer cache的空間是有限的,在MySQL中,通過LRU的機制,會將一些長時間沒有被訪問的數據頁占用的buffer空間釋放。如果這些頁面中包含臟頁,則必須要等到臟頁刷新到硬盤以后才能釋放。這樣就確保了下次讀取該數據,一定能夠讀取到最新的版本。
在Aurora中,並不存在臟頁刷新的過程,所有數據頁的合並都是由底層存儲節點來完成的。所以與MySQL實例臟頁刷新向上看不同,Aurora需要向下看,通過將Page LSN大於VDL的數據頁釋放,可以確保,所有Buffer中Page涉及的更新都已經持久化到硬盤中,同時在cache未命中的情況下,可以讀取到截止到當前VDL的最新版本的數據頁。
所以在Aurora中,Buffer Cache更像是一個純粹的Cache。
在Aurora日常讀取中,並不需要達到3/6的Quorum,因為有VDL的存在,我們可以根據讀請求發起時的VDL建立一個readpoint,找到包含小於VDL的所有完整log record的存儲節點,直接進行讀取。通過同一個PG內部的Segment之間的相互詢問,可以建立一個PG的最小的read point,該read point以下的log record實際上才可以被回收合並。
只讀節點
在Aurora中,最多可以為一個writer實例創建15個只讀實例,這15個只讀實例掛載的是相同的存儲卷,只讀實例不會額外增加存儲的開銷。為了減少延遲,Writer實例會將寫入到存儲系統的redo log日志同樣發送給只讀實例,只讀實例接收到redo log日志后,如果要更新的數據頁命中了buffer cache,直接在buffer cache中進行更新,但是需要注意的是,如果是同一個mini-transaction的redo log record,必須確保mini-transaction的原子性。如果buffer cache沒有命中,則該記錄被丟棄。另外,如果被執行的log record的lsn大於當前的VDL,也不會被執行,直接丟棄。
這樣的設計確保Aurora只讀實例相較於Writer實例延遲不超過20ms。
本文未結束,敬請期待下篇。
網易有數:企業級大數據可視化分析平台。面向業務人員的自助式敏捷分析平台,采用PPT模式的報告制作,更加易學易用,具備強大的探索分析功能,真正幫助用戶洞察數據發現價值。可點擊這里免費試用。
了解 網易雲 :
網易雲官網:https://www.163yun.com/
新用戶大禮包:https://www.163yun.com/gift
網易雲社區:https://sq.163yun.com/