分布式技術(shù)原理與實(shí)戰(zhàn)45講--第14講:如何實(shí)現(xiàn)服務(wù)注冊(cè)與發(fā)現(xiàn)
你好,歡迎來到第 14 課時(shí),本課時(shí)主要講解如何實(shí)現(xiàn)服務(wù)注冊(cè)與發(fā)現(xiàn)。
在分布式服務(wù)中, 服務(wù)注冊(cè)和發(fā)現(xiàn) 是一個(gè)特別重要的概念,為什么需要服務(wù)注冊(cè)和發(fā)現(xiàn)?常用的服務(wù)發(fā)現(xiàn)組件有哪些?服務(wù)注冊(cè)和發(fā)現(xiàn)對(duì)一致性有哪些要求呢?下面我們就來學(xué)習(xí)服務(wù)發(fā)現(xiàn)相關(guān)的知識(shí)。
為什么需要服務(wù)注冊(cè)和發(fā)現(xiàn)
分布式系統(tǒng)下微服務(wù)架構(gòu)的一個(gè)重要特性就是可以快速上線或下線,從而可以讓服務(wù)進(jìn)行水平擴(kuò)展,以保證服務(wù)的可用性。
假設(shè)有一個(gè)電商會(huì)員服務(wù),隨著業(yè)務(wù)發(fā)展,服務(wù)器負(fù)載越來越高,需要新增服務(wù)器。如果沒有服務(wù)注冊(cè)與發(fā)現(xiàn),就要把新的服務(wù)器地址配置到所有依賴會(huì)員模塊的服務(wù),并相繼重啟它們,這顯然是不合理的。
服務(wù)注冊(cè)與發(fā)現(xiàn)就是保證當(dāng)服務(wù)上下線發(fā)生變更時(shí),服務(wù)消費(fèi)者和服務(wù)提供者能夠保持正常通信。
有了服務(wù)注冊(cè)和發(fā)現(xiàn)機(jī)制,消費(fèi)者不需要知道具體服務(wù)提供者的真實(shí)物理地址就可以進(jìn)行調(diào)用,也無須知道具體有多少個(gè)服務(wù)者可用;而服務(wù)提供者只需要注冊(cè)到注冊(cè)中心,就可以對(duì)外提供服務(wù),在對(duì)外服務(wù)時(shí)不需要知道具體是哪些服務(wù)調(diào)用了自己。
服務(wù)注冊(cè)和發(fā)現(xiàn)原理
服務(wù)注冊(cè)和發(fā)現(xiàn)的基本流程如下圖所示:

首先,在服務(wù)啟動(dòng)時(shí),服務(wù)提供者會(huì)向注冊(cè)中心注冊(cè)服務(wù),暴露自己的地址和端口等,注冊(cè)中心會(huì)更新服務(wù)列表。服務(wù)消費(fèi)者啟動(dòng)時(shí)會(huì)向注冊(cè)中心請(qǐng)求可用的服務(wù)地址,并且在本地緩存一份提供者列表,這樣在注冊(cè)中心宕機(jī)時(shí)仍然可以正常調(diào)用服務(wù)。
如果提供者集群發(fā)生變更,注冊(cè)中心會(huì)將變更推送給服務(wù)消費(fèi)者,更新可用的服務(wù)地址列表。
典型服務(wù)發(fā)現(xiàn)組件的選型
在目前的微服務(wù)解決方案中,有三種典型的服務(wù)發(fā)現(xiàn)組件,分別是 ZooKeeper、Eureka 和 Nacos。
ZooKeeper
ZooKeeper 主要應(yīng)用在 Dubbo 的注冊(cè)中心實(shí)現(xiàn),由于 Dubbo 在國內(nèi)的流行,Dubbo + ZooKeeper 的典型服務(wù)化方案,使得 ZooKeeper 成為注冊(cè)中心的經(jīng)典解決方案。
ZooKeeper 是一個(gè)樹形結(jié)構(gòu)的目錄服務(wù),支持變更推送。使用 ZooKeeper 實(shí)現(xiàn)服務(wù)注冊(cè),就是應(yīng)用了這種目錄結(jié)構(gòu)。
服務(wù)提供者在啟動(dòng)的時(shí)候,會(huì)在 ZooKeeper 上注冊(cè)服務(wù)。以 com.dubbo.DemoService 為例,注冊(cè)服務(wù),其實(shí)就是在 ZooKeeper 的 /dubbo/com.dubbo.DemoService/providers 節(jié)點(diǎn)下創(chuàng)建一個(gè)子節(jié)點(diǎn),并寫入自己的 URL 地址,這就代表了 com.dubbo.DemoService 這個(gè)服務(wù)的一個(gè)提供者。
服務(wù)消費(fèi)者在啟動(dòng)的時(shí)候,會(huì)向 ZooKeeper 注冊(cè)中心訂閱服務(wù)列表,就是讀取并訂閱 ZooKeeper 上 /dubbo/com.dubbo.DemoService/providers 節(jié)點(diǎn)下的所有子節(jié)點(diǎn),并解析出所有提供者的 URL 地址來作為該服務(wù)地址列表。
Eureka
在 Spring Cloud 中,提供了 Eureka 來實(shí)現(xiàn)服務(wù)發(fā)現(xiàn)功能。Eureka 采用的是 Server 和 Client 的模式進(jìn)行設(shè)計(jì),Eureka Server 扮演了服務(wù)注冊(cè)中心的角色,為 Client 提供服務(wù)注冊(cè)和發(fā)現(xiàn)的功能。
Eureka Client 通過客戶端注冊(cè)的方式暴露服務(wù),通過注解等方式嵌入到服務(wù)提供者的代碼中,當(dāng)服務(wù)啟動(dòng)時(shí),服務(wù)發(fā)現(xiàn)組件會(huì)向注冊(cè)中心注冊(cè)自身提供的服務(wù),并周期性地發(fā)送心跳來更新服務(wù)。

如果連續(xù)多次心跳不能夠發(fā)現(xiàn)服務(wù),那么 Eureka Server 就會(huì)將這個(gè)服務(wù)節(jié)點(diǎn)從服務(wù)注冊(cè)表中移除,各個(gè)服務(wù)之間會(huì)通過注冊(cè)中心的注冊(cè)信息來實(shí)現(xiàn)調(diào)用。
Euerka 在 Spring Cloud 中廣泛應(yīng)用,目前社區(qū)中集成的是 1.0 版本,在后續(xù)的版本更新中,Netflix 宣布 Euerka 2.0 閉源,于是開源社區(qū)中也出現(xiàn)了許多新的服務(wù)發(fā)現(xiàn)組件,比如 Spring Cloud Alibaba Nacos。
Nacos
Nacos 是阿里巴巴推出來的一個(gè)開源項(xiàng)目,提供了服務(wù)注冊(cè)和發(fā)現(xiàn)功能,使用 Nacos 可以方便地集成 Spring Cloud 框架。如果正在使用 Eureka 或者 Consul,可以通過少量的代碼就能遷移到 Nacos 上。
Nacos 的應(yīng)用和 Eureka 類似,獨(dú)立于系統(tǒng)架構(gòu),需要部署 Nacos Server。除了服務(wù)注冊(cè)和發(fā)現(xiàn)之外,Nacos 還提供了配置管理、元數(shù)據(jù)管理和流量管理等功能,并且提供了一個(gè)可視化的控制臺(tái)管理界面。

關(guān)于 Nacos 的更多應(yīng)用,可以在 Nacos 官網(wǎng) 找到相關(guān)的文檔。
一致性對(duì)比
在討論分布式系統(tǒng)時(shí),一致性是一個(gè)繞不開的話題,在服務(wù)發(fā)現(xiàn)中也是一樣。CP 模型優(yōu)先保證一致性,可能導(dǎo)致注冊(cè)中心可用性降低,AP 模型優(yōu)先保證可用性,可能出現(xiàn)服務(wù)錯(cuò)誤。
為了保證微服務(wù)的高可用,避免單點(diǎn)故障,注冊(cè)中心一般是通過集群的方式來對(duì)外服務(wù),比如 ZooKeeper 集群。
ZooKeeper 核心算法是 Zab,實(shí)現(xiàn)的是 CP 一致性,所以 ZooKeeper 作為服務(wù)發(fā)現(xiàn)解決方案,在使用 ZooKeeper 獲取服務(wù)列表時(shí),如果 ZooKeeper 正在選主,或者 ZooKeeper 集群中半數(shù)以上機(jī)器不可用時(shí),那么將無法獲得數(shù)據(jù)。
在 Spring Cloud Eureka 中,各個(gè)節(jié)點(diǎn)都是平等的,幾個(gè)節(jié)點(diǎn)掛掉不影響正常節(jié)點(diǎn)的工作,剩余的節(jié)點(diǎn)依然可以提供注冊(cè)和查詢服務(wù)。只要有一臺(tái) Eureka 還在,就能保證注冊(cè)服務(wù)可用,只不過查到的信息可能不是最新的版本,不保證一致性。
Spring Cloud Nacos 在 1.0.0 版本正式支持 AP 和 CP 兩種一致性協(xié)議,可以動(dòng)態(tài)切換,感興趣的同學(xué)可以去了解一下。
對(duì)于服務(wù)注冊(cè)和發(fā)現(xiàn)場景來說,一般認(rèn)為,可用性比數(shù)據(jù)一致性更加重要。針對(duì)同一個(gè)服務(wù),即使注冊(cè)中心的不同節(jié)點(diǎn)保存的服務(wù)提供者信息不相同,會(huì)出現(xiàn)部分提供者地址不存在等,不會(huì)導(dǎo)致嚴(yán)重的服務(wù)不可用。對(duì)于服務(wù)消費(fèi)者來說,能消費(fèi)才是最重要的,拿到可能不正確的服務(wù)實(shí)例信息后嘗試消費(fèi),也要比因?yàn)闊o法獲取實(shí)例信息而拒絕服務(wù)好。
總結(jié)
這一課時(shí)主要分析了服務(wù)注冊(cè)和發(fā)現(xiàn)的基本流程、幾種典型的服務(wù)發(fā)現(xiàn)組件,以及在不同服務(wù)發(fā)現(xiàn)組件中,是如何實(shí)現(xiàn)一致性的。
你可以結(jié)合實(shí)際工作思考一下,目前公司里的服務(wù)發(fā)現(xiàn)是如何實(shí)現(xiàn)的,是自研還是使用開源組件,以及為什么選擇這種服務(wù)注冊(cè)和發(fā)現(xiàn)方式?