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

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

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

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

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

③ 開啟 Nacos 服務,再次點擊上下線就不會報錯了
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)者的的服務】
- 調(diào)用服務【調(diào)用生產(chǎn)者的服務】
配置 Nacos 連信息
spring:
application:
name: nacos-consumer-demo
cloud:
nacos:
discovery:
server-addr: localhost:8848
username: nacos
password: nacos
register-enabled: false #消費者(不需要將此服務注冊到 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服務
public interface UserService {
@RequestMapping("/user/getnamebyid") // 調(diào)用生產(chǎn)者的接口
public String getNameById(@RequestParam("id") Integer id); //@RequestParam
}
方法中的參數(shù)最好添加 @RequestParam 注解,否則可能拿不到參數(shù)。
調(diào)用服務
@RestController // 消費者
public class BusinessController {
@Autowired
private UserService userService;
@RequestMapping("/getnamebyid")
public String getNameById(Integer id) {
return userService.getNameById(id);
}
}【測試消費者】
開啟兩個生產(chǎn)者和一個消費者(測試負載均衡默認的輪詢方式)


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

刷新后:(輪詢的方式)

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

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

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


PS:永久實例 - 對應配置文件中的ephemeral: false

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

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

第二次訪問:

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

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

當有北京的調(diào)用者來獲取服務的時候,他肯定是調(diào)用北京的服務是最快的,因為對于北京的調(diào)用者來說,北京的網(wǎng)絡(luò),路由調(diào)的次數(shù)肯定比深圳少,所以它的速度肯定快,那么深圳的調(diào)用者肯定是調(diào)用深圳的服務最快,這就是地域就近訪問。
3. 權(quán)重:實例級別的設(shè)置。范圍為 0-10000,用于負載均衡決策,權(quán)重越大,分配給該實例的流量越大。當權(quán)重為 0 的時候,和點擊下線功能是一樣的效果。
Nacos 的負載均衡策略總的來說有兩種方式:
① 基于健康檢測和權(quán)重
② 基于第三方 CMDB 的標簽負載均衡器
這在官方的 《Nacos架構(gòu)與原理》一書中原話是這樣說的:
在 Nacos 0.7.0 版本中,我們除了提供基于健康檢查和權(quán)重的負載均衡方式外, 還新提供了基于第三方 CMDB 的標簽負載均衡器
臨時實例 VS 永久實例
① 定義和刪除方式不同
- 1. 永久實例:其注冊信息會一直保留在 Nacos 服務器上,直到主動注銷或被刪除。這就意味著即使服務實例下線,或者不健康了,他的注冊信息仍然會保留在 Nacos 上。
- 2. 臨時實例:其注冊信息在服務實例下線,斷開連接或者不健康時,會自動從服務注冊列表中被刪除。
如何刪除永久實例:1.停服務;2. 刪除 nacos/data 目錄下的 protocol 文件夾;3. 啟動 nacos 服務
② 健康檢測機制不同
- 1. 永久實例:服務器反向探測機制,服務器主動來詢問永久實例的健康與否。
- 2. 臨時實例:客戶端主動上報機制,客戶端主動向服務器匯報自己的健康與否。
PS:臨時實例每隔 5 秒就會主動上報一次自己的健康狀態(tài),發(fā)送的數(shù)據(jù)包叫做心跳包,發(fā)送心跳包的機制叫做心跳機制。如果Nacos 服務端在 15 秒都沒收到心跳,就會將實例設(shè)置為不健康,在 30 秒沒收到心跳時就會將這個臨時實例摘除。
總結(jié)
以上為個人經(jīng)驗,希望能給大家一個參考,也希望大家多多支持腳本之家。
相關(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

