開篇
這篇文章是基于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(配置中心) | ||
cap | cp | ap | ap+cp | |||
使用接口(多語言能力) | 支援http和dns | 用戶端 | http/grpc | 用戶端/http | 用戶端(多語言) http | 用戶端(java) |
watch支援 | 全量/支援long polling | 支援long polling | 不支援(client定期fetch) | 支援(服務端推送) | ||
安全 | acl/https | acl | https支援 | https | ||
spring cloud內建 |
和大家所熟知的Nacos對比,我們在金融級和分布式(存儲量級)上具有很大優勢,易用性和雲原生方面,目前還在追趕
![]()
我們做出了一個分布式注冊中心
歡迎加入我們
一個人可以走得很快,但一群人可以走的更遠
SOFARegistry是一個開源項目,也是開源社群SOFA重要的一環,我們希望用社群的力量推動SOFARegistry的前進,而不是隻有螞蟻的工程師去開發。我們在今年也啟動了兩個項目,用于支援更多的開發者參與進來:
- Trun-Key Project (開箱即用計劃): https://github.com/sofastack/sofa-registry/projects/5
- Deep-Dive Project(深入淺出計劃): https://github.com/sofastack/sofa-registry/projects/4
計劃目前還處在初期階段,歡迎大家加入進來,可以幫助我們解決一個issue,或是寫一篇文檔,都可以更好地幫助社群,幫助自己去成長。
本周推薦閱讀
- RFC8998+BabaSSL---讓國密駛向更遠的星辰大海
- 還在為多叢集管理煩惱嗎?OCM來啦!
- MOSN 子項目 Layotto:開啟服務網格+應用運作時新篇章
- 開啟雲原生 MOSN 新篇章 — 融合 Envoy 和 GoLang 生态
更多文章請掃碼關注“金融級分布式架構”公衆号
![]()
我們做出了一個分布式注冊中心