基於Ceph快照的異地災備設計

做者:吳香偉 發表於 2017/02/06
版權聲明:能夠任意轉載,轉載時務必以超連接形式標明文章原始出處和做者信息以及版權聲明前端

喜歡請點擊右邊打賞,謝謝支持!數據庫


引子

技術改變生活。
愈來愈方便的手機讓你們可以更有效的利用碎片時間,我很享受在上下班的公交車上或在陽光明媚的花園裏梳理思路,並寫成文字上傳到簡書;要是擱在幾年前的PC時代畫風多是坐在星巴克靠窗的桌子上邊喝咖啡邊敲鍵盤;若是時間再久遠點,應該有間書房有張書桌,書桌邊有個磨墨的小書童…後端

第一種情形跟後兩種情形有着本質的區別。咖啡可能灑在鍵盤上燒壞主板,辛苦一下午寫出的文字再也找不回來了;後院可能起火將寫了兩天的文字燒成灰燼,再也找不回來了。花園散步也可能摔一跤手機掉進水裏開不了機,但沒必要擔憂由於個人文字早已經實時同步到了簡書的服務器,而且不止保存了一份,而且不僅保存在一個地區。因此不用擔憂跌倒,也不用擔憂地震,由於背後有異地災備技術。緩存

背景

這是去年初(2016年)爲一緊急項目而設計,20K+代碼量,陸陸續續花了大半年時間。異地災備講究兩地三中心,兩地指距離較遠的兩個地方,好比北京到上海一千多千米。三中心指3個數據中心,兩個數據中心在同城,另外一個在異地。同城兩個數據中心間的數據採用同步方式,以IO爲粒度。異地數據中心間通常採用異步複製。服務器

Ceph社區有兩種方法能夠作站點間的數據複製:一種基於快照,主站點備份時爲存儲塊打快照,將快照的差別部分發送到備站點從新生成新快照;另外一種是當時社區正在開發的基於Rbd Journal的Rbd Mirror方案。網絡

當時兩種方案都有問題。Mirror方案正在開發不成熟,跟數據庫配合也是個問題。快照已經很成熟,但有先天的缺陷:一方面打快照對原塊的性能有很大影響,尤爲是隨機IO;另外一方面,快照間的差別部分是在備份時計算出來的,所以很耗時,即便兩個快照間沒有差別也要花上很長一段時間來掃描差別部分。通過權衡,採用了第一種方案。如今社區還有個叫Ceph-backup的開源項目也是基於快照,不過與本方案相比要簡陋不少。架構

整體架構

概念。
主站點,生產環境的數據中心;
備站點,備份環境的數據中心;
備份策略,肯定備份的時間段、頻率以及快照回收的頻率;
備份任務,包括備份哪一個存儲塊,由誰來備份。併發

網絡結構。
主備站點間有獨立的災備網絡,災備網絡爲千兆帶寬,延遲爲33毫秒左右。站點內部除了災備網外還有3個網絡:前端、後端和管理網絡。前端網絡用於鏈接存儲節點和數據庫服務器,數據庫服務器使用存儲集羣提供的Lun。管理網絡鏈接管理節點和各個存儲節點,管理節點和其中一個存儲節點部署在同臺服務器。負載均衡

備份過程主要能夠分爲3大步:
(1)主站點建立快照,導出兩個快照間的差別到文件;
(2)將差別文件拷貝到備站點;
(3)備站點導入差別文件生成和主戰點同名的快照,備份過程結束。運維

這個過程當中最重要的問題是數據完整性。快照自己沒法保證數據完整性,也就是說,採用應用程序運行過程當中建立的快照的數據來重啓應用程序並不能保證應用程序回到打快照那一時刻的狀態,甚至可能讓應用程序出現異常沒法啓動。這是由於應用程序運行時所依賴的數據包括兩部份內容,一部分已經持久化到硬盤,另外一部分尚停留在各級緩存中。快照只能恢復出Lun的第一部分數據,第二部分數據對快照來講已經丟失。

第二重要的問題是備份效率,主要來自4個方面。首先,兩個數據中心間相距一千多千米,網絡延遲33毫秒左右。千兆網絡中,若是延遲爲0,那麼帶寬能夠達到100兆,可以使用Scp命令拷貝大文件來測速。33毫秒延遲的狀況下只有原來的30%左右,也就是30兆。其次,掃描快照間差別很是耗時,對10TB的存儲塊即便只有5M的差別數據也要從頭至尾掃描整個存儲塊。第三,落盤次數過多,一次備份有4次落盤,主戰點兩次,備站點兩次,讀兩次寫兩次。最後,存在多個存儲塊同時備份的狀況。

架構整體上仍是集中式的結構,包含4種不一樣角色的進程:Scheduler、Backup、Proxy和Agent。Agent進程部署在每臺數據庫服務器中,用於感知應用;Scheduler進程主要負責備份、還原、主備切換等任務的調度工做以及全部Backup進程的管理;Backup部署在集羣的每一個節點,只負責備份或者還原兩個任務的數據傳輸;Proxy進程的功能是轉發Agent和Scheduler間的消息,由於Agent跑在前端網絡而Scheduler跑在災備網絡,二者沒法直接連通。

備份還原

爲解決數據完整性問題,Agent提供了一組API接口,容許應用程序以插件的方式提供對應的驅動程序,只有提供了驅動的應用程序才容許備份。

應用程序能夠擁有本身獨有的保障數據完整性的方法,Agent不關心具體機制,只負責將備份準備、開始、完成以及恢復準備、開始、完成的消息通知給驅動。此外,Agent還提供一個數據通道用於保存驅動程序的私有數據,這些數據在備站點還原時將從新傳遞給驅動,驅動能夠根據這些私有數據來保證應用程序還原到給定的狀態。

驅動程序保障數據完整性的最簡單暴力的方式是,當接收到準備備份的通知時將緩存Flush到硬盤。不過,數據庫通常都有本身的方式。以XX數據庫爲例,它會維護一個叫作FileLSN的版本號,表明該版本前面的數據已經持久化到硬盤。準備備份時只要維護好FileLSN和快照的對應關係便可,恢復時將數據庫滾回到FileLSN的版本。

中途落盤問題。
中途落盤會帶來兩個影響,一是備份效率低,二是每一個節點須要預留足夠的磁盤空間用於保存臨時的差別文件。對此採起分片傳輸的策略來解決該問題。分片大小默認爲128M,分片從主站點讀取出來後繞過本地磁盤和遠端磁盤直接寫入備戰點,待全部分片都完成後在備戰點新建同名快照,完成一次備份。分片策略在解決中途落盤問題的同時也爲咱們提供了一種監控備份進度的手段,進度的最小粒度爲分片大小。不過,它也帶來了新的問題,若是備份過程當中Backup節點異常將致使備站點的存儲塊成爲髒塊。這會引入一系列數據一致性的問題。爲此,須要一個地方維護記錄存儲塊的狀態,咱們將這些狀態記錄在一個Rados對象。

掃描差別效率低的問題。
主站點的Backup進程將備份過程劃分爲生成分片、讀取分片、合併分片、發送分片4個階段,每一個階段都有獨立的若干線程來完成,線程間經過隊列交換數據,數據以流水線的方式從上個階段傳遞給下個階段。

生成分片階段將給定的存儲塊切割成若干固定大小的區間,每一個讀取分片階段的線程領取到一個區間後開始計算區間內兩個快照間的差別數據。因爲計算比較耗時,因此採用了多個線程併發執行的策略以縮短總體時間。正常狀況下每一個分片的數據做爲一個請求發送給備戰點。但實際狀況中存儲塊的大部分區間是空的,發送空分片也會消耗不少額外時間。合併分片階段甄別出連續爲空的分片,將這些分片合併成一個請求。極端狀況下,若是兩個快照間沒有差別,那麼只要一個請求就能完成備份了。

負載均衡問題。
備份任務應該分配給哪兩個Backup節點?主站點的Scheduler根據備份策略和備站點中存儲塊的狀態新建備份任務,而後將備份任務下發給主站點的Backup節點以啓動備份。備份任務是一組關於備份信息的數據集合,其中包含兩個Backup節點的地址,一個節點位於主站點用於讀取併發送差別數據,另外一個節點位於備站點用於接收並寫入差別數據到集羣。這兩個Backup節點分別由主站點和備站點的Scheduler節點選出。

Scheduler選擇Backup節點主要考慮兩個因素:第一個因素是Backup節點正在運行的備份任務個數,第二個因素是Backup節點最近5分鐘內的平均負載。選取兩個因素加權和最小的節點,兩個因素的權重可配置,默認爲6:4。

主備切換

主站點切換爲備站點,或者備站點切換爲主站點,對服務進程來講意味着元數據和程序行爲的改變。

主站點切換爲備站點主要劃分爲三個階段:停服務、切換元數據、改變程序行爲。主站點Scheduler節點接收到切換爲備站點的請求後會生成3個對應於停服務、切換元數據和改變程序行爲的站點級任務,將這些任務寫入Task對象,並啓動第一個任務。

保護備站點的儲存塊不受污染。
備份過程當中,備站點的Backup進程一直在寫儲存塊,若是存在其它的應用程序同時寫儲存塊的話將引發兩個致命問題:
(1)備站點的快照數據和主站點不一致;
(2)其它應用程序會發現數據不穩定,常常被Backup進程改寫。
咱們爲每一個儲存塊提供了兩種訪問方式,一種經過iSCSI協議,另外一種經過RBD私有協議。外部應用程序只容許使用iSCSI協議,內部應用程序默認使用私有協議。爲解決污染問題,備站點必須限制參與備份的儲存塊只支持私有訪問協議。所以在主站點切換爲備站點的停服務階段,Scheduler首先通知全部Agent讓全部外部應用程序中止對儲存塊的訪問,而後通知全部Backup節點取消對儲存塊的iSCSI協議支持。一樣地,在備站點切換爲主站點的起服務階段,Scheduler通知全部Backup節點對參與備份的儲存塊增長對iSCSI協議的支持。

切換元數據。
咱們將服務進程相關的數據劃分爲兩大類,第一類是會影響服務角色判斷以及能夠動態改變的數據,將這類數據記爲元數據;第二類是不影響角色判斷的數據,例如線程池大小、端口號、日誌級別等,將這類數據記爲配置數據。配置數據保存在配置文件,元數據保存在集羣元數據池(默認爲.backup池)的不一樣Rados對象內。

整體上元數據又能夠劃分爲3大類:站點級別、儲存塊級別以及臨時任務。站點級元數據包含了主站點的Fsid和備站點的Fsid,Scheduler經過比較本身的Fsid和主站點Fsid來判斷本身的角色。切換元數據時只要互換主備站點的Fsid便可。

儲存塊級元數據包括兩部份內容:第一部分記錄參與備份的主站點儲存塊和備站點儲存塊之間的對應關係,同時保存在主站點和備站點;第二部分描述每一個儲存塊的狀態,主站點只描述主站點的儲存塊,備站點只描述備站點的儲存塊,所以各自保存。切換元數據時只要切換第一部份內容便可。

臨時任務元數據是爲了應對Scheduler節點故障而設計,是運行時數據不須要切換。

改變程序行爲。
元數據切換完成後,隨着站點角色的轉變,Scheduler的部分行爲已經完成改變。除此以外,Scheduler還有一些子服務須要從新激活或關閉,例如備份策略任務、快照回收任務等。

備站點切換爲主站點也劃分爲三個階段:切換元數據、改變程序行爲、起服務。

故障處理

Scheduler故障。
Scheduler乃系統中樞,負責備份策略、快照回收、心跳檢測等核心功能。若是Scheduler故障將致使整個系統沒法工做。爲此對Scheduler作了高可用,經過Keepalived實現。

Keepalived爲主節點配置一個虛IP地址,並檢測每一個節點,當發現主節點故障後將Vip切換到新節點。虛IP漂移涉及到兩個問題,一是新舊節點間如何共享數據,二是舊節點故障前正在處理的請求可能會丟失。對第一個問題,咱們將全部元數據保存在集羣元數據池,所以新舊節點均可以共享數據。第二個問題經常使用的解決思路是持久化每一個消息到元數據池,不過咱們沒有采用這種方法而是採用了更簡單的重試方法。因爲Scheduler已經作了高可用,所以咱們假設Scheduler節點是永不宕機的。Scheduler客戶端在超時或者對端關閉引發錯誤時將重發請求。

Backup故障。
Backup節點故障最直接的影響是排隊中和正在運行的備份任務要麼還沒開始執行要麼只備份了一部份內容就結束了。針對這種狀況,咱們實現了斷點續備功能。Scheduler將備份任務分配給Backup節點後將按期檢查備份任務的執行狀況,在發現Backup節點鏈接中斷或者任務憑空消失時將從新爲給定的儲存塊準備一個新的備份任務以繼續完成剩餘內容的備份。斷點續備的關鍵是如何找到上次備份的結束位置,其實只要以備站點接收到的數據爲準便可。

Backup節點離線的一個結果是不能再繼續接受備份任務了,所以Scheduler要及時檢測到離線的節點,避免將備份任務分配給無效的節點。

Backup故障對狀態監控的影響。
監控服務經過讀取儲存塊的狀態元數據來在界面中顯示儲存塊的狀態,其中的備份狀態包括空閒、備份中、備份中斷、本地恢復、遠端恢復、恢復中斷等。若是備份任務失敗,那麼應該在界面中顯示備份中斷或恢復中斷。

若是備站點Backup退出或者災備網絡斷開,那麼對應的主站點Backup可以檢測到這類故障並作好元數據的修改,並不會致使主站點的監控數據出錯。

若是主站點Backup異常退出或重啓未來不及修改狀態元數據,從而致使監控數據出錯。一樣地咱們藉助Scheduler來檢查任務是否異常,發現異常後修正狀態元數據。對每一個備份任務,Scheduler一方面將其保存在元數據池(即上文說起的臨時任務),另外一方面將任務發送給Backup節點執行。在元數據池中保留備份任務的存根帶來兩個好處:一是應對Scheduler故障,二是應對Backup故障。

主備切換過程故障。
主備切換涉及到Agent、Scheduler、Backup每一個服務進程,切換過程當中有部分故障能夠自動修復但也有一些故障須要人工干預,例如存在離線的Backup節點、數據庫故障等。對須要人工干預的故障問題,提供了「從新激活」任務的運維工具。

舉個例子,假設主備切換總共須要完成10個任務,在執行到第5個任務時某個Agent出現故障。這時須要運維人員介入先處理Agent故障,而後使用運維工具從新激活切換任務,此時將從新運行第5個任務。

狀態監控

(待續)

附加功能

一致性組。
備站點查看備份數據。

(待續)

存在的問題

儲存層異地災備的價值思考。 (待續)

相關文章
相關標籤/搜索