1. 程式人生 > >【架構】一、服務單元化

【架構】一、服務單元化

轉載:https://mp.weixin.qq.com/s/jfbHvEMSZtgXis3AtSOZyw

一、為什麼要做單元化

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

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

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

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

二、能不能單元化

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

所謂單元,是指一個能完成所有業務操作的自包含集合,在這個集合中包含了所有業務所需的所有服務,以及分配給這個單元的資料。單元化架構就是把單元作為系統部署的基本單位,在全站所有機房中部署數個單元,每個機房裡的單元數目不定,任意一個單元都部署了系統所需的所有的應用,資料則是全量資料按照某種維度劃分後的一部分。 傳統意義上的 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(Region Zone):最符合理論上單元定義的 zone,每個 RZone 都是自包含的,擁有自己的資料,能完成所有業務。

  • GZone(Global Zone):部署了不可拆分的資料和服務,這些資料或服務可能會被RZone依賴。GZone 在全域性只有一組,資料僅有一份。

  • CZone(City Zone):同樣部署了不可拆分的資料和服務,也會被 RZone 依賴。跟 GZone 不同的是,CZone 中的資料或服務會被 RZone 頻繁訪問,每一筆業務至少會訪問一次;而 GZone 被 RZone 訪問的頻率則低的多。

 

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

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

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

  • 把資料搬到本地:在某個機房建立或更新的公共資料,以增量的方式同步給異地所有機房,並且同步是雙向的,也就是說在大多數時間,所有機房裡的公共資料庫,內容都是一樣的。這就使得部署在任何城市的 RZone,都可以在本地訪問公共資料,消除了跨地訪問的影響。整個過程中唯一受到異地延時影響的,就只有資料同步,而這影響,也會被下面所說的時間差抹掉。

  • 時間差假設:舉例說明,2 個使用者分屬兩個不同的 RZone,分別部署在兩地,使用者 A 要給使用者 B 做一筆轉賬,系統處理時必須同時拿到 A 和 B 的會員資訊;而 B 是一個剛剛新建的使用者,它建立後,其會員資訊會進入它所在機房的公共資料庫,然後再同步給 A 所在的機房。如果 A 發起轉賬的時候,B 的資訊還沒有同步給 A 的機房,這筆業務就會失敗。時間差假設就是,對於 80% 以上的公共資料,這種情況不會發生,也就是說 B 的會員資訊建立後,過了足夠長的時間後,A 才會發起對 B 的轉賬。

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

 三、需要哪些支援

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

1、一套支援單元化的中介軟體

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

 

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

 

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

 

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

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

 

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

 

一個面向單元的釋出部署和監控平臺