郭憶:網易資料庫高可用架構最新進展!

humengyi發表於2018-09-03

【IT168 專稿】本文根據郭憶老師在2018年5月12日【第九屆中國資料庫技術大會(DTCC)】現場演講內容整理而成。

講師簡介:

郭憶——七年雲端資料庫開發經驗,主導了網易私有云關聯式資料庫服務的建設,支撐了網易雲音樂、考拉海購、網易新聞等大型網際網路應用,專注於雲端資料庫的高可用架構和效能優化。

摘要:

過去一年中,資料庫的高可用技術出現了很多令人欣喜的進展,AWS 公佈了Aurora的實現細節,第一次讓我們看到了Cloud-Native資料庫的高可用是如何實現的,更令人興奮的是2017年末的AWS re: Invent大會上,Aurora支援mutil-master,解決了寫擴充套件的問題;與Aurora share storage不同的是,MySQL Group Replication作為一個share nothing架構的高可用解決方案,在MySQL 官方的主導下也日趨完善。本次分享將為大家介紹這些新技術的實現細節,以及網易在這些新技術的方案選型方面的考量。

分享大綱:

1、資料庫高可用發展歷程

2、Aurora高可用架構設計

3、MGR高可用架構設計

4、網易多副本資料一致高可用架構設計

正文:

1、資料庫高可用發展歷程

首先我們先來簡單回顧一下資料庫高可用的發展歷程,最原始的資料庫高可用的做法是基於replication快速搭建主從複製架構。因為replication是MySQL官方原生支援的,所以搭建起來非常快速和容易,但MySQL原生是一個非同步複製,非同步複製在一些核心的業務場景下存在資料丟失的問題,儘管MySQL 5.5釋出了Semi Sync Replication,但因為它實現機制的缺陷,它是在事務提交以後才傳送給從機,再返回客戶端的流程,所以還是存在資料丟失的風險,MySQL引入了group commit之後,它丟的是最後一個group的事務。

 

undefined

 

直到MySQL官方5.7版本推出無損複製lossless replication,這時的同步複製是在事務提交之前就把資料傳送給從機,能夠確保資料的完全一致,但是這種同步複製在寫密集型的場景下依舊存在問題,主要表現在從庫沒辦法跟上主庫進行復制,導致主庫長期處於非同步複製狀態,從而導致切換的時候丟失資料。

另外同步複製還依賴於複製的延遲,我們知道MySQL是基於Binlog在做複製, Binlog是在事務提交之後才產生的,也就是說從庫天生就慢於主庫,這樣就導致必須把從庫的Relay log回放完才能進行切換。所以複製延遲就很大程度上決定了切換時間,這也是基於Binlog複製進行資料庫高可用的一個缺陷。

undefined

 

第二條思路是基於日誌的資料庫高可用架構,業界比較成熟的兩個產品一個是MHA,它在一些網際網路公司有比較廣泛的使用。另外一個是通過Binlog雙寫的機制,把Binlog寫在共享儲存或者是其它的高可用裝置上,來確保資料的可靠性。它的好處就是在限定場景下能夠確保資料的一致性,比如MHA實現的基本原理是主庫掛掉後,它通過SSH到主庫的伺服器上拿取主庫的Binlog,然後把這部分Binlog補全到從庫上面去,但實現前提是它能夠通過SSH登陸到原先的主機所在的伺服器上,假如說這個伺服器宕掉了、SSH登不上去了或者是主機所在伺服器網路卡掛掉了、網路登不上去了,這樣都會導致丟資料情況的發生。

日誌雙寫的思路跟MySQL同步複製是有點相似的,它的缺點同樣是存在非同步狀態下丟資料的問題,如果寫密集壓力比較大的情況下,就會存在長期非同步狀態,從而導致丟失資料。

undefined

 

第三個資料庫高可用的實踐方向是基於塊裝置映象的資料庫高可用實現方式,其中兩個業界典型的方案,一個是Amazon RDS技術方案的實現,它是基於EBS硬碟的資料庫高可用來實現RDS資料庫高可用。另外一個是開源方案DRBD基於檔案系統層和裝置管理層之間的基於塊裝置映象的方式來實現資料庫高可用,它的優勢是在於對資料庫方案來說是透明的,換句話說我可以跑資料庫,我也可以跑任何的應用,因為我是基於塊裝置層來做高可用,所以它對資料庫是透明的,它是一個通用的高可用解決方案。

它也有缺點,使用過DRBD的同學應該都瞭解,它的效能其實非常差,至少在一些核心應用場景下是根本沒有辦法使用的,它跨網路的流量比較大,因為所有的IO都要跨網路,這樣本身的網路卡對於頻寬要求就會非常高,其次本身跨網路的IO代價也非常高。

undefined


第四個方向是MGR(MySQL Group Replication),其實它是多副本的高可用的架構,這裡有兩個標誌性的產品,一個是Galera,它是MySQL在MGR之前的一個技術方案,兩者總的技術方向都是Shared-nothing多副本的高可用資料庫架構,Galera的話,首先說優點,它是一個shared-nothing的架構,原來是兩副本,現在有多副本及金融級的資料可靠,另外可能還有跨機房的部署支援。

第二個是MGR,新版本的MGR支援多寫,可以解決寫擴充套件性問題。原來一談到寫擴充套件性問題最先想到的一般都是分庫分表的方案, MGR從另外一個層面提供瞭解決寫擴充套件的技術方向。接下里談缺點,缺點是它本身是基於Binlog進行的資料同步,那就會存在資料複製延遲的問題,第二個是多寫模式下所有的事務提交都需要進行衝突檢測,即使沒有衝突事務也要進行衝突檢測,在MGR的場景下其實效能是有一定折損的。

接下來講講Galera和MGR之間的一些區別,Galera也是多副本,但是它們的同步複製協議不一樣,Galera是基於單令牌環的同步複製演算法, MGR是基於改進的Paxos協議實現的資料同步複製演算法,相比下來MGR的效能是遠勝於Galera。

 

undefined

 

第五個資料庫高可用方向是Cloud-Native Date base,這裡也有兩個標誌性產品,在2014年12月份Amazon就已經發布了Aurora產品,去年阿里也釋出了PolarDB產品,它們優點都是Shared disk cluster基於共享磁碟的架構,另外它們都做到了計算儲存分離,解決了擴充套件性問題。另外從它們的方案上來看都是具有通用性,也就是說換一個資料庫可以很快複製出一個基於相同架構的PG資料庫,另外它們都標稱自己的效能比原生的MySQL可能有幾倍甚至幾十倍的效能提升。但它們也有缺點,一個是技術門檻高,因為對MySQL進行了大幅的改動,Aurora沒有使用InnoDB,它完全是自研的基於LSM Tree的方式去做的,另一個是強依賴於底層基礎設施,底層都是最新的裝置,比如RDMA網路層的加速裝置來幫助它獲得一些更好的效能。

2、Aurora高可用架構設計

其實我自己很喜歡Aurora高可用設計,之前的AWS RDS其實也是AWS的三大服務之一,除了雲主機物件儲存,第三個賣的最賺錢的就是RDS,之前的RDS存在什麼樣的問題呢?使用過AWS RDS的同學應該有印象就是它的效能比較差,一般認為基於雲的資料庫它一定是做不過物理級的效能的。

 

undefined

 

但Aurora給了一個相反的答案,我們首先要看看它是怎麼做到的,第一個就是上圖中原生的AWS RDS所有需要跨網路資料傳輸的資料有哪些?首先有redo、Binlog,還有Page、Double Write和FRM檔案,其中還有三次的傳輸是序列的,也就是說它是具有先後次序執行的,這樣的效能其實很難滿足資料庫線上業務的應用場景。


 

undefined

 

Aurora設計的基本思想是資料傳輸,之前需要傳輸前面的5個資料,尤其是Page,現在只傳輸redo,而且上層的instance和下層的Storage之間只通過redo進行資料更新的傳輸,另外它底層是用統一的跨可用區、多副本高可用的共享儲存系統,資料庫例項和儲存系統只通過redo進行資料的同步,Cache之間通過redo來同步減少資料的延遲。

Recovery非同步執行可以做到秒級的故障恢復,原來MySQL是需要有一個check point的,在故障恢復的時候,它把故障恢復之前的已經提交的事務但沒有更新的髒頁全部執行完,才叫Recovery結束,所以它會有一個Recovery時間。在Aurora中沒有這個Recovery過程,它的Recovery很簡單,後面我會具體介紹。


undefined

 

它的Storage設計也相對來說非常有特色,它底層的資料庫例項的儲存都是由10G大小的Segment來組成的,每個Segment有6個副本分佈在3個可用域內,儲存節點是掛載了本地SSD的EC2,這點是需要特別注意的,剛才提到的server instance層和Storage層只通過redo進行日誌的傳輸, Storage層其實就是一個掛載了本地盤的EC2例項,所以它用的全都是本地盤,除了redo是跨網路的,Page的更新全都是本地的,這樣它的效能獲得了很大的一個提升。另外它的單個資料庫最大的支援64TB,Segment是儲存數系統資料修復的最小單位,因為它只有10G,所以它可以快速的併發的進行修復。通過標記Segment不可用可以完成計劃內的資料遷移,尤其是在熱點不均衡情況下進行資料的遷移。

undefined

 

作為高可用的一個設計來說,Quorum設計是非常重要的,每個Segment有6個副本部署在3個可用域上,每一次寫要寫4個副本,每次讀要讀3個副本,這樣就可以保證它讀到的資料是一致的,它寫的資料是可持久化的也是一致的。它的一個容錯性是失去整個可用域和另外一個可用域的儲存節點,都不會影響整個系統的讀可用性,失去任意的兩個節點,無論是同一個可用域還是不同可用域,都不會影響它寫的可用性,這是它高可用設計的基本原則。


undefined

 

上圖是Aurora的事務提交流程,首先redo在mtr提交時會copy到redo log buffer裡面去, redo log record根據每個redo log的Page ID,就是這個redo log所更新的是哪一個Page,根據Page所在的儲存節點會劃分成多個batch,然後傳送到具體的儲存節點。如果一個PG內的6個Segment中有4個寫成功了,基於Quorum設計原則,資料會返回客戶端,則事務提交成功,並且會推動VDL。

VDL是在Recovery中很重要的一個標誌,首先VDL可以理解為一個LSN(Lock sequence number),每個Page根據待更新的redo log record的長度來決定Page的更新,這個是Aurora實現的非常重要的改變, MySQL在刷髒頁的時候,它會根據redo log直接在Page上面去做更新,但Aurora不是根據check point去做頁面更新,它會細化到每個頁,根據每個頁上待更新的redo log的長度來決定這個Page要不要做更新,所以它不是根據check point去做頁面更新的。

另外就是同一個PG內不同的Segment通過gossip協議來補全日誌,因為它每個節點上面6個副本寫4個副本,另外2個副本不一定會有資料,所以它需要通gossip協議去補齊資料,來保證它的一致性。


undefined

理解Aurora的故障恢復,首先需要理解三個概念,第一個概念叫做CPL,每個mtr( Mini-transaction)是MySQL內部來確保一個頁或者多個頁更新的一致性的原子事務,它最後一個Log Event對應的LSN叫CPL,VCL是持久化最大的一個log record lsn,基於前面兩個概念,其實可以理解VDL是小於VCL的最大的CPL,持久化最大的mtr的Log Event。

Aurora做故障恢復的時候需要建立VDL來確保各個副本達成一致性的一致性點,VDL之前的Lock Sequence代表的是已經提交的事務是可讀的,VDL之後的其實是沒有提交的事務,是需要進行回滾的,但是提交和回滾是Aurora都是通過非同步來完成的,不是像MySQL是同步完成的。

 

undefined

 

最新發布的Aurora支援多寫,之前Aurora是單節點的寫入,它實現的基本原理是利用Lamport Clock邏輯時鐘的概念,解決在併發系統中具有因果關係的事務順序執行問題。

多寫中有個很重要的問題就是衝突檢測,如果兩個事務同時更新了同一個Page的話,如何來進行衝突檢測呢?它是以Page為單位進行衝突檢測,基於LSN來實現版本管理和衝突檢測,基於邏輯時鐘來解決具有因果關係的事務執行問題,基於Quorum原則,最先寫成功4個副本的事務就會提交,沒有寫成功的事務就會被回滾掉。

在上圖中,每一個redo log record 都攜帶了一個它要更新的Page的PageID和它要更新的PageID對應的LSN(注意區分本條redo log record的lsn ),如果兩個事務同時更新同一個Page,起始狀態下,兩個事務對應的log record上攜帶的要更新的Page的lsn是一樣的,並且與Page的實際lsn也是一致的,如果此時,一個事務更新成功,這個事務會更新page上的lsn(會更大),另外一個事務要去更新該page的時候,就會發現page上的lsn 已經和該事務攜帶的要更新的page的lsn 不一致了,這樣Page就會拒絕更新,則兩個事務,只有第一個執行成功了,另外一個事務會被回滾。基於Quorum原則,最早取得quorum的事務則寫入成功,沒有獲取quorum的事務被回滾。

3、MGR高可用架構設計

undefined

 

剛才介紹了Aurora具體的實現細節,那我們接下來看另外一個MGR高可用的具體實現,MGR跟Aurora是完全不同的方向,Aurora是基於共享硬碟儲存、共享硬碟叢集的方向。MGR是基於一個Shared-nothing的技術架構,也就是說每個節點具有相同的資料副本,進行獨立處理。

MGR最大的亮點是基於Paxos協議實現了資料多副本的一致性叢集,同時MGR支援single-master和multi-master模式,基本上可以看到現在的資料一致性叢集都開始往支援多寫的趨勢發展。另外它會作為MySQL InnoDB cluster解決方案的組成部分, MySQL其實之前有NDB儲存引擎層的高可能解決方案,但對於InnoDB層MySQL官方沒有一個很標準的高可用解決方案。


undefined

 

MGR基本實現原理是所有節點都具有相同的資料副本,它本質上是基於Binlog來實現資料的同步,本地事務在提交的時候會進入全域性的排序,事務在節點去提交執行的時候,它會先在本地節點進行執行,一直到這個事務提交的時候才會進入Paxos協議全域性排序階段,所以說它前面的事務執行流程都是在本地進行的,在事務提交的時候才進入全域性排序階段。

基於Paxos協議,它可以確保叢集內所有的節點按照相同的事務執行次序去執行,即Paxos協議給了MGR的所有節點都按照相同的事務執行次序,這個就是Paxos協議的核心,也是MGR最大精華之處。

另外是衝突檢測問題,如果支援多寫的話,勢必會存在衝突的問題,它是基於write set來進行衝突檢測,write set可以理解為是MySQL Binlog的一個Log Event,這個後面會詳細介紹。

undefined

 

一致性協議是基於Paxos協議的改進協議,原生的Basic Paxos協議它的任意節點都可以發起提議,每個value至少需要兩次網路開銷、兩次磁碟持久化並且容易產生活鎖,這是原來Basic Paxos協議的一個劣勢。基於Basic Paxos協議,發展出來兩個比較主流的改進協議,一個是raft協議,它是單寫的並且簡化了prepare階段的開銷,大幅提高了它的效能。另外一個是Muti-Paxos協議,它有點類似raft但跟raft不同的是它的prepare是基於租約的方式去實行的,另外一個它的日誌是允許空洞的,raft的協議是不允許空洞的。

MGR中也使用了Mencius協議,相對於Basic Paxos,它也同樣節約prepare階段的開銷,相比於Muti-Paxos它消除了leader的效能瓶頸,叢集內每個成員都會負責一部分提議的生成,這個叢集內的每個節點都會負責一部分提案的提交。但有一個前提是叢集每個節點它處理的事務負載都是一樣的,都是按照相同的頻率來去處理事務。

但這個在實際場景下是不可能做到的,所以它加了很多優化和限制,比如說加了skip訊息,假如說一個節點,當前如果沒有要提交的事務的話,我可以發一個skip訊息,把所有的事務直接跳掉,其它節點接到skip訊息後,直接就跳到下一個節點進行提交,這樣它的事務提交速度就得到了提升。


undefined

 

MGR另外一個就是write set,它可以理解為在每個事務中都增加了一個Log Event,關心的小夥伴可以去看一下,能發現MySQL Binlog檔案裡面並沒有Log Event,這個Log Event它在哪裡呢?其實它在記憶體裡面,它根本就沒有寫檔案,是在記憶體裡面維護的Log Event,所以你在檔案裡面其實找不到Log Event。

 Log Event主要包括哪些資訊呢?一個是事務更新的主鍵,還有這個事務所對應的資料庫的快照版本,快照版本是用一個gtid-executed的數值來表示的。它只在記憶體中維護,不會寫出Binlog檔案來保證相容性。

另外一個是它的衝突檢測,剛才提到了所有事務在執行完提交階段都會進入Paxos協議層來確保所有成員節點按照相同的次序去執行,然後分別進行衝突檢測,也就是說衝突檢測實際上是在成員內的每個節點上獨立進行完成的。因為大家都是按照相同的次序執行相同的事務,所以得到的都是相同的結果,這是衝突檢測的最基本原理。

每個成員節點實際上都維護了一個衝突檢測的資料庫,所有待檢測的事務對應的資料庫版本都必須要大於衝突檢測中已經通過的檢測記錄版本,也就是說衝突檢測資料庫裡面維護的是一個更新的主鍵ID和這個記錄所對應的版本,一個事務想要去更新這條記錄,必須保證你更新的事務已經包含了這個記錄所對應的版本才能更新,如果不包含的話就存在衝突。

所有節點對已經執行的這個事務對應的記錄會從衝突檢測從資料庫中進行purge,剛才講到衝突檢測資料庫會不會去維護所有資料庫記錄呢?它會進行一個優化,會進行非同步的purge, purge的原則是假如說這個事務已經在所有節點執行完了、執行成功了,這個記錄就會被purge掉,這是MGR的衝突檢測資料庫的記錄維護的一個基本原理。


undefined


 

舉個例子, MGR叢集裡有T1、T2兩個事務分別在兩個節點來執行,這兩個節點的資料庫快照版本都是gtid-executed:group:1—100,經過全域性排序以後,按照T1和T2的事務執行次序去執行,T1先執行T2後執行,首先T1去執行衝突檢測,衝突檢測資料庫中是有一條記錄的,比如說ID=1這個記錄對應的版本是group:1—100,這個T1對應的也是group:1—100,可以認為T1對應的版本已經包含了這個記錄的版本,那T1是通過沖突檢測的。

然後T2開始執行衝突檢測時,T2對應的版本還是1—100,但是這時候衝突檢測資料庫中這個記錄1對應的版本已經從1—101了,T2所對應的版本已經不能包含記錄1所對應的資料庫版本,這時候的T2是應該被回滾掉的,因為已經存在衝突了,這就是T1和T2兩個事務更新同一條記錄在MGR叢集中衝突檢測和發現回滾的基本流程。

4、網易多副本資料一致高可用架構設計

網易公司在2012年就開始在資料庫同步複製這塊進行了一些探索,並且在2012年就已經研發了基於MySQL Group Replication實現的同步複製技術。在剛才提到資料庫一年中發生了兩個重要的變化,一個是基於Shared-storge,一個是基於Shared-nothing。

 

undefined

 

網易雲資料庫是2012年在公司內部開始進行大規模推廣,現在大家其實可以看到網易的網際網路產品,網易考拉海購、雲音樂、郵箱都已經執行在雲資料庫上,它底層是一個laaS的架構,laaS之上構建了RDS和DDB分庫分表的分散式中介軟體,外圍還有一些資料遷移、資料庫效能診斷以及資料庫運維的工具鏈。對於RDS來說,根據業務需求分為三個產品,一個是單機版的,一個是雙機高可用版的,還有一個就是多副本高可用版的。

undefined

 

今天我們重點介紹一下多副本的實現,網易雲資料庫是基於一個雲基礎設施來構建的,網易基於openstack進行自研的基於KVM的虛擬化的laaS環境,也是基於MGR來進行多副本的資料庫高可用的架構,它的3個節點位於3個不同的可用域中,這個可用域在物理上完全隔離的,基於VPC網路來實現叢集內部的資料同步,它會有一個RDS的VPC,在整個VPC網路內進行資料的同步,提供讀寫只讀兩個域名,使用者其實可以通過讀寫域名訪問primary結點,通過只讀域名來訪問secondary節點,通過權重來影響節點的切換。


undefined

 

上圖是基於MGR的基本故障恢復流程,故障恢復時間主要由兩部分組成,選舉時間和apply time,故障節點修復以後會重新加入到MGR叢集中,並且選擇只讀節點作為Seed節點。其實MGR有一個很好用的功能叫做流控,我們通過控制只讀的能力來儘快完成資料的修復。

 

undefined


 

剛才提到流控,它有三個引數,MGR的缺陷是基於Binlog進行資料同步,就會存在複製延遲問題,但MGR有流控系統,它可以在發現從庫複製延遲比較高的情況下,限制主庫的寫入速度,來減少主從複製的延遲,其實這是一種自保護的機制。

 

undefined

 

最後就是大家比較關心的效能問題,上圖可以看到,MGR的效能其實是可以達到甚至超過原有同步複製的水平,當然相對於非同步複製水平可能還是稍微差一點,但是基本上是可以達到原有同步複製的水平,並且獲得了更高的可用性,這個結果已經超出了我們設計的目標。

來自 “ ITPUB部落格 ” ,連結:http://blog.itpub.net/31547542/viewspace-2213447/,如需轉載,請註明出處,否則將追究法律責任。

相關文章