本文做者:時暉(玄霄) ,螞蟻金服高級技術專家,現負責中間件微服務團隊。2010年應屆加入支付寶,一直在基礎技術部門工做。經歷了支付寶/螞蟻金服從SOA化到異地多活架構的發展歷程,參與過運維平臺、服務註冊中心、配置中心、微服務平臺的建設。熟悉螞蟻技術架構演進歷史,對分佈式系統高可用設計有切身體會。同時還從事螞蟻科技輸出工做,爲多家金融機構提供過技術架構解決方案諮詢。
本文根據玄霄 2018 年上海 QCon 演講內容整理,完整的分享 PPT 獲取方式見文章底部。
「異地多活」是互聯網系統的一種高可用部署架構,而「單元化」正是實現異地多活的一個解題思路。git
提及這個話題,不得不提兩個事件:一件是三年多前的往事,另外一件就發生今年的杭州雲棲大會上。github
2015年5月27日,因市政施工,支付寶杭州某數據中心的光纜被挖斷,形成對部分用戶服務不可用,時間長達數小時。其實支付寶的單元化架構容災很早就開始啓動了,2015年也基本上成型了。當時因爲事發忽然,仍是碰到不少實際問題,花費了數小時的時間,纔在確保用戶數據徹底正確的前提下,完成切換、恢復服務。雖然數據沒有出錯,但對於這樣體量的公司來講,服務不可用的社會輿論影響也是很是大的。數據庫
527這個數字,成爲螞蟻金服全體技術人心中懸着那顆苦膽。咱們甚至把技術部門所在辦公樓的一個會議室命名爲527,把每一年的5月27日定爲技術日,來時刻警醒本身敬畏技術,不斷打磨技術。小程序
通過幾年的臥薪嚐膽,時間來到2018年9月。雲棲大會上,螞蟻金服發佈了「三地五中心金融級高可用方案」。現場部署了一個模擬轉帳系統,在場觀衆經過小程序互相不斷轉帳。服務端分佈在三個城市的五個數據中心,爲了感覺更直觀,把杭州其中一個數據中心機櫃設置在了會場。工做人員當場把杭州兩個數據中心的網線剪斷,來模擬杭州的城市級災難。後端
網線剪斷以後,部分用戶服務不可用。通過26秒,容災切換完成,全部受影響的用戶所有恢復正常。這個Demo固然只是實際生產系統的一個簡化模型,可是其背後的技術是一致的。這幾年來,其實每隔幾周咱們就會在生產環境作一次真實的數據中心斷網演習,來不斷打磨系統容災能力。
緩存
從大屏幕上能夠看到,容災切換包含了「數據庫切換」「緩存容災切換」「多活規則切換」「中間件切換」「負載均衡切換」「域名解析切換」等多個環節。異地多活架構是一個複雜的系統工程,其包含的技術內涵很是豐富,單場分享實難面面俱到。本場是微服務話題專場,咱們也將以應用層的微服務體系做爲切入點,一窺異地多活單元化架構的真面目。服務器
任何一個互聯網系統發展到必定規模時,都會不可避免地觸及到單點瓶頸。「單點」在系統的不一樣發展階段有不一樣的表現形式。提升系統伸縮能力和高可用能力的過程,就是不斷與各類層面的單點鬥爭的過程。網絡
咱們不妨以一個生活中最熟悉的場景做爲貫穿始終的例子,來推演系統架構從簡單到複雜,所遇到的問題。架構
上圖展現的是用支付寶買早餐的情景,固然角色是虛構的。負載均衡
最先支付寶只是從淘寶剝離的一個小工具系統,處於單體應用時代。這個時候移動支付固然還沒出現,咱們的例子僅用於幫助分析問題,請忽略這個穿幫漏洞。
假設圖中的場景發生在北京,而支付寶系統是部署在杭州的機房。在小王按下「支付」按鈕的一瞬間,會發生什麼事情呢?
支付請求要從客戶端發送到服務端,服務端最終再把結果返回客戶端,必然會有一次異地網絡往返,耗時大約在數十毫秒的數量級,咱們用紅色線表示。應用進程內部會發生不少次業務邏輯運算,用綠色圈表示,不涉及網絡開銷,耗時忽略不計。應用會訪問屢次數據庫,因爲都在部署在同一個機房內,每次耗時按一毫秒如下,一筆支付請求按10次數據庫訪問算(對於支付系統來講並不算多,一筆業務可能涉及到各類數據校驗、數據修改)。耗時大頭在無可避免的用戶到機房物理距離上,系統內部處理耗時很小。
到了服務化時代,一個好的RPC框架追求的是讓遠程服務調用像調本地方法同樣簡單。隨着服務的拆分、業務的發展,本來進程內部的調用變成了網絡調用。因爲應用都部署在同一個機房內,業務總體網絡耗時仍然在可接受範圍內。開發人員通常也不會特別在乎這個問題,RPC服務被當成幾乎無開銷成本地使用,應用的數量也在逐漸膨脹。
服務化解決了應用層的瓶頸,緊接着數據庫就成爲制約系統擴展的瓶頸。雖然咱們本次重點討論的是服務層,但要講單元化,數據存儲是不管如何繞不開的話題。這裏先插播一下分庫分表的介紹,做爲一個鋪墊。
經過引入數據訪問中間件,能夠實現對應用透明的分庫分表。一個比較好的實踐是:邏輯拆分先一步到位,物理拆分慢慢進行。以帳戶表爲例,將用戶ID的末兩位做爲分片維度,能夠在邏輯上將數據分紅100份,一次性拆到100個分表中。這100個分表能夠先位於同一個物理庫中,隨着系統的發展,逐步拆成2個、5個、10個,乃至100個物理庫。數據訪問中間件會屏蔽表與庫的映射關係,應用層沒必要感知。
解決了應用層和數據庫層單點後,物理機房又成爲制約系統伸縮能力和高可用能力的最大單點。
要突破單機房的容量限制,最直觀的解決辦法就是再建新的機房,機房之間經過專線連成同一個內部網絡。應用能夠部署一部分節點到第二個機房,數據庫也能夠將主備庫交叉部署到不一樣的機房。
這一階段,只是解決了機房容量不足的問題,兩個機房邏輯上還是一個總體。平常會存在兩部分跨機房調用:
服務層邏輯上是無差異的應用節點,每一次RPC調用都有一半的機率跨機房
每一個特定的數據庫主庫只能位於一個機房,因此宏觀上也必定有一半的數據庫訪問是跨機房的
同城跨機房專線訪問的耗時在數毫秒級,圖中用黃色線表示。隨着微服務化演進如火如荼,這部分耗時聚沙成塔也很可觀。
改進後的同城多機房架構,依靠不一樣服務註冊中心,將應用層邏輯隔離開。只要一筆請求進入一個機房,應用層就必定會在一個機房內處理完。固然,因爲數據庫主庫只在其中一邊,因此這個架構仍然不解決一半數據訪問跨機房的問題。
這個架構下,只要在入口處調節進入兩個機房的請求比例,就能夠精確控制兩個機房的負載比例。基於這個能力,能夠實現全站藍綠髮布。
「兩地三中心」是一種在金融系統中普遍應用的跨數據中心擴展與跨地區容災部署模式,但也存在一些問題。異地災備機房距離數據庫主節點距離過遠、訪問耗時過長,異地備節點數據又不是強一致的,因此沒法直接提供在線服務。
在擴展能力上,因爲跨地區的備份中心不承載核心業務,不能解決核心業務跨地區擴展的問題;在成本上,災備系統僅在容災時使用,資源利用率低,成本較高;在容災能力上,因爲災備系統冷備等待,容災時可用性低,切換風險較大。
小結一下前述幾種架構的特色。直到這時,微服務體系自己的變化並不大,無非是部署幾套、如何隔離的問題,每套微服務內部仍然是簡單的架構。
架構類型 |
優點 |
問題 |
單體應用 |
網絡開銷小 |
擴展性差,維護困難 |
單機房服務化 |
解耦,可擴展 |
容量受限,機房級單點 |
同城多機房階段一 |
突破單機房容量瓶頸 |
非必要的跨機房網絡開銷大 |
同城多機房階段二 |
非必要的跨機房網絡開銷小;機房級容災能力 |
城市級單點 |
兩地三中心 |
異地容災能力 |
網絡耗時與數據一致性難兩全 |
螞蟻金服發展單元化架構的原始驅動力,能夠歸納爲兩句話:
異地多活容災需求帶來的數據訪問耗時問題,量變引發質變
數據庫鏈接數瓶頸制約了總體水平擴展能力,危急存亡之秋
第一條容易理解,正是前面討論的問題,傳統的兩地三中心架構在解決地區級單點問題上效果並不理想,須要有其餘思路。但這畢竟也不是很急的事情,真正把單元化之路提到生死攸關的重要性的,是第二條。
到2013年,支付寶核心數據庫都已經完成了水平拆分,容量綽綽有餘,應用層無狀態,也能夠隨意水平擴展。可是按照當年雙十一的業務指標作技術規劃的時候,卻碰到了一個棘手的問題:Oracle數據庫的鏈接不夠用了。
雖然數據庫是按用戶維度水平拆分的,可是應用層流量是徹底隨機的。以圖中的簡化業務鏈路爲例,任意一個核心應用節點C可能訪問任意一個數據庫節點D,都須要佔用數據庫鏈接。鏈接是數據庫很是寶貴的資源,是有上限的。當時的支付寶,面臨的問題是不能再對應用集羣擴容,由於每增長一臺機器,就須要在每一個數據分庫上新增若干鏈接,而此時幾個核心數據庫的鏈接數已經到達上限。應用不能擴容,意味着支付寶系統的容量定格了,不能再有任何業務量增加。別說大促,可能再過一段時間連平常業務也支撐不了了。
單元化架構基於這樣一種設想:若是應用層也能按照數據層相同的拆片維度,把整個請求鏈路收斂在一組服務器中,從應用層到數據層就能夠組成一個封閉的單元。數據庫只須要承載本單元的應用節點的請求,大大節省了鏈接數。「單元」能夠做爲一個相對獨立總體來挪動,甚至能夠把部分單元部署到異地去。
單元化有幾個重要的設計原則:
核心業務必須是可分片的
必須保證核心業務的分片是均衡的,好比支付寶用用戶ID做分片維度
核心業務要儘可能自包含,調用要儘可能封閉
整個系統都要面向邏輯分區設計,而不是物理部署
在實踐上,咱們推薦先從邏輯上切分若干均等的單元,再根據實際物理條件,把單元分佈到物理數據中心。單元均等的好處是更容易作容量規劃,能夠根據一個單元的壓測結果方便換算成整站容量。
咱們把單元叫作Regional Zone。例如,數據按100份分片,邏輯上分爲5個Regional Zone,每一個承載20份數據分片的業務。初期多是部署成兩地三中心(容許多個單元位於同一個數據中心)。隨着架構的發展,再整單元搬遷,演化成三地五中心,應用層無需感知物理層面的變化。
回到前面買早餐的例子,小王的ID是12345666,分片號是66,應該屬於Regional Zone 04;而張大媽ID是54321233,分片號33,應該屬於Regional Zone 02。
應用層會自動識別業務參數上的分片位,將請求發到正確的單元。業務設計上,咱們會保證流水號的分片位跟付款用戶的分片位保持一致,因此絕大部分微服務調用都會收斂在Regional Zone 04內部。
可是轉帳操做必定會涉及到兩個帳戶,極可能位於不一樣的單元。張大媽的帳號就恰好位於另外一個城市的Regional Zone 02。當支付系統調用帳務系統給張大媽的帳號加錢的時候,就必須跨單元調用Regional Zone 02的帳務服務。圖中用紅線表示耗時很長(幾十毫秒級)的異地訪問。
從宏觀耗時示意圖上就能夠比較容易地理解單元化的思想了:單元內高內聚,單元間低耦合,跨單元調用沒法避免,但應該儘可能限定在少數的服務層調用,把總體耗時控制在可接受的範圍內(包括對直接用戶體驗和對總體吞吐量的影響)。
前面講的是正常狀況下如何「多活」,機房故障狀況下就要發揮單元之間的容災互備做用了。
一個城市總體故障的狀況下,應用層流量經過規則的切換,由事先規劃好的其餘單元接管。
數據層則是依靠自研的基於Paxos協議的分佈式數據庫OceanBase,自動把對應容災單元的從節點選舉爲主節點,實現應用分片和數據分片繼續收斂在同一單元的效果。咱們之因此規劃爲「兩地三中心」「三地五中心」這樣的物理架構,實際上也是跟OceanBase的副本分佈策略息息相關的。數據層異地多活,又是另外一個宏大的課題了,之後能夠專題分享,這裏只簡略提過。
這樣,藉助單元化異地多活架構,才能實現開頭展現的「26秒完成城市級容災切換」能力。
單元化是個複雜的系統工程,須要多個組件協同工做,從上到下涉及到DNS層、反向代理層、網關/WEB層、服務層、數據訪問層。
整體指導思想是「多層防線,迷途知返」。每層只要能獲取到足夠的信息,就儘早將請求轉到正確的單元去,若是實在拿不到足夠的信息,就靠下一層。
DNS層照理說感知不到任何業務層的信息,但咱們作了一個優化叫「多域名技術」。好比PC端收銀臺的域名是cashier.alipay.com,在系統已知一個用戶數據屬於哪一個單元的狀況下,就讓其直接訪問一個單獨的域名,直接解析到對應的數據中心,避免了下層的跨機房轉發。例如上圖中的cashiergtj.alipay.com,gtj就是內部一個數據中心的編號。移動端也能夠靠下發規則到客戶端來實現相似的效果。
反向代理層是基於Nginx二次開發的,後端系統在經過參數識別用戶所屬的單元以後,在Cookie中寫入特定的標識。下次請求,反向代理層就能夠識別,直接轉發到對應的單元。
網關/Web層是應用上的第一道防線,是真正能夠有業務邏輯的地方。在通用的HTTP攔截器中識別Session中的用戶ID字段,若是不是本單元的請求,就 forward到正確的單元。並在Cookie中寫入標識,下次請求在反向代理層就能夠正確轉發。
服務層RPC框架和註冊中心內置了對單元化能力的支持,能夠根據請求參數,透明地找到正確單元的服務提供方。
數據訪問層是最後的兜底保障,即便前面全部的防線都失敗了,一筆請求進入了錯誤的單元,在訪問數據庫的時候也必定會去正確的庫表,最多耗時變長,但絕對不會訪問到錯誤的數據。
這麼多的組件要協同工做,必須共享同一份規則配置信息。必須有一個全局的單元化規則管控中心來管理,並經過一個高效的配置中心下發到分佈式環境中的全部節點。
規則的內容比較豐富,描述了城市、機房、邏輯單元的拓撲結構,更重要的是描述了分片ID與邏輯單元之間的映射關係。
服務註冊中心內置了單元字段,全部的服務提供者節點都帶有「邏輯單元」屬性。不一樣機房的註冊中心之間互相同步數據,最終全部服務消費者都知道每一個邏輯單元的服務提供者有哪些。RPC框架就能夠根據須要選擇調用目標。
RPC框架自己是不理解業務邏輯的,要想知道應該調哪一個單元的服務,信息只能從業務參數中來。若是是從頭設計的框架,可能直接約定某個固定的參數表明分片ID,要求調用者必須傳這個參數。可是單元化是在業務已經跑了好多年的狀況下的架構改造,不可能讓全部存量服務修改接口。要求調用者在調用遠程服務以前把分片ID放到ThreadLocal中?這樣也很不優雅,違背了RPC框架的透明原則。
因而咱們的解決方案是框架定義一個接口,由服務提供方給出一個實現類,描述如何從業務參數中獲取分片ID。服務提供方在接口上打註解,告訴框架實現類的路徑。框架就能夠在執行RPC調用的時候,根據註解的實現,從參數中截出分片ID。再結合全局路由規則中分片ID與邏輯單元之間的映射關係,就知道該選擇哪一個單元的服務提供方了。
本文着重介紹了螞蟻金服異地多活單元化架構的原理,以及微服務體系在此架構下的關鍵技術實現。要在工程層面真正落地單元化,涉及的技術問題遠不止此。例如:數據層如何容災?沒法水平拆分的業務如何處理?
螞蟻技術團隊會堅持走技術開放路線,後續還會以不一樣的形式分享相關話題,也歡迎各位讀者留言探討。
完整 PPT 地址:
http://www.sofastack.tech/posts/2018-11-06-01
長按關注,獲取分佈式架構乾貨
歡迎你們共同打造 SOFAStack https://github.com/alipay