撤出云平臺六年后,我們做了一次“斷網測試”
如同肌肉一樣,災難準備的能力也需要不斷訓練和演習。
把時間線撥到 2021 年 11 月 18 日星期四,Dropbox 服務一切如常。用戶沒有感覺到任何異樣,就如同無數個歲月靜好的日子。但真是這樣嗎?當然不是,那天下午五點,一群 Dropbox 員工在 Zoom 頻道里吵作一團,因為大家突然接到命令,要求把圣何塞數據中心跟 Dropbox 網絡直接斷開。
這可是件大事,畢竟災難恢復(DR)團隊為此準備了一年有余,而影響到的可是 Dropbox 六年多積累下的工作結晶。
但面對自然災害愈發普遍的世界,我們必須考慮數據中心受到此類影響的可能性。就是說我們不僅要在數據中心選址方面精心規劃,同時也得建立起有助于降低風險的應對策略。
自 2015 年從 AWS 遷出之后,Dropbox 的基礎設施就大量集中在圣何塞地區。雖然用戶的元數據多年來一直在跨區域復制,但必須承認的是,我們的大多數服務都誕生在圣何塞、成熟在圣何塞。這是塊寶地,但也靠近圣安地列斯斷層,所以我們得保證突如其來的地震不會讓 Dropbox 意外離線。
怎么向客戶證明我們已經為災害做好了準備?答案就是恢復時間目標(RTO,Recovery Time Objective),這項指標用于衡量我們要花多長時間才能從災難性事件中恢復正常。多年以來,我們一直在通過工作流程縮短預期 RTO,希望能更從容地應對包括地震在內的可能災難。
也正是依靠 2020 年和 2021 年的跨職能協作,災難準備團隊最終下決心把圣何塞數據中心完全斷開,看看 Dropbox 是不是真的能夠把 RTO 降低到目前的水平。下面,咱們就來回顧這段驚心動魄的故事。
一切要從架構設計說起
為了更好地理解如何縮短 RTO 周期,我們首先得明白 Dropbox 是怎么進行架構設計的。
Dropbox 擁有兩大核心服務棧:其一用于塊(文件)數據,其二用于元數據。不少關注 Dropbox 技術動向的朋友可能知道,我們的塊存儲解決方案名為 Magic Pocket,其設計就是通過多宿主主機提高可靠性。所謂多宿主服務,就是說這項服務在設計上能夠依托于多個數據中心保持運行。
Magic Pocket 還是一套所謂雙活系統。就是說除了多宿主設計之外,它還能同時且獨立地為來自多處數據中心的塊數據提供服務。Magic Pocket 設計包含內置復制與冗余機制,能夠保證把區塊故障給業務造成的影響控制在最低。這套架構還具備災難彈性,所以用戶能夠明確看到哪處數據中心出了問題、但服務體驗并不太受到影響。在部署了 Magic Pocket 之后,Dropbox 又啟動了一項三段式計劃,先是增強元數據堆棧彈性、最終在元數據層面同樣建立雙活架構。
具體來講,計劃的第一階段就是實現主動 - 被動架構。也就是說,在完成必要的變更之后,我們就能把元數據從當前主動城域——即圣何塞數據中心(SJC)——轉移至另一被動城域。這個過程就是所謂故障轉移。
我們的首次故障轉移已經在 2015 年成功完成,但這還只是達成最終目標的小小一步。之后,我們開始為元數據堆棧構建主動 - 主動的雙活架構,希望以獨立方式為來自多處數據中心的用戶元數據提供服務。到了這一步,麻煩開始出現。
元數據讓問題愈發復雜
我們的元數據堆棧建立在兩個大型分片 MySQL 部署之上。其一用內部數據庫 Edgestore 承載著通用元數據,其二則負責承載文件系統元數據。集群中的每個分片由六臺物理設備組成:兩個核心區域,各自對應一臺主機 primary 和兩臺副本 replica。
而 MySQL 層中的兩大權衡性設計,再加上 Edgestore 中的數據建模復雜性,迫使我們不得不重新考量整個災難準備計劃。
MySQL 中的第一個權衡就是如何處理復制操作。我們之前使用半同步復制以求取數據完整性和寫入延遲之間的平衡性。但正是由于這一設計,導致各區域間的復制只能異步完成——意味著遠程 replica 始終落后于 primary 主機。這種復制層面的滯后,導致我們很難處理主區域中的突發性故障。有鑒于此,我們對可能發生的故障做出預判,通過設計確保主區域在事件之下仍能保持一段時間的正常運行。冗余電源和網絡系統都已部署到位,我們對實際效果也算是比較滿意。
MySQ 中的第二個權衡則是一致性級別。我們的 MySQL 采用的是讀取提交隔離模式,由此實現的強一致性使得開發人員能夠輕松處理數據,但同時也限制了數據庫的擴展能力。目前比較常見的擴展方式就是引入緩存以降低整體一致性,但同時增加讀取吞吐量。在我們這套系統中,雖然 Dropbox 已經建立起緩存層,但它在設計上仍然與數據庫保持強一致性。這個決定使得設計方案相當復雜,同時也限制了所能容忍的數據庫緩存內容滯后度。
最后,因為 Edgestore 是一套面向多種用途的大型多租戶圖數據庫,所以往往很難搞清其中的數據所有權。這種復雜的所有權模型,導致我們幾乎沒法簡單將用戶數據中的特定子集轉移到其他區域。
這些權衡設計的存在,直接決定了我們后續構建雙活系統的基本思路。開發者已經適應了前一種權衡所帶來的高寫入性能,也適應了后一種權衡實現的強一致性。總而言之,這些選擇嚴重限制了我們在設計雙活系統時的架構選項,也導致最終系統變得愈發復雜。到 2017 年,災難準備工作已經停滯不前,但開發強大故障應對方案的壓力卻絲毫未減。為了保障能在災難發生時獲得良好的業務連續性,我們決定改變方向,朝著主動 - 被動故障模型邁出探索的腳步。
我們的災難準備團隊
在決定轉向主動 - 被動方案后,我們開始為更頻繁的故障轉移設計必要工具。2019 年,我們完成了第一次正式的故障轉移,之后每個季度都會再次嘗試轉移、并借此機會改進整個流程。2020 年是個重要的轉折點——除了新冠疫情的爆發,我們 Dropbox 的災難準備水平也自此真正上了一個新臺階。
2020 年 5 月,我們的故障轉移工具發生嚴重故障并引發宕機,業務癱瘓達 47 分鐘。負責驅動故障轉移的腳本在執行當中出錯,致使我們身陷半中斷狀態。這次失利也暴露出我們災難準備策略中的幾個重大問題:
驅動故障轉移的系統本身缺乏故障彈性。
各服務團隊使用自己的故障轉移流程與工具,互不相通。
我們的故障轉移頻度不足,因此對方案的實踐考查不夠全面。
為了解決第一個問題,我們開始對現有故障轉移工具和流程開展緊急審計。我們還做出必要變更,確保工具擁有良好的故障彈性;同時建立起新的清單,確保能夠以更嚴格的方式執行故障轉移演習。
對于第二和第三個問題,我們組建了專門的故障轉移團隊,也就是前文一直提到的災難準備(DR)團隊。有了這樣一支專業隊伍,我們就能把每季度一次的故障轉移頻度提升為每月一次。更頻繁的故障轉移不僅能幫助我們積累經驗、提振信心,同時也讓我們以前所未有的速度實現了災難響應與災難恢復。
明確的使命與新組建的七人小隊,讓我們有了設定更高目標的底氣。到 2021 年底,Dropbox 必須把 RTO 控制在更短水平。
故障轉移迎來實質性改進
2020 年 5 月那次宕機事故,凸顯出了我們的一大重要問題——總是想用單一 Go 二進制文件完成城域之間的故障轉移。雖然這種方法最初效果不錯,但隨著我們對于故障轉移不斷提出更高要求,整個思路也變得愈發難以為繼。
因此,我們決定從頭開始重寫這款工具,提升它的模塊化與可配置水平。我們從 Facebook 的 Maelstrom 論文中獲得了靈感,其中詳細介紹了一種巧妙的外向流量導引思路,足以承載起龐大的數據中心災難恢復需求。雖然有了參照對象,但我們還是從最小可行產品做起,希望整套方案更適合 Dropbox 自己的系統。
我們借用了 Maelstrom 中的 Runbook 概念。Runbook 中包含一個或多個任務,每個任務負責執行特定操作。這些任務共同形成了一個有向無環圖,使我們不僅能夠描述故障轉移演習中的每一個必要步驟,同時也能概括一切通用性的災難恢復場景。以此為基礎,我們可以使用易于解析和編輯的配置語言,整理出一份描述各項故障轉移條件的專用 Runbook,這樣后續的故障轉移調整將會像編輯配置文件一樣簡單快捷。
與直接編輯 Go 二進制文件相比,新方法不僅更加輕巧、同時也提高了 Runbook 的重用能力,幫助災難準備團隊輕松完成一次又一次定期測試。下圖所示,為 Runbook 流程和其中的任務。
轉載請在文章開頭和結尾顯眼處標注:作者、出處和鏈接。不按規范轉載侵權必究。
未經授權嚴禁轉載,授權事宜請聯系作者本人,侵權必究。
本文禁止轉載,侵權必究。
授權事宜請至數英微信公眾號(ID: digitaling) 后臺授權,侵權必究。
評論
評論
推薦評論
暫無評論哦,快來評論一下吧!
全部評論(0條)