天天看點

Amazon新一代雲端關系資料庫Aurora(上)為什麼要有Aurora?存儲系統的設計對資料庫的操作

本文由 網易雲 釋出

作者:郭憶

本篇文章僅限内部分享,如需轉載,請聯系網易擷取授權。

在2017年5月芝加哥舉辦的世界頂級資料庫會議SIGMOD/PODS上,作為全球最大的公有雲服務提供商,Amazon首次系統的總結了新一代雲端關系資料庫Aurora的設計實作。Aurora是Amazon在2014 AWS re:Invent大會上推出的一款全新關系資料庫,提供商業級的服務可用性和資料可靠性,相比MySQL有5倍的性能提升,并基于RDS 提供自動化運維和管理;

Amazon新一代雲端關系資料庫Aurora(上)為什麼要有Aurora?存儲系統的設計對資料庫的操作

經過2年時間發展,Aurora已經成長為AWS 客戶增長最快的雲服務之一,包括全球知名的線上遊戲網站Expedia、社交遊戲公司

Zynga都在使用Aurora。Aurora的推出一時引起了國内資料庫研究人員的熱烈讨論,大家關注的一個焦點就是Aurora是否是基于MySQL推出的一個新的存儲引擎?下面我們就根據會議釋出的論文,一起走進Aurora。

為什麼要有Aurora?

 在了解Aurora設計的初衷之前,我們首先來了解一下AWS RDS MySQL的高可用部署架構設計。與我們之前的猜測是一緻的, AWS RDS是基于EC2、EBS這樣的雲基礎設施建構的,資料庫執行個體部署在EC2内,資料盤由一組通過鏡像實作的兩副本EBS提供。

Amazon新一代雲端關系資料庫Aurora(上)為什麼要有Aurora?存儲系統的設計對資料庫的操作

為了實作跨資料中心的高可用,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?存儲系統的設計對資料庫的操作

存儲系統的設計

Amazon為Aurora實作了一個高可用、高可靠、可擴充、多租戶共享的存儲系統。

多副本

為了實作資料的可靠性,Aurora在多個可用域内部署了多個資料副本,基于Quorum原則確定多個副本資料的最終一緻性。

Quorum原則要求V個資料副本,一次讀操作必須要讀取Vr個資料副本,一次寫操作必須要同時寫入Vw個資料副本,Vw和Vr需要滿足:Vw + Vr > V,且 Vw > V/2。Quorum原則可以確定一份資料不能被同時讀寫,同時也確定了兩個寫操作必須串行化,後一個寫操作可以基于前一個的結果進行更新。

Amazon新一代雲端關系資料庫Aurora(上)為什麼要有Aurora?存儲系統的設計對資料庫的操作

一般最小的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。

Amazon新一代雲端關系資料庫Aurora(上)為什麼要有Aurora?存儲系統的設計對資料庫的操作

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。

Amazon新一代雲端關系資料庫Aurora(上)為什麼要有Aurora?存儲系統的設計對資料庫的操作

Aurora中存儲節點對資料的管理采用了log-structured storage方式,每個PG的redo log record首先按照page進行歸類,同一個page的redo log record在寫入時,直接append在該頁面之後,頁面中的已有記錄會有一個連接配接指針,指向最新的記錄版本。

Amazon新一代雲端關系資料庫Aurora(上)為什麼要有Aurora?存儲系統的設計對資料庫的操作

除此之外,每個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/