1. 程式人生 > 其它 >SET化架構與RabbitMQ基礎元件封裝

SET化架構與RabbitMQ基礎元件封裝

一、網際網路架構遇到的問題 

  隨著大型網際網路公司業務的多元化發展,就拿滴滴、美團等大廠來講,如滴滴打車、單車、外賣、酒店、旅行、金融等業務持續高速增長,單個大型分散式體系的叢集,通過加機器+叢集內部拆分(kv、mq、Mysql等),雖然具備了一定的可擴充套件性。但是,隨著業務量的進一步增長,這個叢集規模琢漸變的巨大,從而一定會在某個點達到效能瓶頸,無法滿足擴充套件性需要,並且大叢集核心服務出現問題,會影響全網所有使用者。

  以滴滴打車、美團外賣舉例來說:

    打車業務體量巨大,尤其在早晚高峰期。全年訂單量已越10億。

    外賣業務體量龐大,目前單量突破1700w/天,對應如此龐大的單個大型分散式叢集,會面臨一下問題:

      1、容災問題

      2、資源擴充套件性問題

      3、大叢集拆分問

  容災問題

    核心服務(比如訂單服務)掛掉,會影影響全網所有的使用者,導致整個業務不可用;

    資料庫主庫集中在一個IDC,主機房掛掉,會影響全網所有使用者,整個業務無法快速切換和恢復

  資源擴充套件問題

    單IDC的資源(機器、網路頻寬等)已經沒法滿足,擴充套件IDC時,存在跨機房訪問延時問題(增加異地機房,時延問題嚴重)

    資料庫主庫單點,連線數有限,不能支援應用程式的持續發展;

  大叢集拆分問題

    核心問題:分散式叢集規模擴大後,會響應的帶來資源擴充套件、大叢集拆分以及容災問題

    所有處於對業務擴充套件性以及容災需求的考慮,我們需要一套從底層架構徹底解決問題的方案,業界主流解決方案:單元化架構方案

二、SET單元化架構方案

(一)同城 "雙活" 架構介紹

  同城雙活是在同城或相近區域內建立兩個機房。同城雙機房距離比較近,通訊線路質量較好,比較容易實現資料的同步複製 ,保證高度的資料完整性和資料零丟失。同城兩個機房各承擔一部分流量,一般入口流量完全隨機,內部RPC調用盡量通過就近路由閉環在同機房,相當於兩個機房映象部署了兩個獨立叢集,資料仍然是單點寫到主機房資料庫,然後實時同步到另外一個機房。下圖展示了同城雙活簡單部署架構,當然一般真實部署和考慮問題要遠遠比下圖複雜。

      

  1、服務路由 zk叢集:

    每個機房都部署一個zk叢集,機房之間zk資料進行實時雙向同步,每個機房都擁有所有機房zk註冊資料。 路由方案:條件路由 > 就近路由 > 跨機房路由,儘量避免跨機房呼叫。 訂閱方案:consumer訂閱所有機房服務,provider只向該機房zk叢集進行註冊。

  2、資料雙活 MySQL:

    採用MHA部署方案,主從半同步方案保證資料一致性。讀寫分離、讀就近路由到機房內資料節點、寫路由到master節點所在機房。 Redis: Redis cluster模式主從同步,就近讀、寫路由主節點機房。採用原生主從同步跨機房寫效能較低,也可以依靠CRDT理論構建多節點雙向同步,實現機房就近讀寫,但是整體實現較為複雜。

   3、同城雙活方案評估

    優勢:

      (1)服務同城雙活,資料同城災備,同城不丟失資料情況下跨機房級別容災。

      (2)架構方案較為簡單,核心是解決底層資料雙活,由於雙機房距離近,通訊質量好,底層儲存例如mysql可以採用同步複製,有效保證雙機房資料一致性。

    劣勢:

      (1)資料庫寫資料存在跨機房呼叫,在複雜業務以及鏈路下頻繁跨機房呼叫增加響應時間,影響系統性能和使用者體驗。

      (2)保證同城市地區容災,當服務所在的城市或者地區網路整體故障、發生不可抗拒的自然災害時候有服務故障以及丟失資料風險。對於核心金融業務至少要有跨地區級別的災備能力。

      (3)服務規模足夠大(例如單體應用超過萬臺機器),所有機器連結一個主資料庫例項會引起連線不足問題。

(二)兩地三中心架構介紹

  所謂兩地三中心是指 同城雙中心 + 異地災備中心。異地災備中心是指在異地的城市建立一個備份的災備中心,用於雙中心的資料備份,資料和服務平時都是冷的,當雙中心所在城市或者地區出現異常而都無法對外提供服務的時候,異地災備中心可以用備份資料進行業務的恢復。

      

  兩地三中心方案評估:

    優勢:

      (1)服務同城雙活,資料同城災備,同城不丟失資料情況下跨機房級別容災。

      (2)架構方案較為簡單,核心是解決底層資料雙活,由於雙機房距離近,通訊質量好,底層儲存例如mysql可以採用同步複製,有效保證雙機房資料一致性。

      (3)災備中心能防範同城雙中心同時出現故障時候利用備份資料進行業務的恢復。

    劣勢:

      (1)資料庫寫資料存在跨機房呼叫,在複雜業務以及鏈路下頻繁跨機房呼叫增加響應時間,影響系統性能和使用者體驗。

      (2)服務規模足夠大(例如單體應用超過萬臺機器),所有機器連結一個主資料庫例項會引起連線不足問題。

      (3)出問題不敢輕易將流量切往異地資料備份中心,異地的備份資料中心是冷的,平時沒有流量進入,因此出問題需要較長時間對異地災備機房進行驗證。

  同城雙活和兩地三中心建設方案建設複雜度都不高,兩地三中心相比同城雙活有效解決了異地資料災備問題,但是依然不能解決同城雙活存在的多處缺點,想要解決這兩種架構存在的弊端就要引入更復雜的解決方案去解決這些問題。

三、異地多活與Set化部署

(一)異地多活

  異地多活指分佈在異地的多個站點同時對外提供服務的業務場景。異地多活是高可用架構設計的一種,與傳統的災備設計的最主要區別在於“多活”,即所有站點都是同時在對外提供服務的。

  1、異地多活挑戰

    (1)應用要走向異地,首先要面對的便是物理距離帶來的延時。如果某個應用請求需要在異地多個單元對同一行記錄進行修改,為滿足異地單元間資料庫資料的一致性和完整性,需要付出高昂的時間成本。

    (2)解決異地高延時即要做到單元內資料讀寫封閉,不能出現不同單元對同一行資料進行修改,所以我們需要找到一個維度去劃分單元。

    (3)某個單元內訪問其他單元資料需要能正確路由到對應的單元,例如A使用者給B使用者轉賬,A使用者和B使用者資料不在一個單元內,對B使用者的操作能路由到相應的單元。

    (4)面臨的資料同步挑戰,對於單元封閉的資料需全部同步到對應單元,對於讀寫分離型別的,我們要把中心的資料同步到單元。

  2、單元化

    所謂單元(下面我們用RZone代替),是指一個能完成所有業務操作的自包含集合,在這個集合中包含了所有業務所需的所有服務,以及分配給這個單元的資料。

    單元化架構就是把單元作為系統部署的基本單位,在全站所有機房中部署數個單元,每個機房裡的單元數目不定,任意一個單元都部署了系統所需的所有的應用。單元化架構下,服務仍然是分層的,不同的是每一層中的任意一個節點都屬於且僅屬於某一個單元,上層呼叫下層時,僅會選擇本單元內的節點。

      

    選擇什麼維度來進行流量切分,要從業務本身入手去分析。例如電商業務和金融的業務,最重要的流程即下單、支付、交易流程,通過對使用者id進行資料切分拆分是最好的選擇,買家的相關操作都會在買家所在的本單元內完成。對於商家相關操作則無法進行單元化,需要按照下面介紹的非單元化模式去部署。當然使用者操作業務並非完全能避免跨單元甚至是跨機房呼叫,例如兩個買家A和B轉賬業務,A和B所屬資料單元不一致的時候,對B進行操作就需要跨單元去完成,後面我們會介紹跨單元呼叫服務路由問題。

  3、非單元化應用和資料

    對於無法單元化的業務和應用,會存在下面兩種可能性:

    (1)延時不銘感但是對資料一致性非常銘感,這類應用只能按照同城雙活方式部署。其他應用呼叫該類應用的時候會存在跨地區呼叫可能性,要能容忍延時,這類應用我們稱為MZone應用。

    (2)對資料呼叫延時銘感但是可以容忍資料短時間不一致,這類應用和資料可以保持一個機房一份全量資料,機房之間以增量的方式實時同步,這類應用我們暫時稱為QZone。

    加上兩種以上非單元化應用我們的機房部署可能是下面這樣,每個機房有兩個RZone,MZone保持類似兩地三中心部署方式,異地機房呼叫MZone服務需要跨地區、跨機房呼叫。而QZone每個機房都保持一份完整資料,機房之間通過資料鏈路實時相互同步。

      

  4、請求路由

  (1)Api入口閘道器
    為了保證使用者請求能正確進入自己所屬單元,每一個機房都會部署流量入口閘道器叢集。當用戶請求到達進入機房內最先進入到流量閘道器,流量閘道器能感知全域性的流量分片情況,計算使用者所處流量單元並將流量轉發到對應的單元,這樣就可以將使用者請求路由到對應的單元內。

      

    採用GateWayr轉發方式可以確定使用者單元從而將使用者流量路由到正確位置,但是HTTP轉發也會造成一定效能損耗。為了減少HTTP流量轉發量,可以在在使用者請求返回的時候在cookie上帶上該使用者的路由標識資訊。當用戶下次在請求的時候請求的時候可以提前獲取到路由標識直接請求到對應的單元,這種方式可以大幅度減少HTTP流量轉發。

  (2)服務路由

    雖然應用已經進行了單元化,但是依然無法避免跨單元呼叫,例如A使用者給B使用者轉賬,如果A和B所處單元不同,對B使用者操作需要跨單元去呼叫,這個時候需要能將請求路由到B使用者資料所在的單元。異地多活情況下RPC、MQ、DB等等中介軟體都需要提供路由能力,將請求能正確路由到對應的單元。下面以RPC路由為例說明異地多活下中介軟體是如何進行路由的,對於其他中介軟體(資料庫中介軟體、快取中間、訊息中介軟體等)也是一樣方法。

public interface ManualInterventionFacade {
    @ZoneRoute(zoneType= ZoneType.RZone,uidClass = UidParseClass.class)
    ManualRecommendResponse getManualRecommendCommodity(ManualRecommendRequest request);
}  

    上面展示了多活下的RPC介面定義方法,需要註明該RPC型別,如果是RZone服務必須要提供解析uid方法。下圖展示了RPC註冊中心路由定址過程,和同城雙活有一定的差異性。

      

  5、資料同步
  (1)QZone型別資料:這種資料只需要保證最終一致性,對於短暫不一致無影響,但是對延時非常銘感,例如一些演算法、風控、配置等資料。這類資料基本上都是每個機房部署一套QZone,然後機房之間相互同步。

      

  (2)MZone資料:這類資料對一致性非常銘感,不能出現不一致,只能採用同城雙活部署方式,業務需要能容忍異地呼叫延時。

      

  (3)RZone資料:這類資料每個Zone都有自己的主節點,如果資料不在該單元內需要路由到對應的節點去寫。這類資料部署情況像下面這樣

     

  6、方案評估
    優勢:

      容災能力大幅度提高,服務異地多活,資料異地多活。

      理論上系統服務可以水平擴充套件,異地多機房突破大幅度提升整體容量,理論上不會有效能擔憂。

      將使用者流量切分到多個機房和地區去,有效能減少機房和地區級別的故障影響範圍。

    劣勢

      架構非常複雜,部署和運維成本很高,需要對公司依賴的中介軟體、儲存做多方面能力改造。

      對業務系統有一定的侵入性,由於單元化影響服務呼叫或者寫入資料要路由到對應的單元,業務系統需要設定路由標識(例如uid)。

      無法完全避免跨單元、跨地區呼叫服務,例如上面的轉賬業務。我們要做的是盡力避免跨地區的服務呼叫。

(二)Set化部署

   Set化部署實際就是在異地多活的基礎上衍生出來的。

      

  解決容災問題: UnitA一套業務的核心元件,比如網購,從加入購物車到下單,經過A、B、C、D等步驟,全部部署到UnitA的一個機房中,UnitB和UnitC是UnitA的備份,如果UnitA的服務或MQ發生故障,就會路由到UnitB或UnitC中 非核心的業務元件部署到center中 解決擴充套件問題: UnitA可以是旅遊,UnitB可以是外賣,將來還可以擴充套件

  相關概念

    流量路由:按照特殊的key(通常為userid)進行路由,判斷某次請求該路由到中心叢集還是單元化叢集

    中心叢集:為進行單元化改造的服務(通常不在核心交易鏈路)成為中心叢集,跟當前架構儲存一致

    單元化叢集: 每個單元化叢集只負責本單元內的流量處理,以及實現流量拆分及故障隔離。每個單元化叢集前期只儲存本單元產生的交易資料,後續會做雙向資料同步,實現容災切換需求

    中介軟體(RPC、KV、MQ等)

      RPC:對於SET服務,呼叫封閉在SET內;對於非SET服務,沿用現有路由邏輯

      KV:支援分SET的資料產生和查詢

      MQ:支援分SET的訊息生產和消費

    資料同步:全域性資料(資料量小且變化不大,比如商家的菜品資料)部署在中心叢集,其他單元化叢集同步全域性資料到本單元化內。未來演變為異地多活架構時,各單元化叢集資料需要進行雙向同步來實現容災需要

  SET化路由策略及其能力

    異地容災: 通過SET化架構的流量排程能力,將SET分別部署到不停地區的資料中心,實現跨地區容災支援

    高效本地化服務:利用前端位置資訊採集和域名解析策略,將流量路由由最近的SET,提供最高效的本地化服務 比如O2O場景天然具有本地生產,本地消費的特點,更加需要SET化支援

    集裝箱式擴充套件 SET的封裝性支援更靈活的部署擴充套件性,比如SET一鍵建立/下線,SET一鍵釋出等(比如docker)

(三)RabbitMQ-SET化架構實現

  SET化訊息中介軟體架構實現(RabbitMQ雙活)

      

  使用RabbitMQ非同步訊息通訊外掛 Federation(節點和節點、叢集和叢集之間通訊) 安裝與配置:

  安裝外掛

rabbitmq-plugins enable rabbitmq_federation
rabbitmq-plugins enable rabbitmq_federation_management

  備註:當你再一個cluster鍾使用了federation外掛,所有在叢集中的 nodes都需要安裝federation外掛

  使用RabbitMQ通訊外掛Rederation:

    Federation外掛是一個在不需要cluster進行資料同步的(選擇一個cluster中的節點和另一個cluster節點同步),而brokers之間傳輸訊息的高新效能外掛。

    Federation外掛可以在brokers或者cluster之間傳輸訊息,連結的雙方可以使用不同的users和virtual hosts、或者雙方的rabbitmq和erlang版本不一致,federation外掛使用AMQP協議通訊,可以接受不連續的傳輸。

  SET化配置規則:

    1、Federation Exchanges,可以看成Downstream(82節點)從Upstream(81節點)主動拉取訊息,並不是拉取所有訊息,必須是在Downstream上已經明確定義Bindings關係的Exchange,也就是有實際的物理Queue來接收訊息,才會從Upstream拉取訊息到Downstream。使用AMQP協議實施代理間通訊,Downstream會將繫結關係組合在一起,繫結/解綁命令將傳送到Upstream交換機。

    2、經過配置後,Upstream節點已經可以把訊息直接通過Federation Exchanges路由給我們的Downstream節點,然後進行消費。

也就是說可以實現訊息的轉發,接下來也可以在Upstream新增具體的佇列去進行消費Federation Exchanges裡的訊息,我們一條訊息分別傳送到2個RabbitMQ叢集並且消費,這樣我們可以實現SET化的關鍵要素,就是叢集間的訊息同步了。

    3、可以根據自己的業務規則去規劃不同的叢集去監聽不同的訊息佇列,從而達到SET化的手段,保障了效能、可靠性、資料一致性。

  MQ元件實現思路和架構設計方案

      

  MQ元件需要實現功能點

    支援訊息高效能序列化轉換、非同步化傳送訊息

    支援訊息生產例項與消費例項的連結池化、快取化,提升效能

    支援可靠性投遞訊息,保障訊息的100%不丟失

    支援消費端的冪等操作,避免消費端重複消費的問題

    支援迅速訊息傳送模式,在一些日誌收集、統計分析等需求下可以保證高效能,超高吞吐量(可忽略100%投遞)

    支援延遲訊息模式,訊息可以延遲傳送,指定延遲時間,用於某些延遲檢查、服務限流場景

    支援事務訊息,且100%保障可靠性投遞,在金融行業單筆大金額操作是會有此類需求

    支援順序訊息,保證消費送達消費端的前後順序,例如下訂單,再送積分、優惠券等複合性操作

    支援訊息補償,重試,以及快速定位異常/失敗訊息

    支援叢集訊息負載均衡,保障訊息落到具體SET叢集的負責均衡

    支援訊息路由策略,指定某些訊息路由到指定的SET叢集

------------------------------------------------------------------
-----------------------------------------------------------
---------------------------------------------
朦朧的夜 留筆~~