開篇
這篇文章是基於SOFA Meetup合肥站的分享總結,主要針對於註冊中心的定位以及功能介紹,通過對螞蟻註冊中心發展史的分析,帶領大家瞭解,螞蟻的註冊中心是如何一步一步演變為現在的規模和特性的。
更多深入的技術細節,歡迎大家加入到SOFA和SOFARegistry的社群中,探尋結果。
註冊中心是什麼
服務發現 & 服務註冊
註冊中心簡單來說,是為了解決分散式場景下,服務之間互相發現的問題。
如下圖所示,服務A想要呼叫服務B的時候,需要知道B的地址在哪裡,如何解決這個問題?
一般來說,分為兩個點:
- 服務發現可以有一箇中心化的元件或者說是儲存,它承載了所有服務的地址,同時提供出來一個可供查詢和訂閱的能力,服務的消費方可以通過和這個中心化的儲存互動,獲取服務提供方的地址列表。
- 服務註冊:同樣是上文中中心化的元件,但是,這個時候的服務資訊可以有兩種措施
- 服務連線註冊中心,同時上報自身的服務以及後設資料(也是今天本文講述的重點)
- 有一個集中的控制面(control plane)將使用者定義的服務和IP的對映寫入註冊中心,例如AWS的CloudMap
呼叫流程
如上圖所示,就是目前一種主流的註冊中心模式,SOFARegistry和Nacos都是這種模式。
- 服務A,服務B通過SDK或者REST將自身的服務資訊上報給註冊中心
- 服務A需要呼叫服務B的時候,就對註冊中心發起請求,拉取和服務B相關的服務IP列表以及資訊
- 在獲取到服務B的列表之後,就可以通過自身定義的負載均衡演算法訪問服務B
心跳
心跳是註冊中心用於解決服務不可用時,及時拉出服務降低影響的預設方式,如下圖所示
- 服務B的一個節點斷網或是hang住,引發心跳超時;或是當機、斷鏈直接引發心跳失敗
- 註冊中心把問題節點從自身的儲存中拉出(這裡拉出根據具體實現:有的是直接刪除,有的是標記為不健康)
- 服務A收到註冊中心的通知,獲取到服務B最新的列表
DUBBO 註冊中心
下面通過DUBBO的例子,我們來看一下注冊中心是如何使用的,以及流程
首先,DUBBO在2.7和3.0中的配置略有不同,但是都是簡單易懂的,這裡都放上來
DUBBO-2.7
DUBBO-3.0
在RPC客戶端只需要配置一個註冊中心的地址即可,地址中包含了基礎三元素
- protocol(協議型別)比如,zookeeper
- host
- port
基於此,dubbo的註冊流程如下圖所示
- 服務的生產方通過DUBBO客戶端向註冊中心(Registry)發起註冊行為(register)
- 服務的消費方通過DUBBO客戶端訂閱資訊(subscribe)
- 註冊中心通過通知的方式,下發服務列表給服務消費方
註冊中心的本質
通過前文的講解,以及DUBBO元件的具體例子,我們大概可以歸納註冊中心的本質
“儲存” + “可運維”
- 一方面,註冊中心需要儲存能力去記錄服務的資訊,比如應用列表
- 另一方面,註冊中心在實踐過程中,需要提供必需的運維手段,比如關閉某一服務流量
螞蟻註冊中心編年史
史前時代
史前時代的螞蟻是相當久遠的架構,當時所有的服務部署在同一臺物理機上或者JVM上,服務之間不存在有跨機器呼叫的場景,這裡略過不表
硬負載時代
後來,為了解決應用之間的耦合帶來的部署難,運維難問題,我們對服務進行了拆分,拆分後的服務,遇到了一個問題,就是如何處理服務之間的呼叫關係,這個時候,螞蟻用了兩種硬負載 F5 或是 LVS。
通過簡單的4層代理,我們可以把服務部署在代理的後面,服務與服務之間通過代理互相訪問,達到了跨機呼叫的目的
第一代註冊中心 -- 硬負載到軟負載的演變
通過硬負載訪問的方式,一方面解決了服務之間互相呼叫的問題,部署架構也簡單易懂;另一方面,在業務快速增長之後,卻帶來了一定的問題:
- 單點的問題(所有呼叫都走F5的話,F5一旦掛了,很多服務會不可用)
- 容量問題(F5承載的流量太高,本身會到一個效能瓶頸)
這個時候,螞蟻引進了阿里集團的一款產品叫ConfigServer,作為註冊中心進行使用,這個註冊中心的架構就和開頭提到的架構很像了,服務之間可以通過IP直接訪問,而降低了對負載均衡產品的強依賴,減少了單點風險。
第二代註冊中心 -- ScaleUp?ScaleOut?It's a problem
但是,問題還在持續,那就是註冊中心,本身是一個單點,那麼,他就會繼續遇到上文中所說的兩個問題
- 單點風險(註冊中心本身是單機應用)
- 容量瓶頸(單臺註冊中心的連線數和儲存資料的容量是有限的)
解決的方式有兩種
- scale-up(淘寶):通過增加機器的配置,來增強容量以及扛連結能力;同時,通過主-備這樣的架構,來保障可用性
- scale-out(螞蟻):通過分片機制,將資料和連結均勻分佈在多個節點上,做到水平擴充;通過分片之後的備份,做到高可用
螞蟻和淘寶走了兩條不同的路,也推進了螞蟻后面演進出一套獨立的生態系統
螞蟻的演進架構如下,產生了兩種不同的應用節點
- session節點,專門用來抗連結使用,本身無狀態可以快速擴充套件,單機對資源的佔用很小
- data節點,專門用來儲存資料,通過分片的方式降低單個節點的儲存量,控制資源佔用
第五代註冊中心 -- Meta節點的誕生
上面的架構已經很符合目前主流的分散式架構了,但是在運維過程中,產生了一系列問題,比如
- 所有data都是分散式的,data之間的服務發現需要通過啟動時給定一個配置檔案,這樣就和標準運維脫鉤
- data節點的上下線需要去及時修改配置檔案,否則叢集重啟會受到影響
- 分散式儲存一致性問題,每次迭代釋出,需要鎖定paas平臺,防止節點變動帶來的不一致
所有這些問題的產生,我們發現可以引入一個後設資料管理中心(Meta)節點來,解決對data和session管理的問題,data和session通過4層負載或是7層負載對meta訪問即可.
對比業界的解決方案,都有類似的模型,比如HDFS的Name Node、Kafka依賴於ZK,Oceanbase依賴於RootServer 或者 配置中心Apollo依賴於Euraka。
Meta節點的出現,緩解了手工運維註冊中心的瓶頸,但是,依然沒有從根本上解決問題,那麼問題在哪裡?詳見下文分析。
第六代註冊中心 -- 面向運維的註冊中心
上文說道,Meta節點的出現,承接了Data以及Session之間服務發現的問題,但是,叢雲未測來講,還是有很多問題解決不了,比如
- Data節點的釋出在資料量大的前提下,依然是個痛點
- Session節點的新加節點上,可能很久都沒有流量
等等,對於這些問題,在SOFARegistry5.x的基礎上,我們快速迭代了6.0版本,主要是面向運維的註冊中心。
Data節點發布難的問題,說到底是一個影響範圍的問題,如何控制單一data節點發布或者掛掉對資料的影響面,是解決問題的本源,這裡我們採用了兩個措施
- 改進資料儲存演算法(consistent-hash -> hash-slot)
- 應用級服務發現
儲存演算法的演進
之前我們使用了一致性hash的演算法,如下圖所示,每一個節點承載一部分資料,通過是儲存進行hash運算,算出儲存內容的hash值,再計算出hash值落在哪一個data所負責的儲存區間,來儲存資料。
當data節點當機或者重啟時,由下一個data節點接收當機節點的資料以及資料的訪問支援。
這樣依賴,資料遷移的粒度只能以單個data節點所儲存的資料為單位,在資料量較大(單節點8G)的情況下,對資料的重建有一定的影響,而且,在data連續當機的情況下,可能存在資料丟失或是不一致的場景。
改進後的演算法,我們參考了Redis Cluster的演算法機制,使用hash slot進行資料分片
這樣,在data釋出過程中,可以控制資料的遷移以slot為單位(單個data節點多個slot,可配置)
同時,為了解決遷移或是當機期間,資料寫入不一致的場景,我們引入了資料回放的補償機制,data在promotion為slot的master之後,會主動地去和所有的session完成一次資料比對/校驗,增量同步新增資料
應用級服務發現
應用級服務發現是為了解決資料儲存量大的問題,因為篇幅原因,這裡略過不表
開源
SOFARegistry從專案早期就開始了開源的程式,與目前主流的註冊中心的對比如下
我們認為,註冊中心首先需要解決的是可用性的問題,所以,在分散式一致性的問題上,我們選擇了AP的模型,這點也和主流的註冊中心,例如Euraka以及Nacos保持一致的觀點。
其次,在效能方面,基於長連線的SOFARegistry擁有更短的推送延遲,相較於Nacos1.0的推送時延更短(Nacos1.0基於Long Polling的模型,Nacos2.0也使用了長連線的模型)
在協議方面,SOFARegistry使用了螞蟻開源協議棧:BOLT協議(類似於HTTP2.0)的流式協議,更加輕量級,同時協議本身的全雙工模式:無阻塞,大大提升了資源利用率。
Feature | Consul | Zookeeper | Etcd | Eureka | Nacos | SOFARegistry |
---|---|---|---|---|---|---|
服務健康檢查 | 定期healthcheck (http/tcp/script/docker) | 定期心跳保持會話(session) + TTL | 定期refresh(http)+TTL | 定期心跳+TTL;支援自定義healthCheck | 定期連結心跳+斷鏈 | 定期連線心跳 + 斷鏈敏感 |
多資料中心 | 支援 | - | - | - | 支援 | 支援 |
Kv儲存服務 | 支援 | 支援 | 支援 | - | 支援 | 支援 |
一致性 | raft | ZAB | raft | 最終一致性 | 最終一致(註冊中心) Raft(配置中心) | 最終一致性 |
cap | cp | cp | cp | ap | ap+cp | ap |
使用介面(多語言能力) | 支援http和dns | 客戶端 | http/grpc | 客戶端/http | 客戶端(多語言) http | 客戶端(java) |
watch支援 | 全量/支援long polling | 支援 | 支援long polling | 不支援(client定期fetch) | 支援 | 支援(服務端推送) |
安全 | acl/https | acl | https支援 | - | https | acl |
spring cloud整合 | 支援 | 支援 | 支援 | 支援 | 支援 | 支援 |
和大家所熟知的Nacos對比,我們在金融級和分散式(儲存量級)上具有很大優勢,易用性和雲原生方面,目前還在追趕
歡迎加入我們
一個人可以走得很快,但一群人可以走的更遠 -- 題記
SOFARegistry是一個開源專案,也是開源社群SOFA重要的一環,我們希望用社群的力量推動SOFARegistry的前進,而不是隻有螞蟻的工程師去開發。我們在今年也啟動了兩個專案,用於支援更多的開發者參與進來:
- Trun-Key Project (開箱即用計劃):github.com/sofastack/s…
- Deep-Dive Project(深入淺出計劃):github.com/sofastack/s…
計劃目前還處在初期階段,歡迎大家加入進來,可以幫助我們解決一個issue,或是寫一篇文件,都可以更好地幫助社群,幫助自己去成長。
本週推薦閱讀
更多文章請掃碼關注“金融級分散式架構”公眾號