SpringCloud Alibaba Nacos服務(wù)注冊中心解讀
1. 什么是注冊中心?
注冊中心是微服務(wù)架構(gòu)中的一個重要組件,它用于實現(xiàn)服務(wù)注冊與服務(wù)發(fā)現(xiàn)。
【思考一】什么叫服務(wù)注冊 ? 什么叫服務(wù)發(fā)現(xiàn) ?

- 服務(wù)注冊就是生產(chǎn)者,它是服務(wù)的提供方,它用于將服務(wù)存儲起來;
- 服務(wù)發(fā)現(xiàn)是注冊中心將服務(wù)列表推送給調(diào)用服務(wù)的消費者 / 消費者向注冊中心拉取服務(wù)列表;
Nacos 結(jié)合了兩者的優(yōu)勢,提供了一個更加靈活和高效的服務(wù)發(fā)現(xiàn)機制。在默認(rèn)情況下,Nacos 使用推模式來通知消費者,但消費者仍然會定期拉取服務(wù)列表,以應(yīng)對可能出現(xiàn)的消息丟失或延遲等問題。
【思考二】為什么需要服務(wù)注冊和服務(wù)發(fā)現(xiàn)呢 ?服務(wù)之間直接調(diào)用存在什么問題呢 ?
- ① 服務(wù)注冊與服務(wù)發(fā)現(xiàn)是為了更好的實現(xiàn)服務(wù)與服務(wù)之間的通信,降低服務(wù)與服務(wù)間的耦合度。(健康檢測機制)。
- ② 服務(wù)之間直接調(diào)用存在的問題:
- 每個服務(wù)都可能有很多份,那我在調(diào)用的時候,就需要寫很多份,而且需要一個一個手動分配,工作量太大;
- 微服務(wù)里邊,服務(wù)起碼得是集群B1,B2,B3......,如果直接寫死,當(dāng)某一天,某些服務(wù)掛了,就會引發(fā)一系列問題,從而就無法保證系統(tǒng)的高可用。
具體有以下幾個問題:
- 單點故障:因為調(diào)用方直接依賴于特定的服務(wù)實例,所以當(dāng)這個實例不可用時,調(diào)用方無法找到其他的可用實例,從而導(dǎo)致整個調(diào)用鏈路中斷。
- 延遲與超時:當(dāng)一個服務(wù)不可用,調(diào)用方可能會因為網(wǎng)絡(luò)超時而等待很長時間,這會導(dǎo)致用戶體驗下降,并可能引發(fā)其他的連鎖故障。
- 無法進行負(fù)載均衡:如果多個實例都可用,但調(diào)用方總是直接調(diào)用某一個特定實例,那么這將導(dǎo)致流量分布不均,某些實例可能會過載,而其他實例則處于空閑狀態(tài)。
- 無法進行故障轉(zhuǎn)移:當(dāng)目標(biāo)服務(wù)實例出現(xiàn)故障時,調(diào)用方無法自動切換到其他健康的實例。
- 擴展性受限:如果服務(wù)需要進行擴展,增加新的實例,調(diào)用方可能需要修改代碼或配置來適應(yīng)新的服務(wù)地址,這增加了運維的復(fù)雜性。
- 不透明的依賴關(guān)系:如果所有的服務(wù)都是直接相互調(diào)用,那么很難快速地了解服務(wù)之間的依賴關(guān)系,這在故障排查時可能會增加很多麻煩。
基于以上問題,所以我們需要使用服務(wù)注冊于服務(wù)發(fā)現(xiàn)來更好的實現(xiàn)服務(wù)與服務(wù)之間的通信!
注冊中心的作用
- 服務(wù)注冊:服務(wù)實例啟動時,將自身注冊到注冊中心,包括服務(wù)名,地址,端口等;
- 服務(wù)發(fā)現(xiàn):消費者向注冊中心拉取服務(wù)列表 / 注冊中心推送服務(wù)列表給消費者;
- 服務(wù)健康檢測:注冊中心會定期檢測服務(wù)實例的健康狀態(tài),并過濾不健康的實例;
- 服務(wù)路由:決定如何將請求分發(fā)到合適的服務(wù)實例,通常涉及到負(fù)載均衡策略;
- 服務(wù)監(jiān)控:監(jiān)控服務(wù)的狀態(tài),如響應(yīng)時間、錯誤率等,以便及時發(fā)現(xiàn)并處理問題;
- 服務(wù)更新:當(dāng)服務(wù)實例信息變更時,向注冊中心發(fā)送更新信息通知。
2. SpringBoot 整合 Nacos 實現(xiàn)服務(wù)注冊中心
2.1 將服務(wù)注冊到 Nacos
實現(xiàn)之前,Nacos 服務(wù)要啟動起來,創(chuàng)建好 SpringBoot 多模塊項目(一個父模塊和兩個子模塊)
如果不會創(chuàng)建 SpringBoot 多模塊項目的,可以去看我的這篇文章:http://m.fzitv.net/program/360523q80.htm
【實現(xiàn)步驟】
- 添加 Nacos discovery 支持
- 配置 Nacos 連接信息
- 編寫代碼(開發(fā)接口)
PS:完成以上三步后,當(dāng)前項目就會自動注冊到 Nacos 中!
Nacos 連接信息
spring:
application:
name: nacos-discovery-demo
# Nacos 服務(wù)名 (命名不要使用下劃線 _,早期的SpringCloud版本不支持)
cloud:
nacos:
discovery:
server-addr: localhost:8848 # 連哪個 Nacos 的注冊中心
username: nacos
password: nacos
# ephemeral: false # false 設(shè)置此服務(wù)為永久實例,true 為臨時實例
server:
port: 0 # 動態(tài)端口號實現(xiàn)接口
@RestController
@RequestMapping("/user")
public class UserController {
@Autowired
private ServletWebServerApplicationContext context; // 用于獲取動態(tài)端口號
// 服務(wù)
@RequestMapping("/getnamebyid")
public String getNameById(Integer id) {
return "provider-name-" + id +
" | port:" + context.getWebServer().getPort();
}
}
PS:接口的實現(xiàn)不重要,重要的是我們能把它注冊到注冊中心,然后能通過另一個項目,調(diào)用到它!
【思考】為什么服務(wù)注冊到注冊中心,需要使用動態(tài)端口? 而不使用固定端口?
只有當(dāng)用戶去使用 Nacos 的時候,才需要使用一個固定的端口號,它不能每次變化,每次變的話,用戶就猜不出來這個端口號是多少。
而對于微服務(wù)這邊,它只需要將服務(wù)注冊到注冊中心,供消費者來使用,具體端口號是多少,對于程序來說,它不必預(yù)先知道。
并且使用動態(tài)端口有以下好處:
- 靈活性:動態(tài)端口允許服務(wù)在任何可用的端口上啟動,避免了手動配置端口或處理端口沖突的問題。
- 高可用性:如果某個端口不可用(被其他進程占用或由于某些原因被阻止),服務(wù)可以選擇其他任何可用的端口來啟動,這增加了 服務(wù)的高可用性。
- 簡化配置:不需要為每個服務(wù)的實例手動分配和管理固定的端口號。
- 支持多實例:動態(tài)端口允許在同一臺機器上運行多個相同的服務(wù)實例,這對于快速擴展和負(fù)載均衡很有利。
【測試服務(wù)注冊中心】
當(dāng)我們將服務(wù)注冊到注冊中心后,就可以在 Nacos 控制臺看到這些信息了:

這個時候,我們就可以測試一下微服務(wù)里邊的接口好不好使,點擊操作下面的詳情:

我們拿著 IP + 動態(tài)端口去訪問接口,是可以正常訪問得到的:

【上線下線 Nacos 服務(wù)的作用】
服務(wù)的上線與下線通常是指服務(wù)實例的動態(tài)注冊與注銷,利用這一特性,可以實現(xiàn)以下幾種發(fā)布策略:
- 灰度發(fā)布:灰度發(fā)布是指先讓部分用戶試用新版本,而其它用戶還在使用舊版本。通過Nacos,可以將新版本的服務(wù)實例注冊到Nacos中,然后通過權(quán)重配置,讓部分用戶路由到新的服務(wù)實例上。(也可以通過標(biāo)簽配合 geteway 網(wǎng)關(guān)規(guī)則)
- 藍綠部署:藍綠部署是一種將新舊版本同時部署的策略,通過路由控制用戶流量到不同的版本。通過Nacos的服務(wù)注冊與發(fā)現(xiàn),可以輕松地實現(xiàn)藍綠部署:新版本(綠色)可以注冊到Nacos,當(dāng)確認(rèn)新版本穩(wěn)定后,可以將流量切換到新版本,同時下線舊版本(藍色)。
- 金絲雀發(fā)布:金絲雀發(fā)布是灰度發(fā)布的一種,它先將新版本發(fā)布給一小部分用戶,然后根據(jù)這部分用戶的反饋和系統(tǒng)的表現(xiàn),決定是否將新版本推廣給更多的用戶。利用Nacos的權(quán)重配置,可以輕松地實現(xiàn)金絲雀發(fā)布。
- 緊急回滾:如果新版本出現(xiàn)問題,就可以快速地在Nacos中下線新版本的服務(wù)實例,同時上線舊版本的服務(wù)實例,以此來實現(xiàn)緊急回滾。
PS:當(dāng)服務(wù)被下線時,注冊中心在公布服務(wù)列表的時候,就不會包含已經(jīng)下線的服務(wù)了,即使它是健康狀態(tài)。
【點擊上線或下線報錯問題】
當(dāng)點擊上線下線如果報錯了,或者創(chuàng)建臨時實例 / 永久實例,報錯了,可以通過以下方法來解決:
① 停止 Nacos 服務(wù) (Ctrl C 多按幾遍)
② 刪除 nacos/data 目錄下的 protocol 文件夾 (非常好使)

③ 開啟 Nacos 服務(wù),再次點擊上下線就不會報錯了
2.2 實現(xiàn)消費者
【前置工作】
1. 創(chuàng)建一個消費者的 module,在 pom.xml 文件中聲明父節(jié)點
<parent>
<groupId>com.example</groupId>
<artifactId>nacos-discovery-demo</artifactId>
<version>0.0.1-SNAPSHOT</version>
</parent>2. 刪除不必要的依賴:test,nacos-discovery,java.version 等聲明,以及 dependencyManagement 依賴。
3. 在父模塊中聲明子模塊
<modules>
<module>provider</module>
<module>consumer</module>
</modules>【實現(xiàn)步驟】
- 添加框架支持 【nacos discovery、spring cloud LoadBalancer、spring cloud OpenFeign】
- 配置 Nacos 連接信息
- 開啟 OpenFeign 功能
- 聲明 OpenFeign 式的 Service 【生產(chǎn)者的的服務(wù)】
- 調(diào)用服務(wù)【調(diào)用生產(chǎn)者的服務(wù)】
配置 Nacos 連信息
spring:
application:
name: nacos-consumer-demo
cloud:
nacos:
discovery:
server-addr: localhost:8848
username: nacos
password: nacos
register-enabled: false #消費者(不需要將此服務(wù)注冊到 nacos)
server:
port: 8080 # 使用固定端口開啟 OpenFeign 功能
@SpringBootApplication
@EnableFeignClients // 開啟 OpenFeign
public class ConsumerApplication {
public static void main(String[] args) {
SpringApplication.run(ConsumerApplication.class, args);
}
}
PS:在啟動類上加上@EnableFeignClients 注解!
聲明 OpenFeign 式的 Service
@Service
@FeignClient("nacos-discovery-demo") //調(diào)用nacos中的nacos-discovery-demo服務(wù)
public interface UserService {
@RequestMapping("/user/getnamebyid") // 調(diào)用生產(chǎn)者的接口
public String getNameById(@RequestParam("id") Integer id); //@RequestParam
}
方法中的參數(shù)最好添加 @RequestParam 注解,否則可能拿不到參數(shù)。
調(diào)用服務(wù)
@RestController // 消費者
public class BusinessController {
@Autowired
private UserService userService;
@RequestMapping("/getnamebyid")
public String getNameById(Integer id) {
return userService.getNameById(id);
}
}【測試消費者】
開啟兩個生產(chǎn)者和一個消費者(測試負(fù)載均衡默認(rèn)的輪詢方式)


根據(jù)配置信息,使用 localhost:8080/getnamebyid?id=2 進行訪問>>
第一次訪問:

刷新后:(輪詢的方式)

3. 服務(wù)列表各個參數(shù)的含義、作用以及應(yīng)用場景

1. 服務(wù)名:服務(wù)的唯一標(biāo)識符,用于區(qū)分不同的服務(wù),對應(yīng)我們配置文件寫的 spring.application.name.

2.分組名稱:服務(wù)的分組標(biāo)識,用于將服務(wù)進行邏輯隔離的。我們可以根據(jù)不同的環(huán)境或用途為服務(wù)設(shè)置不同的分組,例如“測試組”、“開發(fā)組”、“生產(chǎn)組”等。這樣的隔離機制有助于管理和維護服務(wù)。
3. 集群數(shù)目:在一個服務(wù)內(nèi),可以有多個集群,每個集群下有多個服務(wù)實例。
4. 實例數(shù):當(dāng)前服務(wù)注冊到Nacos的總實例數(shù)量,包括健康和不健康的實例。
5. 健康實力數(shù):可以正常提供服務(wù),沒有故障的實例。
6. 觸發(fā)保護閾值:它是一個 0-1 之間的數(shù),表示當(dāng)健康實例數(shù)低于此閾值時,Nacos會阻止所有服務(wù)實例的自動注銷,以保護剩余的健康實例。(可以在服務(wù)詳情里面的編輯服務(wù)中進行設(shè)置)
為什么要有保護閾值 ?
它是為了防止服務(wù)雪崩的。比如說服務(wù)集群里邊原本有 1000 個實例,但是現(xiàn)在有999 個實例都掛了,只剩下一個實例了,那么原本 1000 個人干的活,現(xiàn)在就只剩一個人了,如果我們再把所有的活再派給這一個人來干,那么這個人他肯定也不在了,他肯定離職了。對于咱們系統(tǒng)來說也是一樣,如果集群實例數(shù)太少的話,這時候還把所有的流量分發(fā)過去,那就會造成服務(wù)癱瘓,進而造成上游調(diào)用這個服務(wù)的整體癱瘓,進而造成服務(wù)雪崩。所以需要保護閾值。
保護閾值它是如何防止服務(wù)雪崩的 ?
想要解決服務(wù)雪崩,無非就是加鎖排隊,但是 Nacos 它本身又不做限流,只有注冊中心和配置中心,那它是怎么做到既沒有限流功能,又要保證不會發(fā)生雪崩問題的呢?它的做法是 "躺平",當(dāng)保護閾值為 true 的時候,它會將所有的請求分發(fā)給所有的服務(wù)實例(不管健康與否),即使有些服務(wù)實例已經(jīng)掛掉了,以此來保護所剩無幾的健康實例!
【保護閾值演示案例】
① 準(zhǔn)備兩個永久服務(wù)實例,一個消費者,然后停掉一個服務(wù)
如何快速創(chuàng)建相同實例 >>


PS:永久實例 - 對應(yīng)配置文件中的ephemeral: false

② 將保護閾值設(shè)置為 0.5,這時保護閾值就變?yōu)?true 了

③ 使用消費者調(diào)用服務(wù)
例如:localhost:8080/getnamebyid?id=2
當(dāng)我們更改了權(quán)重,閾值等參數(shù),它默認(rèn)是會有緩存的,感知不到,所以需要重啟消費者才能看到 nacos 的防止雪崩的策略。
重啟消費者后 >>
第一次訪問:

第二次訪問:

PS:第三次訪問和第一次訪問一樣,第四次訪問又報錯,這就是 Nacos 的一個解決服務(wù)雪崩的手段!
【服務(wù)詳情中的一些參數(shù)的含義】
1. 元數(shù)據(jù):與服務(wù)相關(guān)的額外信息,可以是鍵值對形式的任意數(shù)據(jù)。(它會自動設(shè)置進去)
2. 服務(wù)路由類型:用于指定如何在消費者和成產(chǎn)者之間進行路由決策的,它可以實現(xiàn)請求的負(fù)載均衡。

PS:服務(wù)路由類型最主要的作用就是實現(xiàn) CMDB,地域就近訪問的,什么叫地域就近訪問 ?

當(dāng)有北京的調(diào)用者來獲取服務(wù)的時候,他肯定是調(diào)用北京的服務(wù)是最快的,因為對于北京的調(diào)用者來說,北京的網(wǎng)絡(luò),路由調(diào)的次數(shù)肯定比深圳少,所以它的速度肯定快,那么深圳的調(diào)用者肯定是調(diào)用深圳的服務(wù)最快,這就是地域就近訪問。
3. 權(quán)重:實例級別的設(shè)置。范圍為 0-10000,用于負(fù)載均衡決策,權(quán)重越大,分配給該實例的流量越大。當(dāng)權(quán)重為 0 的時候,和點擊下線功能是一樣的效果。
Nacos 的負(fù)載均衡策略總的來說有兩種方式:
① 基于健康檢測和權(quán)重
② 基于第三方 CMDB 的標(biāo)簽負(fù)載均衡器
這在官方的 《Nacos架構(gòu)與原理》一書中原話是這樣說的:
在 Nacos 0.7.0 版本中,我們除了提供基于健康檢查和權(quán)重的負(fù)載均衡方式外, 還新提供了基于第三方 CMDB 的標(biāo)簽負(fù)載均衡器
臨時實例 VS 永久實例
① 定義和刪除方式不同
- 1. 永久實例:其注冊信息會一直保留在 Nacos 服務(wù)器上,直到主動注銷或被刪除。這就意味著即使服務(wù)實例下線,或者不健康了,他的注冊信息仍然會保留在 Nacos 上。
- 2. 臨時實例:其注冊信息在服務(wù)實例下線,斷開連接或者不健康時,會自動從服務(wù)注冊列表中被刪除。
如何刪除永久實例:1.停服務(wù);2. 刪除 nacos/data 目錄下的 protocol 文件夾;3. 啟動 nacos 服務(wù)
② 健康檢測機制不同
- 1. 永久實例:服務(wù)器反向探測機制,服務(wù)器主動來詢問永久實例的健康與否。
- 2. 臨時實例:客戶端主動上報機制,客戶端主動向服務(wù)器匯報自己的健康與否。
PS:臨時實例每隔 5 秒就會主動上報一次自己的健康狀態(tài),發(fā)送的數(shù)據(jù)包叫做心跳包,發(fā)送心跳包的機制叫做心跳機制。如果Nacos 服務(wù)端在 15 秒都沒收到心跳,就會將實例設(shè)置為不健康,在 30 秒沒收到心跳時就會將這個臨時實例摘除。
總結(jié)
以上為個人經(jīng)驗,希望能給大家一個參考,也希望大家多多支持腳本之家。
- SpringCloud alibaba使用Nacos配置中心解讀
- SpringCloudAlibaba分布式配置中心Nacos持久化方式
- springcloud alibaba nacos config無法加載配置文件的解決方案
- Alibaba?SpringCloud集成Nacos、openFeign實現(xiàn)負(fù)載均衡的解決方案
- SpringCloudAlibaba Nacos開啟鑒權(quán)解決跳過登錄頁面問題
- SpringCloud?Alibaba環(huán)境集成之nacos詳解
- SpringCloud Alibaba Nacos 整合SpringBoot Admin實戰(zhàn)
相關(guān)文章
Java模擬rank/over函數(shù)實現(xiàn)獲取分組排名的方法詳解
這篇文章主要為大家詳細介紹了Java模擬rank()、over()函數(shù)獲取分組排名的方法設(shè)計及實現(xiàn),文中的示例代碼講解詳細,感興趣的小伙伴可以了解一下2023-04-04
Struts2中validate數(shù)據(jù)校驗的兩種方法詳解附Struts2常用校驗器
這篇文章主要介紹了Struts2中validate數(shù)據(jù)校驗的兩種方法及Struts2常用校驗器,本文介紹的非常詳細,具有參考借鑒價值,感興趣的朋友一起看看吧2016-09-09

