突发热点事件下微博高可用注册中心vintage的设计\u0026实践
當前微博服務(wù)化采用公有云+私有云的混合云部署方式,承載了每天百億級的流量,vintage 作為微博微服務(wù)的注冊中心,為管理 10w 級微服務(wù)節(jié)點以及在流量激增的情況下的服務(wù)快速擴縮容,面臨了極大挑戰(zhàn)。例如:復雜網(wǎng)絡(luò)條件下 vintage 服務(wù)的高可用保障、解決大批量節(jié)點狀態(tài)變更觸發(fā)的通知風暴、異常情況下 vintage 節(jié)點的自適應(yīng)和自恢復能力、vintage 多云部署場景下節(jié)點數(shù)據(jù)同步和一致性保障等。
vintage 3.0 優(yōu)雅的解決了上述問題,具備了良好的擴展性,可用性達到6個9。在12月8日北京ArchSummit 全球架構(gòu)師峰會上,來自微博研發(fā)中心的邊劍,以挑戰(zhàn)和問題切入與大家分享了 vintage 設(shè)計原則與方案,以及線上應(yīng)用的最佳實踐。
一、突發(fā)熱點對微博注冊中心的要求與挑戰(zhàn)
1.1 突發(fā)熱點熱點事件
突發(fā)熱點是微博面臨的最常見、最重要的挑戰(zhàn),左圖顯示的就是最近的一個熱點事件,右圖是當時熱點發(fā)生時的流量圖,我們可以看出熱點事件發(fā)生時,在短時間內(nèi)會引發(fā)微博流量的數(shù)倍增長。那么面對如海嘯般的突發(fā)流量,如何應(yīng)對就顯得尤為重要。
根據(jù)峰值流量模型不同,應(yīng)對策略多種多樣,但通??偨Y(jié)為下面三種措施:
1.2 突發(fā)熱點事件對微博注冊中心的要求與挑戰(zhàn)
眾所周知,微服務(wù)的運行必須依賴注冊中心的支持。這就對微博注冊中心提出了4點要求:
然而即使我們滿足了以上四個要求,但時常還會遇到網(wǎng)絡(luò)抖動,流量極端峰值時專線帶寬擁塞等情況。那么如何在網(wǎng)絡(luò)狀態(tài)不好情況下,保障微博注冊中心的可用性,實現(xiàn)微服務(wù)正常擴容就成為了微博注冊中心在設(shè)計時必須要面臨的挑戰(zhàn)。
**二、vintage **高可用設(shè)計\u0026amp;實踐
2.1 設(shè)計目標:
針對上面提到的要求和挑戰(zhàn),設(shè)計微博注冊中心時在功能上要實現(xiàn)公司級別的注冊中心及配置管理平臺,支持多 IDC,支持多語言,具備 10w+級微服務(wù)承載能力,可用性上需滿足6個9。在服務(wù)性能方面,要具備每秒對百級別以上微服務(wù)的擴容能力。同時要求通知平均延遲低于 500ms。而在伸縮性上,微博注冊中心自身必須具備十秒級節(jié)點擴容,以及分鐘級 IDC 注冊中心搭建。
2.2 選型對比
根據(jù)設(shè)計目標,對業(yè)界比較流行的注冊中心進行了調(diào)研。ZooKeeper,Etcd 無法較好滿足微博對多機房支持要求。Consul 雖然滿足了多機房的支持,但在網(wǎng)絡(luò) QoS 發(fā)生時由于其本身的 CP 模型設(shè)計,在服務(wù)可用性方面不能提供很好的保障。而 Eureka 雖然在多機房和可用性方面都滿足微博的要求,但 Eureka 目前僅支持以長輪詢的方式訂閱服務(wù),在通知延遲方面不能很好的支持,同時 Eureka 在社區(qū)支持方面已暫停了新版本的研發(fā)。
綜合考慮上述指標 ZooKeeper,Etcd,Consul,Eureka 均都無法很好的滿足微博對注冊中心提出的要求。因此我們決定在現(xiàn)有的 vintage 系統(tǒng)基礎(chǔ)上進行升級改造,來滿足具備公司級注冊中心的能力。
2.3 vintage 架構(gòu)設(shè)計
vintage 部署拓撲
先從系統(tǒng)拓撲部署了解下新版 vintage 的整體設(shè)計。vintage 服務(wù)采用多 IDC 的部署方式,通過 Gossipe 協(xié)議,實現(xiàn)節(jié)點間的自動發(fā)現(xiàn)。IDC 間主主通信實現(xiàn)多機房間數(shù)據(jù)同步。IDC 內(nèi)采用一主多從的部署方式,基于 Raft 實現(xiàn)了可支持分區(qū)多主的選舉協(xié)議,主從節(jié)點角色之間實現(xiàn)讀寫分離。
vintage 模塊架構(gòu)圖
vintage 系統(tǒng)采用典型三層結(jié)構(gòu)設(shè)計,將網(wǎng)絡(luò)層,業(yè)務(wù)層,存儲層抽象分離。
2.4 高可用實踐
了解整個系統(tǒng)后,將通過網(wǎng)絡(luò)分區(qū),通知風暴,數(shù)據(jù)一致性,高可用部署四個方面介紹 vintage 在高可用方面的實踐,以及 AP 模型注冊中心在數(shù)據(jù)一致性保障方面的措施。
網(wǎng)絡(luò)分區(qū)
場景一:vintage 內(nèi)部網(wǎng)絡(luò)分區(qū)
如上圖,網(wǎng)絡(luò)分區(qū)將 vintage 集群一分為二,同時每個分區(qū)中的節(jié)點數(shù)量均少于 n/2+1 個(n為該 IDC 子集群 vintage 服務(wù)的節(jié)點總數(shù))。在該場景下基于傳統(tǒng) Raft 協(xié)議的注冊中心,由于對數(shù)據(jù)強一致性的要求,將無法提供正常的讀寫服務(wù)。而 Etcd 和 Consul 在解決這個問題時,也僅是通過 stale read 的方式滿足了對數(shù)據(jù)讀取的需要,但仍然無法實現(xiàn)在該場景下對微服務(wù)注冊的需要。
微博注冊中心為實現(xiàn)在網(wǎng)絡(luò)分區(qū)下注冊中心服務(wù)高可用,對原有 Raft 協(xié)議選舉機制進行改造,實現(xiàn)了可對任意分區(qū)情況下的多主選舉支持:(1)解決了分區(qū)發(fā)生時處于少數(shù)分區(qū)內(nèi) rpc-server 與 rpc-client 的注冊及服務(wù)發(fā)現(xiàn)能力。實現(xiàn)任何粒度分區(qū)下 vintage 服務(wù)的高可用。(2)對故障節(jié)點的承受能力大幅提升,由原 Raft 協(xié)議的 n/2-1 個節(jié)點,提升至最大 n-1 節(jié)點。
同時在該場景下網(wǎng)絡(luò)分區(qū)后,微服務(wù)會將自己的心跳匯報到所屬分區(qū)的主節(jié)點。而由于分區(qū)存在,分區(qū)間節(jié)點數(shù)據(jù)無法通信。對于(vintage)IDC 集群中的其他主節(jié)點來說就出現(xiàn)了微服務(wù)心跳丟失的現(xiàn)象,而心跳是作為服務(wù)健康狀態(tài)的重要識別手段。心跳超時的微服務(wù)節(jié)點將會被標識為不可用狀態(tài),從而不會被調(diào)用方訪問。網(wǎng)絡(luò)分區(qū)時往往會出現(xiàn)大批量的微服務(wù)心跳超時,未能妥善處理將直接影響業(yè)務(wù)系統(tǒng)服務(wù)的穩(wěn)定性及SLA指標。而此時 partion handler 模塊將會優(yōu)先于心跳超時感知到網(wǎng)絡(luò)分區(qū)的發(fā)生,啟動 freeze 保護機制(freeze:注冊中心內(nèi)部對微服務(wù)狀態(tài)的保護機制,基于樂觀策略凍結(jié)當前 vintage 系統(tǒng)中的微服務(wù)節(jié)點狀態(tài),禁止節(jié)點不可用狀態(tài)的變更,同時對于接受到心跳的微服務(wù)節(jié)點,支持其恢復可用狀態(tài))。
分區(qū)恢復后,各節(jié)點間通信恢復正常。vintage 會進行再次選舉,從分區(qū)時的多個主節(jié)點中選舉出新的主節(jié)點。vintage 中的數(shù)據(jù)變更都會抽象為一個獨立事件,系統(tǒng)基于向量時鐘實現(xiàn)了對全局事件的順序控制。在多主合并過程中通過 repair 模塊完成節(jié)點間數(shù)據(jù)的一致性修復,保障 IDC 內(nèi)集群最終一致性。
場景二:client 與 vintage 間網(wǎng)絡(luò)分區(qū)
圖中綠色和黃色區(qū)域分別代表兩個不同 IDC 中的 vintage 子集群。紅色和紫色代表 IDC1 內(nèi)的 rpc-server 和 rpc-clinet。此時紅色的 rpc-server 與 IDC1 中的 vintage 主節(jié)點出現(xiàn)了網(wǎng)絡(luò)分區(qū),而紫色的 rpc-client 與 IDC1 的 vintage 集群整體存在網(wǎng)絡(luò)隔離現(xiàn)象。rpc-server 和 rpc-client 之間網(wǎng)絡(luò)通信正常。雖然這是一個相對復雜且極端的分區(qū)場景,但對于微博注冊中心的高可用設(shè)計要求是必須要解決的問題。下面我們來看看 vintage 是如何解決的。
在該場景下 rpc-server 可通過 DNS 發(fā)現(xiàn)的方式獲取該 IDC 內(nèi) vintage 子集群的全部機器列表,并使用 proxy 模式將注冊請求發(fā)送至子集群中任意可達的從節(jié)點。并通過從節(jié)點代理,將注冊請求轉(zhuǎn)發(fā)至主節(jié)點完成服務(wù)注冊。rpc-server 會定期檢測自己與主節(jié)點的連接狀態(tài),一旦發(fā)現(xiàn)連接恢復,將自動關(guān)閉 proxy 模式,并通過向主節(jié)點發(fā)送心跳維護自身狀態(tài)。
rpc-client 可通過跨 IDC 服務(wù)發(fā)現(xiàn)方式,在 IDC2 中訂閱所關(guān)注的 rpc-server 服務(wù)信息,其自身還會定期將獲取到的 rpc-serve 服務(wù)列表保存至本地 snapshot 文件。防止即使 rpc-client 與全部的 vintage 服務(wù)均出現(xiàn)網(wǎng)絡(luò)隔離,也可保證自身正常啟動及調(diào)用。從而實現(xiàn)了 client 與 vintage 服務(wù)分區(qū)時,微服務(wù)注冊與服務(wù)發(fā)現(xiàn)的高可用。
注:vintage 服務(wù)同樣支持跨 IDC 的微服務(wù)注冊。但從實際訪問及運維模型考慮,要求每個 rpcserver 節(jié)點在同一時刻僅可屬于一個 IDC 集群。
通知風暴:
在微博場景下,根據(jù)調(diào)用方對每種微服務(wù)的訂閱數(shù)量的不同,通常會出現(xiàn)百級至千級別的通知放大,老版本 vintage 的訂閱功能是基于 sign(md5 后服務(wù)列表指紋)對比+全量數(shù)據(jù)拉取的方式,根據(jù)微服務(wù)自身規(guī)模同樣會出現(xiàn)十級至百級別的消息體放大(二次放大現(xiàn)象)。若此時出現(xiàn)大量微服務(wù)擴縮容,網(wǎng)絡(luò) QoS 或大面積微服務(wù)機器設(shè)備的故障,經(jīng)過兩次放大的通知規(guī)??蛇_到百萬甚至千萬級別,嚴重占用機器帶寬資源。
針對通知風暴嚴重危害,改造后的 vintage 系統(tǒng)使用了“梳”和“保”兩種策略應(yīng)對。
“疏”主要采用的三種策略
“?!笔峭ㄟ^系統(tǒng)多重防護策略,保障通知風暴下 vintage 及微服務(wù)的狀態(tài)穩(wěn)定。其主要采用的三種策略:
數(shù)據(jù)一致性
不難看出 vintage 是基于AP 模型設(shè)計的注冊中心。該模型下注冊中心內(nèi)節(jié)點間數(shù)據(jù)的一致性問題,成為了 vintage 必須要處理的核心問題。vintage 選擇了最終一致性作為集群的數(shù)據(jù)一致性模型。
接下來介紹 vintage 的最終一致性實現(xiàn)機制。
首先來回顧下 vintage 集群的部署拓撲。vintage 采用多 IDC 部署,各 IDC 間分治獨立,IDC 間通過主主節(jié)點完成數(shù)據(jù)同步,IDC 內(nèi)主從角色讀寫分離。在該拓撲下,vintage 通過集群內(nèi)主從,集群間主主的數(shù)據(jù)同步+差異對比修復相結(jié)合的方式,實現(xiàn)節(jié)點間數(shù)據(jù)的最終一致性。(1)數(shù)據(jù)同步:各 IDC 內(nèi)均由主節(jié)點負責上行請求處理,從節(jié)點通過拉取主節(jié)點新增的變更事件完成數(shù)據(jù)同步。(2)同時 vintage 內(nèi)部對全部存儲的數(shù)據(jù)構(gòu)建了對應(yīng)的 merkle Tree,并隨數(shù)據(jù)變化進行實時更新。
vintage 會定期觸發(fā)集群一致性檢測邏輯。以主節(jié)點中數(shù)據(jù)為標準,IDC 內(nèi)采用主從,IDC 間則是主主方式使用 merkle tree 特點由根節(jié)點逐層對比,精確定位數(shù)據(jù)差異節(jié)點,并完成一致性修復。
注:通過線上運行統(tǒng)計,通常僅有\(zhòng)u0026lt;0.5%的檢測結(jié)果出現(xiàn)數(shù)據(jù)不一致現(xiàn)象。利用 merkle Tree 的特點有效優(yōu)化了數(shù)據(jù)對比及修復過程中對網(wǎng)絡(luò)帶寬不必要的消耗:
99.5%一致性檢測僅需對根節(jié)點數(shù)據(jù)對比即可確認數(shù)據(jù)一致性。
高可用部署:
服務(wù)的高可用通常與部署方式必密不可分,vintage 作為公司級別的注冊中心本身必須具備極高的可用性和故障恢復能力。
vintage 在部署上主要考慮以下4點:
2.5 高性能:
在介紹 vintage 高可用后,再來看看 vintage 系統(tǒng)在高性能方面如何實現(xiàn) 10w+ 節(jié)點的支撐及平均百毫秒級別的通知延遲。
首先了解下微服務(wù)在 vintage 系統(tǒng)中的生命周期,這是一張 vintage 內(nèi)部維護微服務(wù)生命周期的狀態(tài)機。其中 initial,working,unreachable 為 vintage 內(nèi)部對管理微服務(wù)的三個狀態(tài),分別用于說明節(jié)點處于初始注冊狀態(tài),可用狀態(tài),以及不可用狀態(tài)。
微服務(wù)節(jié)點通過調(diào)用 register 接口完成注冊,vintage 會將該節(jié)點狀態(tài)設(shè)置為 initial。注冊成功后微服務(wù)節(jié)點會周期性(5s)向 vintage 發(fā)送心跳,匯報自身健康狀態(tài),更新服務(wù)心跳超時時間。vintage在收到第一個心跳請求后,將該節(jié)點狀態(tài)被為 working。vintage會周期性觸發(fā)對全部 working 狀態(tài)微服務(wù)節(jié)點的健康檢測,當發(fā)現(xiàn)節(jié)點心跳超時,該節(jié)點狀態(tài)將被變更至 unreachable,并通過watch接口將變更時間推送給訂閱方。而 unreachable 狀態(tài)可通過再次發(fā)送心跳,轉(zhuǎn)變?yōu)?working 狀態(tài)。在working To unreachable的變更過程中如果觸發(fā)了 vintage 節(jié)點狀態(tài)保護機制,或出現(xiàn)網(wǎng)絡(luò)分區(qū),狀態(tài)變更會被凍結(jié)。微服務(wù)節(jié)點下線時可通過調(diào)用 unregister 接口實現(xiàn)注銷,完成整個生命周期。
vintage每個 IDC 中僅由主節(jié)點負責全部的上行請求并通過心跳方式維護該 IDC 內(nèi)全部微服務(wù)的健康檢測及狀態(tài)變更。而心跳作為周期性的高頻請求,當單 IDC 內(nèi)節(jié)點數(shù)達到一定量級時,對主節(jié)點的處理能力帶來極大的挑戰(zhàn)。并直接影響到單 IDC 集群的吞吐和服務(wù)節(jié)點承載能力。這就需要一個高效定時器來完成上述的挑戰(zhàn)。
從圖中可以看出,在設(shè)計上要求單 IDC 集群同樣可承擔 10w 級的服務(wù)節(jié)點,支持頻繁的 expire更新,同時要求對節(jié)點狀態(tài)變更精度達到 10ms 級別。
首先對現(xiàn)有的 heartbeat 匯報及超時檢測模型分析后,得出以下幾個特點:
通過對特點的分析,并參考了目前比較流行的一些定時器處理算法。不難看出鏈表,最小堆以及時間輪這些主流定時器的時間復雜度上均會受到節(jié)點數(shù)的直接影響。那是否有一種數(shù)據(jù)結(jié)構(gòu)可以做到 update 和 trigger 都是 o(1) 的時間復雜度呢?
定時器(timer)由 List+Map 共同組成用于維護 vintage 內(nèi)部所有 working 狀態(tài)的微服務(wù)節(jié)點的健康監(jiān)測和心跳續(xù)租。
List 是一個根據(jù) expire 升序排列的有序雙向鏈表,鏈表中的元素為微服務(wù)節(jié)點的狀態(tài)對象,包括節(jié)點 ID 和超時時間。Map 保存了微服務(wù)的 ID 及狀態(tài)對象的引用。當 vintage 收到某個節(jié)點的心跳請求,會根據(jù)節(jié)點 ID 從 Map 中獲取該微服務(wù)節(jié)點狀態(tài)對象,由于心跳續(xù)租時間固定,完成 expire 字段更新后無需排序,可直接將節(jié)點對象插入在鏈表的尾部。
timer會定期觸發(fā)微服務(wù)的超時檢測,根據(jù)鏈表 expire 升序的特點,每次檢測的順序都是由首都到尾部,發(fā)現(xiàn)首節(jié)點 expire 小于當前時間,觸發(fā)過期操作,將節(jié)點從列表中刪除,并調(diào)用 callback 函數(shù),通知存儲模塊將節(jié)點狀態(tài)更新為 unreachabl。依次向后檢查鏈表中的各節(jié)點,直到出現(xiàn)第一個未過期的節(jié)點為止。
當服務(wù)狀態(tài)變更,節(jié)點的注冊與注銷時都會將數(shù)據(jù)記錄到存儲中。vintage 實現(xiàn)了一套基于樹形結(jié)構(gòu)的多版本數(shù)據(jù)存儲。依賴于樹形存儲結(jié)構(gòu),vintage 在實現(xiàn)對數(shù)據(jù)存儲能力外,還可將微服務(wù)依照 /IDC/部門/業(yè)務(wù)線/服務(wù)/集群/服務(wù)節(jié)點 的方式分層管理。同時借助于多版本實現(xiàn)了從數(shù)據(jù)到事件的轉(zhuǎn)換,并通過 Event notify 模塊將變更事件實時回調(diào)通知 watch hub,完成對新增事件的訂閱推送。
watch推送機制
client 注冊 watchhub
client 向 vintage 訂閱服務(wù)變化過程。會首先向 vintage 的 watch hub 進行注冊,watch hub 會為每個訂閱方生成一一對應(yīng)的 watcher 對象,并根據(jù)訂閱目標的 path(ID),將相同路徑的 watcher 合并至一個 watchers 列表中,保存在 watch hub 的 map 索引結(jié)構(gòu)。
存儲層數(shù)據(jù)變更通知
當 storage 完成數(shù)據(jù)存儲后,會將數(shù)據(jù)變更的信息轉(zhuǎn)換為新增事件通過 Event notify 模塊回調(diào)通知 watch hub。watch hub 通過該 event 中的 path 在 map 索引找到訂閱的 watchers 對象,并將事件寫入全部 watcher 的 event queue 中。由 watch 函數(shù)完成事實數(shù)據(jù)推送。
注:若 path 是多層結(jié)構(gòu)時,watch hub 通過逆向遞歸的方式,將該事件依次插入多個 event 隊列,實現(xiàn) watch hub 的 path 遞歸功能。
系統(tǒng)伸縮性
為保障微服務(wù)的快速擴容,vintage 服務(wù)自身必須具備快速的擴容能力 vintage 會通過 Docker 化部署及 node discovery 節(jié)點自動發(fā)現(xiàn)能力,實現(xiàn)秒級別的擴容。并通過整合 Jpool+Dcp 體系,目前可實現(xiàn)分鐘級 IDC 注冊中心搭建。
多語言支持
在多語言支持方面,vintage 系統(tǒng)通過 HTTP Restful API 滿足了公司級跨語言注冊中心的服務(wù)支持。同時也在不斷擴展多語言官方 SDK,目前已實現(xiàn)了 Java,Go的支持。
三、總結(jié)
新版 vintage 系統(tǒng)已在線上運行了一年多,經(jīng)歷了微博春晚保障,土城、永豐核心機房網(wǎng)絡(luò)升級以及數(shù)不勝數(shù)的突發(fā)熱點事件。
vintage 系統(tǒng)使用多 IDC 部署方式支持公司混合云戰(zhàn)略,承擔十萬級別微服務(wù)注冊與服務(wù)發(fā)現(xiàn)。同時系統(tǒng)可用性達到 99.9999%,通知變更平均延遲\u0026lt; 200ms,p999延遲低于800ms。vintage 注冊中心在可用性和性能上,也滿足了業(yè)務(wù)在突發(fā)熱點時的應(yīng)對保障,將常備業(yè)務(wù)機器的 buffer 由 40% 降低至 25%。
嘉賓介紹:
邊劍:新浪微博技術(shù)專家,專注于高可用架構(gòu),有多年高并發(fā)系統(tǒng)架構(gòu)設(shè)計和研發(fā)經(jīng)驗,現(xiàn)就職于微博研發(fā)中心-平臺架構(gòu)部,主要從事微博平臺公共服務(wù)及中間件系統(tǒng)的設(shè)計及優(yōu)化,作為核心技術(shù)成員參與微博服務(wù)化建設(shè)。
總結(jié)
以上是生活随笔為你收集整理的突发热点事件下微博高可用注册中心vintage的设计\u0026实践的全部內(nèi)容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: SQLServer 清空某个库所有表
- 下一篇: 安装Joomla