在分散式系統中,服務提供者和服務消費者不在同一個進程中運行,需要一個紐帶去連接它們。註冊中心就承擔了這一角色,它是微服務架構中實作服務發現的關鍵組件。
註冊中心的核心概念#
為什麼需要註冊中心#
想像一下,你發布了一個服務並部署在一台機器上。如果有人想呼叫這個服務,該如何知道你部署的這台機器的地址呢?
這就像你想去吃肯德基,可以去地圖上搜索,地圖會返回所有店面的地址。在分散式系統中,註冊中心就扮演著這個「地圖」的角色:
- 將部署服務的機器地址記錄到註冊中心
- 服務消費者查詢註冊中心,輸入服務名,得到地址
- 從而發起呼叫
三種角色#
在微服務架構下,主要有三種角色:
| 角色 | 說明 |
|---|---|
| 服務提供者 (RPC Server) | 提供服務的一方 |
| 服務消費者 (RPC Client) | 呼叫服務的一方 |
| 註冊中心 (Registry) | 服務地址的管理者 |
註冊中心的工作原理#
基本交互流程#
sequenceDiagram
participant P as 服務提供者<br/>(Provider)
participant R as 註冊中心<br/>(Registry)
participant C as 服務消費者<br/>(Consumer)
P->>R: 1. 註冊服務
C->>R: 2. 訂閱服務
R->>C: 3. 返回服務地址列表
Note over P,C: 服務運行中...
R-->>C: 4. 發生變化時推送通知
C->>P: 5. 發起呼叫詳細工作流程#
1. 服務註冊
服務提供者在啟動時,根據服務發布文件中組態的發布資訊向註冊中心註冊自己的服務。
2. 服務訂閱
服務消費者在啟動時,根據消費者組態文件中組態的服務資訊向註冊中心訂閱所需要的服務。
3. 地址返回
註冊中心返回服務提供者地址列表給服務消費者。
4. 變更通知
當服務提供者發生變化(節點新增或銷毀),註冊中心將變更通知給服務消費者。
5. 本地緩存
服務消費者將服務節點列表緩存在本地內存中,並與 RPC Server 建立連接。
6. 發起呼叫
服務消費者從本地緩存的服務節點列表中,基於負載均衡算法選擇一台 RPC Server 發起呼叫。
註冊中心的核心功能#
必備的 API#
基本服務接口:
| 接口 | 說明 |
|---|---|
| 服務註冊接口 | 服務提供者完成服務註冊 |
| 服務反註冊接口 | 服務提供者完成服務注銷 |
| 心跳彙報接口 | 服務提供者完成節點存活狀態上報 |
| 服務訂閱接口 | 服務消費者獲取可用的服務提供者節點列表 |
| 服務變更查詢接口 | 服務消費者獲取最新的可用服務節點列表 |
後台管理接口:
| 接口 | 說明 |
|---|---|
| 服務查詢接口 | 查詢當前註冊了哪些服務資訊 |
| 服務修改接口 | 修改某一服務的資訊 |
健康狀態檢測#
註冊中心必須具備對服務提供者節點的健康狀態檢測功能,確保保存的服務節點都是可用的。
以 ZooKeeper 為例:
基於客戶端和服務端的長連接和會話超時控制機制實作:
- 客戶端和服務端建立連接後,會話隨之建立並生成全局唯一的 Session ID
- 服務端和客戶端維持長連接
- 在 SESSION_TIMEOUT 週期內,服務端檢測與客戶端的鏈路是否正常
- 客戶端定時向服務端發送心跳訊息(ping 訊息)
- 服務端重置下次 SESSION_TIMEOUT 時間
- 如果超過 SESSION_TIMEOUT 都沒有收到心跳訊息,認為 Session 已經結束,將服務節點從註冊中心刪除
服務狀態變更通知#
一旦註冊中心探測到有服務提供者節點新加入或被剔除,必須立刻通知所有訂閱該服務的服務消費者。
以 ZooKeeper 的 Watcher 機制為例:
- 服務消費者呼叫 getData 方法訂閱服務時,可以通過監聯器 Watcher 獲取服務變更
- 當服務變更時,通過 Watcher 的 process 方法獲取通知
- 然後呼叫 getData 方法獲取變更後的資料
- 刷新本地緩存的服務節點資訊
註冊中心的高可用設計#
集群部署#
註冊中心一般採用集群部署來保證高可用性,並通過分散式一致性協議確保不同節點之間的資料保持一致。
以 ZooKeeper 為例:
flowchart TB
subgraph ZK["ZooKeeper 集群"]
N1["Node 1<br/>(Leader)"]
N2["Node 2<br/>(Follower)"]
N3["Node 3<br/>(Follower)"]
N1 <-->|ZAB 協議| N2
N2 <--> N3
N1 <--> N3
end
C["服務提供者/服務消費者"]
C -->|連接任意節點| ZK
Note["因為它們的資料是一致的"]
style N1 fill:#fff3e0
style N2 fill:#e3f2fd
style N3 fill:#e3f2fdZooKeeper 的資料一致性保證:
| 機制 | 說明 |
|---|---|
| 內存存儲 | 每個 Server 在內存中存儲一份資料 |
| Leader 選舉 | 啟動時通過 Paxos 協議選舉 Leader |
| 資料更新 | Leader 負責處理所有資料更新操作(ZAB 協議) |
| 多數派原則 | 更新操作成功,當且僅當大多數 Server 在內存中成功修改 |
目錄存儲結構#
以 ZooKeeper 為例,註冊中心存儲服務資訊一般採用層次化的目錄結構:
/
├── services
│ ├── user-service
│ │ ├── providers
│ │ │ ├── 192.168.1.1:8080
│ │ │ └── 192.168.1.2:8080
│ │ └── consumers
│ │ └── 192.168.2.1:9090
│ └── order-service
│ ├── providers
│ │ └── 192.168.1.3:8080
│ └── consumers
└── configZNode 特性:
- 每個目錄叫做 znode,有唯一的路徑標識
- znode 可以包含資料和子 znode
- znode 中的資料可以有多個版本
白名單機制#
問題場景#
在實際的微服務測試和部署時,通常包含多套環境(生產環境、測試環境)。經常會出現開發或測試在部署時,錯誤地把測試環境下的服務節點註冊到了線上註冊中心集群。
這樣會導致線上流量呼叫到測試環境下的 RPC Server 節點,可能造成意想不到的後果。
解決方案#
註冊中心需要提供白名單機制:
- 只有添加到註冊中心白名單內的 RPC Server 才能呼叫註冊接口
- 可以避免測試環境中的節點意外跑到線上環境中
多環境隔離最佳實踐
- 網路隔離:生產環境和測試環境使用不同的網路段
- 註冊中心隔離:不同環境使用不同的註冊中心集群
- 白名單控制:即使共用註冊中心,也通過白名單控制註冊權限
- 環境標籤:服務註冊時攜帶環境標籤,註冊中心進行校驗
註冊中心 vs DNS#
註冊中心實作的服務發現與傳統的 DNS 有很多相似之處,但也有本質區別。
| 特性 | 註冊中心 | DNS |
|---|---|---|
| 實時性 | 秒級變更通知 | 依賴 TTL,分鐘級到小時級 |
| 健康檢查 | 內置健康檢查機制 | 無原生健康檢查 |
| 中繼資料 | 可存儲豐富的服務中繼資料 | 僅存儲 IP 地址 |
| 負載均衡 | 客戶端負載均衡 | 簡單的 Round-Robin |
| 協議支援 | 支援多種協議 | 主要用於 HTTP |
| 部署複雜度 | 較高 | 較低 |
常見的註冊中心實作#
ZooKeeper#
特點:
- 強一致性(CP 系統)
- 基於 ZAB 協議
- 支援 Watcher 機制
- 廣泛用於 Dubbo 生態
適用場景:對一致性要求高的場景
Eureka#
特點:
- 高可用性優先(AP 系統)
- 支援自我保護機制
- Netflix OSS 組件
- Spring Cloud 默認集成
適用場景:對可用性要求高的場景
Consul#
特點:
- 支援健康檢查
- 支援 Key/Value 存儲
- 支援多資料中心
- 提供 DNS 和 HTTP 接口
適用場景:多資料中心部署
Nacos#
特點:
- 同時支援 AP 和 CP 模式
- 服務發現 + 組態管理
- 阿里巴巴開源
- 支援 DNS-F 協議
適用場景:需要統一服務發現和組態管理
註冊中心選型對比
| 特性 | ZooKeeper | Eureka | Consul | Nacos |
|---|---|---|---|---|
| CAP | CP | AP | CP | AP/CP |
| 健康檢查 | 長連接 | 心跳 | HTTP/TCP | 心跳 |
| 一致性協議 | ZAB | - | Raft | Raft |
| 多資料中心 | 不支援 | 不支援 | 支援 | 支援 |
| 組態管理 | 支援 | 不支援 | 支援 | 支援 |
| 社區活躍度 | 高 | 維護模式 | 高 | 高 |
服務發現的實作模式#
客戶端發現模式#
服務消費者負責查詢註冊中心,獲取服務提供者地址列表,並選擇一個進行呼叫。
flowchart TD
C[Consumer] <-->|查詢服務| R[Registry]
C -->|直接呼叫| P[Provider]
style C fill:#e3f2fd
style R fill:#fff3e0
style P fill:#e8f5e9優點:
- 架構簡單
- 客戶端可以實作智能負載均衡
缺點:
- 客戶端與註冊中心耦合
- 需要為不同語言實作服務發現邏輯
服務端發現模式#
通過負載均衡器或 API 閘道來實作服務發現,客戶端只需知道閘道地址。
flowchart TD
C[Consumer] --> G[Gateway/LB]
G <-->|查詢服務| R[Registry]
G --> P[Provider]
style C fill:#e3f2fd
style G fill:#fff3e0
style R fill:#fce4ec
style P fill:#e8f5e9優點:
- 客戶端無需關心服務發現邏輯
- 適合多語言環境
缺點:
- 負載均衡器成為單點
- 增加網路跳數
註冊中心是實作服務化的關鍵。服務提供者可以任意伸縮(增加或減少節點),通過服務健康狀態檢測,註冊中心可以保持最新的服務節點資訊,並將變化通知給訂閱服務的服務消費者。