鵝長微服務發現與治理巨作PolarisMesh實踐-上
@
概述
定義
PolarisMesh 官網地址 //polarismesh.cn/
PolarisMesh 官網中文文檔 //polarismesh.cn/zh/doc/北極星是什麼/簡介.html
PolarisMesh GitHub源碼地址 //github.com/polarismesh
PolarisMesh(北極星)是騰訊開源的支援多語言、多框架的雲原生服務發現和治理中心,提供高性能SDK和無侵入Sidecar兩種接入方式。
前面多篇文章講解Spring Cloud Alibaba微服務一站式解決全組件的原理和實踐,Spring Cloud Alibaba主要服務於Java技術棧,而PolarisMesh提供多語言、框架無關、服務網格的實現,當之無愧的集大成者。北極星在騰訊內部的服務註冊數量超過百萬,日介面調用量超過十萬億,通用性和穩定性都得到了大規模的驗證。
PolarisMesh不僅提供無侵入Sidecar,還提供高性能SDK,實現語義相同的服務發現和治理功能,用戶可以根據業務場景自行選擇。對於請求量大和資源消耗敏感用戶,可以在業務應用或者開發框架中集成北極星SDK,快速補齊服務發現和治理功能。
核心功能
PolarisMesh的功能都是基於插件化設計,可單獨使用,採用計算存儲分離,計算層節點可以隨著客戶端節點的增加平行擴展,輕鬆支援百萬級節點接入。從功能大類來看,分為註冊中心、配置中心以及服務網格三類功能
-
註冊中心
- 服務註冊發現及服務健康檢查:以服務為中心的分散式應用架構,通過服務和註冊發現的方式維護不斷變化的請求地址,提高應用的擴展能力,降低應用的遷移成本。北極星提供對註冊上來的服務實例進行健康檢查,阻止主調方對不健康的服務實例發送請求,同時也提供了保護能力,實例剔除超過一定數量則停止剔除,防止因不健康實例過多導致雪崩效應。
-
配置中心
- 動態配置:提供配置管理的功能,支援應用配置、公共配置的訂閱發布、版本管理、變更通知,實現應用配置動態生效。
-
服務網格
- 路由和負載均衡:根據請求標籤、實例標籤和標籤匹配規則,對線上流量進行動態調度,可以應用於按地域就近、單元化隔離和金絲雀發布等多種場景。
- 熔斷降級和限流:及時熔斷異常的服務、介面、實例或者實例分組,降低請求失敗率。針對不同的請求來源和系統資源進行訪問限流,避免服務被壓垮。
- 可觀測性:支援請求量、請求延時和請求成功率的指標查詢,支援服務調用關係和多維度的流量曲線查詢,實現服務治理功能和流量觀測一體化。
- Proxyless與Proxy接入:提供多語言SDK、以及無侵入的JavaAgent,適配用戶高性能低長尾時延以Porxyless模式的接入場景;同時提供獨立的Sidecar,支援用戶的低侵入性、基於流量接管的Proxy模式接入場景。
組件和生態
PolarisMesh分為控制平面、數據平面以及生態組件3大類,通過這3大類組件,組成一套完整的微服務治理體系。
PolarisMesh兼容常用的開源框架、網關和 kubernetes。主要包含服務發現和治理中心、多語言應用開發、DNS 和 Proxy、網關。
-
服務發現和治理中心
- polaris-console:北極星的可視化控制台,直接面對終端用戶,提供可視化介面供用戶進行服務管理、配置管理、服務治理規則管理、可觀測性等操作。
- polaris:北極星的註冊配置中心,暴露API介面供服務、配置以及治理規則獲取及編輯。支援集群化部署,多個polaris集群之間可以共享同一份數據,支援客戶端就近接入。
- polaris-controller:北極星對接k8s的適配組件,可以將k8s的service以及endpoint的數據變更按需同步到北極星,實現 k8s service 和框架服務的統一管理。
- polaris-limiter:北極星分散式限流的token服務,支援限流配額的匯總以及下發分配。
-
多語言應用開發:支援Java、Go、C、C++、PHP、Lua,不劫持業務請求,幾乎不增加請求延時,CPU 消耗低,不需要部署和運維 Sidecar。支援 grpc 等框架和北極星 SDK 的集成,框架用戶不需要直接使用北極星 SDK。比如:
- Java應用開發:polaris-java(Polaris Java客戶端實現)、grpc-java-polaris(使用grpc-java與polaris-java的集成)、spring-cloud-tencent(SpringCloud與騰訊開源中間件的集成解決方案)、spring-boot-polaris(SpringBoot與polaris-java的集成)、polaris-java-agent(polaris-java注入到SpringCloud和Dubbo)。
- Go應用開發polaris-go(Polaris Go客戶端)、grpc-go-polaris(grpc-java與polaris-go的集成)、go-kratos(go-kratos與polaris-go的集成)、go-zero(go-zero與polaris-go的集成)、go-frame(go-frame與polaris-go的集成)、dubbo-go(dubbo-go與polaris-go的集成)、kitex(kitex與polaris-go的集成)。
-
Sidecar:劫持業務請求,有一定的請求延時,CPU 消耗較高,適用於無侵入的開發場景。
-
JavaAgent:對於Java的應用,直接通過位元組碼的方式載入到進程中,通過攔截器實現無感的接入。
-
支援 nginx 等網關和北極星 SDK 的集成,支援網關將請求轉發到北極星服務。
-
支援 k8s service 自動註冊到北極星,實現 k8s service 和框架服務的統一管理。
特色亮點
- 一站式服務治理中心:集服務註冊中心和服務治理控制面於一體,幫助業務解決分散式或者微服務架構面臨的註冊發現、故障容錯、流量控制和安全問題。
- 支援多種開發語言:提供Java、Go和C++等多種高性能、功能語義相同的SDK,可以輕鬆集成到不同的技術棧,幫助企業實現統一的服務發現和治理。
- 支援常用開發框架:北極星服務治理SDK可以集成到gRPC和Spring Cloud等開發框架中,幫助框架完善服務治理功能。框架用戶不感知,接入成本低。
- 支援Kubernetes:提供原生的k8s polaris-controller,支援k8s service自動注入,幫助k8s無縫兼容微服務框架體系,實現跨集群的服務發現和治理。
- 服務網格:提供高性能SDK和無侵入Sidecar兩種接入方式,採用SDK和Sidecar的服務可以互相訪問,功能語義相同,適用於不同的業務場景。
- 大規模生產應用:騰訊服務治理中心的開源版本,為騰訊百萬服務提供標準的服務治理功能,沉澱了騰訊從虛擬機到容器時代的分散式服務治理經驗
解決哪些問題
在分散式架構及微服務架構實施過程中,業務可能面臨以下四類問題。北極星以服務為中心,提供一站式解決方案。
官方性能數據
在長時間的壓力測試下,不同規格的北極星集群均維持正常運行狀態,集群可承載的實例容量從1k實例到10w實例,相關依賴組件的系統資源消耗也均在預期內,並未出現相關依賴組件高負載不可用現象。通過壓測,不同規格的北極星集群可以穩定支撐服務實例數量均滿足預期。
- 註冊實例的TPS最高可達35912,符合介面預期
- 服務發現的QPS最高可達116021,符合介面預期
- 實例心跳的TPS最高可達78077,符合介面預期
- 註銷實例的TPS最高可達14356,符合介面預期
架構原理
資源模型
PolarisMesh的資源模型與前面學習Nacos很相似,包括如下:
- 命名空間:提供了一種在相同註冊中心下資源的邏輯隔離的機制,同一命名空間下的資源命名必須唯一,但是跨命名空間允許存在同名的資源。命名空間常用於多個團隊或者項目之間的資源的區分隔離。
- 服務:一種資源對外暴露的抽象方式,資源本身通過埠監聽的方式提供網路訪問,並通過提供一系列預定義的服務介面,給主調端進行調用。
- 實例分組:是由一個或多個具有相同標籤屬性的實例組成,這些實例往往具備相同的特徵,比如屬於同一版本、屬於同一個地域、屬於同一環境。
- 服務實例:對應的是暴露一個或多個API介面供主調應用進行網路調用的節點,通過IP:PORT的方式進行唯一標識。
服務治理
基本原理
PolarisMesh是服務發現與治理中心,其主要應用在微服務之間的RPC調用過程中服務可見、流量控制、故障容錯等場景,涉及服務註冊、服務發現、動態路由、負載均衡、健康檢查、訪問限流、熔斷降級。
整體流程如下:
- RPC調用過程的參與者主要涉及兩個角色:主調方和被調方。
- 首先,被調方使用
服務註冊
功能,向北極星註冊自身服務數據,包括節點列表,治理規則等。 - 第二,主調方通過
服務發現
功能,拉取被調方的全量服務數據。 - 第三,主調方通過
路由和負載均衡
功能,篩選出一個合適的被調方實例,進行RPC調用。 - 第四,主調方記錄RPC調用的成功失敗結果,通過
熔斷降級
功能,剔除出現故障的被調方節點。 - 第五,北極星通過
健康檢查
功能,主動剔除已經下線的被調方節點。 - 第六,被調方通過
訪問限流
功能,保護自身不被主調方的異常流量給擊潰。
服務註冊
服務註冊指的是被調方按照服務模型將自身的服務數據註冊到PolarisMesh,以供主調方進行服務發現。服務數據主要包括以下部分:
- 服務名:服務的唯一標識,區分大小寫。
- 服務元數據:服務的標籤資訊,KV格式,可對服務進行分類,可用於過濾。
- 服務實例:提供服務的節點列表,以IP:PORT的方式提供。
- 服務實例元數據:服務實例的標籤資訊,KV格式,通常用於描述節點的集群、版本等,用於後續流量治理等操作。
支援以下4種服務註冊方式:
- 通過SDK註冊:北極星提供了多語言SDK,服務可以通過集成SDK,調用registerInstance介面完成服務註冊。
- 通過服務框架註冊:服務一般與服務框架集成(比如Spring Cloud Tencent (opens new window)),框架本身會提供服務自動註冊功能,服務啟動後,框架會將服務資訊自動註冊到北極星。
- 通過k8s同步的方式註冊:用戶通過k8s部署服務,並註冊為k8s的service,北極星通過controller的機制,從k8s中將service和endpoint資訊同步到北極星,完成服務註冊。
- 通過OpenAPI註冊:北極星控制面提供基於Rest標準的OpenAPI,用戶可通過OpenAPI完成服務註冊的操作。
服務發現
服務發現指的主調方是根據服務名標識,拉取服務實例列表,以供後續進行服務調用的操作。
支援以下4種方式進行服務發現:
- 通過SDK服務發現:北極星提供了多語言SDK,服務可以通過集成SDK,調用getAllInstances介面完成全量服務列表拉取。
- 使用框架服務發現:北極星支援對接多個主流的服務框架(比如Spring Cloud Tencent (opens new window)),主調方服務通過服務框架進行發現RPC請求,即可通過框架內部擴展機制使用北極星服務發現能力。
- 使用sidecar服務發現:北極星提供服務網格能力,服務程式可以基於sidecar的方式,通過DNS或者流量攔截,進行服務發現。
- 使用OpenAPI服務發現:北極星控制面提供基於Rest標準的OpenAPI,用戶可通過OpenAPI完成服務發現的操作。
安裝
部署架構
由於單機安裝比較簡單,我們這裡就直接選擇集群安裝,準備好兩台部署伺服器,而MySQL、Redis、Promethes的安裝可以參考前面對應的文章,這裡就直接使用。
組件 | 類型 | 功能說明 | |
---|---|---|---|
polaris | 最新stable版本 | 系統組件 | 服務治理控制面 |
polaris-console | 最新stable版本 | 系統組件 | 服務治理控制台 |
MySQL | >= 5.7 |
第三方依賴 | 服務數據存儲 |
Redis | >=4.0 |
第三方依賴 | 心跳狀態數據快取 |
Prometheus | >=2.28.0 |
第三方依賴 | 可觀測性 |
集群安裝
- 初始數據導入
# 下載polaris最新版本v1.12.1
wget //github.com/polarismesh/polaris/releases/download/v1.12.1/polaris-server-release_v1.12.1.linux.amd64.zip
# 下載polaris-console最新版本v1.9.1
wget //github.com/polarismesh/polaris-console/releases/download/v1.9.1/polaris-console-release_v1.9.1.linux.amd64.zip
# 解壓polaris-server
unzip polaris-server-release_v1.12.1.linux.amd64.zip
# 解壓polaris-console
unzip polaris-console-release_v1.9.1.linux.amd64.zip
# 進入polaris-server目錄
cd polaris-server-release_v1.12.1.linux.amd64
# 執行mysql腳本導入到mysql資料庫
mysql -u root -p 123456 -h 192.168.50.100 < store/sqldb/scripts/polaris_server.sql
將文件拷貝到兩台伺服器上,下面操作兩台一樣
- 配置資料庫參數:修改polaris-server.yaml裡面的store配置,去掉單機文件存儲的boltdbStore相關配置,並放開defaultStore相關配置。
# 存儲配置
store:
# 資料庫存儲插件
name: defaultStore
option:
master:
dbType: mysql
dbName: polaris_server
dbAddr: 192.168.50.100:3306
dbUser: root
dbPwd: 123456
- 開啟自動註冊:修改polaris-server.yaml裡面的服務自註冊配置,將enable_register改成true,並填入probe_address:
bootstrap:
polaris_service:
# 設置為true代表啟用自動註冊
enable_register: true
# 填入資料庫地址,用於獲取當前節點ip資訊
probe_address:192.168.50.100:3306
- 配置Redis參數:修改polaris-server.yaml裡面的healthcheck配置,去掉heartbeatMemory相關配置,並放開heartbeatRedis相關配置。
healthcheck:
checkers:
- name: heartbeatRedis
option:
#填入redis的IP以及埠
kvAddr: 192.168.50.100:6379
#填入redis的密碼
kvPasswd: 123456
maxIdle: 200
idleTimeout: 120s
connectTimeout: 200ms
msgTimeout: 200ms
concurrency: 200
- 啟動polaris-discover:
bash ./tool/start.sh
bash ./tool/p.sh
- 修改prometheus配置:打開 prometheus.yml文件,修改prometheus的job配置,增加http_sd_configs,其作用是告知prometheus需要從北極星獲取應用的監控上報的地址。
- job_name: 'prometheus'
static_configs:
- targets: ['localhost:9090']
http_sd_configs:
- url: //192.169.5.52:9000/prometheus/v1/clients
honor_labels: true
- 啟動prometheus:
nohup ./prometheus --web.enable-lifecycle --web.enable-admin-api >> prometheus.out 2>&1 &
- 進入polaris-console目錄,修改polaris-console的配置:打開polaris-console.yaml文件,修改monitorServer的地址,將原來的127.0.0.1:9090替換成prometheus的監聽地址
monitorServer:
address: "192.168.5.52:9090"
- 啟動polaris-console:
bash ./tool/start.sh
bash ./tool/p.sh
- 訪問
//192.168.5.52:8080
,可以看到登錄頁面,輸入登錄控制台的默認登錄賬戶資訊polaris/polaris,登錄後可以成功看到北極星服務治理控制台內容
SpringCloud應用接入
版本兼容
Spring Cloud 是 Java 語言生態下的分散式微服務架構的一站式解決方案,為了方便 Spring Cloud 用戶快速接入北極星,我們通過以下幾個示例幫助用戶如何在 Spring Cloud 中體驗北極星的相關功能。 Spring Cloud 版本相對應的 Spring Cloud Tencent 版本如下:
[外鏈圖片轉存失敗,源站可能有防盜鏈機制,建議將圖片保存下來直接上傳(img-nw4H2svH-1666971286536)(image-20221028134706394.png)]
選擇Spring Cloud 版本為 2021.0.3、Spring Cloud Tencent 版本為 1.7.0-2021.0.3
創建演示父項目
在Idea中新建一個空的maven項目,Pom文件增加與Spring Cloud Tencent 的父依賴spring-cloud-tencent-dependencies和SpringBoot的父依賴spring-boot-starter-parent。
<?xml version="1.0" encoding="UTF-8"?><project xmlns="//maven.apache.org/POM/4.0.0" xmlns:xsi="//www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="//maven.apache.org/POM/4.0.0 //maven.apache.org/xsd/maven-4.0.0.xsd"> <parent> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-parent</artifactId> <version>2.6.9</version> <relativePath/> <!-- lookup parent from repository --> </parent> <dependencyManagement> <dependencies> <dependency> <groupId>com.tencent.cloud</groupId> <artifactId>spring-cloud-tencent-dependencies</artifactId> <version>1.7.0-2021.0.3</version> <type>pom</type> <scope>import</scope> </dependency> <dependency> <groupId>org.springframework.cloud</groupId> <artifactId>spring-cloud-dependencies</artifactId> <version>2021.0.3</version> <type>pom</type> <scope>import</scope> </dependency> </dependencies> </dependencyManagement> <dependencies> <!-- 簡單的 Spring Cloud Web 依賴 --> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-web</artifactId> </dependency> <!-- 引入 Spring Cloud Tencent 的服務註冊發現依賴 --> <dependency> <groupId>com.tencent.cloud</groupId> <artifactId>spring-cloud-starter-tencent-polaris-discovery</artifactId> </dependency> </dependencies></project>
提供者微服務示例
在項目中添加一個provider-service模組,在提供者微服務的pom依賴中添加父Maven項目的依賴、 Web 服務依賴、polaris服務註冊依賴
<parent> <groupId>cn.itxs</groupId> <artifactId>spring-cloud-tencent-demo</artifactId> <version>1.0-SNAPSHOT</version> </parent> <!-- 簡單的 Spring Cloud Web 依賴 --> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-web</artifactId> </dependency> <!-- 引入 Spring Cloud Tencent 的服務註冊發現依賴 --> <dependency> <groupId>com.tencent.cloud</groupId> <artifactId>spring-cloud-starter-tencent-polaris-discovery</artifactId> </dependency> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-autoconfigure</artifactId> </dependency>
在provider-service的 resources 目錄下創建 application.yml 文件,並按照如下進行配置
server: port: 28888spring: application: name: provider-service cloud: polaris: # 配置polaris servre地址 address: grpc://192.168.5.52:8091 discovery: enabled: true stat: enabled: true port: 28082
創建提供者微服務演示控制器ProviderHelloController.java
package cn.itxs.controller;import com.tencent.cloud.polaris.PolarisDiscoveryProperties;import org.springframework.web.bind.annotation.PathVariable;import org.springframework.web.bind.annotation.RequestMapping;import org.springframework.web.bind.annotation.RestController;@RestControllerpublic class ProviderHelloController { private final PolarisDiscoveryProperties properties; ProviderHelloController(PolarisDiscoveryProperties properties) { this.properties = properties; } @RequestMapping("/hello/{val}") public String echo(@PathVariable String val) { return "Hello PolarisMesh,this is it xiao shen," + val + ", I'm " + properties.getService(); }}
啟動類ProviderApplication.java
package cn.itxs;import org.springframework.boot.SpringApplication;import org.springframework.boot.autoconfigure.SpringBootApplication;@SpringBootApplicationpublic class ProviderApplication{ public static void main(String[] args) { SpringApplication.run(ProviderApplication.class, args); }}
啟動提供者微服務ProviderApplication
查看控制台頁面服務列表可以看到提供者微服務已經註冊到北極星中default命名空間
消費者微服務示例
與上面服務提供類似,在項目中添加一個consumer-service模組,在消費者微服務的pom依賴中添加父Maven項目的依賴、 Web 服務依賴、polaris服務註冊依賴
<parent>
<groupId>cn.itxs</groupId>
<artifactId>spring-cloud-tencent-demo</artifactId>
<version>1.0-SNAPSHOT</version>
</parent>
<dependencies>
<!-- 簡單的 Spring Cloud Web 依賴 -->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
<!-- 引入 Spring Cloud Tencent 的服務註冊發現依賴 -->
<dependency>
<groupId>com.tencent.cloud</groupId>
<artifactId>spring-cloud-starter-tencent-polaris-discovery</artifactId>
</dependency>
<!-- 引入 Feign 依賴實現 Feign 調用 -->
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-openfeign</artifactId>
</dependency>
</dependencies>
在consumer-service的 resources 目錄下創建 application.yml 文件,並按照如下進行配置
server:
port: 38888
spring:
application:
name: consumer-service
cloud:
polaris:
address: grpc://192.168.5.52:8091
discovery:
enabled: true
stat:
enabled: true
port: 38082
創建Feign介面HelloService.java,通過feign實現遠程方法的調用
package cn.itxs.service;
import org.springframework.cloud.openfeign.FeignClient;
import org.springframework.stereotype.Service;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.RequestMapping;
@Service
@FeignClient(name = "provider-service")
public interface HelloService {
@RequestMapping("/hello/{value}")
String hello(@PathVariable("value") String value);
}
創建提供者微服務演示控制器ProviderHelloController.java
package cn.itxs.controller;
import cn.itxs.service.HelloService;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
@RestController
public class ConsumerHelloController {
private final HelloService helloService;
ConsumerHelloController(HelloService helloService) {
this.helloService = helloService;
}
@RequestMapping(value = "/hello/{val}")
public String echo(@PathVariable String val) {
return helloService.hello(val);
}
}
啟動類ConsumerApplication.java
package cn.itxs;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.cloud.openfeign.EnableFeignClients;
@SpringBootApplication
@EnableFeignClients
public class ConsumerApplication
{
public static void main(String[] args) {
SpringApplication.run(ConsumerApplication.class, args);
}
}
啟動消費者微服務ProviderApplication
查看控制台頁面服務列表可以看到提供者微服務已經註冊到北極星中default命名空間
通過消費者提供控制器訪問介面訪問,//192.168.44.161:38888/hello/1 ,返回服務提供者的結果,成功實現服務註冊和發現。
動態配置示例
引入spring-cloud-starter-tencent-polaris-config 實現 Spring Cloud 配置的動態管理,spring-cloud-starter-bootstrap 以便可以支援 bootstrap.yml 的識別與載入。添加依賴如下:
<dependency>
<groupId>com.tencent.cloud</groupId>
<artifactId>spring-cloud-starter-tencent-polaris-config</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-bootstrap</artifactId>
</dependency>
在 resources 目錄下創建 bootstrap.yml 文件,並按照如下進行配置
server:
port: 48084
spring:
application:
name: config-group
cloud:
polaris:
address: grpc://192.168.5.52:8091
namespace: default
config:
auto-refresh: true # auto refresh when config file changed
groups:
- name: ${spring.application.name} # group name
files: [ "config/user.yaml" ]
創建配置分組以及配置文件
- 創建配置分組 config-group
- 創建配置文件
config/user.yaml
,編輯和發布配置,編輯配置項內容為name: zhangsan
創建提供者微服務演示控制器ConfigController.java
package cn.itxs.controller;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.cloud.context.config.annotation.RefreshScope;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
@RestController
@RefreshScope
public class ConfigController {
@Value("${name}")
private String name;
@RequestMapping("/name")
public String name() {
return name;
}
}
啟動後訪問//192.168.44.161:48084/name,成功讀到北極星配置中心的配置
**本人部落格網站 **IT小神 www.itxiaoshen.com