白楊 2019-03程序員
baiy.cn算法
Copyright (C) 2016 - 2019 Bai Yang, baiy.cn / baiyang.name, baiyang@gmail.com, All Rights Reserved數據庫
AIO vs. SOA後端
長久以來,服務器端的高層架構大致被區分爲對立的兩類:SOA(Service-oriented architecture)以及 AIO(All in one)。SOA 將一個完整的應用分割爲相互獨立的服務,每一個服務提供一個單一標準功能(如:會話管理、交易評價、用戶積分等等)。服務間經過 RPC、WebAPI 等 IPC 機制暴露功能接口,並以此相互通訊,最終組合成一個完整的應用。api
而 AIO 則相反,它將一個應用規約在一個獨立的總體中,SOA 中的不一樣服務在 AIO 架構下呈現爲不一樣的功能組件和模塊。AIO應用的全部組件一般都運行在一個地址空間(一般是同一進程)內,全部組件的代碼也經常放在同一個產品項目中一塊兒維護。緩存
AIO 的優點是部署簡單,不須要分別部署多個服務,併爲每一個服務實現一套高可用集羣。與此同時,因爲可避免網絡傳輸、內存拷貝等 IPC 通訊所帶來的大量開銷,所以 AIO 架構的單點效率一般遠高於 SOA。服務器
另外一方面,因爲 AIO 架構中組件依賴性強,組件間常常知曉並相互依賴對方的實現細節,所以組件的可重用性及可替換性差,維護和擴展也較困難。特別是對於剛加入團隊的新人來講, 面對包含了大量互相深度耦合之組件和模塊的"巨型項目",經常須要花費大量努力、經歷不少挫折而且犯不少錯誤才能真正接手。而即便對於老手來講,因爲模塊 間各自對對方實現細節錯綜複雜的依賴關係,也容易發生在修改了一個模塊的功能後,莫名奇妙地影響到其它看起來絕不相干功能的狀況。微信
與此相反,SOA 模型部署和配置複雜——現實中,一個大型應用經常被拆分爲數百個相互獨立的服務,《程序員》期刊中的一份公開發表的論文顯示,某個國內 "完全擁抱" SOA 的著名(中國排名前5)電商網站將他們的 Web 應用拆分紅了一千多個服務。能夠想象,在多活數據中心的高可用環境內部署成百上千個服務器集羣,而且配置他們彼此間的協做關係是多大的工做量。最近的協程網絡癱瘓事件也是由於上千個服務組成的龐大 SOA 架構致使故障恢復緩慢。網絡
除了部署複雜之外,SOA 的另外一個主要缺點就是低效——從邏輯流的角度看,幾乎每次來自客戶端的完整請求都須要依次流經多個服務後,才能產生最終結果並返回用戶端。而請求(經過消息中間件)每"流經"一個服務都須要伴隨屢次網絡 IO 和磁盤訪問,多個請求可累計產生較高的網絡時延,使用戶請求的響應時間變得不可肯定,用戶體驗變差,並額外消耗大量資源。數據結構
混亂的SOA 依賴關係(圖片來自互聯網)
此外,不管是每一個 Service 各自鏈接不一樣的 DBMS 仍是它們分別接入同一個後端分佈式 DBMS 系統,實現跨服務的分佈式事務支持工做都要落到應用層開發者手中。而分佈式事務(XA)自己的實現複雜度恐怕就以超過大部分普通應用了,更況且還須要爲分佈式事務加上高可靠和高可用保證——須要在單個數據切片上使用 Paxos/Raft 或主從+Arbiter之類的高可用、強一致性算法,同時在涉及多個數據切片的事務上使用 2PC/3PC 等算法來保證事務的原子性。所以 SOA 應用中的跨 Service 事務基本都只能退而求其次,作到最終一致性保證,即使如此,也須要增長大量的額外工做——在稍微複雜點的系統裏,高可用,並能在指定時間內可靠收斂的最終一致性算法實現起來也不是那麼容易。
與此同時,大部分 SOA 系統還常常須要使用消息中間件來實現消息分發服務。若是對消息中間件的可用性(部分節點故障不會影響正常使用)、可靠性(即便在部分節點故障時,也確保消 息不丟失、不重複、並嚴格有序)、功能性(如:發佈/訂閱模型、基於輪轉的任務分發等)等方面有所要求的話,那麼消息中間件自己也容易成爲系統的瓶頸。
SOA 架構的優勢在於其高內聚、低耦合的自然特性。僅經過事先約定的 IPC 接口對外提供服務,再配合服務間隔離(一般是在獨立節點中)運行的特質,SOA 架構劃分出了清晰的接口和功能邊界,所以能夠被很是容易地重用和替換(任何實現了兼容IPC接口的新服務均可替換已有的老服務)。
從軟件工程和項目管理的視角來看,因爲每一個服務自己一般有足夠高的內聚性,而且單個服務實現的功能也較獨立,所以相對於 AIO 意大利麪式的,相互交織的結構來講,SOA 的服務很是便於維護——負責某一服務的開發人員只須要看好本身這一畝三分地便可,只要保持服務對外提供的 API 沒有發生不兼容的變化,就不須要擔憂修改代碼、替換組件等工做會影響到其它"消費者"。
同時,由多個獨立服務所組成的應用也更容易經過加入新服務和從新組合現有服務來進行功能變動和擴展。
μSOA 架構
在經歷了大量實際項目中的權衡、思索和實踐後,我逐步定義、實現和完善了可以兼二者之長的 "μSOA"(Micro SOA)架構。在 μSOA 架構中,獨立運行的服務被替換成了支持動態插拔的跨平臺功能插件(IPlugin);而插件則經過(並僅可經過)API Nexus 來動態地暴露(註冊)和隱藏(註銷)自身所提供的功能接口,同時也使用 API Nexus 來消費其它插件提供服務。
μSOA 徹底繼承了 SOA 架構高內聚、低耦合的優勢,每一個插件如獨立的服務同樣,有清晰的接口和邊界,可容易地被替換和重用。在可維護性上,μSOA 也與 SOA 徹底一致,每一個插件均可以被單獨地開發和維護,開發人員只須要管好本身維護的功能插件便可。經過加入新插件以及對現有功能插件的從新組合,甚至可比 SOA 模式更容易地對現有功能進行變動和擴展。
而在性能方面,因爲全部功能插件都運行在同一個進程內,所以經過 API Nexus 的相互調用不須要任何網絡 IO、磁盤訪問和內存拷貝,也沒有任何形式的其它 IPC 開銷,所以其性能和效率都可與 AIO 架構保持在相同量級。
與此同時,μSOA 的部署與 AIO 一樣簡單——部署在單個節點便可使用,只需部署一個集羣便可實現高可用和橫向擴展。在配置方面也遠比 SOA 簡單,僅須要比 AIO 應用多配置一個待加載模塊列表而已,而且這些配置也可經過各類配置管理產品來實現批量維護。簡單的部署和配置過程不但簡化了運營和維護工做,也大大方便了開發和測試環境的構建。
此外,μSOA 也在極大程度上避免了對消息中間件的依賴,取而代之的是經過 API Nexus 的直接API調用;或是在須要削峯填谷的場合中,使用由內存零拷貝和無鎖算法高度優化的線程間消息隊列。這一方面大大增長了吞吐,避免了延遲,另外一方面也避免了部署和維護一個高可用的消息分發服務集羣所帶來的巨大工做量——μSOA 集羣內的節點間協做和協調通訊需求已被將至最低,對消息分發的可靠性、可用性和功能性都沒有過高要求。在多數狀況下,使用 Gossip Protocol 等去中心化的 P2P 協議即足以知足須要,有時甚至能夠徹底避免這種集羣內的節點間通訊。
從 μSOA 的角度看,也能夠將 DBC 視做一種幾乎全部服務器端應用都須要使用的基礎功能插件,因爲其經常使用性,所以他們被事先實現並加進了 libapidbc 中。由此,經過提供 IPlugin、API Nexus 以及 DBC 等幾個關鍵組件,libapidbc 爲 μSOA 架構奠基了良好的基礎設施。
固然,μSOA 與 SOA 和 AIO 三者間並非互斥的選擇。在實際應用場景中,能夠經過三者間的有機組合來達成最合理的設計。例如:對於視頻轉碼等很是耗時而且不須要同步等待其完成並返回結果的異步操做來講,因爲其絕大部分開銷都耗費在了視頻編解碼計算上,所以將其做爲插件加入其它 App Server 就徹底沒有必要,將它做爲獨立的服務,部署在配置了專用加速硬件的服務器集羣上應該是更好的選擇。
消息端口交換服務
白楊消息端口交換服務(BYPSS)設計用於單點支撐百億量級端口、十萬量級節點規模,每秒處理百萬至千萬量級消息的高可用、強一致、高性能分佈式協調和消息交換服務。其中關鍵概念包括:
端口交換服務對外提供的 API 原語包括:
端口交換服務的客戶端鏈接分爲如下兩類:
與傳統的分佈式協調服務以及消息中間件產品相比,端口轉發服務主要有如下特色:
可見,白楊消息端口轉發服務自己是一個集成了故障檢測、服務選舉、服務發現和分佈式鎖等分佈式協調功能的消息路由服務。它經過犧牲極端條件下的可靠性,在保證了 強一致、高可用、可伸縮(橫向擴展)的前提下,實現了極高的性能和併發能力。
能夠認爲消息端口交換服務就是爲 μSOA 架構量身定作的集羣協調和消息分發服務。μSOA 的主要改進即:將在 SOA 中,每一個用戶請求均須要牽扯網絡中的多個服務節點參與處理的模型改進爲大部分用戶請求僅須要同一個進程空間內的不一樣 BMOD 參與處理。
這樣的改進除了便於部署和維護,以及大大下降請求處理延遲外,還有兩個主要的優勢:
在此前提下,消息端口交換服務以容許在極端狀況下丟失少許將來得及轉發的消息爲代價,來避免磁盤寫入、主從複製等低效模式,以提供極高效率。這對 μSOA 來講是一種很是合理的選擇。
極端條件下的可靠性
傳統的分佈式協調服務一般使用 Paxos 或 Raft 之類基於多數派的強一致分佈式算法實現,主要負責爲應用提供一個高可用、強一致的分佈式元數據 KV 訪問服務。並以此爲基礎,提供分佈式鎖、消息分發、配置共享、角色選舉、服務發現、故障檢測等分佈式協調服務。常見的分佈式協調服務實現包括 Google Chubby(Paxos)、Apache ZooKeeper(Fast Paxos)、etcd(Raft)、Consul(Raft+Gossip)等。
Paxos、Raft 等分佈式一致性算法的最大問題在於其極低的訪問性能和極高的網絡開銷:對這些服務的每次訪問,不管讀寫,都會產生至少三次網絡廣播——以投票的方式確 定本次訪問通過多數派確認(讀也須要如此,由於主節點須要確認本次操做發生時,本身仍擁有多數票支持,還是集羣的合法主節點)。
在實踐中,雖可經過下降系統總體一致性或加入租期機制來優化讀操做的效率,但其整體性能仍十分低下,而且對網絡 IO 有很高的衝擊:Google、Facebook、Twitter 等公司的歷次重大事故中,不少都是因爲發生網絡分區或人爲配置錯誤致使 Paxos、Raft 等算法瘋狂廣播消息,導致整個網絡陷入廣播風暴而癱瘓。
此外,因爲 Paxos、Raft 等分佈式一致性算法對網絡 IO 的吞吐和延遲等方面均有較高要求,而鏈接多座數據中心機房(IDC)的互聯網絡一般又很難知足這些要求,所以致使依賴分佈式協調算法的強一致(抗腦裂)多活 IDC 高可用集羣架構難以以合理成本實現。做爲實例:2015 年 8 月 20 日 Google GCE 服務中斷 12 小時並永久丟失部分數據;2015 年 5 月 27 日和 2016 年 7 月 22 日支付寶兩次中斷數小時;2013 年 7 月 22 日微信服務中斷數小時;以及 2017 年 5 月英國航空癱瘓很多天等重大事故均是因爲單個 IDC 因市政施工(挖斷光纖)等緣由下線,同時未能成功構建多活 IDC 架構,所以形成 IDC 單點依賴所致使的。
前文也已提到過:因爲大部分採用 SOA 架構的產品須要依賴消息中間件來確保系統的最終一致性。所以對其可用性(部分節點故障不會影響正常使用)、可靠性(即便在部分節點故障時,也確保消息不丟 失、不重複、並嚴格有序)、功能性(如:發佈/訂閱模型、基於輪轉的任務分發等)等方面均有較嚴格的要求。這就必然要用到高可用集羣、節點間同步複製、數 據持久化等低效率、高維護成本的技術手段。所以消息分發服務也經常成爲分佈式系統中的一大主要瓶頸。
與 Paxos、Raft 等算法相比,BYPSS 一樣提供了故障檢測、服務選舉、服務發現和分佈式鎖等分佈式協調功能,以及相同等級的強一致性、高可用性和抗腦裂(Split Brain)能力。在消除了幾乎所有網絡廣播和磁盤 IO 等高開銷操做的同時,提供了數千、甚至上萬倍於前者的訪問性能和併發處理能力。 可在對網絡吞吐和延遲等方面無附加要求的前提下,構建跨多個 IDC 的大規模分佈式集羣系統。
與各個常見的消息中間件相比,BYPSS提供了一騎絕塵的單點百萬至千萬條消息每秒的吞吐和路由能力——一樣達到千百倍的性能提高,同時保證消息不重複和嚴格有序。
然而天下沒有免費的午飯,特別是在分佈式算法已經很是成熟的今天。在性能上擁有絕對優點的同時,BYPSS 必然也有其妥協及取捨——BYPSS 選擇放棄極端(平均每一年2次,而且大多由維護引發,控制在低谷時段,基於實際生產環境多年統計數據)情形下的可靠性,對分佈式系統的具體影響包括如下兩方面:
綜上所述,能夠認爲 BYPSS 服務就是爲 μSOA 架構量身定作的集羣協調和消息分發服務。BYPSS 和 μSOA 架構之間造成了揚長避短的互補關係:BYPSS 以極端條件下系統總體性能的輕微波動爲代價,極大提高了系統的整體性能表現。適合用來實現高效率、高可用、高可靠、強一致的 μSOA 架構分佈式系統。
BYPSS特性總結
BYPSS 和基於 Paxos、Raft 等傳統分佈式一致性算法的分佈式協調產品特性對好比下:
特性 | BYPSS | ZooKeeper、Consul、etcd… |
可用性 | 高可用,支持多活 IDC | 高可用,支持多活 IDC |
一致性 | 強一致,主節點經過多數派選舉 | 強一致,多副本複製 |
併發性 | 千萬量級併發鏈接,可支持數十萬併發節點 | 不超過 5000 節點 |
容量 | 每 10GB 內存可支持約 1 億消息端口;每 1TB 內存可支持約 100 億消息端口;兩級併發散列表結構確保容量可線性擴展至 PB 級。 | 一般最高支持數萬 KV 對。開啓了變動通知時則更少。 |
延遲 | 相同 IDC 內每次請求延遲在亞毫秒級(阿里雲中實測爲 0.5ms);相同區域內的不一樣 IDC 間每次請求延遲在毫秒級(阿里雲環境實測 2ms)。 | 因爲每次請求須要至少三次網絡廣播和屢次磁盤 IO,所以相同 IDC 中的每操做延遲在十幾毫秒左右;不一樣 IDC 間的延遲則更長(詳見下文)。 |
性能 | 每 1Gbps 網絡帶寬可支持約 400 萬次/秒的端口註冊和註銷操做。在 2013 年出廠的入門級至強處理器上,每核心可支持約 100 萬次/秒的上述端口操做。性能可經過增長帶寬和處理器核心數量線性擴展。 | 算法自己的特性決定了沒法支持批量操做,不到 100 次每秒的請求性能(因爲每一個原子操做都須要至少三次網絡廣播和屢次磁盤 IO,所以支持批量操做毫無心義,詳見下文)。 |
網絡利用率 | 高:服務器端和客戶端均具有端口註冊、端口註銷、消息發送的批量打包能力,網絡載荷比可接近 100%。 | 低:每請求一個獨立包(TCP Segment、IP Packet、Network Frame) ,網絡載荷比一般低於 5%。 |
可伸縮性 | 有:可經過級聯的方式進行橫向擴展。 | 無:集羣中的節點越多(由於廣播和磁盤IO的範圍更大)性能反而越差。 |
分區容忍 | 無多數派分區時系統下線,但不會產生廣播風暴。 | 無多數派分區時系統下線,有可能產生廣播風暴引起進一步網絡故障。 |
消息分發 | 有,高性能,客戶端和服務器均包含了消息的批量自動打包支持。 | 無。 |
配置管理 | 無,BYPSS 認爲配置類數據應交由 Redis、MySQL、MongoDB 等專門的產品來維護和管理。固然,這些 CMDB 的主從選舉等分佈式協調工做仍可由 BYPSS 來完成。 | 有,可看成簡單的 CMDB 來使用,這種功能和職責上的混淆不清進一步劣化了產品的容量和性能。 |
故障恢復 | 須要從新生成狀態機,但能夠數千萬至數億端口/秒的性能完成。實際使用中幾無波動。 | 不須要從新生成狀態機。 |
上述比較中,延遲和性能兩項主要針對寫操做。這是由於在常見的分佈式協調任務中,幾乎所有有意義的操做都是寫操做。例如:
操做 | 對服務協調來講 | 對分佈式鎖來講 |
端口註冊 | 成功:服務選舉成功,成爲該服務的屬主。 失敗:成功查詢到該服務的當前屬主。 |
成功:上鎖成功。 失敗:上鎖失敗,同時返回鎖的當前屬主。 |
端口註銷 | 放棄服務全部權。 | 釋放鎖。 |
註銷通知 | 服務已下線,可更新本地查詢緩存或參與服務競選。 | 鎖已釋放,可從新開始嘗試上鎖。 |
上表中,BYPSS 的端口註冊對應 ZooKeeper 等傳統分佈式產品中的「寫/建立KV對」;端口註銷對應「刪除KV對」;註銷通知則對應「變動通知」服務。
因而可知,爲了發揮最高效率,在生產環境中一般不會使用單純的查詢等只讀操做。而是將查詢操做隱含在端口註冊等寫請求中,請求成功則當前節點自身成爲屬主;註冊失敗天然會返回請求服務的當前屬主,所以變相完成了屬主查詢( 服務發現/名稱解析)等讀操做。
須要注意的是,就算是端口註冊等寫操做失敗,其實仍是會伴隨一個成功的寫操做。由於仍然要將發起請求的當前節點加入到指定條目的變動通知列表中,以便在端口註銷等變動事件發生時,向各個感興趣的節點推送通知消息。 所以寫操做的性能差別極大地影響了現實產品的實際表現。
從高性能集羣(HPC)的視角來看,BYPSS 與前文所述的傳統分佈式協調產品之間,最大的區別主要體如今如下兩個方面:
因爲傳統分佈式協調服務的性能和容量等限制,在經典的分佈式集羣中,多以服務或節點做爲單位來進行分佈式協調和調度,同時儘可能要求集羣中的節點工做在無狀態模式。服務節點無狀態的設計雖然對分佈式協調服務的要求較低,但同時也帶來了集羣總體性能低下等問題。
與此相反,BYPSS 可輕鬆實現每秒千萬次請求的處理性能和百億至千億量級的消息端口容量。這就給分佈式集羣的精細化協做構建了良好的基礎。與傳統的無狀態集羣相比,基於 BYPSS 的精細化協做集羣可以帶來巨大的總體性能提高。
咱們首先以最多見的用戶和會話管理功能來講明:在無狀態的集羣中,在線用戶並沒有本身的屬主服務器,用戶的每次請求均被反向代理服務隨機地路由至集羣中的任意節點。雖然 LVS、Nginx、HAProxy、TS 等主流反向代理服務器均支持基於 Cookie 或 IP 等機制的節點粘滯選項,但因爲集羣中的節點都是無狀態的,所以該機制僅僅是增長了相同客戶端請求會被路由到某個肯定後臺服務器節點的機率而已,仍沒法提供全部權保證,也就沒法實現進一步的相關優化措施。
而得益於 BYPSS 突出的性能和容量保證,基於 BYPSS 的集羣能夠用戶爲單位來進行協調和調度(即:爲每一個活動用戶註冊一個端口),以提供更優的總體性能。具體的實現方式爲:
與傳統架構相比,考慮到無狀態服務也須要經過 MySQL、Memcached 或 Redis 等技術來實現專門的用戶和會話管理機制,所以以上實現並未增長多少複雜度,可是其帶來的性能提高卻很是巨大,對好比下:
項目 | BYPSS HPC 集羣 | 傳統無狀態集羣 |
1 運維 |
省去用戶和會話管理集羣的部署和維護成本。 | 須要單獨實施和維護用戶管理集羣,併爲用戶和會話管理服務提供專門的高可用保障,增長故障點、增長系統總體複雜性、增長運維成本。 |
2 網絡 |
幾乎全部請求的用戶匹配和會話驗證工做都得以在其屬主節點的內存中直接完成。內存訪問爲納秒級操做,對比毫秒級的網絡查詢延遲,性能提高十萬倍以上。同時有效下降了服務器集羣的內部網絡負載。 | 每次須要驗證用戶身份和會話有效性時,均須要經過網絡發送查詢請求到用戶和會話管理服務,並等待其返回結果,網絡負載高、延遲大。 因爲在一個典型的網絡應用中,大部分用戶請求都須要在完成用戶識別和會話驗證後才能繼續處理,所以這對總體性能的影響很大。 |
3 緩存 |
由於擁有了穩定的屬主服務器,而用戶在某個時間段內老是傾向於重複訪問相同或類似的數據(如自身屬性,本身剛剛發佈或查看的商品信息等)。所以服務器本地緩存的數據局部性強、命中率高。 相較於分佈式緩存而言,本地緩存的優點很是明顯:
等等,而後儘可能將屬於相同分組的用戶優先分配給同一個(或同一組)服務器節點。顯而易見,選擇合適的用戶分組策略可極大提高服務器節點的本地緩存命中率。 這使得絕大部分與用戶或人羣相關的數據都可在本地緩存命中,不但提高了集羣總體性能,還消除了集羣對分佈式緩存的依賴,同時大大下降了後端數據庫的讀負載。 |
無專屬服務器,用戶請求隨機到達集羣中的任意服務器節點;本地緩存命中率低;各節點重複緩存的內容多;須要以更高的成本爲代價依賴分佈式緩存。 後端數據庫服務器的讀壓力高,要對其進行分庫分表、讀寫分離等額外優化。 |
4 更新 |
因爲全部權肯定,能在集羣全局確保任意用戶在給定時間段內,均由特定的屬主節點來提供服務。再加上現代服務器突發宕機故障的機率也較低。 所以能夠將用戶屬性中頻繁變化但重要性或時效性較低的部分緩存在內存中,待積累一段時間後再批量更新至數據庫。這可大大下降後端數據庫服務器的寫壓力。 例如:商城系統可能隨着用戶的瀏覽(好比每次查看商品)進程,隨時收集並記錄用戶的偏好信息。若每次用戶查看了新商品後,都須要即時更新數據庫,則負載較高。再考慮到由於服務器偶發硬件故障致使丟失最後數小時商品瀏覽偏好數據徹底能夠接受,所以可由屬主節點將這些數據臨時保存在本地緩存中,每積累數小時再批量更新一次數據庫。 再好比:MMORPG 遊戲中,用戶的當前位置、狀態、經驗值等數據隨時都在變化。屬主服務器一樣能夠將這些數據變化積累在本地緩存中,並以適當的間隔(好比:每 5 分鐘一次)批量更新到數據庫中。 這不但極大地下降了後端數據庫要執行的請求數量,並且將多個用戶的數據在一個批量事務中打包更新也大大減小數據庫操做時的磁盤刷新動做,進一步提高了效率。 此外,由專門的屬主節點發起對用戶屬性的更新也避免了無狀態集羣中多個節點同時請求更新同一對象時的爭搶問題,進一步提升了數據庫性能。 |
因爲用戶的每次請求均可能被轉發到不一樣服務器節點來處理,所以沒法實現累積寫入優化和批量寫入優化。後端數據庫的寫負擔很是重。 存在多個節點爭搶更新同一條記錄的問題,進一步加劇了數據庫負擔。 爲此要對後端數據庫進行額外的分庫分表等優化,還會引起「須要由應用層來自行處理分佈式事務」等反作用。 |
5 推送 |
因爲同一用戶發起的全部會話均被集中在同一個屬主節點內統一管理,所以可很是方便地向用戶推送即時通知消息(Comet)。 若發送消息的對象與消息接收消息的用戶處於相同節點,則可直接將該消息推送給收件人麾下的全部活動會話。 不然只需將消息定向投遞到收件人的屬主節點便可。消息投遞可以使用 BYPSS 實現(直接向收件人對應端口發消息,應啓用消息批量發送機制來優化),亦可經過專用的消息中間件(如:Kafka、RocketMQ、RabbitMQ、ZeroMQ等)來完成。 若按照本表「項目3」中描述的方法,優先將關聯更緊密的用戶分配到相同屬主節點的話,則可大大提高消息推送在相同節點內完成的機率,此舉可顯著下降服務器間通訊的壓力。 所以咱們鼓勵針對業務的實際狀況來妥善定製用戶分組策略,合理的分組策略可實現讓絕大部分消息都在當前服務器節點內本地推送的理想效果。 例如:對遊戲類應用,可按地圖對象分組,將處於相同地圖副本內的玩家交由同一屬主節點進行管理——傳統 MMORPG 網遊中的絕大部分消息推送都發生在同一地圖副本內的玩家之間(AOI 範圍)。 再好比:對於 CRM、HCM、ERP 等 SaaS 應用來講,可按照公司來分組,將隸屬於相同企業的用戶集中到同一屬主節點上——很顯然,此類企業應用中,近 100% 的通訊都來自於企業內部成員之間。 這樣便可實現近乎 100% 的本地消息推送,達到幾乎免除了服務器間消息投遞的效果,極大地下降了服務器集羣的內部網絡負載。 |
因爲同一用戶的不一樣會話被隨機分配到不一樣節點處理,所以須要開發、部署和維護專門的消息推送集羣,同時專門確保該集羣的高性能和高可用性。 這不但增長了開發和運維成本,並且因爲須要將每條消息先投遞到消息推送服務後,再由該服務轉發給客戶端,所以也加劇了服務器集羣的內部網絡負載,同時也加大了用戶請求的處理延遲。 |
6 平衡 |
集羣可以使用主被動負載平衡相結合的手段進行調度。 被動平衡:集羣中的每一個節點均會按期將其麾下再也不活躍的用戶和會話卸載掉,同時批量通知 BYPSS 服務釋放這些用戶所對應的端口。此算法實現了宏觀上的負載平衡(以較長的時間週期來講,集羣是平衡的)。 主動平衡:集羣會經過 BYPSS 服務推選出負載平衡協調節點,該節點連續監視集羣中各個節點的負載狀況,並主動發出指令進行負載調度(如:要求 A 節點將其麾下 5000 位用戶的全部權轉移給 B 節點)。不一樣於宏觀層面的被動平衡,主動平衡機制能夠在更短的時間片內,以迅捷的反應速度來達成集羣的快速配平。 主動平衡一般在集羣中的部分節點剛剛從故障中恢復(所以處於空載狀態)時效果明顯,它比被動平衡反應更加迅速。如:在一個多活 IDC 集羣中,某個 IDC 的光纜故障剛剛被修復而恢復上線時。 |
若啓用了反向代理中的節點粘滯選項,則其負載平衡性與 BYPSS 集羣的被動平衡算法至關。 若未啓用反向代理中的節點粘滯選項,則在從故障中恢復時,其平衡性低於 BYPSS 主動平衡集羣。與此同時,爲了保證本地緩存命中率等其它性能指標不被過度劣化,管理員一般不會禁用節點粘滯功能。 另外,SOA 架構的多個服務間,容易產生負載不平衡,出現一些服務超載,另外一些輕載的狀況,μSOA 集羣則無此弊端。 |
值得一提的是,這樣的精準協做算法並不會形成集羣在可用性方面的任何損失。考慮集羣中的某個節點因故障下線的狀況:此時 BYPSS 服務會檢測到節點已下線,並自動釋放屬於該節點的全部用戶。待其用戶向集羣發起新請求時,該請求會被路由到當前集羣中,負載最輕的節點。這個新節點將代替已下線的故障節點,成爲此用戶的屬主,繼續爲該用戶提供服務(見前文中的步驟 2-b-i)。此過程對用戶透明,不須要在客戶端中加入額外的處理邏輯。
上述討論以幾乎全部網絡應用中都會涉及的用戶和會話管理功能爲例,爲你們展現了 BYPSS HPC 集羣精細協調能力的優點。但在多數真實應用中,並不僅有用戶管理功能。除此以外,應用中一般還會包含可供其用戶操做的其它對象。例如在優酷、土豆、youtube 等視頻網站中,除了用戶之外,至少還有「可供播放的視頻」這種對象。
下面咱們就以「視頻對象」爲例,探討如何使用 BYPSS 的精細化調度能力來大幅提高集羣性能。
在這個假想的視頻點播類應用中,與前文描述的用戶管理功能相似,咱們首先經過 BYPSS 服務爲每一個活動的視頻對象選取一個屬主節點。其次,咱們將視頻對象的屬性分爲如下兩大類:
此外,咱們還規定對視頻對象的任何寫操做(無論是普通屬性仍是動態屬性)均必須交由其屬主來完成,非屬主節點只能讀取和緩存視頻對象的普通屬性,不能讀取動態屬性,也不能執行任何更新操做。
由此,咱們能夠簡單地推斷出視頻對象訪問的大致業務邏輯以下:
與經典的無狀態 SOA 集羣相比,上述設計帶來的好處以下:
項目 | BYPSS HPC 集羣 | 傳統無狀態集羣 |
1 運維 |
基於全部權的分佈式緩存架構,省去 Memcached、Redis 等分佈式緩存集羣的部署和維護成本。 | 須要單獨實施和維護分佈式緩存集羣,增長系統總體複雜性。 |
2 緩存 |
普通屬性的讀操做在本地緩存命中,若使用「優先以用戶偏好特徵來分組」的用戶屬主節點分配策略,則可極大加強緩存局部性,增長本地緩存命中率,下降本地緩存在集羣中各個節點上的重複率。 正如前文所述,相對於分佈式緩存而言,本地緩存有消除網絡延遲、下降網絡負載、避免數據結構頻繁序列化和反序列化等優勢。 此外,動態屬性使用基於全部權的分佈式緩存來實現,避免了傳統分佈式緩存的頻繁失效和數據不一致等問題。同時因爲動態屬性僅被緩存在屬主節點上,所以也顯著提高了系統總體的內存利用率。 |
無專屬服務器,用戶請求隨機到達集羣中的任意服務器節點;本地緩存命中率低;各節點重複緩存的內容多;須要以更高的成本爲代價依賴額外的分佈式緩存服務。 後端數據庫服務器的讀壓力高,要對其實施分庫分表、讀寫分離等額外優化。 此外,即便爲 Memcached、Redis 等產品加入了基於 CAS 原子操做的 Revision 字段等改進,這些獨立的分佈式緩存集羣仍沒法提供數據強一致保證(意即:緩存中的數據與後端數據庫裏的記錄沒法避免地可能發生不一致)。 |
3 更新 |
因爲全部權肯定,能在集羣全局確保任意視頻對象在給定時間段內,均由特定的屬主節點來提供寫操做和動態屬性的讀操做等相關服務,再加上現代服務器突發宕機故障的機率也較低。 所以能夠將動態屬性中頻繁變化但重要性或時效性較低的部分緩存在內存中,待積累一段時間後再批量更新至數據庫。這可大大下降後端數據庫服務器的寫壓力。 例如:視頻的播放次數、點贊次數、差評次數、平均得分、收藏數、引用次數等屬性都會隨着用戶點擊等操做密集地變化。若每次發生相關的用戶點擊事件後,都須要即時更新數據庫,則負載較高。而在發生「屬主節點因爲硬件故障宕機」等極端狀況時,丟失幾分鐘的上述統計數據徹底能夠接受。所以,咱們能夠將這些字段的變動積累在屬主節點的緩存中,每隔數分鐘再將其統一地批量寫回後端數據庫。 這不但極大地下降了後端數據庫收到的請求數量,並且將多個視頻的數據在一個批量事務中打包更新,也大大減小數據庫操做時的磁盤刷新動做,進一步提高了效率。 此外,由專門的屬主節點單獨發起對視頻記錄的更新也避免了無狀態集羣中多個節點同時請求更新同一對象時的爭搶問題,進一步提升了數據庫性能。 |
因爲每次請求均可能被路由到不一樣服務器節點來處理,所以沒法實現累積寫入優化和批量寫入優化。後端數據庫服務器的寫負擔很是重。存在多個節點爭搶更新同一條記錄的問題,這進一步加劇了數據庫負擔。 爲此要對後端數據庫進行額外的分庫分表等優化,還會引起「須要由應用層來自行處理分佈式事務」等反作用。 |
4 平衡 |
集羣可以使用主被動負載平衡相結合的手段進行調度。 被動平衡:集羣中的每一個節點均會按期將其麾下再也不活躍的視頻對象卸載掉,同時批量通知 BYPSS 服務釋放這些視頻對應的端口。此算法實現了宏觀上的負載平衡(以較長的時間週期來講,集羣是平衡的)。 主動平衡:集羣會經過 BYPSS 服務推選出負載平衡協調節點,該節點連續監視集羣中各個節點的負載狀況,並主動發出指令進行負載調度(如:要求 A 節點將其麾下 10000 個視頻對象的全部權轉移給 B 節點)。不一樣於宏觀層面的被動平衡,主動平衡機制能夠在更短的時間片內,以迅捷的反應速度來達成集羣的快速配平。 主動平衡一般在集羣中的部分節點剛剛從故障中恢復(所以處於空載狀態)時效果明顯,它比被動平衡反應更加迅速。如:在一個多活 IDC 集羣中,某個 IDC 的光纜故障剛剛被修復而恢復上線時。 |
在從故障中恢復時,其平衡性低於 BYPSS 主動平衡集羣。正常狀況下則相差不大。 另外,SOA 架構的多個服務間,容易產生負載不平衡,出現一些服務超載,另外一些輕載的狀況,μSOA集羣則無此弊端。 |
與前文說起的用戶管理案例相似,上述精準協做算法不會爲集羣的服務可用性方面帶來任何損失。考慮集羣中的某個節點因故障下線的狀況:此時 BYPSS 服務會檢測到節點已下線,並自動釋放屬於該節點的全部視頻對象。待用戶下次訪問這些視頻對象時,收到該請求的服務器節點會從 BYPSS 得到此視頻對象的全部權並完成對該請求的處理。至此,這個新節點將代替已下線的故障節點成爲此視頻對象的屬主(見前文中的步驟 2-c-i)。此過程對用戶透明,不須要在客戶端中加入額外的處理邏輯。
以上對「用戶管理」和「視頻服務」案例的剖析均屬拋磚引玉。在實際應用中,BYPSS 經過其高性能、大容量等特徵提供的資源精細化協調能力可適用於包括互聯網、電信、物聯網、大數據批處理、大數據流式計算等普遍領域。
咱們之後還會陸續增長更多實用案例,以供你們參考。
testtesttesttest 20190304 更新記錄測試(for 呂老師)
更新測試:2019-3-3 阿里雲由於 io hang 大面積宕機。
注:本文節選自《白楊應用支撐平臺》中的「5.4 μSOA 基礎庫-libapidbc」小節。
注2:以上所述 μSOA 架構和 BYPSS 分佈式協調算法均受到多項國家和國際發明專利保護。