15-5 分鐘入門單元化架構

在當今的互聯網業內,不少人對 “單元化” 這個詞已經耳熟能詳。很多大型互聯網系統,諸如阿里系的淘寶、支付寶、網商銀行等,都已經實現了單元化架構,並從中獲益匪淺。還有更多的公司,或在規劃着自己的系統架構向單元化演進,或已經在單元化的建設過程中。

單元化架構能給系統帶來什麼樣的能力,又會帶來哪些額外的成本,該不該決定做單元化,要做的話應該怎麼做。本文用螞蟻金服支付寶系統的單元化架構建設實踐,爲大家勾勒一下單元化的肢體骨架和細枝末節。

爲什麼要做單元化

決策一個系統的整體架構方向,將對這個系統的未來產生深遠影響,並且會有實際的技術改造方面的人力投入。這樣的的決策必須是謹慎的,有依據的。所以,對於要不要單元化這個問題,這裏最想告訴大家的是一個忠告:切勿神話單元化。

回顧支付寶的整個單元化歷程,最初促成這個決策的原因是一件看似無關的事情。早在 2011 年,支付寶系統就開始對核心數據庫做水平拆分,而更早之前,對多個關鍵業務數據庫的垂直拆分就已完成。到了 2013 年時,幾乎所有支付寶核心數據庫,都完成了水平拆分,拆分維度爲用戶,拆分爲 100 個數據分區。此時系統的部署模式是這樣的:

同一個應用的所有節點,都會連接這個業務的所有數據分庫,每個分庫上部署了若干數據分區。任意一個應用節點都可能接收到來自任意用戶的業務請求,然後再根據數據分區規則,訪問對應分庫的數據。

這個架構幫助支付寶系統撐過了 2012 年雙 11,卻無論如何過不了 2013 年大促了,原因在於數據庫連接不夠用了。主流的商業數據庫,連接都不是共享的,就是說一個事務必須獨佔一個連接。而連接卻又是數據庫非常寶貴的資源,不能無限增加。當時的支付寶,面臨的問題是不能再對應用集羣擴容,因爲每加一臺機器,就需要在每個數據分庫上新增若干連接,而此時幾個核心數據庫的連接數已經到達上限。應用不能擴容,意味着支付寶系統的容量定格了,不能再有任何業務量增長,別說大促,很可能再過一段時間連日常業務也支撐不了了。如果 OceanBase 在當時已經成熟,可以很好的解決 Sharding 帶來的連接數瓶頸問題,因爲 OceanBase 是分佈式數據庫,連接可以共享。然而那時並沒有一個合適的經過驗證的共享連接數據庫產品,因此單元化成爲了最好的也是唯一的解決辦法。

根據單元化的特性,每個單元中的應用服務器僅連接本單元的數據分庫,如果有 n 個單元,這就相當於所有數據分庫的連接數立刻降爲原來的 1/n。

從支付寶並沒有倒在 2013 年雙 11 可以知道,這次架構改造是成功的,解決了當初的燃眉之急,並且在落地單元化架構的過程中,螞蟻技術團隊也充分拓展了單元化架構的應用場景和架構的能力,從中獲得了更多的架構紅利,主要表現在以下幾個方面:

雖然結果很好,整個單元化演進的過程也是極其艱辛的。在關鍵業務數據庫都已經水平拆分完畢的情況下,支付寶還是用了將近 1 年的時間,改造了幾乎全站業務系統以支持單元化。除此之外,還花費了相當大的力量改造系統使用的各類中間件,包括微服務框架、消息中間件、調度系統等,還建設了專門的單元化運維監控平臺。無論在架構方案上還是技術產品上,螞蟻技術團隊都積累了大量的經驗。

這個過程帶來的啓示是,單元化確實能帶來不少激動人心的特性,但同時也會讓系統架構變的複雜。這不僅會對系統的運維平臺提出更高要求,也會給業務研發帶來一些理解成本,這個思想非常像業界流行的 Cloud Native 的思想,要充分利用雲架構的好處,還需要讓應用層架構設計遵照一定的範式,而螞蟻逐步將這些範式和能力沉澱到了 PaaS 平臺、中間件和數據庫中,成爲一種原生 (Native) 的能力,爲業務開發提供單元化能力支撐。

所以說,單元化不能被神話,它有利有弊,只是看着它的好處就貿然決定開始的做法不可取。應當充分評估當前的系統現狀,識別其中存在的和潛在的問題,判斷單元化是否能解決以及解決所帶來的成本,選擇最合適的性價比最高的架構來支撐業務發展。當然,如果最後的判斷是需要引入單元化,那麼一定義無反顧,畢竟它產生的價值及其誘人。

能不能單元化

如果您是新建一套系統,那麼恭喜你,你只要考慮這個系統的重要性,即將來是否需要在可擴展性、容災能力、業務連續性、成本控制等方面有很高的要求,如果答案是肯定的,那可以一開始就按照單元化的方式去設計,這套架構完全能支持業務從單機房到同城多機房,再到異地多活機房的平滑演進。但如果是一套老系統,就需要評估一下它是否具備單元化的基礎了。

所謂單元,是指一個能完成所有業務操作的自包含集合,在這個集合中包含了所有業務所需的所有服務,以及分配給這個單元的數據。單元化架構就是把單元作爲系統部署的基本單位,在全站所有機房中部署數個單元,每個機房裏的單元數目不定,任意一個單元都部署了系統所需的所有的應用,數據則是全量數據按照某種維度劃分後的一部分。傳統意義上的 SOA 化(服務化)架構,服務是分層的,每層的節點數量不盡相同,上層調用下層時,隨機選擇節點。

單元化架構下,服務仍然是分層的,不同的是每一層中的任意一個節點都屬於且僅屬於某一個單元,上層調用下層時,僅會選擇本單元內的節點。

一個單元,是一個五臟俱全的縮小版整站,它是全能的,因爲部署了所有應用;但它不是全量的,因爲只能操作一部分數據。能夠單元化的系統,很容易在多機房中部署,因爲可以輕易的把幾個單元部署在一個機房,而把另外幾個部署在其他機房。藉由在業務入口處設置一個流量調配器,可以調整業務流量在單元之間的比例。

從這個對單元的定義和特性描述中,可以推導出單元化架構要求系統必須具備的一項能力:數據分區,實際上正是數據分區決定了各個單元可承擔的業務流量比例。數據分區(shard),即是把全局數據按照某一個維度水平劃分開來,每個分區的數據內容互不重疊,這也就是數據庫水平拆分所做的事情。僅把數據分區了還不夠,單元化的另外一個必要條件是,全站所有業務數據分區所用的拆分維度和拆分規則都必須一樣。若是以用戶分區數據,那交易、收單、微貸、支付、賬務等,全鏈路業務都應該基於用戶維度拆分數據,並且採用一樣的規則拆分出同樣的分區數。比如,以用戶 id 末 2 位作爲標識,將每個業務的全量數據都劃分爲 100 個分區(00-99)。

有了以上兩個基礎,單元化纔可能成爲現實。把一個或幾個數據分區,部署在某個單元裏,這些數據分區佔總量數據的比例,就是這個單元能夠承擔的業務流量比例。選擇數據分區維度,是個很重要的問題。一個好的維度,應該:粒度合適。粒度過大,會讓流量調配的靈活性和精細度受到制約;粒度過小,會給數據的支撐資源、訪問邏輯帶來負擔。足夠平均。按這個維度劃分後,每個分區的數據量應該幾乎一致。以用戶爲服務主體的系統(To C),比如支付寶,通常可以按照用戶維度對數據分區,這是一個最佳實踐。

怎麼做單元化

在真正動手之前,有一個必須要知曉並始終記之在心的事實,完美的單元化是不存在的。從單元化的角度,在一個系統當中實際上存在 3 類數據:

1 可分區數據

可以按照選擇好的維度進行分區的數據,真正能被單元化的數據。這類數據通常在系統業務鏈路中處於核心位置,單元化建設最重要的目標實際上就是把這些數據處理好。比如訂單數據、支付流水數據、賬戶數據等,都屬於這一類型。這類數據在系統中的佔比越高,整體單元化的程度就越高,如果系統中全部都是這樣的數據,那我們就能打造一個完美單元化的架構。不過現實中這種情況存在的可能性幾乎爲零,因爲下面提到的兩類數據,或多或少都會存在於系統當中。

2 全局數據,不被關鍵鏈路業務頻繁訪問

不能被分區的數據,全局只能有一份。比較典型的是一些配置類數據,它們可能會被關鍵鏈路業務訪問,但並不頻繁,因此即使訪問速度不夠快,也不會對業務性能造成太大的影響。因爲不能分區,這類數據不能被部署在經典的單元中,必須創造一種非典型單元用以承載它們。

3 全局數據,需要被關鍵鏈路業務頻繁訪問

乍看與上面一類相似,但兩者有一個顯著的區別,即是否會被關鍵鏈路業務頻繁訪問。如果系統不追求異地部署,那麼這個區別不會產生什麼影響;但如果希望通過單元化獲得多地多活的能力,這僅有的一點兒不同,會讓對這兩類數據的處理方式截然不同,後者所要消耗的成本和帶來的複雜度都大幅增加。

究其原因是異地部署所產生的網絡時延問題。根據實際測試,在網絡施工精細的前提下,相距約 2000 公里的 2 個機房,單向通信延時大約 20ms 左右,據此推算在國內任意兩地部署的機房,之間延時在 30ms 上下。假如一筆業務需要 1 次異地機房的同步調用,就需要至少 60ms 的延時(請求去,響應回)。如果某個不能單元化的數據需要被關鍵業務頻繁訪問,而業務的大部分服務都部署在異地單元中,網絡耗時 60ms 的調用在一筆業務中可能有個幾十次,這就是說有可能用戶點擊一個按鈕後,要等待數秒甚至數十秒,系統的服務性能被大幅拉低。

這類數據的典型代表是會員數據,對於支付寶這類 To C 的系統來說,幾乎所有的業務都需要使用到會員信息,而會員數據卻又是公共的。因爲業務必然是雙邊的,會員數據是不能以用戶維度分區的。

支付寶的單元化架構中,把單元稱之爲 “zone”,並且爲上面所說的 3 類數據分別設計了三種不同類型的 zone:

RZone 是成組部署的,組內 A/B 集羣互爲備份,可隨時調整 A/B 之間的流量比例。可以把一組 RZone 部署的任意機房中,包括異地機房,數據隨着 zone 一起走。

GZone 也是成組部署的,A/B 互備,同樣可以調整流量。GZone 只有一組,必須部署在同一個城市中。

CZone 是一種很特殊的 zone,它是爲了解決最讓人頭疼的異地延時問題而誕生的,可以說是支付寶單元化架構的一個創新。CZone 解決這個問題的核心思想是:把數據搬到本地,並基於一個假設:大部分數據被創建(寫入)和被使用(讀取)之間是有時間差的。

通過對支付寶 RZone 業務的分析發現,時間差假設是成立的,實際上超過 90% 的業務,都對數據被創建和被使用之間的時間間隔要求很低。餘下的那些不能忍受時間差的業務(即要求數據被創建後就必須馬上可用,要不就乾脆不能訪問),則必須進行業務改造,忍受異地訪問延時。

需要哪些支持

前面提到,支付寶系統早已實現了數據水平拆分,並且全站拆分維度一致,在具備了這個重要基礎能力的前提下,仍然舉全站之力用了近一年時間才完成單元化改造,除了因爲要改造業務系統以妥善處理 GZone/CZone 的數據以外,還有一項工作也耗費了大量人力和時間,那就是建設起了一個單元化技術支持平臺。單元化架構增加了構複雜性和運維複雜度,如果沒有這樣一個平臺支撐,很難把如此複雜的一個系統健康的維護起來。所謂單元化技術支持平臺,至少應該包含三方面功能。

一套支持單元化的中間件

支付寶的業務開發因單元化架構而變得複雜、不易理解,而實際上現在看到的複雜性比起它的原本的程度來說已經降低了太多。這其中最大程度屏蔽了單元化細節,讓單元化架構儘量對業務層透明,起到至關重要作用的,就是一整套專門針對單元化而研製的中間件,也即上文提到的原生 (Native) 單元化能力。

比較關鍵的幾個包括,數據訪問層中間件,把數據水平分庫分表的細節隱藏在水面之下,上層業務使用起來跟單庫單表沒什麼區別。更進一步的,數據訪問層能實時動態感知單元化分流規則,根據規則變化決策是否連接某個數據分庫,以及一筆業務是否允許訪問某個數據分庫。可以說單元化的本質就是對數據的邏輯隔離,有這樣一個數據訪問中間件對單元化建設來說是必不可少的,它解耦了業務層對數據層結構的依賴,大大降低了理解成本。

另外更爲重要的是幾個負責信息傳遞的中間件,正是它們讓單元可以成爲單元。這其中有微服務框架、消息中間件等,它們能夠根據單元化規則把系統應用間的服務調用或消息流轉約束在一個邏輯區域內,再配合上數據訪問中間件對數據訪問的約束,就讓這一個個邏輯區域形成了一個個單元。如果有些調用必須跨單元發生,也由它們根據規則執行轉發,不需要業務層關心。

一個規則管理和流量調撥系統

前面多次提到了 “規則” 這個詞,在單元化架構中,規則舉足輕重,業務流量在單元間怎麼分配,哪個單元能訪問哪個數據分庫,某次服務調用能否跨出單元,這些都由規則掌管。可想而知,必須有一個統一的位置來全局唯一的管理這套規則,並在變更時能夠及時準確的的推送給各個執行點,否則不同模塊識別到的規則不同,將會造成全系統信息混亂。

規則管理系統的目的就是成爲這樣一個單元化規則權威持有者,運維人員對規則的所有變更,都在這個系統上操作。它通過某種協議連接着系統中所有需要感知規則的模塊,一旦發生規則變化就實時把新規則內容推送給各個模塊,並識別推送結果,對推送失敗的模塊執行重試,確保規則下發到所有位置。

一個面向單元的發佈部署和監控平臺

單元化後,一個系統被劃分成了數量衆多的邏輯單元,這讓系統發佈換版的粒度更細,試錯成本更低,但也讓發佈這件事情更難做,所以一個能面向單元進行發佈的部署平臺就變的非常必要。這個部署平臺能夠以單元爲維度執行發佈,單元間可以互不影響的獨立部署。

同時,平臺需要有能力統一編排和控制不同單元的部署進程,從而能夠實現基於單元的全站藍綠髮布等高階功能。

此外,監控系統要求能夠細化到單元粒度展示監控信息和發送報警,以協助判斷每個單元中的系統健康程度,爲快速執行流量切換以隔離故障等操作提供依據。

以上幾項是一個單元化技術支持平臺必須要具備的能力,在支付寶的單元化進程中,已經沉澱出了完整的這樣一套平臺,並在逐步產品化爲具備完整單元化能力的 SOFA 平臺和 OceanBase 數據庫,搭載在螞蟻金融雲上對外輸出。在幾年中先後支持了螞蟻保險、網商銀行的單元化改造,在未來也將爲更多的金融生態合作伙伴提供服務。

參考 金融電子化雜誌 2016年12期 《金融級分佈式交易的技術路徑》 程立

本文由 Readfog 進行 AMP 轉碼,版權歸原作者所有。
來源https://mp.weixin.qq.com/s/3sKNzPxwUaaIlOZQ51jAEA