(圖片源自網絡)java
從以前的描述,已經能夠看出咱們會採用RPC over MQ的方式作底層實現,相似方法調用的通訊語義會在client和server兩端的庫中做封裝。python
從後端實現來講,咱們用三套後端來知足不一樣的場景:mysql
一、對大中型分佈式系統環境,rabbitmq是很是很是好的支撐。原本覺得須要本身作不少工做,但深刻了解rabbitmq,尤爲是其支持的amqp協議,發現其實前人在不少思路方面已經栽好樹了,好比一致性hash和跨機房等功能,都有相應的插件支撐。
因此,rabbitmq成爲babel的第一選擇,能夠實現咱們規劃功能的全集,咱們的SAAS平臺都是使用的rabbitmq。nginx
二、對少許機器而言,redis提供了很是輕量級的隊列支持,能夠提供有限但必要的功能。
redis沒有相似amqp這樣的協議,須要手動做些封裝。咱們在單機環境使用redis,儘量減小部署和運維的開銷。web
三、對性能有苛刻要求的能夠用zeromq後端去作tcp直連。前兩種mq的方式畢竟會多幾跳中轉,但在路由的靈活性和通信語義的提供更豐富的選擇,並且在大數據量的處理上,吞吐量和平均延時並不會比直連差不少。
但爲了知足特殊環境的須要,咱們預留了zeromq的實現選擇,最近因爲新的需求,正在準備完成這塊拼圖。zeromq的缺點在於須要中央配置系統來幫忙完成路由功能。redis
每種後臺實現對使用者透明,能夠經過配置進行透明切換,可是有些高級通訊語義redis和zeromq不支持。sql
若是對應到web service 三要素:數據庫
UDDI:傳統的rpc或者SOA都是去註冊中心發現遠端對象,而後客戶端主動推送數據到服務端。mq的方式幫咱們省卻了自注冊(訂閱實現)和服務發現(mq本身路由)的問題。json
WSDL:目前咱們經過json的方式來描述rpc的service端,包括機房所在地,持久化,超時等等。後端
SOAP:目前使用json的方式,咱們定義了一個統一的Event對象來封裝一些固定屬性,其餘都在一個map中。由業務代碼本身去打包拆包。固然這種方式在大團隊中不適合。
大量的工做能夠利用mq來實現,咱們的工做主要體如今通信語義的封裝。
❶ client端訪問模式語義
queue語義(消息有去無回):傳統的數據輸送。
簡單rpc(消息一去一回):傳統的rpc和soa都適用於此場景。
輪詢rpc(消息一去多回):一個request出去,多個response回來,適合於輪詢下游節點的場景。
分佈式存儲rpc(一個request消息,只要有最小條件的response消息就返回):適合於分佈式場景下的讀寫。例如三個拷貝,須要至少兩份讀成功或者至少兩份寫成功,等等。目前此方式咱們尚未用到。
❷ 消息分發語義(實際上這裏的行爲參考了storm的部分功能)
Shuffle:一個消息,會有多個接收者,這些接收者根據本身的資源狀況去搶佔同一來源的消息,達到load balance的目的。實際上咱們經過shuffle來作集羣功能,省掉了LB的引入。並且性能強的拉多點,性能弱的拉少點,變相的實現了根據消費者的性能來作分發。
Sharding:與shuffle相似,也是多個consumer來分享消息,不過根據消息的key,保證在拓撲環境不發生改變的狀況下,同一個key始終指向同一個消費者,爲後續分佈式系統的搭建打下基礎
topic語義:全部消費者都會獲得消息的一個拷貝。常見的mq語義
topic+shffule:一組消費者做爲一個總體來訂閱topic,獲得全部的消息,每一個訂閱團體內部經過shuffle的形式去分攤。這種很是適合用大數據環境下,有不一樣類型的數據消費者,每個類型的消費者有各自的實例數。
topic+sharding:一組消費者做爲一個總體來訂閱topic,獲得全部的消息,每一個訂閱團體內部經過sharding的形式去分攤。相似於topic shuffle,只是換用了sharding這種更嚴格的語義。
❸ 數據的封裝語義。用於指定babel上承載數據的特徵,例如:
batch operation:用於指定是否進行批處理傳遞。
Security:暫無使用。
Compressing:指定payload壓縮方法,目前只作了gzip。
機房:指定了機房所在地,框架會根據生產者和消費者的不一樣自動作跨機房的處理。
持久化:指定在無消費者的狀況下,是否須要持久化存儲,以及最大大小。
超時:指定消息的最大有效時間,超過的消息將會被丟棄。
其餘。
對於以上的通信語義,首先須要去底層的mq基礎裏面找到相對應的設施來作封裝,好比對於queue語義做個簡單舉例:
而對於像rpc,輪詢,以及其餘功能,則須要相應的代碼來支撐,好比:
response的返回能夠經過client監聽queue來實現
response和request的串聯能夠經過自定義的requestid來實現
輪詢能夠經過client 端等待多個消息返回,能夠用condition來作同步
……
這裏有很多細節,暫不在本文中進行展開了。
因爲幾種mq都有python和java的客戶端,因此咱們工做會輕鬆不少,只是一樣的邏輯須要寫兩份,好處仍是很明顯的,使得咱們的系統語言無關,方便根據當前人員的技能狀況來分配開發任務。
不過這裏不得不吐槽python的併發,雖然有心理準備,沒想到是如此之差。當使用多線程的時候,性能降低的厲害,比java要差兩個數量級,因此咱們python版作了同步(多線程),異步(協程)兩個版本。異步版本的性能尚可接受;咱們已經準備在build本身的異步python框架,來覆蓋咱們的應用程序。
Babel的一大特點是跨機房通訊,來幫助咱們解決不一樣數據中心的通訊問題,使得業務開發人員只用關心其所負責的業務便可。跨機房的通訊和本機房的通訊有所不一樣:
本地機房的通訊講究高吞吐量,rpc類訪問會要求低延時。
跨機房通訊必須應對複雜的網絡狀況,要求數據不丟,rpc類通訊能夠接受相對較高的延時。
實現上,咱們利用了federation插件,當rpc框架發現存在跨機房訪問時,會自動啓用相應的路由,下圖是同事畫的兩種狀況下的路由,綠線是本地調用,紅線是跨機房調用。
對於業務應用而言,使用上是基本透明的,藉助於mq的中轉,在多機房環境下它也能夠玩轉除數據推送外的RPC類訪問語義。
1 分佈式數據計算平臺
首先是咱們的私有化大數據平臺warden。warden集數據採集、轉換、分發、實時分析和展現等功能於一體,但願從客戶的原始網絡流量中找出異常點和風險事件。
此圖是一個warden分佈式版本的草圖:
採集的數據經過topic sharding類分配給不一樣類型的消費者,好比ES writer,Mysql writer,實時分析引擎;每種消費者能夠有不一樣的實例數。
實時計算引擎經過sharding來分攤流量,達到scale out的效果。
rule引擎須要數據的時候一樣經過簡單的sharding的rpc就能夠得到相應的數據了。
規則引擎的結果能夠經過topic來進行再分發。
目前只有實時引擎是java的,由於性能要求苛刻,其餘模塊採用python開發。
上圖只是個例子,來簡要說明babel是如何支撐一個分佈式數據計算系統的。實際的系統使用了更多的語義,也更加的複雜。不過藉助於Babel的協助,整個系統在實現和運維上已經很大程度上減輕了複雜程度。
2 水平擴展的web系統
第二個例子是咱們曾經作過的SAAS平臺私有化案例,是咱們早期SAAS平臺的極簡版本。
圖畫的略凌亂了些:
系統主架構是用haproxy作負載均衡,發到咱們的兩臺主機上。
兩臺主機內部徹底相同,右邊主機內部組件沒有畫全。
每臺主機有內部的nginx,load balance到本機器內部的諸多python web server 上。
python web server直接讀取本地的nosql數據庫。
寫數據時,因爲寫請求sharding到兩臺機器上,因此咱們有個topic的service來處理nosql數據寫入,保證每一個寫入操做都寫到兩臺機器上,每臺機器的nosql始終存有全量的最新數據。
因爲客戶要求落地關係型數據庫,因此經過shuffle再將寫請求分散開,統一寫入mysql中。
在這個系統中,咱們成功的利用babel創建了本身的一致性框架,從而避免了去使用db作數據一致性;同時因爲對等的服務器架構,在部署維護上省掉了不少事情。
整個框架,咱們都準備了統一的metrics體系去作監控和報警(實際上metrics系統自己的跨機房屬性反而是經過babel來實現),詳盡的監視了RPC的某個環節,以前有過咱們監控的文章,這裏就不重複了。