使用指南
- 1: 服务端安装
- 2: 控制台使用
- 3: Java 应用开发
- 3.1: 使用 Java SDK
- 3.2: 使用 Spring Cloud
- 3.3: 使用 Spring Boot
- 3.4: 使用 Dubbo
- 3.5: 使用 gRPC-Java
- 4: Go 应用开发
- 4.1: 使用 Go SDK
- 4.1.1: 注册发现
- 4.1.2: 动态路由
- 4.1.3: 负载均衡
- 4.1.4: 熔断降级
- 4.1.5: 访问限流
- 4.1.6: 缓存与高可用
- 4.1.7: 网络连接
- 4.1.8: 配置管理
- 4.1.9: 可观测性
- 4.1.10: 二次寻址
- 4.2: 使用 dubbogo
- 4.3: 使用 gRPC-Go
- 5: C++ 应用开发
- 5.1: 使用 C++ SDK
- 5.2: 使用 L5Agent
- 6: K8s 和网格代理
- 6.1: 安装 Polaris Controller
- 6.2: K8s 服务同步
- 6.3: K8s 配置同步(Beta)
- 6.4: Envoy 网格接入
- 6.5: DNS 接入
- 6.6: JavaAgent 接入
- 7: 网关
1 - 服务端安装
1.1 - 单机版安装
北极星支持单机版的安装架构,适用于用户在开发测试阶段,通过本机快速拉起北极星服务进行验证。
单机版包含以下4个组件:
- polaris-console:可视化控制台,提供服务治理管控页面
- polaris-server:控制面,提供数据面组件及控制台所需的后台接口
- polaris-limiter: 分布式限流服务端,提供全局配额统计的功能
- prometheus:服务治理监控所需的指标汇聚统计组件
单机版默认占用以下端口:
服务端监听端口信息
| 进程名 | 端口号 | 协议类型 | 用途 |
|---|---|---|---|
| polaris-console | 8080 | http | 北极星控制台页面端口 |
| polaris-limiter | 8100 | http | 限流可用配额下发客户端数据通信 |
| polaris-limiter | 8101 | grpc | 限流可用配额下发客户端数据通信 |
| polaris-server | 8090 | http | OpenAPI,可以调用注册、配置、治理规则的接口 |
| polaris-server | 8761 | http | eureka 协议通信 |
| polaris-server | 8848 | http | nacos1.x 协议通信 |
| polaris-server | 9848 | grpc | nacos2.x 协议通信 |
| polaris-server | 8091 | grpc | 注册发现/服务治理规则下发客户端数据通信 |
| polaris-server | 8093 | grpc | 配置中心客户端数据通信 |
| polaris-server | 15010 | grpc | xds 数据通信端口 |
下载软件包
单机版的安装需要依赖单机版软件包,单机版软件包的命名格式为polaris-standalone-release_*.zip:
执行所有安装之前,需要下载软件包,可以从以下2个地址下载单机版软件包,请选择最新的release版本:
- Github下载:polaris standalone releases
下载后需要进行解压,如果有需要自定义单机版相关组件的监听端口,需修改压缩包内的port.properties文件。
port.properties 文件概览
polaris_eureka_port=8761
polaris_open_api_port=8090
polaris_service_grpc_port=8091
polaris_config_grpc_port=8093
polaris_prometheus_sd_port=9000
polaris_xdsv3_port=15010
polaris_console_port=8080
prometheus_port=9090
pushgateway_port=9091
nacos_http_port=8848
使用 Linux 安装
下载Linux单机版软件包(polaris-standalone-release_$version.linux.$arch.zip),执行安装命令:
unzip polaris-standalone-release_$version.linux.$arch.zip
cd polaris-standalone-release_$version.linux.$arch
bash install.sh
使用 Window 安装
注意事项:
- 依赖powershell 5.0及以上版本(Windows 10及以上版本默认安装)
- 需要以管理员身份运行安装脚本,执行powershell需要进行授权操作
- 安装脚本可能遭到系统安全软件的误杀,请在安全软件中执行信任操作
下载Windows单机版软件包(polaris-standalone-release_$version.windows.$arch.zip),执行安装命令:
执行解压:polaris-standalone-release_$version.windows.$arch.zip
进入目录:polaris-standalone-release_$version.windows.$arch
执行脚本:install.bat
使用 Mac 安装
注意事项:
- 请在【关于本机】设置中查看Mac机器的芯片类型(Intel/Apple)
- Intel芯片请使用amd64的软件包,Apple芯片请使用arm64的软件包
下载Mac单机版软件包(polaris-standalone-release_$version.darwin.$arch.zip),执行安装命令:
unzip polaris-standalone-release_$version.darwin.$arch.zip
cd polaris-standalone-release_$version.darwin.$arch
bash install.sh
使用 Docker 安装
查看当前镜像需要暴露的端口信息
docker image ls -a | grep "polarismesh/polaris-standalone" | awk '{print $3}' | xargs docker inspect --format='{{range $key, $value := .Config.ExposedPorts}}{{ $key }}{{end}}'| awk '{ gsub(/\/tcp/, " "); print $0 }'
执行以下命令启动
# Publish a container's port(s) to the host
docker run -d --privileged=true \
-p 15010:15010 \
-p 8101:8101 \
-p 8100:8100 \
-p 8080:8080 \
-p 8090:8090 \
-p 8091:8091 \
-p 8093:8093 \
-p 8761:8761 \
-p 8848:8848 \
-p 9848:9848 \
-p 9090:9090 \
-p 9091:9091 polarismesh/polaris-standalone:latest
使用 Docker Compose 安装
下载 Docker Compose 安装包: polaris-standalone-release_$version.docker-compose.zip
创建mysql、redis 存储卷,方便数据持久化
docker volume create --name=vlm_data_mysql
docker volume create --name=vlm_data_redis
启动服务
执行解压:polaris-standalone-release_$version.docker-compose.zip
进入目录:polaris-standalone-release_$version.docker-compose
执行命令:docker-compose up
安装验证
打开控制台
在浏览器里输入北极星控制台地址(127.0.0.1:8080),非容器化场景127.0.0.1可替换成安装北极星的机器host。
- 登录控制台的默认登录账户信息
用户:polaris
密码:polaris
新建服务
进入服务列表页面,点击【新建】按钮,确认是否可以新建服务。新建服务成功表示安装成功
1.2 - 集群版安装
提示
- 建议用户部署北极星时,修改默认的 token salt 信息: 修改步骤指引
- 建议用户部署完北极星后,修改默认 polaris 用户密码
北极星支持高可用的集群安装架构模型,支持多级的容灾架构,适用于用户在生产环境上使用北极星。
集群版控制面无状态化,通过DB以及Redis存储资源信息以及相关状态数据。
服务端监听端口信息
| 进程名 | 端口号 | 协议类型 | 用途 |
|---|---|---|---|
| polaris-console | 8080 | http | 北极星控制台页面端口 |
| polaris-limiter | 8100 | http | 限流可用配额下发客户端数据通信 |
| polaris-limiter | 8101 | grpc | 限流可用配额下发客户端数据通信 |
| polaris-server | 8090 | http | OpenAPI,可以调用注册、配置、治理规则的接口 |
| polaris-server | 8761 | http | eureka 协议通信 |
| polaris-server | 8848 | http | nacos1.x 协议通信 |
| polaris-server | 9848 | grpc | nacos2.x 协议通信 |
| polaris-server | 8091 | grpc | 注册发现/服务治理规则下发客户端数据通信 |
| polaris-server | 8093 | grpc | 配置中心客户端数据通信 |
| polaris-server | 15010 | grpc | xds 数据通信端口 |
下载软件包
可以从以下2个地址下载北极星软件包,请选择最新的release版本:
安装数据库
安装MySQL
北极星可以与应用程序共用一个数据库,如果有现成MySQL则可以跳过这一步。
MySQL版本支持
- 开源MySQL版本支持:当前仅支持 >= 5.7,低版本暂未支持。
- 云厂商MySQL支持
- 腾讯云:支持 Tencent MySQL版,暂不支持 TDSQL-C MySQL兼容
- 阿里云:支持云数据库RDS MySQL 版
安装开源版本MySQL的步骤可参考:MySQL安装
安装完MySQL后,需要执行数据导入,解压源码包并执行导入:
第一次安装北极星
unzip polaris-$version.zip
cd polaris-$version
mysql -u $db_user -p $db_pwd -h $db_host < store/sqldb/scripts/polaris_server.sql
已有在运行的北极星,执行升级store/sqldb/scripts/delta中的升级脚本
unzip polaris-$version.zip
cd polaris-$version
mysql -u $db_user -p $db_pwd -h $db_host < store/sqldb/scripts/delta/v160-v170.sql
安装Redis
北极星可以与应用程序共用一个Redis,如果有现成Redis则可跳过这一步。
安装开源版本Redis的步骤可参考:Redis安装
安装后,需要设置Redis允许远程主机访问。可以修改redis.conf配置文件:
bind 0.0.0.0
protected-mode no
修改后重启Redis生效。
使用 Linux 安装
安装服务端
安装控制面
下载软件包:下载polaris-server-release_$version.linux.$arch.zip,解压后进入polaris-server-release_$version.linux.$arch目录
配置数据库参数:修改polaris-server.yaml里面的store配置,去掉boltdbStore相关配置,并放开defaultStore相关配置。
# 存储配置
store:
# 数据库存储插件
name: defaultStore
option:
master:
dbType: mysql
dbName: polaris_server
dbAddr: ##数据库地址,格式为ip:port##
dbUser: ##数据库用户名##
dbPwd: ##数据库密码##
开启自动注册:修改polaris-server.yaml里面的服务自注册配置,将enable_register改成true,并填入probe_address:
bootstrap:
polaris_service:
# 设置为true代表启用自动注册
enable_register: true
# 填入数据库地址,用于获取当前节点ip信息
probe_address: ##数据库地址##
假如北极星集群管理的注册实例数小于 1w 时,可以选择集群部署去 Redis 方案:修改 conf/polaris-server.yaml 里面的 healthcheck 配置,去掉 heartbeatMemory 相关配置,并放开 heartbeatLeader 相关配置。
主从模式
healthcheck:
checkers:
- name: heartbeatLeader
option:
soltNum: # 心跳数据存储分片 map 的分片数
streamNum: # 用于同步心跳数据的 gRPC stream 客户端数,默认为 runtime.GOMAXPROCS(0)
假如北极星集群管理的注册实例数超过 1w 时,推荐集群部署使用 Redis 方案:修改 02-polaris-server-config.yaml 里面的 healthchec 配置,去掉 heartbeatMemory 相关配置,并放开 heartbeatRedis 相关配置。
单节点,主从模式
healthcheck:
checkers:
- name: heartbeatRedis
option:
#填入redis的IP以及端口
kvAddr: ##REDIS_ADDR##
#填入redis的密码
kvPasswd: ##REDIS_PWD##
maxIdle: 200
idleTimeout: 120s
connectTimeout: 200ms
msgTimeout: 200ms
concurrency: 200
集群模式
healthcheck:
checkers:
- name: heartbeatRedis
option:
deployMode: cluster
addrs:
- "127.0.0.1:7001"
- "127.0.0.1:7002"
- "127.0.0.1:7003"
kvPasswd: "polaris"
poolSize: 233
minIdleConns: 30
idleTimeout: 120s
connectTimeout: 200ms
msgTimeout: 200ms
concurrency: 200
withTLS: false
哨兵模式
healthcheck:
checkers:
- name: heartbeatRedis
option:
deployMode: sentinel
addrs:
- "127.0.0.1:26379"
- "127.0.0.2:26379"
- "127.0.0.3:26379"
masterName: "my-sentinel-master-name"
sentinelUsername: "sentinel-polaris" # sentinel 客户端的用户名
sentinelPassword: "sentinel-polaris-password" # sentinel 客户端的密码
kvPasswd: "polaris" # redis 客户端的密码
poolSize: 233
minIdleConns: 30
idleTimeout: 120s
connectTimeout: 200ms
msgTimeout: 200ms
concurrency: 200
withTLS: false
启动polaris-server:
bash ./tool/start.sh
安装控制台
下载软件包:下载polaris-console-release_$version.linux.$arch.zip,解压后进入polaris-console-release_$version.linux.$arch目录
修改配置:打开polaris-console.yaml文件,修改polarisServer的地址,将原来的127.0.0.1:8090替换成polarisServer的监听地址
polarisServer:
address: "${polaris-server的IP地址}:8090"
启动polaris-console:
bash ./tool/start.sh
安装可选功能
安装监控组件
下载软件包:点击下载链接,下载prometheus版本,解压后进入prometheus-2.28.0.linux-amd64目录中。
修改prometheus配置:打开 prometheus.yml文件,修改prometheus的job配置,增加http_sd_configs,其作用是告知prometheus需要从北极星获取应用的监控上报的地址。
- job_name: 'prometheus'
static_configs:
- targets: ['localhost:9090']
http_sd_configs:
- url: http://${polaris的IP地址}:8090/prometheus/v1/clients
honor_labels: true
启动prometheus:
nohup ./prometheus --web.enable-lifecycle --web.enable-admin-api >> prometheus.out 2>&1 &
修改控制台配置:进入polaris-console的安装目录,打开polaris-console.yaml文件,修改monitorServer的地址,将原来的127.0.0.1:9090替换成prometheus的监听地址。
monitorServer:
address: "${prometheus的IP地址}:9090"
重启控制台:进入polaris-console的安装目录,执行以下语句重启。
bash ./tool/stop.sh
bash ./tool/start.sh
假如您的网络环境不支持 prometheus 主动从北极星 SDK 拉取(pull模式)监控指标,则需要部署 pushgateway 组件,同时调整 prometheus.yml 文件添加以下配置
- job_name: 'pushgateway'
static_configs:
- targets: ['${pushgateway 服务端IP}:9091']
安装分布式限流组件
下载软件包:下载polaris-limiter-release_$version.linux.$arch.zip,解压后进入polaris-limiter-release_$version.linux.$arch目录。
修改配置:打开polaris-limiter.yaml文件,修改polaris-server-address的值为北极星服务端地址。
polaris-limiter多节点需要通过myid保证顺序,关于myid的设置:
- 如果是安装单节点的 polaris-limiter,myid 设置为 1 即可;
- 如果是安装多节点的 polaris-limiter,每个节点的 myid 必须保证唯一。
registry:
enable: true
polaris-server-address: { 北极星服务端 grpc 协议地址 }
name: polaris.limiter
namespace: Polaris
health-check-enable: true
api-servers:
- name: http
option:
ip: 0.0.0.0
port: 8100
- name: grpc
option:
ip: 0.0.0.0
port: 8101
limit:
myid: { 服务端节点唯一标识信息,int 类型}
启动polaris-limiter:
bash ./tool/start.sh
bash ./tool/p.sh
使用 K8s 安装
安装服务端
下载软件包:下载polaris-cluster-release_$version.kubernetes.zip,解压后进入polaris-cluster-release_$version.kubernetes目录。
配置数据库参数:修改02-polaris-server-config.yaml里面的store配置,去掉boltdbStore相关配置,并放开defaultStore相关配置。
# 存储配置
store:
# 数据库存储插件
name: defaultStore
option:
master:
dbType: mysql
dbName: polaris_server
dbAddr: ##数据库地址,格式为ip:port##
dbUser: ##数据库用户名##
dbPwd: ##数据库密码##
开启自动注册:修改02-polaris-server-config.yaml里面的服务自注册配置,将enable_register改成true,并填入probe_address:
bootstrap:
polaris_service:
# 设置为true代表启用自动注册
enable_register: true
# 填入数据库地址,用于获取当前节点ip信息
probe_address: ##数据库地址##
假如北极星集群管理的注册实例数小于 1w 时,可以选择集群部署去 Redis 方案:修改 02-polaris-server-config.yaml 里面的 healthcheck 配置,去掉 heartbeatMemory 相关配置,并放开 heartbeatLeader 相关配置。
主从模式
healthcheck:
checkers:
- name: heartbeatLeader
option:
soltNum: # 心跳数据存储分片 map 的分片数
streamNum: # 用于同步心跳数据的 gRPC stream 客户端数,默认为 runtime.GOMAXPROCS(0)
假如北极星集群管理的注册实例数超过 1w 时,推荐集群部署使用 Redis 方案:修改 02-polaris-server-config.yaml 里面的 healthchec 配置,去掉 heartbeatMemory 相关配置,并放开 heartbeatRedis 相关配置。
单节点,主从模式
healthcheck:
checkers:
- name: heartbeatRedis
option:
#填入redis的IP以及端口
kvAddr: ##REDIS_ADDR##
#填入redis的密码
kvPasswd: ##REDIS_PWD##
maxIdle: 200
idleTimeout: 120s
connectTimeout: 200ms
msgTimeout: 200ms
concurrency: 200
# redis 库,非必选,默认为 0
db: 0
集群模式
healthcheck:
checkers:
- name: heartbeatRedis
option:
deployMode: cluster
addrs:
- "127.0.0.1:7001"
- "127.0.0.1:7002"
- "127.0.0.1:7003"
kvPasswd: "polaris"
poolSize: 233
minIdleConns: 30
idleTimeout: 120s
connectTimeout: 200ms
msgTimeout: 200ms
concurrency: 200
withTLS: false
# redis 库,非必选,默认为 0
db: 0
哨兵模式
healthcheck:
checkers:
- name: heartbeatRedis
option:
deployMode: sentinel
addrs:
- "127.0.0.1:26379"
- "127.0.0.2:26379"
- "127.0.0.3:26379"
masterName: "my-sentinel-master-name"
sentinelUsername: "sentinel-polaris" # sentinel 客户端的用户名
sentinelPassword: "sentinel-polaris-password" # sentinel 客户端的密码
kvPasswd: "polaris" # redis 客户端的密码
poolSize: 233
minIdleConns: 30
idleTimeout: 120s
connectTimeout: 200ms
msgTimeout: 200ms
concurrency: 200
withTLS: false
# redis 库,非必选,默认为 0
db: 0
执行安装
kubectl create -f 00-polaris-namespace-config.yaml
kubectl create -f 01-polaris-console-config.yaml
kubectl create -f 02-polaris-server-config.yaml
kubectl create -f 03-polaris-server.yaml
安装可选功能
安装监控组件
kubectl create -f 04-prometheus.yaml
修改polaris-console-config的ConfigMap,修改monitorServer的地址,将原来的127.0.0.1:9090替换成prometheus的K8S服务域名。
monitorServer:
address: "${prometheus的服务域名}:9090"
假如您的网络环境不支持 prometheus 主动从北极星 SDK 拉取(pull模式)监控指标,则需要部署 pushgateway 组件,同时调整 prometheus.yml 文件添加以下配置
- job_name: 'pushgateway'
static_configs:
- targets: ['${pushgateway 服务端IP}:9091']
安装分布式限流组件
kubectl create -f 05-polaris-limiter-config.yaml
kubectl create -f 06-polaris-limiter.yaml
使用 Helm 安装
下载软件包:下载 polaris-helm-release_$version.kubernetes.zip,解压后进入 polaris-helm-release_$version.kubernetes.zip 目录。
安装服务端
您需要修改 values.yaml ,将 global.mode 设置为 cluster ,同时设置 polaris.storage.db 和 polaris.storaate.redis 的地址信息。 确保您的
mysql 已经使用下面的命令初始化了。
mysql -u $db_user -p $db_pwd -h $db_host < store/sqldb/polaris_server.sql
设置好后,使用下面的命令安装 chart:
$ cd deploy/helm
$ helm install ${release_name} .
假如您的网络环境不支持 prometheus 主动从北极星 SDK 拉取(pull模式)监控指标,则需要部署 pushgateway 组件,同时调整 prometheus.yml 文件添加以下配置
- job_name: 'pushgateway'
static_configs:
- targets: ['${pushgateway 服务端IP}:9091']
检查安装
部署后可以通过以下命令观察到 pod 正常运行:
$ kubectl get po -n polaris-system
NAME READY STATUS RESTARTS AGE
polaris-0 2/2 Running 0 2m44s
polaris-prometheus-6cd7cd5fc6-gqtcz 2/2 Running 0 2m44s
如果您在 values.yaml 中配置了 service.type 为 LoadBalancer 则可以使用 polaris 的 service 的 EXTERNAL-IP:webPort 访问到北极星的页面。 如果您的k8s 集群不支持 LoadBalancer ,可以将 service.type 为 NodePort ,通过 nodeip:nodeport 访问。
配置项说明
| 参数名 | 参数解释 |
|---|---|
| global.mode | 集群类型,支持 cluter 和 standalone ,表示集群版和单机版 |
| polaris.image.repository | polaris-server 镜像仓库地址 |
| polaris.image.tag | polaris-server 镜像 tag |
| polaris.image.pullPolicy | polaris-server 镜像拉取策略 |
| polaris.limit.cpu | polaris-server cpu资源占用限制 |
| polaris.limit.memory | polaris-server 内存资源占用限制 |
| polaris.console.image.repository | polaris-console 的镜像仓库地址 |
| polaris.console.image.tag | polaris-console 镜像 tag |
| polaris.console.image.pullPolicy | polaris-console 镜像拉取策略 |
| polaris.console.limit.cpu | polaris-console cpu资源占用限制 |
| polaris.console.limit.memory | polaris-console 内存资源占用限制 |
| polaris.replicaCount | polaris 副本数 |
| polaris.storage.db.address | polaris 集群版,使用的 mysql 的地址 |
| polaris.storage.db.name | polaris 集群版,使用的 mysql 的 database 名 |
| polaris.storage.db.user | polaris 集群版,使用的 mysql 的用户名 |
| polaris.storage.db.password | polaris 集群版,使用的 mysql 的密码 |
| polaris.storage.redis.address | polaris 集群版,使用的 redis 的地址 |
| polaris.storage.redis.password | polaris 集群版,使用的 redis 的密码 |
| polaris.storage.service.type | polaris service 的类型 |
| polaris.storage.service.httpPort | polaris service 暴露,polaris-server 监听的 http 端口 |
| polaris.storage.service.grpcPort | polaris service 暴露,polaris-server 监听的 grpc 端口 |
| polaris.storage.service.webPort | polaris service 暴露,polaris-server 监听的 web 端口 |
| polaris.auth.consoleOpen | polaris 打开控制台接口鉴权,默认开启 |
| polaris.auth.clientOpen | polaris 打开客户端接口鉴权,默认关闭 |
| monitor.port | 客户端上报监控信息的端口 |
| installation.namespace | 部署polaris组件所在的namespace |
安装后验证
登录控制台的默认登录账户信息。
用户:polaris
密码:polaris
访问http://{控制台IP}:8080,可以看到登录页面,登录后可以成功看到北极星服务治理控制台内容。
执行以下命令,查看 polaris.limiter 服务下的实例信息,是否包含限流服务。
curl --location --request POST '127.0.0.1:8090/v1/Discover' \
--header 'Content-Type: application/json' \
--data-raw '{
"type": 1,
"service": {
"name": "polaris.limiter",
"namespace": "Polaris"
}
}'
可选 开启二次寻址
在大规模集群(百万级别服务)场景下,可对对北极星按照功能模块进行集群拆分,注册发现、健康检查、控制台操作划分为不同集群来进行处理,各集群相互独立,可按照请求量独立扩展。客户端通过埋点集群的二次寻址机制,为接口寻址到目标集群进行功能接口的调用。
服务端配置
注册发现集群的 polaris-server.yaml 配置文件修改
开启服务端自动注册 polaris.discover 服务
bootstrap:
polaris_service:
probe_address: ##数据库地址,格式为ip:port##
enable_register: true
isolated: false
services:
- name: polaris.discover
protocols:
- service-grpc
关闭健康检查客户端接口
apiservers:
- name: service-grpc
option:
listenIP: "0.0.0.0"
listenPort: 8091
connLimit:
openConnLimit: false
maxConnPerHost: 128
maxConnLimit: 5120
enableCacheProto: true
sizeCacheProto: 128
tls:
certFile: ""
keyFile: ""
trustedCAFile: ""
api:
client:
enable: true
include: [discover, register]
健康检查集群的 polaris-server.yaml 配置文件修改
开启服务端自动注册 polaris.healthcheck 服务
bootstrap:
polaris_service:
probe_address: ##数据库地址,格式为ip:port##
enable_register: true
isolated: false
services:
- name: polaris.healthcheck
protocols:
- service-grpc
- name: polaris.checker
protocols:
- service-grpc
只开放健康检查客户端接口
apiservers:
- name: service-grpc
option:
listenIP: "0.0.0.0"
listenPort: 8091
connLimit:
openConnLimit: false
maxConnPerHost: 128
maxConnLimit: 5120
enableCacheProto: true
sizeCacheProto: 128
tls:
certFile: ""
keyFile: ""
trustedCAFile: ""
api:
client:
enable: true
include: [healthcheck]
修改完 polaris-server.yaml 配置之后,重启服务端节点即可
客户端配置
2 - 控制台使用
2.1 - 命名空间
命名空间列表
通过浏览器输入http://127.0.0.1:8080(127.0.0.1可换成服务端实际安装的IP地址),打开Polaris控制台。
在侧边栏点击命名空间,进入命名空间列表页:
创建命名空间
点击新建按钮,在弹出对话框中填入命名空间全局唯一名称,即可完成命名空间的创建。
创建命名空间字段说明:
| 字段名 | 含义 | 必选/可选 |
|---|---|---|
| 名称 | 命名空间名称,全局唯一 | 必选 |
| 描述 | 命名空间描述 | 可选 |
2.2 - 注册中心
2.2.1 - 服务列表
服务
服务列表
在侧边栏点击服务,进入服务列表页,列表各字段含义如下:
创建服务
点击新建按钮,在弹出来的对话框填入命名空间和服务名(同一命名空间下需唯一)等必填信息,即可完成服务的创建。
创建服务字段说明:
| 字段名 | 含义 | 必选/可选 |
|---|---|---|
| 服务名 | 服务标识,同一命名空间下唯一 | 必选 |
| 命名空间 | 服务所属的命名空间 | 必选 |
| 部门 | 服务所在的部门信息,可选 | 可选 |
| 业务 | 服务所在的业务信息,可选 | 可选 |
| 开启就近访问 | 是否开启就近访问,开启的话,SDK会自动筛选就近实例 | 可选,默认关闭 |
| 服务标签 | 服务上的KV标签,仅用于控制台及OpenAPI查询过滤 | 可选 |
| 描述 | 服务的描述信息 | 可选 |
服务实例
服务实例列表
在控制台点击具体服务名,进入服务实例列表页。
创建实例
点击新建按钮,在弹出来的对话框填入实例IP和端口(同一服务下IP和端口组合需唯一),即可完成服务实例的创建。
创建服务实例字段说明:
| 字段名 | 含义 | 必选/可选 |
|---|---|---|
| 实例IP | 服务实例的IP,可填入多个,用换行分割 | 必选 |
| 端口 | 服务实例的端口,可填入多个,用换行分割 | 必选 |
| 权重 | 服务实例的权重,可控制流量的相对百分比,权重为0则不会有流量 | 可选,默认100 |
| 协议 | 服务实例端口协议信息 | 可选 |
| 版本 | 服务实例的版本信息 | 可选 |
| 实例标签 | 服务实例的KV标签信息,用于路由过滤 | 可选 |
| 地域信息 | Region(大区),Zone(可用区),Campus(机房),3级地域信息 | 可选 |
| 健康状态 | 设置实例健康状态,仅当不开启健康检查时有效 | 可选 |
| 开启健康检查 | 设置是否开启健康检查,开启健康检查后,由控制面负责健康状态的变更 | 可选 |
| 是否隔离 | 设置实例是否隔离,实例隔离后则不会有流量 | 可选 |
2.2.2 - 服务可见性
为了解决 spring cloud 等一些微服务调用框架不支持跨命名空间调用的场景,北极星提供了服务可见性的配置。
- 命名空间设置服务可见性:该命名空间下的服务,可以被别的命名空间下的服务所发现
- 服务设置可见性:该服务除了可以被自己所在命名空间下的其他服务发现外,还可以被别的命名空间下的服务所发现
2.3 - 服务网格
2.3.1 - 动态路由
自定义路由
路由规则分类
规则路由是一种根据一段DSL(路由规则)来控制消息分流的机制。
路由规则分为被调规则和主调规则2部分:
-
被调规则代表的是当服务作为被调方时,控制所有主调方进行流量转发的规则。
-
主调规则代表的是当服务作为主调方时,控制所有被调方进行流量转发的规则。
服务上可以配置主调规则和被调规则,如下图所示:
- 主调规则
- 被调规则
配置被调规则
被调规则在服务作为被调方时候生效,配置界面如下:
图上的规则的含义是:当echo-server(服务名)作为被调方时,对于所有主调方过来的,带有user-type:1的标签的请求,都路由给自身服务版本号为1.0.0的实例分组。
配置主调规则
主调规则在服务作为主调方时候生效,配置界面如下:
图上的规则的含义是:当echo-server(服务名)作为主调方时,对于发出去的请求,带有user-type:1的标签的请求,都路由给目标服务版本号为1.0.0的实例分组。
路由规则的匹配流程
请求匹配规则
可选,指定限流规则的请求参数匹配条件,不填代表不过滤,支持以下四种参数类型:
-
自定义参数:自定义KEY和VALUE,具体的请求参数值可通过SDK进行传入。
-
请求头(HEADER):针对协议消息头(http header/grpc header)进行过滤。
-
请求参数(QUERY):针对协议请求参数(http query)进行过滤。
-
请求COOKIE(COOKIE):针对协议 cookie 参数(http cookie)进行过滤。
-
方法(METHOD):针对协议的METHOD(http method/grpc method)进行过滤。
-
主调IP(CALLER_IP):针对主调方机器的IP地址进行过滤。
-
路径(PATH):针对协议请求路径进行过滤
每种类型参数值支持以下几种值匹配模式:
-
全匹配:全值匹配,传入的值与配置的值相同才匹配通过。
-
正则表达式:用户配置正则表达式,通过正则表达式对传入的值进行匹配,正则表达式支持Google RE2标准。
-
不等于:取反匹配,传入的值与所配置的值不相等才算匹配成功。
-
包含:多字符串取OR匹配,传入的值只要匹配到其中一个字符串,就算匹配成功。字符串之间使用逗号进行分割。值格式为’value1,value2,value3‘,匹配到其中一个就算成功。
-
不包含:多字符串取反匹配,传入的值必须都没有出现在所配置的字符串列表中,才算匹配通过。值格式为’value1,value2,value3‘,全部不等于才算成功。
边界条件
- 通过请求标签进行匹配,没有匹配到一个路由规则,则本次请求路由失败,返回空实例列表。
- 通过请求标签进行匹配,匹配到了路由规则,但是路由规则所对应的destination不存在服务实例,则本次请求获取到的服务实例为空。
- 通过请求标签进行匹配,匹配到了路由规则,路由规则对应的2个同优先级的destination,请求会在这2个destination中按照权重比例随机路由,假如其中一个destination不存在服务实例,则路由到该destination的请求获取到的服务实例为空。
自定义路由实践
按版本号灰度实践
场景描述
请求通过网关接入,路由到后端服务。后端服务上线了新版本,新版本只对打了标签的用户请求开放,未打标签的请求继续路由到老版本。
使用方式
-
配置路由规则
由于新版本上线的行为发生在被调方,主调方并不感知被调是否上线了新版本服务,因此路由规则需要配置在被调方。配置一个被调规则,指定只有gray=true的请求,才流入版本号为2.0.0的实例分组,其他请求则流入版本号为1.0.0的实例分组。
(1) 配置兜底规则:将请求导入到1.0.0版本的分组。
(2) 配置灰度规则:将gray=true的请求导入到2.0.0版本的分组,不存在2.0.0分组时,请求导入到1.0.0的分组。
(3) 规则列表:将按顺序进行匹配执行规则。
-
执行服务路由
可以执行各个语言SDK的版本号路由样例进行服务路由功能的执行,执行完可以通过调用结果可以看到灰度的请求都流向了版本号2.0.0的分组。
多环境隔离实践
场景描述
使用微服务架构时,一个业务数据流通常需要跨多个微服务才能完成。而在业务开发过程中,通常会有以下诉求:
- 为了提升开发效率,不同特性开发人员,需要使用特性环境进行并发开发测试联调,特性环境之间需要进行隔离;
- 同时为了降低部署成本,开发测试时,只需要部署特性变更所涉及的服务,链路其他未更改的服务,统一使用基线环境的服务。
使用方式
- 配置路由规则
本次场景,存在2个特性并行开发,特性(dev1)涉及修改的微服务为Svr1和Srv4,特性(dev2)涉及修改的微服务为Svr2。其他不涉及修改的微服务,在开发联调过程中,统一使用基线环境的服务。 为了防止混乱,每个特性开发人员只允许针对自己涉及修改的微服务添加针对当前特性的规则,不涉及修改的微服务不允许添加规则。
(1)所有的服务默认配置一个兜底规则,将请求导入到基线环境。
(2)Srv1服务添加一个主调规则,将来源dev1请求路由到dev1的Svr2。
(3)Svr4服务添加一个被调规则,将来源dev1请求路由到dev1的Svr4。
(4)Svr2服务添加一个被调规则,将来源dev2请求路由到dev2的Svr2。
-
执行服务路由
可以执行各个语言SDK的多环境路由样例进行服务路由功能的执行,执行完可以通过调用结果可以看到不同特性环境的请求都流向了对应特性环境的分组。
2.3.2 - 就近路由
功能描述
北极星提供基于 地域(region) - 城市(zone) - 园区(campus) 这3元组组成的地域信息进行就近路由的能力,能够根据主调的地域信息,结合被调实例的地域信息,进行匹配。实例本身的地域信息来源于有以下几个途径
服务端的 CMDB 插件
- 参考 cmdb 插件开发
客户端的 Location 插件
- 提供 Location 插件,用户可以根据 polaris客户端 中对于 Location 插件的定义,根据客户端所在环境的特性来实现不同的本地地址位置信息获取插件
- env: 将地理位置信息注入至客户端所在机器的环境中,客户端就可以基于系统环境变量自动获取地理位置信息
配置设计
polaris-go 客户端使用
SDK配置属于客户端全局配置,基于该SDK实例所发起的服务发现,都遵循该就近路由策略。 由于就近路由能力通过SDK服务路由模块的插件进行提供,因此就近路由相关配置,也作为插件的特有配置来进行提供。
global:
# 地址提供插件,用于获取当前SDK所在的地域信息
location:
providers:
- type: local
region: ${REGION} # 从环境变量 REGION 中读取
zone: ${ZONE} # 从环境变量 ZONE 中读取
campus: ${CAMPUS} # 从环境变量 CAMPUS 中读取
consumer:
serviceRouter:
# 服务路由链
chain:
- nearbyBasedRouter
# 插件特定配置
plugin:
nearbyBasedRouter:
# 默认就近区域:默认城市
matchLevel: zone
# 最大就近区域,默认为空(全匹配)
maxMatchLevel: zone
polaris-java 客户端使用
SDK配置属于客户端全局配置,基于该SDK实例所发起的服务发现,都遵循该就近路由策略。 由于就近路由能力通过SDK服务路由模块的插件进行提供,因此就近路由相关配置,也作为插件的特有配置来进行提供。
global:
location:
providers:
- type: local
options:
region: ${REGION:} # 从环境变量 REGION 中读取
zone: ${ZONE:} # 从环境变量 ZONE 中读取
campus: ${CAMPUS:} # 从环境变量 CAMPUS 中读取
serviceRouter:
chain:
# 就近路由
- nearbyBasedRouter
plugin:
nearbyBasedRouter:
#描述: 就近路由的最小匹配级别。region(大区)、zone(区域)、campus(园区)
matchLevel: zone
#描述: 最大匹配级别
maxMatchLevel: all
服务配置
就近流程
初始化
- 用户调用NewConsumerAPI或者NewProviderAPI后
- SDK 会使用客户端节点的 IP,往 Polaris 服务端查询该 IP 对应的 CMDB 信息,查询后的结果后返回给客户端
- 如果查询的结果中,没有携带地址信息,则客户端会走自己本地的 CMDB 插件查询客户端的地理位置信息
地域匹配
服务调用过程中,使用拉取的客户端地域信息,进行全词匹配。匹配规则如下:
- 优先按照 matchLevel 进行匹配,匹配不成功(实例不存在或者可用实例比例少于阈值),则进行降级
- 就近降级按照 degrade 所配置的策略进行降级,会进行逐级的降级匹配,直到 lowestMatchLevel
降级策略
| 降级策略:服务实例不可用 | 降级策略:服务实例不存在 | |
|---|---|---|
| matchLevel区域不存在实例 | 逐级降级直到maxMatchLevel。若实例全部不存在,返回LocationMismatch错误 | 逐级降级直到maxMatchLevel,若都不存在,返回LocationMismatch错误 |
| matchLevel区域存在实例,区域中不可用实例百分比大于等于降级比例 | 返回matchLevel区域实例 | 逐级降级直到maxMatchLevel,若都不满足健康实例返回条件,返回实例数大于0的最小区域实例 |
被调信息异常策略
| maxMatchLevel != "" | maxMatchLevel == “” | |
|---|---|---|
| 被调实例对应的CMDB字段缺失 | 忽略该实例 | 当降级到最高匹配级别(全匹配)时,会返回这部分服务实例 |
跨机房容灾场景
背景
服务端有广州云、深圳、南京云设备。客户端在深圳。 那么深圳客户端访问这个服务端时,返回实例列表由深圳、广州、南京实例组成,同时设置优先级,让深圳客户端优先访问深圳;然后是广州(同可用区);最后是南京
解决方案
假设存在服务A,服务A下面节点存在分别属于深圳、广州、南京的实例,CMDB信息如下:
- 华南/ap-guangzho/ap-guangzhou-3
- 华南/ap-shenzhen/ap-shenzhen-2
- 华东/ap-nanjing/ap-nanjing-4
客户端配置:
consumer:
serviceRouter:
plugin:
nearbyBasedRouter:
# 默认按zone进行就近
matchLevel: zone
就近逻辑
客户端配置 matchLevel: zone,默认只访问同 zone(深圳) 的实例,当深圳可用区无实例后,降级访问 region(华南) 的 实例(可访问广州的实例),当华南地区实例也达到降级条件后,降级访问全部 region(包含华东-南京) 的实例
2.3.3 - 访问限流
限流规则说明
北极星支持在界面配置单机限流规则,通过以下路径可以打开限流规则的编辑页面:控制台->服务列表->具体服务->限流规则->新建,打开后,规则各配置项说明如下:
限流类型
- 单机限流:单机限流是一种通过统计单机QPS指标,当达到规则指定阈值时对流量进行限制,保障服务实例不被瞬时流量给冲垮。
- 分布式限流:分布式限流是一种通过统计全局QPS指标,当达到规则指定阈值时对流量进行限制,保障服务实例不被瞬时流量给冲垮。
接口名称
可选,指定限流规则的接口过滤参数,接口名可对应方法名、http url等信息,不填代表不过滤。
- 接口:规则生效所对应的接口名,用于匹配客户端传入的method参数,默认为
空(全部) - 匹配方式:接口字段的匹配方式,支持全匹配、不等于、包含、不包含、正则表达式四种匹配模式
请求匹配规则
可选,指定限流规则的请求参数匹配条件,不填代表不过滤,支持以下四种参数类型:
-
自定义参数:自定义KEY和VALUE,具体的请求参数值可通过SDK进行传入。
-
请求头(HEADER):针对协议消息头(http header/grpc header)进行过滤。
-
请求参数(QUERY):针对协议请求参数(http query)进行过滤。
-
方法(METHOD):针对协议的METHOD(http method/grpc method)进行过滤。
-
主调服务:针对微服务调用场景下,主调方的服务名进行过滤。
-
主调IP:针对主调方机器的IP地址进行过滤。
每种类型参数值支持以下几种值匹配模式:
-
全匹配:全值匹配,传入的值与配置的值相同才匹配通过。
-
正则表达式:用户配置正则表达式,通过正则表达式对传入的值进行匹配,正则表达式支持Google RE2标准。
-
不等于:取反匹配,传入的值与所配置的值不相等才算匹配成功。
-
包含:多字符串取OR匹配,传入的值只要匹配到其中一个字符串,就算匹配成功。字符串之间使用逗号进行分割。值格式为’value1,value2,value3‘,匹配到其中一个就算成功。
-
不包含:多字符串取反匹配,传入的值必须都没有出现在所配置的字符串列表中,才算匹配通过。值格式为’value1,value2,value3‘,全部不等于才算成功。
限流阈值
指定统计周期内的统计阈值,达到阈值则进行限流。可以配置多个限流阈值,多个限流阈值可同时生效,任意触发了一个就进行限流。
- 统计时长:限流阈值的统计时长,单位秒,默认为1秒
- 请求数:达到限流条件的请求数阈值。默认为1
限流效果
限流阈值被触发后,如何进行对流量进行限制,目前支持2种模式(默认为直接拒绝):
- 直接拒绝:当统计时长内请求数达到阈值,后续新的请求会被拒绝,直到下个统计周期到来才恢复。
- 匀速排队:基于漏桶算法,将请求数平均分配到统计时长内(细分的最小度量单位为1ms),从而控制请求以均匀的速度通过。
失败退化策略
分布式限流需要依赖token server,如果出现token server不可访问,则客户端可以根据配置的规则进行降级,保证用户请求最大限度不受影响。
- 退化成单机限流:默认策略。直接退化成单机计算配额的方式进行限流,单机配额=(全局配额/节点数)。
- 直接通过:不执行限流,所有请求都直接放通。
使用场景
针对服务进行限流
在RateLimitServiceJava服务下新建限流规则,指定QPS为10,限流效果选择直接拒绝。
针对接口+标签进行细粒度限流
在 RateLimitServiceJava 服务下新建限流规则,指定QPS为10,方法名为/echo,针对 http 请求中的 header user=foo 进行限流,限流效果选择直接拒绝。
针对接口+标签进行热点参数限流
在 RateLimitServiceJava 服务下新建限流规则,指定QPS为10,方法名为/echo,针对 http 请求中的 header user的每一个参数值进行单独限流,限流效果选择直接拒绝。
热点参数限流规则配置需要满足2个条件,否则无法生效:
- 存在非全匹配规则。”接口名称“、”请求匹配规则“配置中至少存在一条规则是非全匹配规则,比如”不等于“;如果全是全匹配规则,那该限流只是普通限流。
- 不启用”合并计算阈值“。
热点参数限流是一种针对高并发请求中某些热点参数的限流策略;如上述规则的限流效果图如下:
使用匀速排队
在RateLimitServiceJava服务下新建限流规则,指定QPS为10,限流效果选择匀速排队。
2.3.4 - 熔断降级
熔断规则说明
北极星支持在界面配置熔断规则,通过打开北极星控制台,在左侧边栏选择”熔断降级“,可打开熔断降级规则列表,分为3个子TAB,分别配置服务级熔断规则、实例级熔断规则、主动探测规则。
服务级熔断规则
点击新建熔断规则,可以新建服务级熔断规则。服务级熔断规则用于针对特定服务或者服务下的接口进行熔断。
界面各字段含义如下:
基础信息
- 规则名称:规则名,需全局唯一。
- 描述:规则的描述信息,用于补充规则的说明。
匹配条件
匹配条件主要用于决定熔断规则的适用范围,客户端根据匹配条件来过滤本地调用所适用的熔断规则。
- 主调服务:配置作为主调方的服务名和命名空间,可选。不配置则默认对所有的主调生效。
- 被调服务:配置被调的服务名和命名空间,可选。不配置则默认对所有的被调生效。
- 被调接口:配置被调的接口名,表明该熔断规则只对调用某个接口的请求生效,可选。接口名支持多种匹配条件,具体匹配条件可参考:字符串匹配方式
另外,熔断规则中所填的服务名,可为任意服务名,不一定需要存在于北极星注册中心。
熔断配置
- 错误判断条件:可配置多个判断条件,满足任意一个条件的请求会被标识为错误请求。支持返回码和时延2种判断方式。
- 熔断触发条件:可配置多个触发条件,满足任意一个条件即会触发熔断,资源会进入熔断状态。支持连续错误数和错误率2种触发条件。
- 连续错误数:统计调用该服务/接口的请求连续错误数,达到阈值即触发熔断。
- 错误率:统计在周期内调用该服务/接口的请求的错误率,达到阈值即触发熔断。同时为避免少流量下的放大效应,可配置错误率统计的起始请求阈值,请求数超过阈值才进行熔断判断。
- 熔断粒度:指定熔断的资源粒度,支持接口(按单个接口进行统计并熔断,只熔断单个接口),以及服务(按服务维度来统计并熔断,熔断整个服务)。
- 熔断恢复:资源触发熔断后,会熔断请求调度到该资源一段时间。随后系统会对资源进行恢复尝试,当满足一定次数的连续成功请求数后,资源会恢复正常状态。用户可配置资源熔断时长(单位秒),以及连续成功请求数。
主动探测
可选择开启主动探测。开启后,主调方会根据被调服务/接口所关联的探测规则,向被调方发起探测,探测结果会与业务调用合并,作为熔断触发或恢复的依据之一。
熔断后降级
可选择开启降级。开启后,当服务/接口被熔断后,访问该服务/接口的请求,会以自定义响应的方式访问给主调方。
- 返回码:自定义响应的返回码。
- Headers:自定义响应的消息头,可添加多个。
- Body:自定义响应的消息体。
是否开启
选择是否开启该规则。
实例级熔断规则
点击新建熔断规则,可以新建实例级熔断规则。实例级熔断规则用于针对特定分组下多个服务实例或者单个服务实例进行熔断。
界面各字段含义如下:
基础信息
- 规则名称:规则名,需全局唯一。
- 描述:规则的描述信息,用于补充规则的说明。
匹配条件
匹配条件主要用于决定熔断规则的适用范围,客户端根据匹配条件来过滤本地调用所适用的熔断规则。
- 主调服务:配置作为主调方的服务名和命名空间,可选。不配置则默认对所有的主调生效。
- 被调服务:配置被调的服务名和命名空间,可选。不配置则默认对所有的被调生效。
- 被调接口:配置被调的接口名,表明该熔断规则只对调用某个接口的请求生效,可选。接口名支持多种匹配条件,具体匹配条件可参考:字符串匹配方式
另外,熔断规则中所填的服务名,可为任意服务名,不一定需要存在于北极星注册中心。
熔断配置
- 错误判断条件:可配置多个判断条件,满足任意一个条件的请求会被标识为错误请求。支持返回码和时延2种判断方式。
- 熔断触发条件:可配置多个触发条件,满足任意一个条件即会触发熔断,资源会进入熔断状态。支持连续错误数和错误率2种触发条件。
- 连续错误数:统计调用该实例的请求连续错误数,达到阈值即触发熔断。
- 错误率:统计在周期内调用该v的请求的错误率,达到阈值即触发熔断。同时为避免少流量下的放大效应,可配置错误率统计的起始请求阈值,请求数超过阈值才进行熔断判断。
- 熔断粒度:指定熔断的资源粒度,支持实例(按单个实例进行统计并熔断)。
- 熔断恢复:资源触发熔断后,会熔断请求调度到该资源一段时间。随后系统会对资源进行恢复尝试,当满足一定次数的连续成功请求数后,资源会恢复正常状态。用户可配置资源熔断时长(单位秒),以及连续成功请求数。
主动探测
可选择开启主动探测。开启后,主调方会根据被调服务/接口所关联的探测规则,向被调方发起探测,探测结果会与业务调用合并,作为熔断触发或恢复的依据之一。
是否开启
选择是否开启该规则。
主动探测规则
用户可配置主动探测规则,指定被调服务通过什么方式进行探测,探测结果将作为被调资源熔断及恢复的依据。
界面各字段含义如下:
- 规则名称:必选。规则名,需全局唯一。
- 描述:可选。规则的描述信息,用于补充规则的说明。
- 命名空间:必选。被调服务的命名空间。
- 服务名称:必选。被调服务的名称。
- 接口名称:可选。被调接口的名称,支持多种匹配条件,具体匹配条件可参考:字符串匹配方式。
- 周期:可选。探测周期,多久执行一次探测,默认30秒。
- 超时时间:可选,探测最大超时时间,超时未响应则以最大超时时间作为熔断依据。默认60秒。
- 端口:可选,探测端口,默认为服务实例端口。
- 协议:使用什么协议进行探测,会影响接下来的配置,支持HTTP, TCP, UDP 3种协议。
- HTTP协议配置:
- 方法:HTTP方法,默认Get。
- Url:探测Url,默认/。
- Headers:发送探测包所需的消息头,默认空。
- Body:发送探测包所需的消息体,默认空。
- TCP协议配置:TCP默认会采用tcp connect的方式进行探测,用户也可以配置基于报文的探测手段。
- Send:配置所需发送的TCP二进制报文,格式为0x开头的十六进制字符串,如:0x12ab。
- Receive:配置所接收的TCP二进制报文,可配置多个,不配置则不校验应答。
- UDP协议配置:UDP没有连接检测的方式,只能通过基于报文的探测手段。
- Send:配置所需发送的UDP二进制报文,格式为0x开头的十六进制字符串,如:0x12ab。
- Receive:配置所接收的UDP二进制报文,可配置多个。
北极星客户端具体使用哪种协议进行探测,与被探测实例的端口协议有关,主要获取的是实例的protocol属性,对应关系如下:
| 探测协议 | 服务实例的Protocol |
|---|---|
| HTTP | http, HTTP, tcp/http |
| TCP | tcp, gRPC |
| UDP | udp |
客户端接入
附录
字符串匹配方式
熔断规则使用公共的字符串匹配对话框,对话框支持多种匹配模式:
- 全匹配:实际请求字段与文本框所填内容全匹配,区分大小写。
- 正则表达式:文本框所填内容为正则表达式,实际请求字段需匹配所填的正则表达式,遵循Google Re2标准。
- 不等于:实际请求字段不等于文本框所填内容,区分大小写。
- 包含:文本框所填内容为多段的文本,以逗号来进行分割。实际请求字段内容必须全匹配其中某一段文本。
- 不包含:文本框所填内容为多段的文本,以逗号来进行分割。实际请求字段内容必须全不等于其中任何一段文本。
2.4 - 配置中心
2.4.1 - 配置分组
名词解释
- 命名空间(Namespace)
- 通过 Namespace 可以逻辑隔离环境、集群
- 配置分组(FileGroup)
- 一组配置文件的集合
- 配置文件(File)
- 配置编辑、发布的最小单元。例如一份 properties 、yaml 格式的配置文件。
- 配置文件三元组
- 通过 Namespace + FileGroup + File 可以唯一定位一份配置文件。
新增并发布配置文件
创建命名空间
创建配置文件分组
配置文件分组是一组配置文件的集合,通常建议一个应用或者一个微服务对应一个配置分组,例如订单服务 order-service等。如果是客户端 jar 包使用的配置文件,也可以以 jar 包命名,例如 dubbo-rpc。
创建配置文件
这里需要特别指出的是配置文件名可以通过 / 来组织配置文件目录树。因为一个应用往往具有多个模块,每个模块都有自身的配置文件。当配置文件多了之后,如果没有目录结构组织,配置将变的难以管理。北极星配置中心通过配置文件名按 / 分割来组织树状结构。例如上图中 common/bootstrap.properties 效果如下:
再新建一个 common/application.yaml 文件和一个 web/controller/web.properties 效果如下:
可以看到通过树状结构可以清晰的管理自己的配置文件。 需要注意的是只有叶子节点是配置文件,目录不可以是配置文件,跟 Zookeeper 有些区别。例如有一个配置文件名为:common/bootstrap.properties,就不能再建一个 common 的配置文件,因为 common 已经作为 common/bootstrap.properties 的上级目录。
编辑配置文件
选中配置文件 -> 点击编辑 -> 输入配置文件内容 -> 点击保存。
发布配置文件
编辑保存之后,点击发布即可发布配置文件。
查看发布历史
通过详情页“查看发布历史”或者侧边栏“发布历史”入口可以跳转到发布历史页面查看配置文件发布历史记录。
2.4.2 - 配置导入导出
导出配置文件
导航到配置分组,点击上方导出按钮弹出配置导出对话框。
选择要导出的配置文件所在命名空间。
提供两种导出形式:
- 全部导出:将命名空间中的配置分组全部导出
- 导出选中的配置分组:选择命名空间中的配置分组导出
选择完成后,点击提交按钮导出配置,配置文件会已config.zip文件的形式下载到本地。
导出的配置文件config.zip压缩包中文件组织结构为:
├── META // 导出配置的元数据文件
├── group // 配置分组为一级目录
│ ├── filename // 配置文件
│ └── dir // 配置文件子目录
│ ├── otherfile
├── othergroup
如下图示例所示:
META文件记录配置文件的tag信息和comment信息,如下图示例所示:
导入配置文件
导航到配置分组,点击上方导入按钮。
弹出配置导入对话框,选择要导入的命名空间,从本地上传要导入的配置文件。
配置文件需要组织成ZIP压缩包,其文件组织结构需要跟导出的配置文件类似:
├── META // 导入配置的元数据文件
├── group // 配置分组为一级目录
│ ├── filename // 配置文件
│ └── dir // 配置文件子目录
│ ├── otherfile
├── othergroup
导入配置文件时META文件是可选的,如果需要导入配置文件的tag信息和comment信息,则需要提供META文件,否则可以不提供。
如果导入的配置文件与命名空间中已有的配置文件冲突,可以选择跳过或覆盖冲突文件。
导入成功后会显示导入文件详情。
2.4.3 - 配置加密
设计
客户端:
- 客户端本地生成一对公钥和私钥,请求配置文件时携带公钥参数,服务端使用客户端发来的公钥作为KEK(密钥加密密钥)对配置文件的DEK进行加密,然后返回客户端配置密文和DEK密文,客户端收到后用私钥解密DEK密文得到DEK明文,再用DEK解密配置密文。
- 客户端解密流程
控制台:
-
创建加密配置: 创建配置接口增加是否加密参数,如果需要加密,服务端生成数据加密密钥DEK,加密配置文件,保存配置文件密文到配置文件表,保存DEK和配置创建人配置文件的标签表。
-
查看加密配置: 用户在有读权限的前提下,请求获取配置文件,如果配置文件是加密的,服务端额外校验请求人是否为创建人,如果是则使用DEK解密配置文件后返回;如果不是则只返回配置文件密文。
-
控制台创建读取流程
如何启用配置加密
- 在新增配置文件中,点击配置加密的开关按钮
- 确认开启配置加密后,选择期望的配置加密算法
- 正常填写配置内容并发布
- 客户端接口获取到的文件内容是加密的
当前支持的客户端版本
2.4.4 - 配置灰度
功能描述
在使用配置中心对业务集群配置进行集中管理时,如果对某个配置项进行了修改,配置中心会将新的配置下发到所有监听该配置文件的业务进程中。业务进程接受到新的配置后会将新的配置覆盖当前的旧配置从而完成配置生效。由于配置是下发到所有客户端,一旦配置值修改不符合预期,将影响整个业务集群。
因此,在需要对配置进行编辑后下发到业务机器时,推荐先进行灰度发布。灰度发布是指在修改配置需要发布时,根据一定的规则选择一小部份机器,将修改后的配置先下发到这些机器中进行小范围验证。待业务确认无问题时,再将配置进行全量下发。如果在灰度发布期间发现问题,可以立即停止灰度发布。
如何使用
2.5 - 权限控制
2.5.1 - 概述
-
Polarismesh(北极星) 的鉴权功能,您可以清晰地管理资源与用户的访问权限。北极星基于命名空间和服务资源维度实现权限管控。
-
Polarismesh(北极星) 引入策略的概念,将资源的访问权限与不同的用户角色联系到一起。例如下图,
-
Polarismesh(北极星) 默认账户
name: polaris password: polaris
鉴权模型
主账号
也可称为主用户,是所有北极星资源的拥有者,对所有北极星资源有操作权限。
- 主账户可以直接修改子账户的密码
- 主账户可以创建、删除用户
- 主账户可以创建、删除用户组
- 主账户可以为用户组添加、移除用户
- 主账户可以禁用用户、用户组token
- 主账户可以编辑鉴权策略
子账号
由主账户创建的协作账户,默认只能操作没有关联任何鉴权策的北极星资源。
- 子账户能够查看北极星的账户列表,但是只能查看自己的账户信息
- 子账户只能查看自身的token信息
- 子账户只能查看自己所在的用户组列表
- 子账户只能查看自己所在的用户组的token
用户组
北极星的用户组概念,是一组具有相同权限的用户。主账号可以通过创建用户组批量对用户进行授权与管理。
- 用户组只能由主账号创建和授权
- 用户组不能进行控制台登录
授权
主用户可以管理所有子用户以及用户分组的写权限。子用户可将自己拥有写权限的资源权限分配给其他子用户或者用户组。
- 如果用户UserA被加入用户组GroupA,那么UserA可以操作授权给GroupA的资源,但是GroupA无法操作UserA的资源。
- 如果用户UserA从用户组GroupA中被移除,那么UserA将无法操作授权给GroupA的资源。
- 默认策略只能编辑资源信息
资源操作凭据 Token
资源权限将通过token进行控制和管理,用户与用户组均可生成。
- 若用户UserA的token被禁用,则只能读取北极星的资源,但是无法创建、修改北极星的资源。
- 若用户组GroupA的token被禁用,则GroupA只能读取北极星的资源,但是无法创建、修改北极星的资源。
资源鉴权设计
未开启鉴权
- 命名空间、服务、配置分组的读写操作不受限制,任何人都可以对资源进行修改。
开启鉴权
- 开启鉴权前创建的资源,默认没有绑定鉴权策略,任何人都可以对资源进行修改。
- 鉴权行为仅针对有绑定策略的资源生效。
- 命名空间、服务、配置分组,创建之后默认仅能被管理员以及当前创建者进行读写操作。
命名空间
- 任何用户均可以创建命名空间
- 如果用户对该命名空间有写权限,则可以在该命名空间下创建服务以及配置分组。
- 用户可以在创建命名空间时,指定可以操作该命名空间的其他用户,或者用户组。
服务
- 用户可以在创建服务时,指定可以操作该服务的其他用户,或者用户组
- 如果用户对该服务有写权限,则可以对该服务的信息、实例进行操作。
- 如果用户对该服务有写权限,但是没有对应命名空间的写权限,也可以对该服务的信息、实例进行操作。
配置分组
- 如果用户对该配置分组有写权限,则可以对该配置分组的信息、配置文件进行操作。
- 如果用户对该配置分组有写权限,但是没有对应命名空间的写权限,也可以对该配置分组的信息、配置文件进行操作。
2.5.2 - 策略
服务端开启鉴权
- 修改服务端配置文件
polaris-server.yaml
auth:
# 鉴权插件
name: defaultAuth
option:
# token 加密的 salt,鉴权解析 token 时需要依靠这个 salt 去解密 token 的信息
# salt 的长度需要满足以下任意一个:len(salt) in [16, 24, 32]
# 如有自定义需求,需要在首次部署时指定
salt: polarismesh@2021
# 控制台鉴权能力开关,默认开启
consoleOpen: true
# 客户端鉴权能力开关, 默认关闭
clientOpen: false
# 是否启用鉴权的严格模式,即对于没有任何鉴权策略的资源,也必须带上正确的用户/用户组 token 才能操作, 默认开启
# 该配置项在 v1.17.2 版本开始舍弃,如果设置 strict == true, 则相当于 consoleStrict = true & clientStrict = false
strict: false
# 是否启用鉴权的严格模式,即对于没有任何鉴权策略的资源,也必须带上正确的用户/用户组 token 才能操作, 默认开启
# 该配置项在 v1.17.2 版本开始启用
consoleStrict: true
# 是否启用鉴权的严格模式,即对于没有任何鉴权策略的资源,也必须带上正确的用户/用户组 token 才能操作, 默认关闭
# 该配置项在 v1.17.2 版本开始启用
clientStrict: false
-
若为VM部署,修改每个polaris部署节点中的
polaris-server.yaml文件,修改完后执行以下命令进行重启polarisbash tool/stop.sh bash tool/start.shbash tool/stop.cmd bash tool/start.cmd -
若为容器化部署,则先修改名称为
polaris-server-config的configmap,修改完之后,执行以下命令触发polaris的滚动重启kubectl rollout restart statefulset polaris -
如果有修改 salt 的需要,则需要按照以下步骤执行
- 确定最终的 salt 值并将其修改至
polaris-server.yaml中 - 执行auth/defaultauth/token_test.go中的
Test_CustomDesignSalt函数,生成新的token - 执行下列SQL
INSERT INTO `user` ( `id`, `name`, `password`, `source`, `token`, `token_enable`, `user_type`, `comment`, `owner` ) VALUES ( '65e4789a6d5b49669adf1e9e8387549c', 'polaris', '$2a$10$5XMjs.oqo4PnpbTGy9dQqewL4eb4yoA7b/6ZKL33IPhFyIxzj4lRy', 'Polaris', '${新的token}', 1, 20, 'default polaris admin account', '' ); - 这样就完成了主账户的
token变更
- 确定最终的 salt 值并将其修改至
如何创建鉴权策略
- 单击新建策略。填写策略基本信息,在角色栏可以选择需要授权用户或用户组,单击下一步选择授权的资源。
- 在资源栏可选择北极星的资源类型,包括命名空间、服务等资源,主账号可对所有资源进行操作。
- 单击下一步,进入预览界面,详细展示该策略涉及的用户、用户组以及资源。确认信息无误后,单击完成。
- 主账号可在权限策略列表查阅现有的权限策略,可单击编辑进行授权或删除等操作。
新建资源如何选择可操作用户
创建命名空间
在命名空间页面中,点击新建,在弹出页面中,点击高级选择可以操作本资源的用户或者用户组。
创建服务
在服务列表页面中,点击新建,在弹出页面中,点击高级选择可以操作本资源的用户或者用户组。
3 - Java 应用开发
3.1 - 使用 Java SDK
3.1.1 - 注册发现
引入依赖
修改应用根目录下的pom.xml,为 polaris-java 添加 dependencyManagement:
<dependencyManagement>
<dependencies>
<dependency>
<groupId>com.tencent.polaris</groupId>
<artifactId>polaris-dependencies</artifactId>
<version>${version}</version>
<type>pom</type>
<scope>import</scope>
</dependency>
</dependencies>
</dependencyManagement>
然后只需要在
<dependencies>
<dependency>
<groupId>com.tencent.polaris</groupId>
<artifactId>polaris-all</artifactId>
</dependency>
</dependencies>
初始化 polaris.yml
你需要在项目的 main/resources 下创建一个 polaris.yml 文件用于初始化 polaris-java SDK。polaris.yml 配置详细
服务注册
SDK实例构建
当初始化好 polaris.yml 文件之后,你可以直接 import com.tencent.polaris.factory.api.DiscoveryAPIFactory, 使用 DiscoveryAPIFactory 中的方法进行构造一个 ProviderAPI SDK 实例
import com.tencent.polaris.factory.api.DiscoveryAPIFactory;
public static void main(String[] args) throws Exception {
ProviderAPI providerAPI = DiscoveryAPIFactory.createProviderAPI();
}
注册请求体
InstanceRegisterRequest request = new InstanceRegisterRequest();
// 设置实例所属服务信息
request.setService(service);
// 设置实例所属服务的命名空间信息
request.setNamespace(namespace);
// 设置实例的 host 信息
request.setHost(host);
// 设置实例的端口信息
request.setPort(port);
// 可选,资源访问Token,即用户/用户组访问凭据,仅当服务端开启客户端鉴权时才需配置
request.setToken(token);
// 设置实例版本
request.setVersion(version);
// 设置实例的协议
request.setProtocol(protocol);
// 设置实例权重
request.setWeight(weight);
// 设置实例的标签
request.setMetadata(metadata);
// 设置实例地理位置 zone 信息
request.setZone(zone);
// 设置实例地理位置 region 信息
request.setRegion(region);
// 设置实例地理位置 campus 信息
request.setCampus(campus);
// 设置心跳健康检查ttl,单位为s,不填默认为5s,TTL的取值范围为 (0s, 60s]
// 开启了心跳健康检查,客户端必须以TTL间隔上报心跳
// 健康检查服务器3个TTL未受到心跳则将实例置为不健康
request.setTtl(ttl);
发起注册请求
你在初始化完 InstanceRegisterRequest 结构体后,只需要调用 ProviderAPI.RegisterInstance 方法即可完成实例注册,并且 RegisterInstance 方法内部会自动维护实例的心跳上报。
InstanceRegisterResponse registerResp = providerAPI.registerInstance(registerRequest)
服务发现
SDK实例构建
当初始化好 polaris.yml 文件之后,你可以直接 import com.tencent.polaris.factory.api.DiscoveryAPIFactory, 使用 DiscoveryAPIFactory 中的方法进行构造一个 ConsumerAPI SDK 实例
import com.tencent.polaris.factory.api.DiscoveryAPIFactory;
public static void main(String[] args) throws Exception {
ConsumerAPI consumerAPI = DiscoveryAPIFactory.createConsumerAPI();
}
发现服务实例
GetAllInstances
直接返回目标服务下的所有实例,包括不健康、隔离、权重为0、被熔断的实例,也会在返回的实例列表中。
GetAllInstancesRequest request = new GetAllInstancesRequest();
// 设置服务命名空间
request.setNamespace(String namespace);
// 设置服务名称
request.setService(String service);
// 设置超时时间
request.setTimeoutMs(long timeoutMs);
// 调用 ConsumerAPI 执行该请求
consumerAPI.getAllInstance(request);
GetHealthyInstances
每次获取一批可用服务提供者实例。
该方法默认会过滤掉不健康、隔离、权重为0、被熔断的实例。
GetInstancesRequest request = new GetInstancesRequest();
// 设置服务命名空间
request.setNamespace(String namespace);
// 设置服务名称
request.setService(String service);
// 可选,设置主调服务信息,只用于路由规则匹配
SourceService serviceInfo = new SourceService();
// 设置主调服务命名空间
serviceInfo.setNamespace(String namespace);
// 设置主调服务名称
serviceInfo.setService(String service);
// 设置主调方的请求标签信息
serviceInfo.setArguments(Set<RouteArgument> arguments);
request.setServiceInfo(serviceInfo);
// 设置超时时间
request.setTimeoutMs(long timeoutMs);
// 调用 ConsumerAPI 执行该请求
consumerAPI.getInstances(request);
GetOneInstances
每次仅获取一个可用服务提供者实例,该方法会依次执行路由、负载均衡流程。
该方法默认会过滤掉不健康、隔离、权重为0、被熔断的实例。
执行路由流程的条件
- 配置了 GetOneInstanceRequest.ServiceInfo.Metadata 属性,会触发自定义路由流程
- 设置了 GetOneInstanceRequest.Metadata 属性,会触发元数据路由流程
public class Criteria {
/**
* 指定负载均衡策略
*/
private String lbPolicy;
/**
* 一致性hash的key
*/
private String hashKey;
}
GetOneInstanceRequest request = new GetOneInstanceRequest();
// 设置服务命名空间
request.setNamespace(String namespace);
// 设置服务名称
request.setService(String service);
// 可选,元数据信息,仅用于dstMetadata路由插件的过滤
request.setMetadata(Map<String, String> metadata);
// 可选,设置元数据路由兜底措施
// 当前支持的元数据路由兜底措施如下
// - 默认不降级: METADATAFAILOVERNONE("metadataFailoverNone")
// - 降级返回所有节点: METADATAFAILOVERALL("metadataFailoverAll")
// - 返回不包含元数据路由key的节点: METADATAFAILOVERNOTKEY("metadataFailoverNoKey")
request.setMetadataFailoverType();
// 可选,对应自定义路由规则中请求标签中的方法(Method)
request.setMethod(String method);
// 如果需要走 Hash 负载均衡的话,需要设置
Criteria criteria = new Criteria();
request.setCriteria(criteria);
// 可选,设置主调服务信息,只用于路由规则匹配
SourceService serviceInfo = new SourceService();
// 设置主调服务命名空间
serviceInfo.setNamespace(String namespace);
// 设置主调服务名称
serviceInfo.setService(String service);
// 设置主调方的请求标签信息
serviceInfo.setArguments(Set<RouteArgument> arguments);
request.setServiceInfo(serviceInfo);
// 设置超时时间
request.setTimeoutMs(long timeoutMs);
// 调用 ConsumerAPI 执行该请求
consumerAPI.getOneInstance(request);
如何基于 polaris-java 客户端完成一个服务发现的程序
3.1.2 - 动态路由
引入依赖
修改应用根目录下的pom.xml,为 polaris-java 添加 dependencyManagement:
<dependencyManagement>
<dependencies>
<dependency>
<groupId>com.tencent.polaris</groupId>
<artifactId>polaris-dependencies</artifactId>
<version>${version}</version>
<type>pom</type>
<scope>import</scope>
</dependency>
</dependencies>
</dependencyManagement>
然后只需要在
<dependencies>
<dependency>
<groupId>com.tencent.polaris</groupId>
<artifactId>polaris-all</artifactId>
</dependency>
</dependencies>
初始化 polaris.yml
你需要在项目的 main/resources 下创建一个 polaris.yml 文件用于初始化 polaris-java SDK。polaris.yml 配置详细
服务注册
SDK实例构建
当初始化好 polaris.yml 文件之后,你可以直接 import com.tencent.polaris.factory.api.RouterAPIFactory, 使用 RouterAPIFactory 中的方法进行构造一个 RouterAPI SDK 实例
import com.tencent.polaris.factory.api.RouterAPIFactory;
public static void main(String[] args) throws Exception {
RouterAPI routerAPI = RouterAPIFactory.createRouterAPI();
}
注册请求体
ProcessRoutersRequest request = new ProcessRoutersRequest();/
// 被调服务命名空间
request.setNamespace();
// 被调服务名称
request.setService();
// 可选,对应自定义路由规则中请求标签中的方法(Method)
request.setMethod();
// 可选,设置主调服务信息,只用于路由规则匹配
SourceService serviceInfo = new SourceService();
// 设置主调服务命名空间
serviceInfo.setNamespace(String namespace);
// 设置主调服务名称
serviceInfo.setService(String service);
// 设置主调方的请求标签信息
serviceInfo.setArguments(Set<RouteArgument> arguments);
request.setSourceService(serviceInfo);
// 设置待参与路由的目标实例
request.setDstInstances();
ProcessRoutersRequest.RouterNamesGroup group = new ProcessRoutersRequest.RouterNamesGroup();
// 设置前置路由
group.setBeforeRouters();
// 设置业务路由
group.setCoreRouters();
// 设置后置路由
group.setAfterRouters();
// 可选,设置路由插件执行链
// 当前支持的路由插件类型如下
// - 就近路由: nearByRoute
// - 自定义路由: ruleRouter
// - 元数据路由: metadataRoute
request.setRouters();
如果当前 ProcessRoutersRequest 还不支持 putRouterArgument 方法,或者不存在 class SourceService, 同时服务端版本 >= 1.12.0,请求标签对应的 key 名称如下:
- 路径: $path
- 方法: $method
- 请求头: $header.{标签键}
- 请求参数: $query.{标签键}
- 请求COOKIE: $cookie.{标签键}
- 主调IP: $caller_ip
- 自定义: {标签键}
执行服务路由
你在初始化完 ProcessRoutersRequest 结构体后,只需要调用 RouterAPI.processRouters 方法即可完成服务路由
ProcessRoutersResponse resp = routerAPI.processRouters(registerRequest)
如何基于 polaris-java 客户端完成一个服务路由的程序
3.1.3 - 负载均衡
引入依赖
修改应用根目录下的pom.xml,为 polaris-java 添加 dependencyManagement:
<dependencyManagement>
<dependencies>
<dependency>
<groupId>com.tencent.polaris</groupId>
<artifactId>polaris-dependencies</artifactId>
<version>${version}</version>
<type>pom</type>
<scope>import</scope>
</dependency>
</dependencies>
</dependencyManagement>
然后只需要在
<dependencies>
<dependency>
<groupId>com.tencent.polaris</groupId>
<artifactId>polaris-all</artifactId>
</dependency>
</dependencies>
初始化 polaris.yml
你需要在项目的 main/resources 下创建一个 polaris.yml 文件用于初始化 polaris-java SDK。polaris.yml 配置详细
服务注册
SDK实例构建
当初始化好 polaris.yml 文件之后,你可以直接 import com.tencent.polaris.factory.api.RouterAPIFactory, 使用 RouterAPIFactory 中的方法进行构造一个 RouterAPI SDK 实例
import com.tencent.polaris.factory.api.RouterAPIFactory;
public static void main(String[] args) throws Exception {
RouterAPI routerAPI = RouterAPIFactory.createRouterAPI();
}
负载均衡
public class Criteria {
// 一致性hash的key
private String hashKey;
}
ProcessLoadBalanceRequest request = new ProcessLoadBalanceRequest();
// 设置需要参与负载均衡的服务实例
request.setDstInstances(ServiceInstances dstInstances);
// 设置负载均衡策略
// 当前支持的负载均衡策略如下
// - 权重随机负载均衡: weightedRandom
// - 权重一致性负载均衡: ringHash
request.setLbPolicy(String lbPolicy);
// 如果需要走 Hash 负载均衡的话,需要设置
Criteria criteria = new Criteria();
request.setCriteria(criteria);
执行服务负载均衡
你在使用 ConsumerAPI.getAllInstances 或者 ConsumerAPI.getInstances 获取到服务实例列表后,完成 ProcessLoadBalanceRequest 初始化,只需要调用 RouterAPI.processLoadBalance 方法即可完成负载均衡
ProcessLoadBalanceResponse resp = routerAPI.processLoadBalance(request)
如何基于 polaris-java 客户端完成一个服务负载均衡的程序
3.1.4 - 熔断降级
熔断整个服务
配置熔断规则
配置服务熔断规则,针对default命名空间下所有的服务,对于时延大于500毫秒,或者返回码为500的请求,标识为错误请求,一旦一分钟内错误率30%及以上或连续错误数在5个以上,则对服务进行熔断。
使用SDK进行熔断判断
方法说明
北极星Java SDK提供以下熔断相关的方法,所有的方法都在com.tencent.polaris.circuitbreak.api.CircuitBreakAPI接口中提供。
- check:检查资源是否可被调用,并对资源获取调用申请。对于半开的资源,如果半开的调用配额申请成功,返回true,否则返回false。
- report:该方法供用户在资源调用完成后,上报调用的结果,包括返回码、时延等信息,供熔断逻辑判断。
- makeFunctionalDecorator:创建一个函数调用装饰器
FunctionalDecorator,装饰器可以对Java的函数接口进行装饰。装饰后的逻辑,会在函数逻辑调用前,先通过check方法检查资源是否可被调用,如果不能被调用,会抛出资源熔断异常(CallAbortedException)。调用完成后,会通过report接口上报本次调用结果。FunctionalDecorator包含以下方法:- decorateSupplier:对函数接口Supplier进行封装。
- decorateConsumer:对函数接口Consumer进行封装。
- decorateFunction:对函数Function进行封装。
- decoratePredicate:对函数接口Predicate进行封装。
使用示例
// 创建CircuitBreakAPI实例
CircuitBreakAPI circuitBreakAPI = CircuitBreakAPIFactory.createCircuitBreakAPI();
// 通过传入服务名(testService1)和命名空间(default),创建FunctionalDecorator
FunctionalDecoratorRequest makeDecoratorRequest = new FunctionalDecoratorRequest();
makeDecoratorRequest.setService(new ServiceKey("default", "testService1"));
FunctionalDecorator decorator = circuitBreakAPI.makeFunctionalDecorator(makeDecoratorRequest);
// 封装函数接口
Consumer<Integer> integerConsumer = decorator.decorateConsumer(new Consumer<Integer>() {
@Override
public void accept(Integer object) {
// 执行服务调用...
}
});
// 通过执行函数接口,进行服务调用
// 在调用过程中,如果出现熔断,会抛出CallAbortedException异常
for (int i = 0; i < 500; i++) {
try {
integerConsumer.accept(i);
} catch(CallAbortedException e) {
e.printStackTrace();
}
}
样例地址
熔断单个接口
配置熔断规则
配置接口熔断规则,针对default命名空间所有服务的foo接口,对于时延大于500毫秒,或者返回码为500的请求,标识为错误请求,一旦一分钟内错误率30%及以上或连续错误数在5个以上,则对接口进行熔断。
使用SDK进行熔断判断
熔断所使用的SDK接口及方法与服务级熔断相同,这里不再重复介绍。
使用示例
// 创建CircuitBreakAPI实例
CircuitBreakAPI circuitBreakAPI = CircuitBreakAPIFactory.createCircuitBreakAPI();
// 通过传入服务名(testService1)、命名空间(default)和方法名(foo),创建FunctionalDecorator
FunctionalDecoratorRequest makeDecoratorRequest = new FunctionalDecoratorRequest();
makeDecoratorRequest.setService(new ServiceKey("default", "testService1"));
makeDecoratorRequest.setMethod("foo");
FunctionalDecorator decorator = circuitBreakAPI.makeFunctionalDecorator(makeDecoratorRequest);
// 封装函数接口
Consumer<Integer> integerConsumer = decorator.decorateConsumer(new Consumer<Integer>() {
@Override
public void accept(Integer object) {
// 执行服务接口调用...
}
});
// 通过执行函数接口,进行服务调用
// 在调用过程中,如果出现熔断,会抛出CallAbortedException异常
for (int i = 0; i < 500; i++) {
try {
integerConsumer.accept(i);
} catch(CallAbortedException e) {
e.printStackTrace();
}
}
样例地址
熔断单个实例
配置熔断规则
配置实例熔断规则,针对default命名空间下所有的服务实例,对于时延大于500毫秒,或者返回码为500的请求,标识为错误请求,每个实例的错误率是单独统计的,一旦一分钟内错误率30%及以上或连续错误数在5个以上,则对被调实例(IP:PORT)进行熔断。
使用SDK进行熔断判断
当实例被熔断时,该实例会暂时不接收请求,原本路由到该实例的请求会路由到其他实例。这个过程在服务路由过程中自动完成,用户无需进行额外的熔断状态判断等操作。
引入依赖
修改应用根目录下的pom.xml,为 polaris-java 添加 dependencyManagement:
<dependencyManagement>
<dependencies>
<dependency>
<groupId>com.tencent.polaris</groupId>
<artifactId>polaris-dependencies</artifactId>
<version>${version}</version>
<type>pom</type>
<scope>import</scope>
</dependency>
</dependencies>
</dependencyManagement>
然后只需要在
<dependencies>
<dependency>
<groupId>com.tencent.polaris</groupId>
<artifactId>polaris-all</artifactId>
</dependency>
</dependencies>
配置北极星服务端地址
用户需要在项目的 main/resources 下创建一个 polaris.yml 文件用于初始化 polaris-java SDK。
global:
serverConnector:
# 北极星服务端地址,端口为8091
addresses:
- 127.0.0.1:8091
执行服务路由
import com.tencent.polaris.factory.api.DiscoveryAPIFactory;
public static void main(String[] args) throws Exception {
CircuitBreakAPI circuitBreakAPI = CircuitBreakAPIFactory.createCircuitBreakAPI();
ConsumerAPI consumerAPI = DiscoveryAPIFactory.createConsumerAPI();
// 执行服务路由,筛选出单个实例,在这个过程中,会自动剔除熔断的实例
GetOneInstanceRequest getOneInstanceRequest = new GetOneInstanceRequest();
getOneInstanceRequest.setNamespace("default");
getOneInstanceRequest.setService("testService1");
InstancesResponse oneInstance = consumerAPI.getOneInstance(getOneInstanceRequest);
Instance targetInstance = oneInstance.getInstances()[0];
// 执行服务调用 --- 伪代码
httpResult, delay = rpc(targetInstance.host, targetInstance.port, body);
// invoke rpc call with targetInstance
InstanceResource instanceResource = new InstanceResource(new ServiceKey(namespace, service),
targetInstance.getHost(), targetInstance.getPort(), sourceService.getServiceKey());
circuitBreakAPI.report(new ResourceStat(instanceResource, httpResult.code, delay));
}
样例地址
启用主动探测
业务往往会存在高峰期和低峰期,低峰期流量比较少,不足以触发熔断,会出现当部分实例出现数据不可达的问题时,没法及时发现,导致高峰期到来时出现故障。
主动探测可以解决这个问题,启用主动探测后,主调方会定时根据探测规则,对被调实例进行探测,探测结果可作为熔断的判断依据,可实现对故障资源的快速熔断。
配置主动探测规则
配置一个主动探测规则,对服务(名为testService1,命名空间为default)进行探测。探测使用的协议是HTTP协议,由于服务开启了鉴权,因此探测时需要传入鉴权头。
注意:主动探测的规则,服务名可以选择全部服务,则规则针对全部服务生效。如果需要针对只接口进行探测,则可以在接口字段中填入对应的接口名。
在熔断规则中开启主动探测
需要在熔断规则中开启探测,这样才可以把探测结果用于熔断。
3.1.5 - 访问限流
引入依赖
修改应用根目录下的pom.xml,为 polaris-java 添加 dependencyManagement:
<dependencyManagement>
<dependencies>
<dependency>
<groupId>com.tencent.polaris</groupId>
<artifactId>polaris-dependencies</artifactId>
<version>${version}</version>
<type>pom</type>
<scope>import</scope>
</dependency>
</dependencies>
</dependencyManagement>
然后只需要在
<dependencies>
<dependency>
<groupId>com.tencent.polaris</groupId>
<artifactId>polaris-all</artifactId>
</dependency>
</dependencies>
初始化 polaris.yml
你需要在项目的 main/resources 下创建一个 polaris.yml 文件用于初始化 polaris-java SDK。polaris.yml 配置详细
SDK实例构建
当初始化好 polaris.yml 文件之后,你可以直接 import com.tencent.polaris.ratelimit.factory, 使用 LimitAPIFactory 中的方法进行构造一个 ProviderAPI SDK 实例
import com.tencent.polaris.ratelimit.factory.LimitAPIFactory;
public static void main(String[] args) throws Exception {
LimitAPI limitAPI = LimitAPIFactory.createLimitAPI();
}
请求配额
QuotaRequest quotaRequest = new QuotaRequest();
// 设置需要进行限流的服务信息:设置命名空间信息
quotaRequest.setNamespace(String namespace);
// 设置需要进行限流的服务信息:设置服务名称信息
quotaRequest.setService(String service);
// 设置本次被调用的方法信息
quotaRequest.setMethod(String method);
// 设置本次的请求标签
quotaRequest.setArguments(Set<Argument> arguments)
// 设置需要申请的请求配额数量
quotaRequest.setCount(1);
如果当前 QuotaRequest 还不支持 setArguments 方法,同时服务端版本 >= 1.11.0,SetLabels 对应的 key 名称如下:
- 路径: $path
- 方法: $method
- 请求头: $header.{标签键}
- 请求参数: $query.{标签键}
- 主调服务: $caller_service
- 主调IP: $caller_ip
- 自定义: {标签键}
发起配额申请请求
你在初始化完 QuotaRequest 结构体后,只需要调用 LimitAPI.getQuota 方法即可完成服务限流
QuotaResponse resp = limitAPI.getQuota(registerRequest)
分布式限流使用
如果要使用分布式限流,请先确保已经部署了北极星分布式限流 server
部署完后确认北极星控制台存在服务 命名空间: Polaris, 服务名: polaris.limiter。
确认完毕后,调整 polaris.yml 配置文件,在控制台配置分布式限流规则,SDK 仍然使用 QuotaResponse resp = limitAPI.getQuota(registerRequest) 即可。
provider:
rateLimit:
enable: true
limiterNamespace: Polaris
limiterService: polaris.limiter
如何基于 polaris-java 客户端完成一个服务限流的程序
3.1.6 - 配置管理
引入依赖
修改应用根目录下的pom.xml,为 polaris-java 添加 dependencyManagement:
<dependencyManagement>
<dependencies>
<dependency>
<groupId>com.tencent.polaris</groupId>
<artifactId>polaris-dependencies</artifactId>
<version>${version}</version>
<type>pom</type>
<scope>import</scope>
</dependency>
</dependencies>
</dependencyManagement>
然后只需要在
<dependencies>
<dependency>
<groupId>com.tencent.polaris</groupId>
<artifactId>polaris-all</artifactId>
</dependency>
</dependencies>
初始化 polaris.yml
你需要在项目的 main/resources 下创建一个 polaris.yml 文件用于初始化 polaris-java SDK。polaris.yml 配置详细
SDK实例构建
当初始化好 polaris.yml 文件之后,你可以直接 import com.tencent.polaris.configuration.factory, 使用 ConfigFileServiceFactory 中的方法进行构造一个 ConfigFileService SDK 实例
import com.tencent.polaris.configuration.factory.ConfigFileServiceFactory;
public static void main(String[] args) throws Exception {
ConfigFileService configFileService = ConfigFileServiceFactory.createConfigFileService();
}
配置文件读取操作
// 获取特定远程的配置文件
ConfigFile configFile = configFileService.getConfigFile(String namespace, String fileGroup, String fileName);
System.out.println(configFile.getContent());
对配置文件发起监听
//获取配置文件
ConfigFile configFile = configFileService.getConfigFile(namespace, fileGroup, fileName);
//添加变更监听器
configFile.addChangeListener(new ConfigFileChangeListener() {
@Override
public void onChange(ConfigFileChangeEvent event) {
}
});
查询加密配置
需要更新 polaris-java 的版本至 v1.13.0 +
// 获取特定远程的配置文件
ConfigFile getConfigFile(String namespace, String fileGroup, String fileName);
// 获取特定远程的配置文件
ConfigFile getConfigFile(ConfigFileMetadata configFileMetadata);
调整 polaris.yml 配置文件
# 配置中心默认配置
config:
# 配置过滤器
configFilter:
enable: true
chain:
# 启用配置解密插件
- crypto
plugin:
crypto:
# 配置解密插件的算法插件类型
type: AES
监听配置分组下的已发布文件列表变化
需要更新 polaris-java 的版本至 v1.14.0 及以上版本, 获取到目标配置分组后, 调用配置分组的 addChangeListener 方法监听改配置分组下已发布配置文件列表的变化
ConfigFileGroup configFileGroup = configFileService.getConfigFileGroup(namespace, fileGroup);
if (configFileGroup != null) {
configFileGroup.addChangeListener(new ConfigFileGroupChangeListener() {
@Override
public void onChange(ConfigFileGroupChangedEvent event) {
Utils.print(event.toString());
}
});
}
ConfigFileGroupChangedEvent 结构体的具体信息
public class ConfigFileGroupChangedEvent {
// 配置分组自身元数据信息
private final ConfigFileGroupMetadata configFileGroupMetadata;
// 当前配置分组下的最新已发布的配置文件列表
private final List<ConfigFileMetadata> configFileMetadataList;
public ConfigFileGroupChangedEvent(ConfigFileGroupMetadata configFileGroupMetadata, List<ConfigFileMetadata> configFileMetadataList) {
this.configFileGroupMetadata = configFileGroupMetadata;
this.configFileMetadataList = configFileMetadataList;
}
public ConfigFileGroupMetadata getConfigFileGroupMetadata() {
return configFileGroupMetadata;
}
public List<ConfigFileMetadata> getConfigFileMetadataList() {
return configFileMetadataList;
}
@Override
public String toString() {
return "ConfigFileGroupChangedEvent{" +
"configFileGroupMetadata=" + configFileGroupMetadata +
", configFileMetadataList=" + configFileMetadataList +
'}';
}
}
配置文件修改操作
使用 ConfigFileServicePublishFactory 中的方法进行构造一个 ConfigFilePublishService SDK 实例
import com.tencent.polaris.configuration.factory.ConfigFileServicePublishFactory;
public static void main(String[] args) throws Exception {
ConfigFilePublishService configFilePublishService = ConfigFileServicePublishFactory.createConfigFilePublishService();
}
操作配置文件的方法
// 创建配置文件
void createConfigFile(String namespace, String fileGroup, String fileName, String content);
// 创建配置文件
void createConfigFile(ConfigFileMetadata configFileMetadata, String content);
// 修改配置文件
void updateConfigFile(String namespace, String fileGroup, String fileName, String content);
// 修改配置文件
void updateConfigFile(ConfigFileMetadata configFileMetadata, String content);
// 发布配置文件
void releaseConfigFile(String namespace, String fileGroup, String fileName);
// 发布配置文件
void releaseConfigFile(ConfigFileMetadata configFileMetadata);
相关示例工程代码
3.1.7 - 可观测性
引入依赖
修改应用根目录下的pom.xml,为 polaris-java 添加 dependencyManagement:
<dependencyManagement>
<dependencies>
<dependency>
<groupId>com.tencent.polaris</groupId>
<artifactId>polaris-dependencies</artifactId>
<version>${version}</version>
<type>pom</type>
<scope>import</scope>
</dependency>
</dependencies>
</dependencyManagement>
然后只需要在
<dependencies>
<dependency>
<groupId>com.tencent.polaris</groupId>
<artifactId>polaris-all</artifactId>
</dependency>
</dependencies>
通过配置文件 polaris.yml 开启监控上报
你需要在项目的 main/resources 下创建一个 polaris.yml 文件用于初始化 polaris-java SDK。polaris.yml 配置详细
通过 prometheus pull 模式上报监控数据
global:
#描述: 监控及日志数据上报相关配置
statReporter:
#描述: 是否启用上报
enable: true
plugin:
prometheus:
type: pull
#描述: 设置 prometheus http-server 的监听端口
#类型:int
#默认值: 28080
#如果设置为负数,则不会开启默认的http-server,如果设置为0,则随机选择一个可用端口进行启动 http-server
port: 28080
#描述: 设置 prometheus http-server 的拉取path
#类型:string
#默认值: /metric
path: /metric
通过 pushgateway push 模式上报监控数据
global:
#描述: 监控及日志数据上报相关配置
statReporter:
#描述: 是否启用上报
enable: true
plugin:
prometheus:
type: push
#描述: 设置 pushgateway 的地址, 仅 type == push 时生效
#类型:string
address: 127.0.0.1:9091
#描述:设置metric数据推送到pushgateway的执行周期, 仅 type == push 时生效
#类型:string
#格式:^\d+(s|m|h)$
#范围:[1s:...]
#默认值:10s
pushInterval: 10s
通过代码开启监控上报
通过 prometheus pull 模式上报监控数据
ConfigurationImpl configuration = (ConfigurationImpl) ConfigAPIFactory
.defaultConfig(ConfigProvider.DEFAULT_CONFIG);
configuration.getGlobal().getStatReporter().setEnable(true);
PrometheusHandlerConfig prometheusHandlerConfig = configuration.getGlobal().getStatReporter()
.getPluginConfig("prometheus", PrometheusHandlerConfig.class);
prometheusHandlerConfig.setPort(28080);
prometheusHandlerConfig.setPath("/metrics");
configuration.getGlobal().getStatReporter()
.setPluginConfig("prometheus", prometheusHandlerConfig);
通过 pushgateway push 模式上报监控数据
ConfigurationImpl configuration = (ConfigurationImpl) ConfigAPIFactory
.defaultConfig(ConfigProvider.DEFAULT_CONFIG);
configuration.getGlobal().getStatReporter().setEnable(true);
PrometheusPushHandlerConfig prometheusHandlerConfig = configuration.getGlobal().getStatReporter()
.getPluginConfig("prometheus", PrometheusPushHandlerConfig.class);
prometheusHandlerConfig.setType("push");
prometheusHandlerConfig.setAddress("127.0.0.1:9091");
prometheusHandlerConfig.setPushInterval(30 * 1000L);
configuration.getGlobal().getStatReporter()
.setPluginConfig("prometheus", prometheusHandlerConfig);
SDK实例构建
当初始化好 polaris.yml 文件之后,你可以直接 import com.tencent.polaris.factory.api.DiscoveryAPIFactory, 使用 DiscoveryAPIFactory 中的方法进行构造一个 ConsumerAPI SDK 实例
import com.tencent.polaris.factory.api.DiscoveryAPIFactory;
public static void main(String[] args) throws Exception {
ConsumerAPI consumerAPI = DiscoveryAPIFactory.createConsumerAPI();
}
服务调用结果
public enum RetStatus {
// 服务调用成功
RetSuccess,
// 服务调用失败
RetFail,
// 服务调用超时
RetTimeout,
}
ServiceCallResult result = new ServiceCallResult();
// 设置被调服务所在命名空间
result.setNamespace(String namespace);
// 设置被调服务的服务信息
result.setService(String service);
// 设置被调实例
result.setInstance(Instance instance);
// 设置本次请求的响应码
result.setRetCode(String code);
// 设置本次请求的耗时
result.setDelay(String delay);
// 设置本次请求的结果状态
result.setRetStatus(RetStatus status);
// 设置本次请求的请求标签,格式为 key=value;key=value;
result.setLabels(String labels);
// 设置本次请求调用的方法
result.setMethod(String method);
上报请求调用结果
你在根据请求调用情况对 ServiceCallResult 结构体完成初始化后,只需要调用 ConsumerAPI.updateServiceCallResult 方法即可完成请求调用结果上报。SDK 内部会根据上报的调用结果信息,将其转换为相应的流量调用指标数据,上报至 prometheus。
consumerAPI.updateServiceCallResult(ServiceCallResult)
3.1.8 - 二次寻址
引入依赖
修改应用根目录下的pom.xml,为 polaris-java 添加 dependencyManagement:
<dependencyManagement>
<dependencies>
<dependency>
<groupId>com.tencent.polaris</groupId>
<artifactId>polaris-dependencies</artifactId>
<version>${version}</version>
<type>pom</type>
<scope>import</scope>
</dependency>
</dependencies>
</dependencyManagement>
然后只需要在
<dependencies>
<dependency>
<groupId>com.tencent.polaris</groupId>
<artifactId>polaris-all</artifactId>
</dependency>
</dependencies>
初始化 polaris.yml
你需要在项目的 main/resources 下创建一个 polaris.yml 文件用于初始化 polaris-java SDK。polaris.yml 配置详细
修改 polaris.yml 开启二次寻址
global:
system:
discoverCluster:
namespace: Polaris # 设置服务注册发现集群服务所在的命名空间
service: polaris.discover # 设置服务注册发现集群服务的服务名称
sameAsBuiltin: false
healthCheckCluster:
namespace: Polaris # 设置健康检查集群服务所在的命名空间
service: polaris.healthcheck # 设置健康检查集群服务的服务名称
sameAsBuiltin: false
3.2 - 使用 Spring Cloud
3.3 - 使用 Spring Boot
3.3.1 - 概述
警告
该接入方式官方暂停维护,建议升级至 Spring Cloud Tencent 享受 Polaris 全部服务治理能力.
功能简介
Spring Boot是一个构建在Spring框架顶部的项目。它提供了一种简便,快捷的方式来设置,配置和运行基于Web的简单应用程序,为了方便 Spring Boot 用户快速接入北极星,我们通过以下几个示例帮助用户如何在 Spring Boot 中体验北极星的相关功能。
快速入门
前提条件
您需要先下载 Polaris Server,具体操作参见 Polaris 服务端安装
确定 Spring Boot 版本
确认自己项目的 Spring Boot 版本
➜ mvn dependency:tree | grep "org.springframework.boot:spring-boot-starter:jar"
[INFO] | +- org.springframework.boot:spring-boot-starter:jar:2.6.9:compile
根据命令查询到的 spring boot 版本信息,我们在根据下面的版本列表对应关系选择合适的 Spring Boot 以及 Spring Boot Polaris 版本
版本列表
这里列出了不同 Spring Boot 版本相对应的 Spring Boot Polaris 版本。 您需要先查看您当前使用的 Spring Boot 版本,从而确定需要引入的 Spring Boot Polaris 版本。
| Spring Boot 兼容版本 | Spring Boot Polaris 版本 |
|---|---|
| 2.4.x | 1.1.0 |
接下来所有的示例我们将基于 Spring Boot 版本为 2.4.3、Spring Boot Polaris 版本为 1.1.0 开展。
3.3.2 - 服务注册
初始化项目
使用 jetbrain idea 等工具初始化一个 maven 项目
引入依赖
在上一步初始化好一个 maven 项目之后,我们在 pom.xml 中引入 Spring Boot Polaris 相关依赖。
- 引入 spring-boot-polaris-dependencies 进行管理 Spring Boot Polaris 相关组件的依赖版本。
- 引入 spring-boot-polaris-discovery-starter 实现 Spring Boot 服务注册到北极星中。
<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 https://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<parent>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-parent</artifactId>
<version>2.4.3</version>
<relativePath/> <!-- lookup parent from repository -->
</parent>
...
<dependencyManagement>
<dependencies>
<dependency>
<groupId>com.tencent.polaris</groupId>
<artifactId>spring-boot-polaris-dependencies</artifactId>
<version>1.1.0</version>
<type>pom</type>
<scope>import</scope>
</dependency>
</dependencies>
</dependencyManagement>
<dependencies>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
<!-- 引入 Spring Boot Polaris Discovery 依赖用于实现服务注册 -->
<dependency>
<groupId>com.tencent.polaris</groupId>
<artifactId>spring-boot-polaris-discovery-starter</artifactId>
</dependency>
</dependencies>
...
</project>
配置 application.properties
在 resources 目录下创建 application.properties 文件,并按照如下进行配置
.
├── java
│ └── com
│ └── example
│ └── springbootpolarisprovider
│ └── SpringbootProviderApplication.java
└── resources
└── application.properties
server.port=28888
spring.application.name=BootEchoServer
polaris.address=grpc://127.0.0.1:8091
polaris.discovery.register.enable=true
示例代码
```java
@SpringBootApplication
public class SpringbootProviderApplication {
public static void main(String[] args) {
SpringApplication.run(SpringbootProviderApplication.class, args);
}
@RestController
static class EchoController {
private final PolarisDiscoveryProperties properties;
EchoController(PolarisDiscoveryProperties properties) {
this.properties = properties;
}
@GetMapping(value = "/echo/{string}")
public String echo(@PathVariable String string) {
return "Hello PolarisMesh " + string + ", I'm " + properties.getApplicationName();
}
}
}
验证
启动 Spring Boot 应用
在 Spring Boot 启动日志中,找到如下日志信息, 则表示 Spring Boot 应用已经成功注册到北极星中。
[Polaris] success to register instance 127.0.0.1:28888, service is BootEchoServer, namespace is default
[Polaris] success to schedule heartbeat instance 127.0.0.1:28888, service is BootEchoServer, namespace is default
可以通过 curl 命令查询服务端是否有该实例。
curl --location --request POST '127.0.0.1:8090/v1/Discover' \
--header 'Content-Type: application/json' \
--data-raw '{
"type": 1,
"service": {
"name": "BootEchoServer",
"namespace": "default"
}
}'
3.3.3 - 服务发现
引入 Spring Cloud Tencent
如果您当前的 Spring Boot 应用还未引入任何 Spring Cloud 依赖,可以将 Spring Boot 调整为 Spring Cloud 项目,使用 Spring Cloud Tencent 中的服务发现能力。
参考文档:Spring Cloud 应用接入
使用 Spring Boot Polaris Feign
初始化项目
使用 jetbrain idea 等工具初始化一个 maven 项目
引入依赖
在上一步初始化好一个 maven 项目之后,我们在 pom.xml 中引入 Spring Boot Polaris 相关依赖。
- 引入 spring-boot-polaris-dependencies 进行管理 Spring Boot Polaris 相关组件的依赖版本。
- 引入 spring-boot-polaris-discovery-starter 实现发现北极星中的服务并进行远程调用。
<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 https://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<parent>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-parent</artifactId>
<version>2.4.3</version>
<relativePath/> <!-- lookup parent from repository -->
</parent>
...
<dependencyManagement>
<dependencies>
<dependency>
<groupId>com.tencent.polaris</groupId>
<artifactId>spring-boot-polaris-dependencies</artifactId>
<version>1.1.0</version>
<type>pom</type>
<scope>import</scope>
</dependency>
</dependencies>
</dependencyManagement>
<dependencies>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
<!-- 引入 Spring Boot Polaris Discovery 依赖用于实现服务注册 -->
<dependency>
<groupId>com.tencent.polaris</groupId>
<artifactId>spring-boot-polaris-discovery-starter</artifactId>
</dependency>
</dependencies>
...
</project>
配置 application.properties
在 resources 目录下创建 application.properties 文件,并按照如下进行配置
.
├── java
│ └── com
│ └── example
│ └── springbootpolarisconsumer
│ └── SpringbootConsumerApplication.java
└── resources
└── application.properties
server.port=38888
spring.application.name=BootEchoConsumer
polaris.address=grpc://127.0.0.1:8091
polaris.discovery.register.enable=true
示例代码
@SpringBootApplication
public class SpringbootconsumerApplication {
public static void main(String[] args) {
SpringApplication.run(SpringbootconsumerApplication.class, args);
}
@RestController
static class EchoController {
private final PolarisFeignBuilder targetBuilder;
EchoController(PolarisFeignBuilder targetBuilder) {
this.targetBuilder = targetBuilder;
}
@GetMapping(value = "/echo")
public String echo(@RequestParam(name = "value") String val) {
EchoServer echoServerBoot = Feign.builder().decoder(new StringDecoder())
.addCapability(targetBuilder.buildCircuitBreakCapability())
.target(targetBuilder.buildTarget(EchoServer.class,
PolarisFeignOptions.build().withService("BootEchoServer")));
return echoServerBoot.echo(val);
}
}
public interface EchoServer {
@RequestLine("GET /echo/{value}")
String echo(@Param("value") String value);
}
}
验证
通过 curl 命令对服务消费者发起调用。
curl --location --request GET '127.0.0.1:38888/echo?value=hello'
预期的结果如下
Hello PolarisMesh hello, I'm BootEchoServer
3.4 - 使用 Dubbo
3.4.1 - 服务注册
Dubbo 分类
Dubbo当前常用的有2个分支版本,一个是apache dubbo(GroupID是org.apache.dubbo), 一个是dubbox (GroupID是com.alibaba)。两个分支的dubbo,对应不同的接入插件,大家接入之前可以先通过GroupID判断下当前项目依赖的是哪个分支的dubbo。
Apache Dubbo 接入
支持版本
- dubbo 2.x 版本的接入,最新版本为
0.2.2 - dubbo 3.x 版本的接入,最新版本请参考: release
引入依赖
<p class="notice-title">
<span class="icon-notice baseline">
<svg xmlns="http://www.w3.org/2000/svg" viewBox="300.5 134 300 300">
</span>提示</p><p>Dubbo 应用级注册发现 仅适用于北极星服务端版本 >= 1.18.0</p></div>
在 pom.xml 中引入以下依赖
<!-- 北极星注册发现插件 -->
<dependency>
<groupId>com.tencent.polaris</groupId>
<artifactId>dubbo-registry-polaris</artifactId>
<version>${version}</version>
</dependency>
<!-- 北极星元数据中心插件 -->
<dependency>
<groupId>com.tencent.polaris</groupId>
<artifactId>dubbo-metadatareport-polaris</artifactId>
<version>${revision}</version>
</dependency>
在 pom.xml 中引入以下依赖
<!-- 北极星注册发现插件 -->
<dependency>
<groupId>com.tencent.polaris</groupId>
<artifactId>dubbo-registry-polaris</artifactId>
<version>${version}</version>
</dependency>
参数配置
接下来,需要添加北极星registry的配置,指定北极星的地址及相关配置信息,可以通过配置文件及代码的方式进行指定:
配置文件方式添加:
dubbo.registry.address=polaris://127.0.0.1:8091
dubbo.metadata-report.address=polaris://127.0.0.1:8091
dubbo.registry.address=polaris://127.0.0.1:8091
北极星地址的URL支持通过参数指定可选的配置,具体参数列表如下:
| 参数 | 类型 | 含义 |
|---|---|---|
| namespace | string | 指定服务的命名空间 |
| token | string | 指定用户token |
| persist_enable | bool | 设置是否开启客户端本地文件容灾缓存 |
| stat_type | string | 设置监控数据上报方式, pull 或者 push |
| stat_pull_port | int | stat_type == pull 时,设置 SDK 额外暴露的 metrics web 端口 |
| stat_push_addr | string | stat_type == push 时,设置 pushgateway 的 IP:PORT 地址 |
| stat_push_interval | int | stat_type == push 时,设置上报周期,单位为毫秒 |
| config_port | int | 设置北极星配置中心链接端口,默认为8093 |
| discover_port | int | 设置北极星注册中心链接端口,默认为8091 |
结果验证
服务注册样例可以参考:
3.4.2 - 元数据中心
提示
Dubbo 元数据中心仅适用于北极星服务端版本 >= 1.18.0
Dubbo 分类
Dubbo当前常用的有2个分支版本,一个是apache dubbo(GroupID是org.apache.dubbo), 一个是dubbox (GroupID是com.alibaba)。两个分支的dubbo,对应不同的接入插件,大家接入之前可以先通过GroupID判断下当前项目依赖的是哪个分支的dubbo。
Apache Dubbo 接入
支持版本
- dubbo 3.x 版本的接入,最新版本请参考: release
引入依赖
在 pom.xml 中引入以下依赖
<!-- 北极星注册发现插件 -->
<dependency>
<groupId>com.tencent.polaris</groupId>
<artifactId>dubbo-registry-polaris</artifactId>
<version>${version}</version>
</dependency>
<!-- 北极星元数据中心插件 -->
<dependency>
<groupId>com.tencent.polaris</groupId>
<artifactId>dubbo-metadatareport-polaris</artifactId>
<version>${revision}</version>
</dependency>
参数配置
接下来,需要添加北极星 metadata-report 的配置,指定北极星的地址及相关配置信息,可以通过配置文件及代码的方式进行指定:
配置文件方式添加:
dubbo.metadata-report.address=polaris://127.0.0.1:8091
北极星地址的URL支持通过参数指定可选的配置,具体参数列表如下:
| 参数 | 类型 | 含义 | 支持版本 |
|---|---|---|---|
| namespace | string | 指定服务的命名空间 | 起始版本:0.1.0-3.2.7 |
| token | string | 指定用户token | 起始版本:0.1.0-3.2.7 |
| multi_address | string | 仅用于元数据中心多注册多发现, eg: nacos://127.0.0.1:8848?namespace=xxxxx&username=xxx | 起始版本:0.3.2-3.2.7 |
结果验证
服务接口定义
服务契约名称格式样例
"name": "dubbo::metadata::dubbo-provider::2e2e13eddf24272edcaa60c34afc5067",
"namespace": "dubbo",
"service": "dubbo-provider",
"protocol": "dubbo",
"version": "",
"revision": "2e2e13eddf24272edcaa60c34afc5067",
服务接口运维数据
服务契约名称格式样例
"name": "dubbo::metadata::1.0.0::provider::dubbo-provider",
"namespace": "dubbo",
"service": "dubbo-provider",
"protocol": "dubbo",
"version": "1.0.0",
"revision": "d297643d19dc4700a8c11d7fd57ef808",
接口-应用映射
服务契约名称格式样例
"name": "dubbo::mapping::com.tencent.polaris.dubbo.api.HelloService",
"namespace": "dubbo",
"service": "",
"protocol": "dubbo",
"version": "",
"revision": "f31bc6a132c84ce9afc39c1b98fdb6a7",
查询该接口下有多少应用提供了该接口
{
"@type": "type.googleapis.com/v1.ServiceContract",
"id": "535e686a7e8707b1d53e63f7578e80a2a94e4747",
"name": "dubbo::mapping::com.tencent.polaris.dubbo.api.HelloService",
"namespace": "dubbo",
"service": "",
"protocol": "dubbo",
"version": "",
"revision": "f31bc6a132c84ce9afc39c1b98fdb6a7",
"content": "",
"interfaces": [
{
"id": "6be61ef353a9e1918d5b84c100db0c8a5637f5a5",
"name": "dubbo-provider"
}
]
}
3.4.3 - 动态路由
Dubbo 分类
Dubbo当前常用的有2个分支版本,一个是apache dubbo(GroupID是org.apache.dubbo), 一个是dubbox (GroupID是com.alibaba)。两个分支的dubbo,对应不同的接入插件,大家接入之前可以先通过GroupID判断下当前项目依赖的是哪个分支的dubbo。
Apache Dubbo 接入
支持版本
- dubbo 2.x 版本的接入,最新版本为
0.2.2 - dubbo 3.x 版本的接入,最新版本请参考: release
引入依赖
首先,动态路由需要依赖以下2个插件,需要将2个插件引入POM中,插件版本建议使用最新版本。
<!-- 北极星注册发现插件 -->
<dependency>
<groupId>com.tencent.polaris</groupId>
<artifactId>dubbo-registry-polaris</artifactId>
<version>${version}<version>
</dependency>
<!-- 北极星动态路由插件 -->
<dependency>
<groupId>com.tencent.polaris</groupId>
<artifactId>dubbo-router-polaris</artifactId>
<version>${version}</version>
</dependency>
配置北极星注册中心地址
接下来,需要添加北极星 registry 的配置,指定北极星的地址及相关配置信息,可以通过配置文件及代码的方式进行指定:
配置文件方式添加:
<dubbo:registry address="polaris://127.0.0.1:8091"/>
dubbo.registry.address=polaris://127.0.0.1:8091
启用北极星的路由插件
<dubbo:reference filter="polaris_router">
dubbo.consumer.filter=polaris_router
路由规则字段
动态路由可以实现基于dubbo的请求消息内容来对请求调度到不同的实例分组,比如将带了某些user标签的请求调度到灰度分组。
当前支持针对dubbo消息的以下内容进行路由调度:
应用级注册发现
| 消息类型 | dubbo消息内容 | 路由规则请求类型 |
|---|---|---|
| 消息头 | attachment | 请求头(HEADER) |
| RPC接口 | dubbo interface 全限定名 | 路径(PATH) |
| RPC方法 | dubbo interface 下的具体某个方法的名称 | 请求匹配规则-方法(METHOD) |
| 请求体参数 | dubbo 方法入参某个字段 | 请求匹配规则-请求参数(QUERY) |
接口级注册发现
| 消息类型 | dubbo消息内容 | 路由规则请求类型 | |
|---|---|---|---|
| 消息头 | attachment | 请求头(HEADER) | |
| RPC方法 | method | 方法(METHOD) | |
| 请求体参数 | dubbo 方法入参某个字段 | 请求匹配规则-请求参数(QUERY),字段格式 |
功能验证
动态路由样例包括3个工程,代表的是多个服务之间调用,调用链路为:front->middle->back。
配置自定义路由规则,指定带有附件 user 为 polaris 的请求,路由到 env 为 gray 的实例上。
执行服务调用,调用时,需要设置一下当前请求的attachement。
// 设置attachment,指定当前用户
public String doSayHello(String name) {
RpcContext.getClientAttachment().setAttachment("user", name);
return greetingService.sayHello(name);
}
代码中无需额外添加路由判断代码,插件会自动在被调端进行请求信息进行路由。
最终路由效果
➜ ~ curl http://127.0.0.1:15700/echo\?method\=sayHi\&value\=123
[FrontService] sayHi, 123 -> [MiddleService-gray] sayHello, 123 -> [BackendService-gray] sayHello, 123%
➜ ~ curl http://127.0.0.1:15700/echo\?method\=sayHi\&value\=123
[FrontService] sayHi, 123 -> [MiddleService-gray] sayHello, 123 -> [BackendService-gray] sayHello, 123%
➜ ~ curl http://127.0.0.1:15700/echo\?method\=sayHi\&value\=123
[FrontService] sayHi, 123 -> [MiddleService-normal] sayHello, 123 -> [BackendService-normal] sayHello, 123%
➜ ~ curl http://127.0.0.1:15700/echo\?method\=sayHi\&value\=123
[FrontService] sayHi, 123 -> [MiddleService-normal] sayHello, 123 -> [BackendService-normal] sayHello, 123%
➜ ~ curl http://127.0.0.1:15700/echo\?method\=sayHi\&value\=123
[FrontService] sayHi, 123 -> [MiddleService-gray] sayHello, 123 -> [BackendService-normal] sayHello, 123%
➜ ~ curl http://127.0.0.1:15700/echo\?method\=sayHi\&value\=123
[FrontService] sayHi, 123 -> [MiddleService-gray] sayHello, 123 -> [BackendService-normal] sayHello, 123%
➜ ~ curl http://127.0.0.1:15700/echo\?method\=sayHi\&value\=123
[FrontService] sayHi, 123 -> [MiddleService-gray] sayHello, 123 -> [BackendService-gray] sayHello, 123%
➜ ~ curl http://127.0.0.1:15700/echo\?method\=sayHi\&value\=123
[FrontService] sayHi, 123 -> [MiddleService-gray] sayHello, 123 -> [BackendService-gray] sayHello, 123%
➜ ~ curl http://127.0.0.1:15700/echo\?method\=sayHi\&value\=123
[FrontService] sayHi, 123 -> [MiddleService-gray] sayHello, 123 -> [BackendService-gray] sayHello, 123%
➜ ~ curl http://127.0.0.1:15700/echo\?method\=sayHi\&value\=123
[FrontService] sayHi, 123 -> [MiddleService-normal] sayHello, 123 -> [BackendService-normal] sayHello, 123%
➜ ~ curl http://127.0.0.1:15700/echo\?method\=sayHi\&value\=123
[FrontService] sayHi, 123 -> [MiddleService-normal] sayHello, 123 -> [BackendService-normal] sayHello, 123%
➜ ~ curl http://127.0.0.1:15700/echo\?method\=sayHi\&value\=123
[FrontService] sayHi, 123 -> [MiddleService-gray] sayHello, 123 -> [BackendService-normal] sayHello, 123%
➜ ~ curl http://127.0.0.1:15700/echo\?method\=sayHi\&value\=123
[FrontService] sayHi, 123 -> [MiddleService-gray] sayHello, 123 -> [BackendService-normal] sayHello, 123%
➜ ~ curl http://127.0.0.1:15700/echo\?method\=sayHi\&value\=123
[FrontService] sayHi, 123 -> [MiddleService-gray] sayHello, 123 -> [BackendService-gray] sayHello, 123%
➜ .dubbo curl http://127.0.0.1:15700/echo\?method\=sayHi\&value\=polaris
[FrontService] sayHi, polaris -> [MiddleService-gray] sayHello, polaris -> [BackendService-gray] sayHello, polaris%
➜ .dubbo curl http://127.0.0.1:15700/echo\?method\=sayHi\&value\=polaris
[FrontService] sayHi, polaris -> [MiddleService-gray] sayHello, polaris -> [BackendService-gray] sayHello, polaris%
➜ .dubbo curl http://127.0.0.1:15700/echo\?method\=sayHi\&value\=polaris
[FrontService] sayHi, polaris -> [MiddleService-gray] sayHello, polaris -> [BackendService-gray] sayHello, polaris%
➜ .dubbo curl http://127.0.0.1:15700/echo\?method\=sayHi\&value\=polaris
[FrontService] sayHi, polaris -> [MiddleService-gray] sayHello, polaris -> [BackendService-gray] sayHello, polaris%
➜ .dubbo curl http://127.0.0.1:15700/echo\?method\=sayHi\&value\=polaris
[FrontService] sayHi, polaris -> [MiddleService-gray] sayHello, polaris -> [BackendService-gray] sayHello, polaris%
路由样例包括 3 个工程。
- front工程:dubbo-router-front
- middle工程:dubbo-router-middle
- back工程:dubbo-router-back
3.4.4 - 访问限流
Dubbo 分类
Dubbo当前常用的有2个分支版本,一个是apache dubbo(GroupID是org.apache.dubbo), 一个是dubbox (GroupID是com.alibaba)。两个分支的dubbo,对应不同的接入插件,大家接入之前可以先通过GroupID判断下当前项目依赖的是哪个分支的dubbo。
Apache Dubbo 接入
支持版本
- dubbo 2.x 版本的接入,最新版本为
0.2.2 - dubbo 3.x 版本的接入,最新版本请参考: release
引入依赖
首先,动态路由需要依赖以下2个插件,需要将2个插件引入POM中,插件版本建议使用最新版本。
<!-- 北极星注册发现插件 -->
<dependency>
<groupId>com.tencent.polaris</groupId>
<artifactId>dubbo-registry-polaris</artifactId>
<version>${version}<version>
</dependency>
<!-- 北极星限流功能插件 -->
<dependency>
<groupId>com.tencent.polaris</groupId>
<artifactId>dubbo-ratelimit-polaris</artifactId>
<version>${version}<version>
</dependency>
启用北极星访问限流插件
<dubbo:service filter="polaris_ratelimit">
dubbo.provider.filter=polaris_ratelimit
配置北极星注册中心地址
接下来,需要添加北极星 registry 的配置,指定北极星的地址及相关配置信息,可以通过配置文件及代码的方式进行指定:
配置文件方式添加:
<dubbo:registry address="polaris://127.0.0.1:8091"/>
dubbo.registry.address=polaris://127.0.0.1:8091
限流规则字段
访问限流可以实现在被调端基于dubbo的请求消息内容来对请求进行流量限制,比如将带了某些user标签的请求限制速率为100/s。
当前支持针对dubbo消息的以下内容进行流量限制:
应用级注册发现
| 消息类型 | dubbo消息内容 | 路由规则请求类型 |
|---|---|---|
| 消息头 | attachment | 请求头(HEADER) |
| RPC接口 | dubbo interface 全限定名 | 接口名称 |
| RPC方法 | dubbo interface 下的具体某个方法的名称 | 请求匹配规则-方法(METHOD) |
| 请求体参数 | dubbo 方法入参某个字段 | 请求匹配规则-请求参数(QUERY) |
接口级注册发现
| 消息类型 | dubbo消息内容 | 路由规则请求类型 | |
|---|---|---|---|
| 消息头 | attachment | 请求头(HEADER) | |
| RPC方法 | method | 方法(METHOD) | |
| 请求体参数 | dubbo 方法入参某个字段 | 请求匹配规则-请求参数(QUERY),字段格式 |
- 请求匹配规则为 请求参数(QUERY)
- 请求匹配规则为 请求头(HEADER):
- 标签来源: RPC 调用的额外标签信息,即 Invoaction.Attachments()
- 根据 Dubbo 的 dubbo.application.register-mode 字段的值,决定限流规则的读取
- instance: 仅读取 dubbo 应用级的限流规则
- interface: 仅读取 dubbo 接口级的限流规则
- all: 同时读取 dubbo 应用级、接口级的限流规则,先匹配应用级下的限流规则,后匹配接口级限流规则,只要其中有一个触发限流,Filter 返回错误
功能验证
针对 Dubbo 接口级别的限流
针对 Dubbo 接口下某个方法的限流
代码中无需额外添加限流判断代码,插件会自动在被调端进行请求的限流计算和拦截。
最终限流效果
18:21:58.748 |-ERROR [DubboServerHandler-10.21.22.75:20880-thread-8] .apache.dubbo.rpc.filter.ExceptionFilter: -|
[DUBBO] Got unchecked and undeclared exception which called by 10.21.22.75. service: com.tencent.polaris.dubbo.example.
api.GreetingService, method: sayHi, exception: org.apache.dubbo.rpc.RpcException: Failed to invoke service com.tencent.
polaris.dubbo.example.api.GreetingService.sayHi because exceed max service tps., dubbo version: 3.2.6, current host:
192.168.255.10, error code: 5-36. This may be caused by , go to https://dubbo.apache.org/faq/5/36 to find instructions.
org.apache.dubbo.rpc.RpcException: Failed to invoke service com.tencent.polaris.dubbo.example.api.GreetingService.sayHi
because exceed max service tps.
访问限流样例包括2个工程,代表的是主调端和被调端,限流行为工作在被调端。
环境变量设置
export CONFIG_CENTER_ADDR=127.0.0.1:8093
export METADATA_REPORT_ADDR=127.0.0.1:8091
export POLARIS_DISCOVERY_ADDR=127.0.0.1:8091
export REGISTER_MODE=all
export POD_IP={IP}
- consumer工程:dubbo-governance-consumer
- provider工程:dubbo-governance-provider
代码中无需额外添加限流判断代码,插件会自动在被调端进行请求的限流计算和拦截。
最终限流效果
18:21:58.748 |-ERROR [DubboServerHandler-10.21.22.75:20880-thread-8] .apache.dubbo.rpc.filter.ExceptionFilter: -|
[DUBBO] Got unchecked and undeclared exception which called by 10.21.22.75. service: com.tencent.polaris.dubbo.example.
api.GreetingService, method: sayHi, exception: org.apache.dubbo.rpc.RpcException: Failed to invoke service com.tencent.
polaris.dubbo.example.api.GreetingService.sayHi because exceed max service tps., dubbo version: 3.2.6, current host:
192.168.255.10, error code: 5-36. This may be caused by , go to https://dubbo.apache.org/faq/5/36 to find instructions.
org.apache.dubbo.rpc.RpcException: Failed to invoke service com.tencent.polaris.dubbo.example.api.GreetingService.sayHi
because exceed max service tps.
代码中无需额外添加限流判断代码,插件会自动在被调端进行请求的限流计算和拦截,假如出现限流,则会返回PolarisBlockException异常给调用端。
访问限流样例包括2个工程,代表的是主调端和被调端,限流行为工作在被调端。
- consumer工程:dubbo-ratelimit-consumer
- provider工程:dubbo-ratelimit-provider
3.4.5 - 熔断降级
Dubbo 分类
Dubbo当前常用的有2个分支版本,一个是apache dubbo(GroupID是org.apache.dubbo), 一个是dubbox (GroupID是com.alibaba)。两个分支的dubbo,对应不同的接入插件,大家接入之前可以先通过GroupID判断下当前项目依赖的是哪个分支的dubbo。
Apache Dubbo 接入
支持版本
- dubbo 2.x 版本的接入,最新版本为
0.2.2 - dubbo 3.x 版本的接入,最新版本请参考: release
引入依赖
首先,熔断降级需要依赖以下2个插件,需要将2个插件引入POM中,插件版本建议使用最新版本。
<!-- 北极星注册发现插件 -->
<dependency>
<groupId>com.tencent.polaris</groupId>
<artifactId>dubbo-registry-polaris</artifactId>
<version>${revision}<version>
</dependency>
<!-- 北极星熔断功能插件 -->
<dependency>
<groupId>com.tencent.polaris</groupId>
<artifactId>dubbo-circuitbreaker-polaris</artifactId>
<version>${revision}</version>
</dependency>
启用北极星熔断降级插件
<dubbo:reference filter="polaris_circuitbreaker">
dubbo.consumer.filter=polaris_circuitbreaker
配置北极星注册中心地址
接下来,需要添加北极星registry的配置,指定北极星的地址及相关配置信息,可以通过配置文件及代码的方式进行指定:
配置文件方式添加:
<dubbo:registry address="polaris://127.0.0.1:8091"/>
dubbo.registry.address=polaris://127.0.0.1:8091
使用服务熔断
结果验证
➜ ~ curl http://127.0.0.1:15800/echo\?method\=sayHi\&value\=123
org.apache.dubbo.rpc.RpcException: Failed to invoke the method sayHi in the service com.tencent.polaris.dubbo.example.
api.GreetingService. Tried 3 times of the providers [192.168.31.119:20880] (1/1) from the registry 127.0.0.1:8091 on
the consumer 192.168.255.10 using the dubbo version 3.2.6. Last error is: com.tencent.polaris.circuitbreak.client.
exception.CallAbortedException: ERR-1020(CLIENT_CIRCUIT_BREAKING): rule application_rule, fallbackInfo null%
使用接口熔断
结果验证
➜ ~ curl http://127.0.0.1:15800/echo\?method\=sayHi\&value\=123
org.apache.dubbo.rpc.RpcException: java.util.concurrent.ExecutionException: org.apache.dubbo.rpc.RpcException: I'm bad sayHi provider%
➜ ~ curl http://127.0.0.1:15800/echo\?method\=sayHi\&value\=123
org.apache.dubbo.rpc.RpcException: java.util.concurrent.ExecutionException: org.apache.dubbo.rpc.RpcException: I'm bad sayHi provider%
➜ ~ curl http://127.0.0.1:15800/echo\?method\=sayHi\&value\=123
circuitbreaker downgrade info%
➜ ~ curl http://127.0.0.1:15800/echo\?method\=sayHi\&value\=123
circuitbreaker downgrade info%
使用节点熔断
节点熔断可以根据RPC调用的连续错误数、失败率等统计指标,对异常节点进行剔除,保障请求只会路由到健康的节点上去。
当前支持针对RPC调用的服务名和接口进行设置熔断规则。
规则中,设置针对该服务下节点的调用,出现连续5次的失败, 则熔断该节点。
为了测试熔断效果,服务调用的时候,可以针对服务进行多次调用。
结果验证
➜ ~ curl http://127.0.0.1:15800/echo\?method\=sayHi\&value\=123
org.apache.dubbo.rpc.RpcException: java.util.concurrent.ExecutionException: org.apache.dubbo.rpc.RpcException: I'm bad sayHi provider%
➜ ~ curl http://127.0.0.1:15800/echo\?method\=sayHi\&value\=123
[provider by polaris] hi, 123, source from 2.2.2.2%
➜ ~ curl http://127.0.0.1:15800/echo\?method\=sayHi\&value\=123
[provider by polaris] hi, 123, source from 2.2.2.2%
➜ ~ curl http://127.0.0.1:15800/echo\?method\=sayHi\&value\=123
[provider by polaris] hi, 123, source from 2.2.2.2%
➜ ~ curl http://127.0.0.1:15800/echo\?method\=sayHi\&value\=123
[provider by polaris] hi, 123, source from 2.2.2.2%
➜ ~ curl http://127.0.0.1:15800/echo\?method\=sayHi\&value\=123
样例
熔断样例包括2个工程,代表的是2个服务之间调用,调用链路为:consumer->provider(ok/nok)。
provider 通过环境变量来控制是否返回回包失败,启动的时候设置环境变量 EXCEPTION=true,则该provider进程固定会返回回包异常。
可以启动2个 provider 进程,一个进程启动的时候,不设置 EXCEPTION 变量,代表正常进程;另外一个进程设置 EXCEPTION 变量,代表不正常,用于测试熔断。
环境变量设置
export CONFIG_CENTER_ADDR=127.0.0.1:8093
export METADATA_REPORT_ADDR=127.0.0.1:8091
export POLARIS_DISCOVERY_ADDR=127.0.0.1:8091
export REGISTER_MODE=all
export POD_IP={IP}
- connsumer工程:dubbo-governance-consumer
- provider工程:dubbo-governance-provider
- connsumer工程:dubbo-circuitbreak-consumer
- provider工程:dubbo-circuitbreak-provider
3.4.6 - 配置中心
提示
Dubbo 动态配置中心仅适用于北极星服务端版本 >= 1.18.0
Dubbo 分类
Dubbo当前常用的有2个分支版本,一个是apache dubbo(GroupID是org.apache.dubbo), 一个是dubbox (GroupID是com.alibaba)。两个分支的dubbo,对应不同的接入插件,大家接入之前可以先通过GroupID判断下当前项目依赖的是哪个分支的dubbo。
Apache Dubbo 接入
支持版本
- dubbo 3.x 版本的接入,最新版本请参考: release
引入依赖
在 pom.xml 中引入以下依赖
<!-- 北极星注册发现插件 -->
<dependency>
<groupId>com.tencent.polaris</groupId>
<artifactId>dubbo-registry-polaris</artifactId>
<version>${version}</version>
</dependency>
<!-- 北极星元数据中心插件 -->
<dependency>
<groupId>com.tencent.polaris</groupId>
<artifactId>dubbo-metadatareport-polaris</artifactId>
<version>${revision}</version>
</dependency>
<!-- 北极星动态配置中心插件 -->
<dependency>
<groupId>com.tencent.polaris</groupId>
<artifactId>dubbo-configcenter-polaris</artifactId>
<version>${revision}</version>
</dependency>
参数配置
接下来,需要添加北极星 registry、config-center 的配置,指定北极星的地址及相关配置信息,可以通过配置文件及代码的方式进行指定:
配置文件方式添加:
dubbo.registry.address=polaris://127.0.0.1:8091
dubbo.metadata-report.address=polaris://127.0.0.1:8091
dubbo.config-center.address=polaris://127.0.0.1:8093
北极星地址的URL支持通过参数指定可选的配置,具体参数列表如下:
| 参数 | 类型 | 含义 |
|---|---|---|
| namespace | string | 指定服务的命名空间 |
| token | string | 指定用户token |
| persist_enable | bool | 设置是否开启客户端本地文件容灾缓存 |
| stat_type | string | 设置监控数据上报方式, pull 或者 push |
| stat_pull_port | int | stat_type == pull 时,设置 SDK 额外暴露的 metrics web 端口 |
| stat_push_addr | string | stat_type == push 时,设置 pushgateway 的 IP:PORT 地址 |
| stat_push_interval | int | stat_type == push 时,设置上报周期,单位为毫秒 |
| config_port | int | 设置北极星配置中心链接端口,默认为8093 |
| discover_port | int | 设置北极星注册中心链接端口,默认为8091 |
验证
服务注册样例可以参考:dubbo-discovery-provider
这里我们已 dubbo 本身的 QOS 能力开关做一个示范, 这里我们现在北极星创建一个控制 dubbo QOS 能力的配置
- 北极星配置分组名为 dubbo application name
- dubbo 默认会给配置中心的接入地址填充 namespace 信息为 dubbo
未在配置中心发布 Dubbo 配置
我们在启动 dubbo 应用之后,可以观察到 dubbo 开启了 qos-server
12:36:50.117 |-INFO [main] org.apache.dubbo.qos.server.Server:123 -| [DUBBO] qos-server bind localhost:22222, dubbo version: 3.2.6, current host: 10.21.22.75
在配置中心发布 Dubbo 配置
我们在启动 dubbo 应用之后,可以观察到 dubbo 在启动过程中, 从北极星配置中心读取到到了 dubbo.application.qos-enable=false 配置,因此不会启动 dubbo 内置的 qos-server
15:26:03.571 |-INFO [main] he.dubbo.qos.protocol.QosProtocolWrapper:109 -| [DUBBO] qos won't be started because it is disabled.
Please check dubbo.application.qos.enable is configured either in system property, dubbo.properties or XML/spring-boot configuration., dubbo version: 3.2.6, current host: 10.21.22.75
3.5 - 使用 gRPC-Java
3.5.1 - 服务注册
引入依赖
<dependency>
<groupId>com.tencent.polaris</groupId>
<artifactId>grpc-java-polaris</artifactId>
<version>${grpc-java-polaris.version}</version>
</dependency>
初始化 polaris.yaml
你需要在项目的根路径下创建一个 polaris.yaml 文件用于 grpc-java-polaris 初始化 polaris sdk。polaris.yaml配置详细
如何使用
将原本的 ServerBuilder 替换为 PolarisGrpcServerBuilder 即可实现将 gRPC-java 服务注册到北极星中
原本 gRPC-java 的创建方式
server = ServerBuilder.forPort(port).addService(new GreeterImpl()).build().start();
使用 gRPC-java-polaris 的创建方式
Server server = PolarisGrpcServerBuilder.forPort(port).addService(new GreeterImpl()).build().start();
注册信息控制
命名空间
默认情况下,gRPC-java 注册到北极星的 default 命名空间中,如果希望注册到别的命名空间,可通过设置namespace的方式
public class GrpcServerDemo {
public static void main(String[] args) {
Server server = PolarisGrpcServerBuilder
.forPort(0)
.namespace("grpc-java-demo")
.addService(new HelloProvider(metadata))
.addService(new HiProvider())
.build();
Server server = server.start();
JvmHookHelper.addShutdownHook(() -> {
server.shutdown();
});
}
}
注册粒度
默认情况下,gRPC-java的注册粒度是按照 ServerServiceDefinition 来进行注册的,如果希望将整个 gRPC-java 进程作为一个服务进行注册的话,可通过设置 applicationName 的方式
public class GrpcServerDemo {
public static void main(String[] args) {
Server server = PolarisGrpcServerBuilder
.forPort(0)
.applicationName("grpc-java-demo")
.addService(new HelloProvider(metadata))
.addService(new HiProvider())
.build();
Server server = server.start();
JvmHookHelper.addShutdownHook(() -> {
server.shutdown();
});
}
}
实例属性设置
public class GrpcServerDemo {
public static void main(String[] args) {
Server server = PolarisGrpcServerBuilder
.forPort(0)
// 设置实例的权重信息
.weight(int)
// 设置实例的元数据信息
.metadata(Map<String, String>)
// 设置实例的版本信息
.version(String)
.addService(new HelloProvider(metadata))
.addService(new HiProvider())
.build();
Server server = server.start();
JvmHookHelper.addShutdownHook(() -> {
server.shutdown();
});
}
}
如何基于 grpc-java-polaris 完成一个服务注册的程序
3.5.2 - 服务发现
引入依赖
<dependency>
<groupId>com.tencent.polaris</groupId>
<artifactId>grpc-java-polaris</artifactId>
<version>${grpc-java-polaris.version}</version>
</dependency>
初始化 polaris.yaml
你需要在项目的根路径下创建一个 polaris.yaml 文件用于 grpc-java-polaris 初始化 polaris sdk。polaris.yaml配置详细
如何使用
方式一
SDKContext context = SDKContext.initContext();
ManagedChannel channel = ManagedChannelBuilder.forTarget(target)
.nameResolverFactory(new PolarisNameResolverProvider(context))
.usePlaintext()
.build();
方式二
ManagedChannel channel = PolarisManagedChannelBuilder.forTarget(target).usePlaintext().build();
额外参数设置
命名空间设置
默认情况下,gRPC-java只发现北极星default命名空间中的服务,如果希望发现别的命名空间下的服务,可通过设置url参数的方式
public class GrpcClientDemo {
public static void main(String[] args) {
ManagedChannel channel = PolarisManagedChannelBuilder.forTarget("polaris://grpc-java-demo?namespace=demo")
.usePlaintext()
.build();
}
}
如何基于 grpc-java-polaris 完成一个服务发现的程序
3.5.3 - 动态路由
当前支持针对 gRPC 消息的以下内容进行动态路由:
| 消息类型 | gRPC 消息内容 | 路由规则请求类型 |
|---|---|---|
| 消息头 | metadata | 请求头(HEADER) |
| gRPC方法 | method | 路径(PATH) |
引入依赖
<dependency>
<groupId>com.tencent.polaris</groupId>
<artifactId>grpc-java-polaris</artifactId>
<version>${grpc-java-polaris.version}</version>
</dependency>
初始化 polaris.yaml
你需要在项目的根路径下创建一个 polaris.yaml 文件用于 grpc-java-polaris 初始化 polaris sdk。polaris.yaml配置详细
gRPC Client 构建
// 使用 grpc-java-polaris 提供的 PolarisManagedChannelBuilder 即可
ManagedChannel channel = PolarisManagedChannelBuilder.forTarget(target).usePlaintext().build();
如何配置动态路由参数
gRPC-Java 中的 PolarisMesh Balancer 扩展点实现,能够根据用户配置的服务路由规则,自动的从当前 RPC 调用上下文以及请求信息中识别出需要参与服务路由的请求标签信息。
假定一个场景:
- 希望 uid 为 user-1 的请求,路由到 env 标签为 dev 的实例上
- 希望 uid 为 user-2 的请求,路由到 env 标签为 pre 的实例上
- 其他则路由到 env 标签为 prod 的实例上,那可以为 gRPC-Java 服务设置三条路由规则。
- 请求匹配规则为 请求头(HEADER):
- 标签来源: RPC 调用的额外标签信息,即 PickSubchannelArgs.getHeaders()
示例代码(gRPC-Java原生使用方式)
Metadata metadata = new Metadata();
headers.forEach((s, val) -> {
if (StringUtils.equals("uid", s.toLowerCase())) {
metadata.put(Key.of(s.toLowerCase(), Metadata.ASCII_STRING_MARSHALLER), val.get(0));
}
})
HelloGrpc.HelloBlockingStub helloBlockingStub = HelloGrpc.newBlockingStub(channel);
helloBlockingStub = helloBlockingStub.withInterceptors(MetadataUtils.newAttachHeadersInterceptor(metadata));
HelloPolaris.request request = HelloPolaris.request.newBuilder().setMsg(value).build();
HelloPolaris.response response = helloBlockingStub.sayHello(request);
验证
可根据 grpc-java-polaris example 开展
3.5.4 - 访问限流
当前支持针对 gRPC 消息的以下内容进行访问限流:
| 消息类型 | gRPC 消息内容 | 路由规则请求类型 |
|---|---|---|
| 消息头 | metadata | 请求头(HEADER) |
| gRPC方法 | method | 路径(PATH) |
引入依赖
<dependency>
<groupId>com.tencent.polaris</groupId>
<artifactId>grpc-java-polaris</artifactId>
<version>${grpc-java-polaris.version}</version>
</dependency>
初始化 polaris.yaml
你需要在项目的根路径下创建一个 polaris.yaml 文件用于 grpc-java-polaris 初始化 polaris sdk。polaris.yaml配置详细
gRPC Server 构建
Server polarisGrpcServer = PolarisGrpcServerBuilder
.forPort(0)
.namespace("default")
.applicationName("RateLimitServerGRPCJava")
// 注入限流的 server 拦截器
.intercept(PolarisHelper.buildRateLimitInterceptor()
.build())
.heartbeatInterval(5)
.addService(new HelloProvider())
.addService(new HiProvider())
.build();
如何配置访问限流参数
gRPC-Java 中的 PolarisMesh RateLimiter 扩展点实现,能够根据用户配置的限流规则,自动的从当前 RPC 调用上下文以及请求信息中识别出需要参与限流的请求标签信息。
比如对 gRPC-Java 中的 sayHello 方法,对 Metadata 中 uid 为 user-1 的进行限流,速率为10/s。
- 请求匹配规则为 请求头(HEADER):
- 标签来源: RPC 调用的额外标签信息,即 interceptCall(ServerCall<ReqT, RespT> call, Metadata headers, ServerCallHandler<ReqT, RespT> next)
验证
可根据 grpc-java-polaris example 开展
4 - Go 应用开发
4.1 - 使用 Go SDK
4.1.1 - 注册发现
引入依赖
go get github.com/polarismesh/polaris-go@latest
初始化 polaris.yaml
你需要在项目的根路径下创建一个 polaris.yaml 文件用于初始化 polaris-go SDK。polaris.yaml配置详细
服务注册
SDK实例构建
当初始化好 polaris.yaml 文件之后,你可以直接使用在 package github.com/polarismesh/polaris-go 下的 NewProviderAPI 方法进行构造一个 ProviderAPI SDK 实例
import (
...
"github.com/polarismesh/polaris-go"
)
func main() {
provider, err := polaris.NewProviderAPI()
}
注册请求体
// InstanceRegisterRequest 注册服务请求
type InstanceRegisterRequest struct {
// 必选,服务名
Service string
// 必选,命名空间
Namespace string
// 必选,服务监听host,支持IPv6地址
Host string
// 必选,服务实例监听port
Port int
// 可选,资源访问Token,即用户/用户组访问凭据,仅当服务端开启客户端鉴权时才需配置
ServiceToken string
// 以下字段可选,默认nil表示客户端不配置,使用服务端配置
// 服务协议
Protocol *string
// 服务权重,默认100,范围0-10000
Weight *int
// 实例提供服务版本号
Version *string
// 用户自定义metadata信息
Metadata map[string]string
// 该服务实例是否健康,默认健康
Healthy *bool
// 该服务实例是否隔离,默认不隔离
Isolate *bool
// 设置心跳健康检查ttl,单位为s,不填默认为5s,TTL的取值范围为 (0s, 60s]
// 开启了心跳健康检查,客户端必须以TTL间隔上报心跳
// 健康检查服务器3个TTL未受到心跳则将实例置为不健康
TTL *int
// Location 当前注册实例的地理位置信息,主要用于就近路由
Location *Location
// 可选,单次查询超时时间,默认直接获取全局的超时配置
// 用户总最大超时时间为(1+RetryCount) * Timeout
Timeout *time.Duration
// 可选,重试次数,默认直接获取全局的超时配置
RetryCount *int
}
发起注册请求
你在初始化完 InstanceRegisterRequest 结构体后,只需要调用 ProviderAPI.RegisterInstance 方法即可完成实例注册,并且 RegisterInstance 方法内部会自动维护实例的心跳上报。
resp, err := provider.RegisterInstance(registerRequest)
服务发现
SDK实例构建
consumer, err := polaris.NewConsumerAPI()
发现服务实例
GetAllInstances
直接返回目标服务下的所有实例,包括不健康、隔离、权重为0、被熔断的实例,也会在返回的实例列表中。
// GetAllInstancesRequest 获取所有实例的请求
type GetAllInstancesRequest struct {
// 必选,服务名
Service string
// 必选,命名空间
Namespace string
// 可选,单次查询超时时间,默认直接获取全局的超时配置
// 用户总最大超时时间为(1+RetryCount) * Timeout
Timeout *time.Duration
// 可选,重试次数,默认直接获取全局的超时配置
RetryCount *int
}
// 调用该方法执行请求
consumer.GetAllInstances()
GetInstances
每次获取一批可用服务提供者实例,该方法会执行路由流程。
该方法默认会过滤掉不健康、隔离、权重为0、被熔断的实例。
执行路由流程的条件
- 配置了 GetInstancesRequest.SourceService.Metadata 属性,会触发自定义路由流程
- 设置了 GetInstancesRequest.Metadata 属性,会触发元数据路由流程
// GetInstancesRequest 批量服务实例查询请求
type GetInstancesRequest struct {
// 必选,服务名
Service string
// 必选,命名空间
Namespace string
// 可选,元数据信息,仅用于dstMetadata路由插件的过滤
Metadata map[string]string
// 主调方服务信息,只用于路由规则匹配
SourceService *ServiceInfo
// 可选,是否跳过服务路由筛选,默认false
SkipRouteFilter bool
// 可选,单次查询超时时间,默认直接获取全局的超时配置
// 用户总最大超时时间为(1+RetryCount) * Timeout
Timeout *time.Duration
// 可选,重试次数,默认直接获取全局的超时配置
RetryCount *int
}
// 调用该方法执行请求
consumer.GetInstances()
GetOneInstance
每次仅获取一个可用服务提供者实例,该方法会依次执行路由、负载均衡流程。
该方法默认会过滤掉不健康、隔离、权重为0、被熔断的实例。
执行路由流程的条件
- 配置了 GetOneInstanceRequest.SourceService.Metadata 属性,会触发自定义路由流程
- 设置了 GetOneInstanceRequest.Metadata 属性,会触发元数据路由流程
// GetOneInstanceRequest 单个服务实例查询请求
type GetOneInstanceRequest struct {
// 必选,服务名
Service string
// 必选,命名空间
Namespace string
// 可选,元数据信息,仅用于dstMetadata路由插件的过滤
Metadata map[string]string
// 是否开启元数据匹配不到时启用自定义匹配规则,仅用于dstMetadata路由插件
EnableFailOverDefaultMeta bool
// 自定义匹配规则,仅当EnableFailOverDefaultMeta为true时生效
FailOverDefaultMeta FailOverDefaultMetaConfig
// 用户计算hash值的key
HashKey []byte
// 主调方服务信息
SourceService *ServiceInfo
// 可选,单次查询超时时间,默认直接获取全局的超时配置
// 用户总最大超时时间为(1+RetryCount) * Timeout
Timeout *time.Duration
// 可选,重试次数,默认直接获取全局的超时配置
RetryCount *int
// 可选,备份节点数
// 对于一致性hash等有状态的负载均衡方式
ReplicateCount int
// 可选,负载均衡算法
LbPolicy string
}
// 调用该方法执行请求
consumer.GetOneInstance()
如何基于 polaris-go 客户端完成一个服务发现的程序
4.1.2 - 动态路由
引入依赖
go get github.com/polarismesh/polaris-go@latest
初始化 polaris.yaml
你需要在项目的根路径下创建一个 polaris.yaml 文件用于初始化 polaris-go SDK。polaris.yaml配置详细
SDK实例构建
router, err := polaris.NewRouterAPI()
路由请求
// ProcessRoutersRequest 执行路由请求结构体
type ProcessRoutersRequest struct {
// 可选参数,设置本次路由请求期望执行的路由插件
// 当前支持的路由插件如下
// - 自定义路由:ruleBasedRouter
// - 就近路由:nearbyBasedRouter
// - 元数据路由:dstMetaRouter
Routers []string
// 可选参数,主调服务信息,你可以通过 ServiceInfo.Metadata 设置本次请求的流量标签信息
SourceService ServiceInfo
// 必选参数,待执行服务路由的实例列表
// 1. InstancesResponse, returned from ConsumerAPI.GetAllInstances.
// 2. DefaultServiceInstances, for user to construct manually.
DstInstances ServiceInstances
// 可选参数,对应路由规则中的方法($method)标签
Method string
// 可选,单次查询超时时间,默认直接获取全局的超时配置
// 用户总最大超时时间为(1+RetryCount) * Timeout
Timeout *time.Duration
// 可选,重试次数,默认直接获取全局的超时配置
RetryCount *int
}
如果当前 ProcessRoutersRequest 还不支持 AddArgument 方法,同时服务端版本 >= 1.12.0,SourceService.Metadata 对应的 key 名称如下:
- 路径: $path
- 方法: $method
- 请求头: $header.{标签键}
- 请求参数: $query.{标签键}
- 请求COOKIE: $cookie.{标签键}
- 主调IP: $caller_ip
- 自定义: {标签键}
执行服务路由
你在根据本次调用的上下文信息,初始化完成 ProcessRoutersRequest 结构体之后,只需要调用 RouterAPI.ProcessRouters 执行服务路由, 并从响应 model.InstancesResponse 获取符合本次路由条件的实例列表。
resp, err := router.ProcessRouters(routerRequest)
instances := resp.GetInstances()
如何基于 polaris-go 客户端完成一个动态路由的程序
4.1.3 - 负载均衡
引入依赖
go get github.com/polarismesh/polaris-go@latest
初始化 polaris.yaml
你需要在项目的根路径下创建一个 polaris.yaml 文件用于初始化 polaris-go SDK。polaris.yaml配置详细
SDK实例构建
router, err := polaris.NewRouterAPI()
负载均衡请求
// ProcessLoadBalanceRequest 执行负载均衡请求结构体
type ProcessLoadBalanceRequest struct {
// 必选参数,待执行负载均衡的实例列表
// 1. InstancesResponse, returned from ConsumerAPI.GetAllInstances.
// 2. DefaultServiceInstances, for user to construct manually.
DstInstances ServiceInstances
// 可选参数,负载均衡策略
// 当前支持的负载均衡策略如下
// - 权重随机: weightedRandom
// - 一致性hash环: ringHash
// - maglev hash: maglev
// - 普通hash: hash
LbPolicy string
// 可选参数,对于有状态的负载均衡方式,用户可以设置用于 hash 计算的 Key
HashKey []byte
}
执行负载均衡
你在你在使用 ConsumerAPI.getAllInstances 或者 ConsumerAPI.getInstances 获取到服务实例列表后,完成 ProcessLoadBalanceRequest 初始化,只需要调用 RouterAPI.ProcessLoadBalance 执行服务路由即可
resp, err := router.ProcessLoadBalance(loadbalanceRequest)
instance := resp.GetInstance()
如何基于 polaris-go 客户端完成一个负载均衡的程序
4.1.4 - 熔断降级
引入依赖
go get github.com/polarismesh/polaris-go@latest
初始化 polaris.yaml
你需要在项目的根路径下创建一个 polaris.yaml 文件用于初始化 polaris-go SDK。polaris.yaml配置详细
SDK实例构建
当初始化好 polaris.yaml 文件之后,你可以直接使用在 package github.com/polarismesh/polaris-go 下的 NewCircuitBreakerAPI 方法进行构造一个 CircuitBreakerAPI SDK 实例
import (
...
"github.com/polarismesh/polaris-go"
)
func main() {
circuitbreakerAPI, err := polaris.NewCircuitBreakerAPI()
}
熔断整个服务
配置熔断规则
配置服务熔断规则,针对 default 命名空间下所有的服务,对于时延大于 500 毫秒,或者返回码为 500 的请求,标识为错误请求,一旦一分钟内错误率30%及以上或连续错误数在5个以上,则对服务进行熔断。
使用SDK进行熔断判断
方法说明
北极星 Go SDK 提供以下熔断相关的方法,所有的方法都在CircuitBreakAPI接口中提供。
- Check: 检查资源是否可被调用,并对资源获取调用申请。对于半开的资源,如果半开的调用配额申请成功,返回true,否则返回false。
- Report: 该方法供用户在资源调用完成后,上报调用的结果,包括返回码、时延等信息,供熔断逻辑判断。
- MakeFunctionDecorator: 创建一个函数调用装饰器
model.DecoratorFunction,装饰器可以对 Go 的函数接口进行装饰。具体的定义如下
// @param ctx: 当前调用上下文信息
// @param args: 方法入参
// @return interface{}: 用户方法实际执行的返回结果
// @return *CallAborted: 如果方法调用、服务调用被熔断, 则会返回 CallAborted 结构体指针
// @return error: 返回用户方法调用的 error 或者内部熔断执行逻辑的内部错误
type DecoratorFunction func(ctx context.Context, args interface{}) (interface{}, *CallAborted, error)
使用示例
// 创建CircuitBreakAPI实例
circuitbreakerAPI, err := polaris.NewCircuitBreakerAPI()
dealF := circuitbreakerAPI.MakeFunctionDecorator(func(ctx context.Context, args interface{}) (interface{}, error) {
// 用户业务逻辑函数
}, &api.RequestContext{
RequestContext: model.RequestContext{
Callee: &model.ServiceKey{
Namespace: "被调服务所在命名空间",
Service: "被调服务名称",
},
Caller: &model.ServiceKey{
Namespace: "主调服务所在命名空间",
Service: "主调服务名称",
},
},
})
ret, abort, err := dealF(context.Background(), endpoint)
样例地址
熔断单个接口
配置熔断规则
配置接口熔断规则,针对 default 命名空间所有服务的 /echo 接口,对于时延大于500毫秒,或者返回码为 500 的请求,标识为错误请求,一旦一分钟内错误率30%及以上或连续错误数在5个以上,则对接口进行熔断。
使用SDK进行熔断判断
熔断所使用的SDK接口及方法与服务级熔断相同,这里不再重复介绍。
使用示例
circuitbreakerAPI, err := polaris.NewCircuitBreakerAPI()
dealF := circuitbreakerAPI.MakeFunctionDecorator(func(ctx context.Context, args interface{}) (interface{}, error) {
resp, err := http.Get(fmt.Sprintf("http://%+v/echo", args))
if resp != nil {
defer resp.Body.Close()
}
if err != nil {
return nil, err
}
data, _ := ioutil.ReadAll(resp.Body)
return string(data), nil
}, &api.RequestContext{
RequestContext: model.RequestContext{
Callee: &model.ServiceKey{
Namespace: "被调服务所在命名空间",
Service: "被调服务名称",
},
Caller: &model.ServiceKey{
Namespace: "主调服务所在命名空间",
Service: "主调服务名称",
},
Method: "接口名称",
},
})
ret, abort, err := dealF(context.Background(), endpoint)
样例地址
熔断单个实例
配置熔断规则
配置实例熔断规则,针对default命名空间下所有的服务实例,对于时延大于500毫秒,或者返回码为500的请求,标识为错误请求,每个实例的错误率是单独统计的,一旦一分钟内错误率30%及以上或连续错误数在5个以上,则对被调实例(IP:PORT)进行熔断。
使用SDK进行熔断判断
当实例被熔断时,该实例会暂时不接收请求,原本路由到该实例的请求会路由到其他实例。这个过程在服务路由过程中自动完成,用户无需进行额外的熔断状态判断等操作。
执行服务路由
// model.ResourceStat 中 RetStatus 字段的取值
// RetSuccess 调用成功
RetSuccess RetStatus = "success"
// RetFail 调用失败
RetFail RetStatus = "fail"
// RetTimeout 调用超时
RetTimeout RetStatus = "timeout"
// RetFlowControl 限流
RetFlowControl RetStatus = "flow_control"
// RetReject 被熔断
RetReject RetStatus = "reject"
// RetUnknown
RetUnknown RetStatus = "unknown"
circuitbreakerAPI, err := polaris.NewCircuitBreakerAPI()
// 构造 model.InstanceResource 对象
insRes, _ := model.NewInstanceResource(&model.ServiceKey{
Namespace: "被调服务所在命名空间",
Service: "被调服务名称",
}, &model.ServiceKey{
Namespace: "主调服务所在命名空间",
Service: "主调服务名称",
}, "协议信息, 比如 http/grpc/dubbo/tcp 等等", "被调实例的 IP", {被调实例端口信息})
// 上报每次的调用结果
circuitbreakerAPI.Report(&model.ResourceStat{
Delay: time.Since(start),
RetStatus: model.RetFail, //
RetCode: "响应码, string 类型",
Resource: insRes,
})
// 获取一个服务实例进行调用
getOneRequest := &polaris.GetOneInstanceRequest{}
getOneRequest.Namespace = namespace
getOneRequest.Service = service
getOneRequest.IncludeCircuitBreakInstances = true
oneInstResp, err := svr.consumer.GetOneInstance(getOneRequest)
样例地址
4.1.5 - 访问限流
引入依赖
go get github.com/polarismesh/polaris-go@latest
初始化 polaris.yaml
你需要在项目的根路径下创建一个 polaris.yaml 文件用于初始化 polaris-go SDK。polaris.yaml配置详细
SDK实例构建
当初始化好 polaris.yaml 文件之后,你可以直接使用在 package github.com/polarismesh/polaris-go 下的 NewLimitAPI 方法进行构造一个 LimitAPI SDK 实例
import (
...
"github.com/polarismesh/polaris-go"
)
func main() {
limiter, err := polaris.NewLimitAPI()
}
请求配额
type QuotaRequest interface {
// SetNamespace 设置命名空间
SetNamespace(string)
// SetService 设置服务名
SetService(string)
// SetLabels 设置业务标签信息
// Deprecated: please use AddArgument instead
SetLabels(map[string]string)
// SetMethod set method
SetMethod(method string)
// AddArgument add the match argument
AddArgument(argument model.Argument)
// SetToken set token to acquire
SetToken(uint32)
// SetTimeout 设置单次请求超时时间
SetTimeout(timeout time.Duration)
// SetRetryCount 设置最大重试次数
SetRetryCount(retryCount int)
}
如果当前 QuotaRequest 还不支持 AddArgument 方法,同时服务端版本 >= 1.11.0,SetLabels 对应的 key 名称如下:
- 路径: $path
- 方法: $method
- 请求头: $header.{标签键}
- 请求参数: $query.{标签键}
- 主调服务: $caller_service
- 主调IP: $caller_ip
- 自定义: {标签键}
发起请求配额申请
你在接收到请求之后对 QuotaRequest 结构体完成初始化后,只需要调用 LimitAPI.GetQuota 方法即可完成本次请求配额的申请。
ret, err := limiter.GetQuota(QuotaRequest)
对于请求配额结果的结构体如下。
// QuotaFuture 实时/延时分配future
type QuotaFuture interface {
// Done 标识分配是否结束
Done() <-chan struct{}
// Get 等待一段时间后,获取分配结果,用于匀速排队
Get() *model.QuotaResponse
// GetImmediately 立刻获取分配结果,不等待
GetImmediately() *model.QuotaResponse
// Release 释放资源,仅用于并发数限流的场景
Release()
}
分布式限流使用
如果要使用分布式限流,请先确保已经部署了北极星分布式限流 server
部署完后确认北极星控制台存在服务 命名空间: Polaris, 服务名: polaris.limiter。
确认完毕后,调整 polaris.yaml 配置文件,在控制台配置分布式限流规则,SDK 仍然使用 ret, err := limiter.GetQuota(QuotaRequest) 即可。
provider:
rateLimit:
enable: true
limiterNamespace: Polaris
limiterService: polaris.limiter
如何基于 polaris-go 客户端完成一个节点限流的程序
4.1.6 - 缓存与高可用
概述
我们研发的项目在使用服务注册发现后,可以在请求过程中自动匹配到最合适的节点,并能通过服务注册中心灵活的调整访问路由规则、限流策略、熔断策略,实现灰度发布、失败熔断等复杂的业务运维场景。北极星SDK大幅减轻了业务研发的负担,使业务代码不需要直接参与服务注册中心的交互,只要调用SDK提供的基础API就可以获得最终结果,SDK能够实现上述抽象统合能力,缓存的设计和实现是基础。 使用北极星的业务研发理解SDK缓存实现机制,有助于编写更安全的代码逻辑,设计合理的高可用方案和相关配置
本文试图回答的场景问题:
- 北极星SDK产生了哪些缓存,各自有什么用
- 怎样调节和观测这些缓存的内容
- 缓存对业务高可用机制产生哪些影响
- 我们需要关注哪些缓存相关的配置项,应该在哪些场景进行调整
缓存构成
内存缓存
为什么需要内存缓存
性能
在使用服务注册发现的业务场景中,为了保障访问的目标后端地址符合预期,访问端(Consumer)每次连接被访问端(Provider)时,都需要经过基于服务注册发现的一系列查询和过滤逻辑,包括:查询当前有哪些健康的被访问端实例、经过路由策略筛选掉哪些、经过熔断策略筛选掉哪些、最终经过负载均衡策略筛选出唯一的被访问端地址
在这一系列的服务发现过程中,都需要从服务注册中心(Server)获取各类实时数据,包括:被访问端的全部实例列表、路由策略配置、熔断策略配置等。如果每次业务请求都需要经过一系列的服务信息查询,势必会大幅降低业务性能,同时对服务注册中心造成巨大压力 SDK需要提供上述信息的动态缓存能力,让业务可以直接通过内存中获取到需要的数据信息
可靠性
同样的,缓存手段也保障了在服务注册中心不可用情况下的业务连续性,详细请见 典型场景 高可用 章节
缓存哪些内容
缓存数据格式
每个SDKContex维护一个全局的sync.Map内存缓存表,各类缓存数据均保存在这个缓存表中。其中Key标识数据类型和服务名,Value为数据报文。以服务实例的缓存表内容为例:
SDK使用 sync.Map的Load()、Store()、Delete()等原子动作对缓存表进行维护
缓存类型
实例信息
- 类型:Instances
- 说明:单个服务的所有实例信息,包含所有健康或异常的实例
- 使用场景:调用GetInstances场景使用,查询所有实例
路由信息
- 类型:Routing
- 说明:单个服务的所有路由规则数据
- 使用场景:调用ProcessRouter场景使用,查询服务关联的路由规则
熔断信息
- 类型:CircuitBreaker
- 说明:单个服务的所有熔断规则信息
- 使用场景:调用GetInstances场景使用,用于判断返回的实例是否被熔断
限流信息
- 类型:RateLimiting
- 说明:单个服务的所有限流规则数据
服务信息
- 类型:Services
- 说明:根据输入的标签批量查询服务
- 使用场景:调用WatchServices/GetServices场景使用,查询所有服务信息
怎样产生和更新
SDK的Cache模块对上层模块提供Get/Load/Report等原语方法
以获取服务实例信息为例:
- 获取缓存:上层模块优先调用Get原语,Get尝试从内存缓存表中获取对应的服务数据,如果Get数据为空或以失效,则发起远程调用的Load流程
- 远程调用:上层模块调用Load会触发生成查询任务,并由任务调度队列轮询发往服务注册中心,由SDK维护的固定长连接发送和接收数据报文,详见 网络连接 。查询任务产生后,SDK就开启了针对这条服务信息的Watch流程
- Watch机制:SDK的连接模块持续监听服务注册中心的回包,并根据回包类型产生缓存数据,更新到缓存表中,Watch流程包含两个关键点:
- 差异化更新:为了避免不必要的缓存表更新,对回包revision和缓存数据revision进行对比,有差异再更新
- Watch频率:为了控制每个客户端SDK与服务注册中心的通信频率,每条任务轮询的最小间隔时长由配置
.consumer.localCache.serviceRefreshInterval确定,默认为2秒
- 更新缓存状态:上层模块通过调用Report原语更新缓存表中服务实例的熔断状态,用于下一次查询获取服务实例的熔断信息
缓存多久
请求计数:SDK的Cache模块对上层模块提供Get原语获取缓存数据,每次调用Get获取缓存表中的一条数据后,就会对应更新这条数据的最后访问时间(lastVisitTime)
缓存GC:为了避免缓存表占用空间越来越大,查询任务队列越来越多,SDK设计支持缓存的GC机制。通过配置 .consumer.localCache.serviceExpireTime(默认24小时)定义过期时长,当一条缓存数据大于过期时长没有被访问后,将会被从缓存表中删除,并会连带删除这条缓存数据对应的同步任务和持久化文件缓存。缓存数据被GC后,意味着对应服务的Watch流程也终结,将由下一次Get查询获取结果为空时重新发起Watch和缓存
判断缓存是否过期的公式可简化为:
time.Now() - lastVisitime > serviceExpiretime
持久化缓存
为什么需要持久化缓存
可靠性
服务注册中心故障后,业务依靠内存缓存表可以继续对其他服务寻址,但是如果业务碰巧也重启了,内存缓存表就会丢失,这时就需要文件缓存来顶上
可维护性
通常业务研发对SDK产生的数据会经过再加工使用,文件缓存增加了服务发现数据的可视性,我们可以通过观测缓存文件来分析SDK的内存数据内容,进而在遇到服务发现数据不准时,方便判断问题的归属区域
存在哪里
由配置项 .consumer.localCache.persistDir 确定,默认为 ./polaris/backup
什么格式
以服务default/demo的实例缓存和路由缓存数据为例:
- 文件名称:svc#$命名空间$服务名$数据类型.json
- 文件内容:数据类型返回的请求报文
读写机制
读取
服务启动时由配置项 .consumer.localCache.startUseFileCache (默认false)决定是否由持久化缓存产生内存缓存表,如果持久化缓存被读取到内存缓存表中,由配置项.consumer.localCache.persistAvailableInterval(默认5分钟)决定这份数据是否有效,文件缓存在内存缓存表中的有效范围可简化表示为:
startUseFileCache && (time.Now() - file.ModTime() < persistAvailableInterval)
更新 当内存缓存Watch流程判定缓存发生新增、更新或删除时,均会发起持久化缓存更新调度任务,调度任务每100毫秒轮询一次,对待执行的任务进行持久化操作,既写入到文件
删除 当内存缓存表被GC时,对应的持久化缓存文件同时也会被删除
典型场景
高可用
故障场景
1.注册中心故障
服务注册中心发生故障时,SDK缓存使业务能够继续保持通信和路由选择,直到缓存失效
2.访问端与注册中心网络断开
对于访问端服务A,与服务注册中心发生故障效果相同,SDK缓存使业务能够继续保持通信和路由选择,直到缓存失效
3.被访问端与注册中心网络断开
被访问端服务B与注册中心连接断开时,因为B无法向注册中心更新心跳信息,访问端服务A获取到服务B的所有实例均为下线状态。SDK会执行默认的兜底路由逻辑,认为所有的服务实例均为健康状态,不影响服务A向服务B访问
4.上述故障场景+服务A重启
服务A配置开启文件缓存并且允许初始化读取时,重启后会读取持久化缓存到内存缓存表中,这样业务能够继续保持与服务B的通信和路由选择
边界条件
上述故障场景生效期间,当以下条件同时触发时,缓存机制无法保障业务的通信或路由选择符合预期
1.被访端服务实例下线
被访问端B的服务实例下线后,因为服务A内的缓存无法通过Watch注册中心动态更新,A有可能继续访问到异常的服务实例
2.访问端缓存过期
访问端缓存过期后(具体触发条件参考 缓存构成 章节),因为前述故障条件,服务A不再能够重新生成缓存,A访问B必现失败
可用性矩阵
| 注册中心故障 | 访问端与注册中心断连 | 被访端与注册中心断连 | 访问端重启 | 被访端实例下线 | 被访端缓存失效 | 访问端业务是否可用 |
|---|---|---|---|---|---|---|
| N | N | Y | N | N | N | 可用 |
| N | Y | N | N | N | N | 可用 |
| Y | Y | Y | N | N | N | 可用 |
| Y | Y | Y | Y | N | N | 可用 |
| Y | Y | Y | Y | Y | N | 部分可用 |
| Y | Y | Y | Y | Y | Y | 不可用 |
多Context用法
因为部分历史原因,业务研发有在同一个进程内开启多个SDKContext的用法,每个SDKContext实例会产生独立的长连接与服务注册中心交互,并各自维护独立的内存缓存表,但默认共享使用同一份持久化缓存
这种用法可能导致缓存同步异常和问题排查的困难,强烈建议改为单个业务进程使用全局共享一个SDKContext。如果由于特殊原因无法改造,需要对使用方式做如下约束:
// 初始化配置X
cfgX := config.NewDefaultConfigurationWithDomain()
// 开启文件缓存、设置独立的文件缓存路径
cfgX.GetConsumer().GetLocalCache().SetPersistDir("./polaris/ctx-x/backup")
cfgX.GetConsumer().GetLocalCache().SetPersistEnable(true)
// 使用指定的配置初始化SDKContextX
sdkCtxFoo, _ := polaris.NewSDKContextByConfig(cfgX)
// 初始化配置Y
cfgY := config.NewDefaultConfigurationWithDomain()
// 开启文件缓存、设置独立的文件缓存路径
cfgY.GetConsumer().GetLocalCache().SetPersistDir("./polaris/ctx-y/backup")
cfgY.GetConsumer().GetLocalCache().SetPersistEnable(true)
// 使用指定的配置初始化SDKContextY
sdkCtxY, _ := polaris.NewSDKContextByConfig(cfgY)
配置汇总
- 配置项:
consumer.localCache.serviceExpireTime - 说明:内存缓存过期时间
- 默认值:24小时
- 配置项:
consumer.localCache.serviceRefreshInterval - 说明:内存缓存任务最小发送间隔
- 默认值:2秒
- 配置项:
consumer.localCache.persitEnable - 说明:是否开启持久化缓存
- 默认值:true
- 配置项:
consumer.localCache.persistDir - 说明:持久化缓存存放路径
- 默认值:./polaris/config
- 配置项:
consumer.localCache.startUseFileCache - 说明:启动读取持久化缓存初始化内存缓存表
- 默认值:false
- 配置项:
consumer.localCache.persistAvailableInterval - 说明:启动读取持久化缓存数据有效时间
- 默认值:60秒
4.1.7 - 网络连接
概述
北极星go sdk做为业务层代码调用北极星服务能力的中间层,为业务层抽象了服务、配置、限流相关的接口能力,使业务层不需要感知和管理与北极星服务端的连接。本文介绍北极星go sdk网络连接管理的内部实现机制和相关配置项,为业务研发和运维优化提供参考。
本文试图回答的场景问题:
- 北极星SDK与北极星服务端有哪些连接
- 这些连接断开或超时异常时,会触发什么问题和现象
- 我们需要关注哪些连接相关的配置项,应该在哪些场景进行调整
连接分类
服务连接(Register)
服务注册反注册、路由规则、负载均衡、熔断、健康检查等业务能力使用服务连接
连接地址
配置项 global.serverConnector.address
连接分类
长连接
- 客户端调用服务发现(Disover)接口发起长连接,并周期性发起针对某项数据的监听任务;当超过配置项
consumer.localCache.serviceExpireTime(默认24小时)后没有访问该项数据,则停止该周期性监听任务;当长连接中没有任何监听任务,超过global.serverConnector.connectionIdleTimeout(默认3s)时长没有访问流量后,长连接会断开,由下一次查询重新发起;
短链接
- 非周期性:服务注册(Register)/反注册(DeRegister)发起,调用结束后关闭
- 周期性:上报客户端(ReportClient)接口定时向服务端上报客户端信息,上报动作发起的定时周期由
global.api.reportInterval(默认2分钟) 配置项规定,;每个SDKContext运行一个周期性上报客户端协程,通常使用场景下每个业务客户端运行一个全局SDKContext - 周期性:服务注册后,需要周期性向Server端发起心跳(HeartBeat),更新Server端记录的服务实例的心跳时间;心跳动作会发起短链接,更新完成后关闭;心跳动作发起的周期为服务注册参数中的TTL时间,默认为5秒
配置连接(Configuration)
客户端对配置文件、配置分组相关的操作使用配置连接
连接地址
配置项 config.configConnector.address
连接分类
短连接
- 非周期性:客户端对配置的增删改成接口均会发起短链接,在接口操作完成后关闭
限流连接(RateLimiter)
客户端对限流接口的调用使用限流连接
连接地址
配置项 provider.rateLimit.limiterNamespace(默认为Polaris) 和 provider.rateLimit.limiterService(默认为polaris.limiter) 注册的后端服务
连接分类
长连接
- 客户端调用限流接口(GetQuota)查询发起长连接,超过配置项
provider.rateLimit.purgeInterval(默认1分钟)时长没有调用访问Quota数据时,会发起闲置检查;闲置连接检查超过global.serverConnector.connectionIdleTimeout(默认3秒)时长没有访问流量后,长连接会断开,由下一次查询重新发起
监控连接(StatReporter)
客户端上报服务调用结果相关的监控数据
连接地址
配置项 global.statReporter.plugin.prometheus.address
连接分类
短连接
- 周期性:客户端启动后,定时间隔上报服务调用、路由、限流结果等监控数据。
连接信息汇总
相关配置汇总
配置项:global.serverConnector.connectTimeout
说明:服务客户端连接服务端同步请求超时时间
默认值:500毫秒
配置项:global.serverConnector.messageTimeout
说明:服务客户端接受服务端异步消息超时时间
默认值:1500毫秒
配置项:global.serverConnector.connectionIdelTimeout
说明:服务连接闲置连接超时时间
默认值:3秒
配置项:global.serverConnector.reconnectInterval
说明:服务客户端重连时间间隔
默认值:500毫秒
配置项:global.api.reportInterval
说明:客户端定时上报周期
默认值:2分钟
配置项:consumer.localCache.serviceExpireTime
说明:客户端缓存失效时间
默认值:24小时
配置项:config.configConnector.connectTimeout
说明:配置客户端连接服务端同步请求超时时间
默认值:500毫秒
配置项:config.configConnector.messageTimeout
说明:配置客户端接受服务端异步消息超时时间
默认值:1500毫秒
配置项:config.configConnector.connectionIdelTimeout
说明:配置连接闲置连接超时时间
默认值:3秒
配置项:config.configConnector.reconnectInterval
说明:配置客户端重连时间间隔
默认值:500毫秒
配置项:provider.ratelimit.purgeInterval
说明:限流查询任务超时检查周期
默认值:1分钟
配置项:global.statReporter.plugin.prometheus.interval
说明:监控数据定时上报周期
默认值:1分钟
业务场景Q&A
Q:北极星SDK与北极星服务端有哪些连接
A:正常业务运行情况下,1个服务发现长连接 + 1个限流长连接 + 若干实时打开关闭的短连接,例如:注册一个服务,TTL设置为2秒,操作系统默认TCP MSL 30秒(net.ipv4.tcp_fin_timeout=60) ,则通过 netstat -ano |grep 8091 预期看到 2 个 ESTABLISHED 状态连接 和 30个左右 TIMEOUT 状态连接
Q:这些连接断开或超时异常时,会触发什么问题和现象
A:重点关注:服务发现长连接异常断开后,调用SDK负载均衡、路由等接口不受影响,临时使用缓存数据,直到serviceExpireTime触发缓存数据失效或连接恢复;限流长连接断开后,调用SDK限流接口不受影响,临时退化到单机限流能力直到连接恢复
Q:我们需要关注哪些连接相关的配置项,应该在哪些场景进行调整
A:当客户端与服务端网络条件不稳定时,应适度调整增加以下参数提高容错性:
consumer.localCache.serviceExpireTime (服务发现连接断开后缓存可用时间)
global.serverConnector.connectTimeout (服务发现同步gRPC请求超时时间)
global.serverConnector.messageTimeout (服务发现异步gRPC请求回包超时时间)
config.configConnector.connectTimeout (配置同步gRPC请求超时时间)
config.configConnector.messageTimeout (配置异步gRPC请求回包超时时间)
4.1.8 - 配置管理
引入依赖
go get github.com/polarismesh/polaris-go@latest
初始化 polaris.yaml
你需要在项目的根路径下创建一个 polaris.yaml 文件用于初始化 polaris-go SDK。polaris.yaml配置详细
SDK实例构建
当初始化好 polaris.yaml 文件之后,你可以直接使用在 package github.com/polarismesh/polaris-go 下的 NewConfigAPI 方法进行构造一个 ConfigAPI SDK 实例
import (
...
"github.com/polarismesh/polaris-go"
)
func main() {
configAPI, err := polaris.NewConfigAPI()
}
获取配置文件
// namespace: 命名空间
// fileGroup: 配置分组名称
// fileName: 配置文件名称
GetConfigFile(namespace, fileGroup, fileName string) (model.ConfigFile, error)
对配置文件发起监听
func changeListener(event model.ConfigFileChangeEvent) {
}
func main() {
configFile, err := configAPI.GetConfigFile(namespace, fileGroup, fileName)
configFile.AddChangeListener(changeListener)
}
查询加密配置
需要更新 polaris-go 的版本至 v1.5.0 及以上
// namespace: 命名空间
// fileGroup: 配置分组名称
// fileName: 配置文件名称
GetConfigFile(namespace, fileGroup, fileName string) (model.ConfigFile, error)
调整 polaris.yaml 配置文件
# 配置中心默认配置
config:
# 配置过滤器
configFilter:
enable: true
chain:
# 启用配置解密插件
- crypto
plugin:
crypto:
# 配置解密插件的算法插件类型
entries:
- name: AES
监听配置分组下的已发布文件列表变化
需要更新 polaris-go 的版本至 v1.5.6 及以上版本
// namespace: 命名空间
// group: 配置分组名称
GetConfigGroup(namesapce, group string) (model.ConfigFileGroup, error)
获取到目标配置分组后, 调用配置分组的 AddChangeListener 方法监听改配置分组下已发布配置文件列表的变化
group.AddChangeListener(func(event *model.ConfigGroupChangeEvent) {
before, _ := json.Marshal(event.Before)
after, _ := json.Marshal(event.After)
log.Printf("receive config_group change event\nbefore: %s\nafter: %s", string(before), string(after))
})
model.ConfigGroupChangeEvent 结构体的具体信息
type SimpleConfigFile struct {
// 配置文件命名空间
Namespace string
// 配置文件所在分组名称
FileGroup string
// 配置文件名称
FileName string
// 配置文件的发布版本号,由服务端
Version uint64
Md5 string
ReleaseTime time.Time
}
// ConfigGroupChangeEvent 配置文件变更事件
type ConfigGroupChangeEvent struct {
// Before 该配置分组之前所有已发布的配置文件列表信息
Before []*SimpleConfigFile
// After 该配置分组当前已发布的所有配置文件列表信息
After []*SimpleConfigFile
}
相关示例工程代码
4.1.9 - 可观测性
引入依赖
go get github.com/polarismesh/polaris-go@latest
通过配置文件 polaris.yaml 开启监控上报
- 你需要在项目的根路径下创建一个 polaris.yaml 文件用于初始化 polaris-go SDK。polaris.yaml配置详细
通过 prometheus pull 模式上报监控数据
#描述:全局配置项
global:
#统计上报设置
statReporter:
#描述:是否将统计信息上报至monitor
#类型:bool
enable: true
#描述:启用的统计上报插件类型
#类型:list
#范围:已经注册的统计上报插件的名字
chain:
- prometheus
plugin:
prometheus:
type: pull
#描述: 设置 prometheus http-server 的监听IP
#类型:string
#默认使用SDK的绑定IP
metricHost:
#描述: 设置 prometheus http-server 的监听端口
#类型:int
#默认值: 28080
#如果设置为负数,则不会开启默认的http-server
#如果设置为0,则随机选择一个可用端口进行启动 http-server
metricPort: 28080
通过 pushgateway push 模式上报监控数据
#描述:全局配置项
global:
#统计上报设置
statReporter:
#描述:是否将统计信息上报至monitor
#类型:bool
enable: true
#描述:启用的统计上报插件类型
#类型:list
#范围:已经注册的统计上报插件的名字
chain:
- prometheus
plugin:
prometheus:
type: push
#描述: 设置 pushgateway 的地址, 仅 type == push 时生效
#类型:string
#默认 ${global.serverConnector.addresses[0]}:9091
address: 127.0.0.1:9091
#描述:设置metric数据推送到pushgateway的执行周期, 仅 type == push 时生效
#类型:string
#格式:^\d+(ms|s|m|h)$
#范围:[1m:...]
#默认值:10m
interval: 10s
通过代码开启监控上报
通过 prometheus pull 模式上报监控数据
cfg := config.NewDefaultConfiguration([]string{"127.0.0.1:8091"})
cfg.GetGlobal().GetStatReporter().SetEnable(true)
cfg.GetGlobal().GetStatReporter().SetChain([]string{"prometheus"})
cfg.GetGlobal().GetStatReporter().SetPluginConfig("prometheus", &prometheus.Config{
Type: "pull",
PortStr: "28080",
IP: "",
})
通过 pushgateway push 模式上报监控数据
cfg := config.NewDefaultConfiguration([]string{"127.0.0.1:8091"})
cfg.GetGlobal().GetStatReporter().SetEnable(true)
cfg.GetGlobal().GetStatReporter().SetChain([]string{"prometheus"})
cfg.GetGlobal().GetStatReporter().SetPluginConfig("prometheus", &prometheus.Config{
Type: "push",
Interval: 10 * time.Second,
Address: "",
})
SDK实例构建
使用在 package github.com/polarismesh/polaris-go 下的 NewConsumerAPI 方法进行构造一个 ConsumerAPI SDK 实例
import (
...
"github.com/polarismesh/polaris-go"
)
func main() {
consumer, err := polaris.NewConsumerAPI()
}
上报调用情况
type ServiceCallResult struct {
// 上报的服务实例
CalledInstance Instance
// 调用接口方法
Method string
// 必选,本地服务调用的状态,正常or异常
RetStatus RetStatus
// 必选,本地服务调用的返回码
RetCode *int32
// 必选,被调服务实例获取接口的最大时延
Delay *time.Duration
// 可选,主调服务实例的服务信息
SourceService *ServiceInfo
}
上报请求调用结果
你在根据请求调用情况对 ServiceCallResult 结构体完成初始化后,只需要调用 ConsumerAPI.UpdateServiceCallResult 方法即可完成请求调用结果上报。SDK 内部会根据上报的调用结果信息,将其转换为相应的流量调用指标数据,上报至 prometheus。
consumer.UpdateServiceCallResult(ServiceCallResult)
4.1.10 - 二次寻址
引入依赖
go get github.com/polarismesh/polaris-go@latest
初始化 polaris.yaml
你需要在项目的根路径下创建一个 polaris.yaml 文件用于初始化 polaris-go SDK。polaris.yaml配置详细
修改 polaris.yaml 开启二次寻址
#描述:全局配置项
global:
#描述系统相关配置
system:
#服务发现集群
discoverCluster:
namespace: Polaris
service: polaris.discover
#可选:服务刷新间隔
refreshInterval: 10m
#健康检查集群
healthCheckCluster:
namespace: Polaris
service: polaris.healthcheck
#可选:服务刷新间隔
refreshInterval: 10m
4.2 - 使用 dubbogo
4.2.1 - 服务注册
在 dubbogo 中快速体验北极星的服务注册以及服务发现能力
环境准备
参考 dubbogo 官网文档
dubbogo.yaml 配置文件
dubbo:
registries:
polaris-1:
protocol: polaris
address: ${北极星服务端IP}:8091
namespace: ${北极星命名空间信息}
token: ${北极星资源鉴权 token} # 如果北极星服务端开启了针对客户端的鉴权,则需要配置该参数
示例代码(dubbogo 原生使用方式)
当前 PolarisMesh 已实现了 dubbogo 的注册发现扩展点,因此你只需要调整你的 dubbogo.yaml 文件中的 registries 配置项,新增 protocol 为 polaris 的注册中心配置即可,可以参考下面的样例。
func init() {
config.SetProviderService(&UserProvider{})
hessian.RegisterPOJO(&User{})
}
type UserProvider struct {}
func (u *UserProvider) GetUser(ctx context.Context, req *User) (*User, error) {
rsp := User{"A001", "Alex Stocks", 18, time.Now()}
return &rsp, nil
}
func main() {
if err := config.Load(); err != nil {
panic(err)
}
initSignal()
}
验证
可根据 dubbogo example 开展
4.2.2 - 服务发现
在 dubbogo 中快速体验北极星的服务发现能力
环境准备
参考 dubbogo 官网文档
dubbogo.yaml 配置文件
dubbo:
registries:
polaris-1:
protocol: polaris
address: ${北极星服务端IP}:8091
namespace: ${北极星命名空间信息}
token: ${北极星资源鉴权 token} # 如果北极星服务端开启了针对客户端的鉴权,则需要配置该参数
示例代码(dubbogo 原生使用方式)
dubbogo 在进行服务调用时,会先通过 Polaris Registry 的 Extension 获取到服务的实例列表,然后转换为 dubbogo invoker,最终完成 dubbogo 服务调用。
当前 Polaris 已实现了 dubbogo 原生的服务发现扩展点,因此原本的 dubbogo 服务调用无需调整业务代码,仅需要在 dubbogo.yaml 中新增 protocol 为 polaris 的注册中心配置即可。
func main() {
var userProvider = &UserProvider{}
config.SetConsumerService(userProvider)
hessian.RegisterPOJO(&User{})
if err := config.Load(); err != nil {
panic(err)
}
user, err := userProvider.GetUser(context.TODO(), &User{Name: "Alex001"})
if err != nil {
panic(err)
}
logger.Infof("response result: %v\n", user)
}
验证
可根据 dubbogo example 开展
4.2.3 - 动态路由
当前支持针对 dubbogo 消息的以下内容进行动态路由:
| 消息类型 | dubbo消息内容 | 路由规则请求类型 |
|---|---|---|
| 消息头 | attachment | 请求头(HEADER) |
| RPC方法 | method | 路径(PATH) |
环境准备
参考 dubbogo 官网文档
dubbogo.yaml 配置文件
dubbo:
registries:
polaris-1:
protocol: polaris
address: ${北极星服务端IP}:8091
namespace: ${北极星命名空间信息}
token: ${北极星资源鉴权 token} # 如果北极星服务端开启了针对客户端的鉴权,则需要配置该参数
- 在使用动态路由能力时,需要先启用 Polaris 在 dubbogo 中的注册发现功能。
如何配置服务路由参数
dubbogo 中的 PolarisMesh PriorityRouter 扩展点实现,能够根据用户配置的服务路由规则,自动的从当前 RPC 调用上下文以及请求信息中识别出需要参与服务路由的请求标签信息。
假定一个场景:
- 希望 uid 为 user-1 的请求,路由到 environment 标签为 pre 的实例上
- 希望 uid 为 user-2 的请求,路由到 environment 标签为 dev 的实例上
- 其他则路由到 environment 标签为 prod 的实例上,那可以为 dubbogo 服务设置三条路由规则。
- 请求匹配规则为 请求参数(QUERY)
- 请求匹配规则为 请求头(HEADER):
- 标签来源: RPC 调用的额外标签信息,即 Invoaction.Attachments()
示例代码(dubbogo 原生使用方式)
func (s *Service) GetUser(uid string) {
atta := make(map[string]interface{})
atta["uid"] = uid
// 通过这种方式往 attachement 传入路由条件
reqContext := context.WithValue(context.Background(), constant.DubboCtxKey("attachment"), atta)
for i := 0; i < 5; i++ {
time.Sleep(200 * time.Millisecond)
user, err := userProvider.GetUser(reqContext, &User{Name: "Alex001"})
if err != nil {
logger.Errorf("error: %v\n", err)
}
logger.Infof("response: %v\n", user)
}
}
验证
可根据 dubbogo example 开展
4.2.4 - 访问限流
当前支持针对 dubbogo 消息的以下内容进行访问限流:
| 消息类型 | dubbo消息内容 | 路由规则请求类型 |
|---|---|---|
| 消息头 | attachment | 请求头(HEADER) |
| RPC方法 | method | 路径(PATH) |
环境准备
参考 dubbogo 官网文档
dubbogo.yaml 配置文件
在 dubbogo 中启用 Polaris 的 TpsLimiter,具体开启配置参考如下
dubbo:
registries:
polaris-1:
protocol: polaris
address: ${北极星服务端IP}:8091
namespace: ${北极星命名空间信息}
token: ${北极星资源鉴权 token} # 如果北极星服务端开启了针对客户端的鉴权,则需要配置该参数
provider:
services:
UserProvider:
interface: org.apache.dubbo.UserProvider.Test
tps.limiter: polaris-limit # 配置 tps.limiter 为 polaris-limiter 即可
- Polaris 的访问限流能力是工作在 Provider 侧的。
- 在使用访问限流能力时,需要先启用 Polaris 在 dubbogo 中的注册发现功能。
如何配置服务限流参数
dubbogo 中的 PolarisMesh TpsLimiter 扩展点实现,能够根据用户配置的限流规则,自动的从当前 RPC 调用上下文以及请求信息中识别出需要参与限流的请求标签信息。
比如对 dubbogo 中的 GetUser 方法,对请求参数 Name 为 Alex 的请求进行限流,速率为10/s。
- 请求匹配规则为 请求参数(QUERY)
- 请求匹配规则为 请求头(HEADER):
- 标签来源: RPC 调用的额外标签信息,即 Invoaction.Attachments()
验证
可根据 dubbogo example 开展
4.3 - 使用 gRPC-Go
4.3.1 - 服务注册
引入依赖
go get github.com/polarismesh/grpc-go-polaris@latest
初始化 polaris.yaml
你需要在项目的根路径下创建一个 polaris.yaml 文件用于 grpc-go-polaris 初始化 polaris sdk。polaris.yaml配置详细
服务注册
// 完成 grpc Server 的创建以及注册 grpc service
srv := grpc.NewServer()
listen, err := net.Listen("tcp", "0.0.0.0:8080")
if err != nil {
log.Fatal(err)
}
pb.RegisterEchoServerServer(srv, &EchoQuickStartService{
actualPort: listen.Addr().(*net.TCPAddr).Port,
})
// 将 使用 polaris.Serve 方法启动 grpc server
if err := polaris.Serve(srv, listen,
polaris.WithServiceName("QuickStartEchoServerGRPC"),
); nil != err {
log.Printf("listen err: %v", err)
}
服务端 Options
WithGRPCServerOptions(opts …grpc.ServerOption)
设置 gRPC-Server 的相关 Option。
WithServerNamespace(namespace string)
设置 grpc 服务注册到北极星的命名空间,默认为 default。
WithServiceName(svcName string)
设置 grpc 服务的名称,可选,不过不设置,则会通过 grpc.Server 的 GetServiceInfo() 获取所有 grpc service 信息,进行服务注册。
WithServerMetadata(metadata map[string]string)
设置服务实例的标签信息。
WithServerHost(host string)
设置服务实例注册的 host 信息,可选,默认将通过和北极星服务端建立一次 TCP 连接获取本机对外 IP
WithServerVersion(version string)
设置服务实例的版本信息。
WithTTL(ttl int) ServerOption
设置服务实例心跳上报的周期,默认 5s
WithToken(token string)
当北极星服务端开启客户端鉴权时,需要设置用户/用户组访问凭据,鉴权文档可参考 权限控制。
WithDelayRegisterEnable(strategy DelayStrategy)
设置延迟注册策略
WithGracefulStopEnable(duration time.Duration)
启用服务实例优雅下线能力,默认开启
WithGracefulStopDisable()
禁用服务实例优雅下线能力
如何基于 grpc-go-polaris 完成一个服务注册的程序
4.3.2 - 服务发现
引入依赖
go get github.com/polarismesh/grpc-go-polaris-go@latest
初始化 polaris.yaml
你需要在项目的根路径下创建一个 polaris.yaml 文件用于 grpc-go-polaris 初始化 polaris sdk。polaris.yaml配置详细
服务发现
// 使用 grpc-go-polaris 提供的 DialContext 即可
conn, err := polaris.DialContext(ctx, "polaris://QuickStartEchoServerGRPC",
polaris.WithGRPCDialOptions(grpc.WithTransportCredentials(insecure.NewCredentials())),
polaris.WithDisableRouter(),
)
客户端 Options
WithGRPCDialOptions(opts …grpc.DialOption)
设置 grpc.DialContext 需要的 grpc.DialOption 参数
WithClientNamespace(namespace string)
设置主调服务所在的命名空间,可选
WithSrcService(srcService string)
设置主调服务的服务名称,可选
WithPolarisConfig(polarisCfg config.Configuration)
通过代码设置 polaris-go 的配置信息
WithDisableRouter()
禁用 polaris 的动态路由能力
WithEnableRouter()
启用 polaris 的动态路由能力
如何基于 grpc-go-polaris 完成一个服务发现的程序
4.3.3 - 动态路由
当前支持针对 gRPC 消息的以下内容进行动态路由:
| 消息类型 | gRPC 消息内容 | 路由规则请求类型 |
|---|---|---|
| 消息头 | metadata | 请求头(HEADER) |
| gRPC方法 | method | 路径(PATH) |
引入依赖
go get github.com/polarismesh/grpc-go-polaris@latest
初始化 polaris.yaml
你需要在项目的根路径下创建一个 polaris.yaml 文件用于 grpc-go-polaris 初始化 polaris sdk。polaris.yaml配置详细
gRPC Client 构建
// 使用 grpc-go-polaris 提供的 DialContext 即可
conn, err := polaris.DialContext(ctx, "polaris://QuickStartEchoServerGRPC",
polaris.WithGRPCDialOptions(grpc.WithTransportCredentials(insecure.NewCredentials())),
polaris.WithEnableRouter(),
)
如何配置动态路由参数
gRPC-Go 中的 PolarisMesh Balancer 扩展点实现,能够根据用户配置的服务路由规则,自动的从当前 RPC 调用上下文以及请求信息中识别出需要参与服务路由的请求标签信息。
假定一个场景:
- 希望 uid 为 user-1 的请求,路由到 env 标签为 dev 的实例上
- 希望 uid 为 user-2 的请求,路由到 env 标签为 pre 的实例上
- 其他则路由到 env 标签为 prod 的实例上,那可以为 gRPC-Go 服务设置三条路由规则。
- 请求匹配规则为 请求头(HEADER):
- 标签来源: RPC 调用的额外标签信息,即 metadata.FromOutgoingContext(balancer.PickInfo.Ctx)
示例代码(gRPC-Go原生使用方式)
func (s *Service) GetUser(uid, value string) {
md := metadata.Pairs("uid", uid)
ctx := metadata.NewOutgoingContext(context.Background(), md)
for i := 0; i < 5; i++ {
time.Sleep(200 * time.Millisecond)
resp, err := s.echoClient.Echo(ctx, &pb.EchoRequest{Value: value})
if err != nil {
logger.Errorf("error: %v\n", err)
}
logger.Infof("response: %v\n", user)
}
}
验证
可根据 grpc-polaris-go example 开展
4.3.4 - 负载均衡
引入依赖
go get github.com/polarismesh/grpc-go-polaris@latest
初始化 polaris.yaml
你需要在项目的根路径下创建一个 polaris.yaml 文件用于初始化 polaris-go SDK。polaris.yaml配置详细
设置默认负载均衡策略
修改 polaris.yaml 文件
#描述:主调端配置
consumer:
...
#描述:负载均衡相关配置
loadbalancer:
#描述:负载均衡类型
#范围:已注册的负载均衡插件名
#默认值:权重随机负载均衡
#支持参数:ringHash(一致性hash环)/maglev(maglev算法一致性hash)/hash(普通一致性hash)
type: weightedRandom
plugin:
#描述:虚拟节点的数量
#类型:int
#默认值:500
#ringHash:
# vnodeCount: 500
#maglev:
# # 初始化表向量区间
# tableSize: 65537
设置请求级别负载均衡策略
ctx := metadata.NewIncomingContext(context.Background(), metadata.MD{})
// 请求时设置本次请求的负载均衡算法
ctx = polaris.RequestScopeLbPolicy(ctx, api.LBPolicyRingHash)
ctx = polaris.RequestScopeLbHashKey(ctx, r.Header.Get("uid"))
resp, err := echoClient.Echo(ctx, &pb.EchoRequest{Value: value})
4.3.5 - 访问限流
当前支持针对 gRPC 消息的以下内容进行访问限流:
| 消息类型 | gRPC 消息内容 | 路由规则请求类型 |
|---|---|---|
| 消息头 | metadata | 请求头(HEADER) |
| gRPC方法 | method | 路径(PATH) |
引入依赖
go get github.com/polarismesh/grpc-go-polaris@latest
初始化 polaris.yaml
你需要在项目的根路径下创建一个 polaris.yaml 文件用于 grpc-go-polaris 初始化 polaris sdk。polaris.yaml配置详细
gRPC Server 构建
listen, err := net.Listen("tcp", "0.0.0.0:0")
if err != nil {
log.Fatal(err)
}
listenAddr := listen.Addr().String()
interceptor := polaris.NewRateLimitInterceptor().WithServiceName("RateLimitEchoServerGRPC")
// 注册 polaris 服务限流拦截器
srv := grpc.NewServer(grpc.UnaryInterceptor(interceptor.UnaryInterceptor))
pb.RegisterEchoServerServer(srv, &EchoRateLimitService{})
// 启动服务
if err := polaris.Serve(srv, listen,
polaris.WithServiceName("RateLimitEchoServerGRPC"),
); nil != err {
log.Printf("listen err: %v", err)
}
如何配置访问限流参数
gRPC-Go 中的 PolarisMesh RateLimiter 扩展点实现,能够根据用户配置的限流规则,自动的从当前 RPC 调用上下文以及请求信息中识别出需要参与限流的请求标签信息。
比如对 gRPC-Go 中的 Echo(context.Context, &EchoRequest) 方法,对 Metadata 中 uid 为 user-1 的进行限流,速率为10/s。
- 请求匹配规则为 请求头(HEADER):
- 标签来源: RPC 调用的额外标签信息,即 metadata.FromIncomingContext(context.Context)
验证
可根据 grpc-polaris-go example 开展
5 - C++ 应用开发
5.1 - 使用 C++ SDK
5.1.1 - 引入依赖
本文档提供如果编译并在自己的项目中引入Polaris CPP SDK方法
编译安装
下载源码
支持两种方式下载源码:
- 使用git clone源码然后切到最新的tag
- 直接在polaris cpp仓库的tags页面上下载最新的tag源码
编译打包
注:目前支持make, bazel方式编译。其他编译方式待支持,欢迎贡献。
make方式编译
# 编译
make
# 测试
make test
# 打包,可添加参数package_name指定打包名,默认polaris_cpp_sdk
make package # package_name=polaris_cpp_sdk
执行make package后会在当前目录下生成一个polaris_cpp_sdk.tar.gz压缩文件。该文件的内容如下:
|-- include/polaris # 头文件
| |-- consumer.h provider.h limit.h config.h context.h log.h defs.h ...
|-- dlib # 动态库
| |-- libpolaris_api.so
`-- slib # 静态库
|-- libpolaris_api.a libprotobuf.a
其中include/polaris/为头文件目录。业务程序使用#include "polaris/xxx.h"这种方式包含头文件。
dlib/为动态库目录。libpolaris_api.so为polaris的动态库。注:该动态库已经链接了libprotobuf.a
使用动态库,在发布应用程序时需要将该动态库一起发布,并需要确保能搜到这些动态库。
slib/为静态库目录。用户使用静态编译时需要链接该目录下libpolaris_api.a和libprotobuf.a两个静态库。
自定义PB3版本
目前SDK与北极星Server通信使用的PB3,如果用户使用了PB2,需要升级到PB3,PB3兼容PB2。 且当前为了支持c++98编译,默认集成了protobuf 3.5.1版本。用户可以根据需要使用自己的PB3库
在Makefile中找到protobuf相关路径定义,修改以下三个路径指向自己的PB3即可:
PROTOBUF_INC_DIR = # 修改成自己的PB3头文件路径
PROTOBUF_LIB = # 修改成自己的PB3静态库路径
PROTOC = # 修改成自己的PB3可执行文件protoc路径
兼容其他版本PB
有一些业务使用了其他的PB版本,例如PB2或者与北极星自带的PB3.5.1不同的版本。 如果同时链接两个版本的PB库,会导致符号冲突。 有一种方案可以隐藏北极星使用的PB库符号。该方案只支持业务链接北极星动态库时可用。
具体步骤如下:
-
到北极星源码根目录下执行
rm -rf third_party/protobuf/build*删除编译出来的protobuf库 -
修改北极星Makefile文件,protobuf的configure命令加上符号隐藏选项"CXXFLAGS=-fvisibility=hidden"。 如下是编译64位库时修改的地方:
$(PROTOBUF_DIR)/build64/libprotobuf.a: $(PROTOBUF_DIR)/configure
@echo "[PROTOBUF] Preparing protobuf 64bit lib and protoc"
@cd $(PROTOBUF_DIR); ./configure --with-pic --disable-shared --enable-static "CXXFLAGS=-fvisibility=hidden"
注:编译32位时修改32位PB编译命令的"CXXFLAGS=-m32"为"CXXFLAGS=-m32 -fvisibility=hidden"即可
- 在北极星根目录执行make clean 然后重新make即可
bazel方式编译
sh bazel_build.sh # 编译polaris_api
sh bazel_clean.sh # 编译清理
待补充:
test用例的bazel编译待补充
通过Makefile引入
静态库方式使用
g++ -I./polaris_cpp_sdk/include main.cpp -L./polaris_cpp_sdk/slib -lpolaris_api -lprotobuf -pthread -lz -lrt -o main
动态库方式使用
g++ -I./polaris_cpp_sdk/include main.cpp -L./polaris_cpp_sdk/dlib -lpolaris_api -pthread -lz -lrt -o main
通过CMake引入
静态库方式使用
set(POLARIS_SDK_DIR /data/example/polaris_cpp_sdk) # 需要修改polaris_cpp_sdk解压目录
include_directories(${POLARIS_SDK_DIR}/include)
link_directories(${POLARIS_SDK_DIR}/slib)
add_executable(main main.cpp)
target_link_libraries(main libpolaris_api.a libprotobuf.a pthread z rt)
动态库方式使用
set(POLARIS_SDK_DIR /data/example/polaris_cpp_sdk) # 需要修改polaris_cpp_sdk解压目录
include_directories(${POLARIS_SDK_DIR}/include)
link_directories(${POLARIS_SDK_DIR}/dlib)
add_executable(main main.cpp)
target_link_libraries(main polaris_api pthread z rt)
通过Bazel引入
在WORKSPACE中添加依赖:
git_repository(
name = "polaris_cpp",
remote = "https://github.com/polarismesh/polaris-cpp",
tag = "v1.1.0", # 替换成需要依赖的版本
)
在WORKSPACE中加载北极星依赖:
# 可以放到比较后面,这样如果有自定义其他依赖版本,则会优先使用其他自定义版本
load("//:polaris_deps.bzl", "polaris_deps")
polaris_deps()
在BUILD中设置编译目标添加依赖:
deps = [
"@polaris_cpp//:polaris_api",
],
5.1.2 - 注册发现
引入依赖
参考文档:依赖引入
初始化 polaris.yaml
你需要在项目的根路径下创建一个 polaris.yaml 文件用于初始化 polaris-cpp SDK。polaris.yaml配置详细
服务注册
SDK实例构建
当初始化好 polaris.yaml 文件之后,你可以直接使用 include polaris/provider.h, 使用polaris::ProviderApi::CreateWithDefaultFile() 方法进行构造一个 ProviderAPI SDK 实例
#include "polaris/provider.h"
int main(int argc, char** argv) {
provider_ = std::unique_ptr<polaris::ProviderApi>(polaris::ProviderApi::CreateWithDefaultFile());
}
注册请求体
// 服务实例注册请求
// 用于向指定命令空间的服务注册服务实例。必须拥有服务token才能进行服务实例注册。
// 服务实例注册成功后,其他服务调用服务发现接口能发现该服务实例,可能会立即向该服务实例发送请求。
// @note 所以必须在服务实例启动完成后才去进行服务注册。
class InstanceRegisterRequest : Noncopyable {
public:
/// @brief 构造服务实例注册请求对象
/// @param service_namespace 服务名所属命名空间
/// @param service_name 服务名
/// @param service_token 服务名对应的token
/// @param host 服务实例监听地址
/// @param port 服务实例监听端口
InstanceRegisterRequest(const std::string& service_namespace, const std::string& service_name,
const std::string& service_token, const std::string& host, int port);
/// @brief 设置请求超时时间。可选,默认为SDK配置的API超时时间
void SetTimeout(uint64_t timeout);
/// @brief 设置服务实例的VPC ID。可选,默认为空
void SetVpcId(const std::string& vpc_id);
/// @brief 设置服务实例协议。可选,默认为空
void SetProtocol(const std::string& protocol);
/// @brief 设置服务实例权重。可选,默认为100
void SetWeight(int weight);
/// @brief 设置服务实例优先级。可选,置默认为0
void SetPriority(int priority);
/// @brief 设置服务实例版本信息。可选,默认为空
void SetVersion(const std::string& version);
/// @brief 设置服务实例的metada数据。可选,默认为空
void SetMetadata(const std::map<std::string, std::string>& metadata);
/// @brief 设置服务实例是否开启健康检查。可选,默认不开启
void SetHealthCheckFlag(bool health_check_flag);
/// @brief 设置健康检查类型。可选,默认为心跳健康检查
void SetHealthCheckType(HealthCheckType health_check_type);
/// @brief 设置心跳健康检查ttl,单位为s,不填默认为5s,TTL的取值范围为 (0s, 60s]
/// 开启了心跳健康检查,客户端必须以TTL间隔上报心跳
/// 健康检查服务器3个TTL未受到心跳则将实例置为不健康
void SetTtl(int ttl);
/// @brief 设置节点的位置信息。可选
/// @param region 节点所在区域
/// @param zone 节点所在城市
/// @param campus 节点所在园区
void SetLocation(const std::string& region, const std::string& zone, const std::string& campus);
};
发起注册请求
你在初始化完 InstanceRegisterRequest 结构体后,需要调用 ProviderAPI.Register 方法完成实例注册, 如果实例开启了心跳上报,则还需要调用 heartbeat 方法定期上报实例心跳
polaris::InstanceRegisterRequest register_req(service_namespace_, service_name_, service_token_, host_, port_);
// 开启健康检查
register_req.SetHealthCheckFlag(true);
register_req.SetHealthCheckType(polaris::kHeartbeatHealthCheck);
register_req.SetTtl(kHeartbeatTtl);
// 注册实例
auto ret_code = provider_->Register(register_req, instance_id_);
if (ret_code != polaris::kReturnOk && ret_code != polaris::kReturnExistedResource) {
std::cout << "register instance with error:" << polaris::ReturnCodeToMsg(ret_code).c_str() << std::endl;
return ret_code;
}
// 启动心跳上报线程
heartbeat_thread_ = std::unique_ptr<std::thread>(new std::thread([=] {
while (!signal_received) { // 循环上报心跳
polaris::InstanceHeartbeatRequest heartbeat_req(service_token_, instance_id_);
auto ret_code = provider_->Heartbeat(heartbeat_req);
if (ret_code != polaris::kReturnOk) {
std::cout << "instance heartbeat with error:" << polaris::ReturnCodeToMsg(ret_code).c_str() << std::endl;
sleep(1);
continue;
}
sleep(kHeartbeatTtl);
}
}));
服务发现
SDK实例构建
当初始化好 polaris.yaml 文件之后,你可以直接使用 include polaris/consumer.h, 使用polaris::ConsumerApi::CreateWithDefaultFile() 方法进行构造一个 ConsumerApi SDK 实例
#include "polaris/consumer.h"
int main(int argc, char** argv) {
consumer_ = std::unique_ptr<polaris::ConsumerApi>(polaris::ConsumerApi::CreateWithDefaultFile());
}
发现服务实例
GetAllInstances
直接返回目标服务下的所有实例,包括不健康、隔离、权重为0、被熔断的实例,也会在返回的实例列表中。
/// @brief 获取批量服务实例请求
class GetInstancesRequest : Noncopyable {
public:
/// @brief 构造获取批量服务实例请求
/// @param service_key 命名空间和服务名
explicit GetInstancesRequest(const ServiceKey& service_key);
};
// 调用该方法执行请求
consumer.GetAllInstances()
GetInstances
每次获取一批可用服务提供者实例,该方法会执行路由流程。
该方法默认会过滤掉不健康、隔离、权重为0、被熔断的实例。
执行路由流程的条件
- 配置了 GetInstancesRequest.SourceService.Metadata 属性,会触发自定义路由流程
- 设置了 GetInstancesRequest.Metadata 属性,会触发元数据路由流程
/// @brief 获取批量服务实例请求
class GetInstancesRequest : Noncopyable {
public:
/// @brief 构造获取批量服务实例请求
/// @param service_key 命名空间和服务名
explicit GetInstancesRequest(const ServiceKey& service_key);
/// @brief 设置服务路由时否包含不健康的服务实例。可选,默认不包含
/// @note 即使设置不包含的情况下仍然可能降级返回不健康实例
void SetIncludeUnhealthyInstances(bool include_unhealthy_instances);
/// @brief 设置服务路由时是否包含熔断的服务实例。可选,默认不包含。
/// @note 即使设置不包含的情况下仍然可能降级返回熔断实例
void SetIncludeCircuitBreakInstances(bool include_circuit_breaker_instances);
/// @brief 设置是否跳过服务路由。可选,默认不跳过服务路由
void SetSkipRouteFilter(bool skip_route_filter);
/// @brief 设置源服务信息,用于服务路由计算。可选
void SetSourceService(const ServiceInfo& source_service);
/// @brief 设置元数据,用于元数据路由
void SetMetadata(std::map<std::string, std::string>& metadata);
/// @brief 设置元数据路由匹配失败时的降级策略,默认不降级
void SetMetadataFailover(MetadataFailoverType metadata_failover_type);
};
// 调用该方法执行请求
consumer.GetInstances()
GetOneInstances
每次仅获取一个可用服务提供者实例,该方法会依次执行路由、负载均衡流程。
该方法默认会过滤掉不健康、隔离、权重为0、被熔断的实例。
执行路由流程的条件
- 配置了 GetOneInstanceRequest.SourceService.Metadata 属性,会触发自定义路由流程
- 设置了 GetOneInstanceRequest.Metadata 属性,会触发元数据路由流程
/// @brief 获取单个服务实例请求
class GetOneInstanceRequest : Noncopyable {
public:
/// @brief 构建获取单个服务实例请求对象
/// @param service_key 命名空间和服务名
explicit GetOneInstanceRequest(const ServiceKey& service_key);
/// @brief 设置hash key,用于一致性哈希负载均衡算法选择服务实例。其他负载均衡算法不用设置
void SetHashKey(uint64_t hash_key);
/// @brief 设置 hash 字符串, sdk 会用 hash_string 算出一个 uint64_t
/// 的哈希值用于一致性哈希负载均衡算法选择服务实例。其他负载均衡算法不用设置
void SetHashString(const std::string& hash_string);
/// @brief 设置是否略过跳过半开探测节点
/// @note 只在重试业务时设置为true。如果一直设置为true,则熔断节点在网络探测成功后也一直无法恢复
void SetIgnoreHalfOpen(bool ignore_half_open);
/// @brief 设置源服务信息,用于服务路由计算。可选
/// @param source_service 源服务信息,包括源服务命名空间和用于过滤的metadata
void SetSourceService(const ServiceInfo& source_service);
/// @brief 设置请求超时时间。可选,默认为全局配置的API超时时间
void SetTimeout(uint64_t timeout);
/// @brief 设置请求标签,用于接口级别熔断
void SetLabels(const std::map<std::string, std::string>& labels);
/// @brief 设置元数据,用于元数据路由
void SetMetadata(std::map<std::string, std::string>& metadata);
/// @brief 设置元数据路由匹配失败时的降级策略,默认不降级
void SetMetadataFailover(MetadataFailoverType metadata_failover_type);
/// @brief 设置负载均衡类型。可选,默认使用配置文件中设置的类型
void SetLoadBalanceType(LoadBalanceType load_balance_type);
/// @brief 设置用于重试的实例数。可选,默认不返回用于重试的实例
/// @note 第一个实例由负载均衡器给出,外加backup_instance_num个实例,实例不重复,但不保证数量
/// 内部的一致性环hash负载均衡返回实例后方相邻的实例,其他返回随机实例
/// 从GetOneInstance的InstancesResponse获取实例
/// @param backup_instance_num 重试(备份)实例数
void SetBackupInstanceNum(uint32_t backup_instance_num);
/// @param replicate_index 副本索引,默认为0表示当前hash实例本身
/// 大于0表示从hash实例后面的第几个副本
void SetReplicateIndex(int replicate_index);
};
// 调用该方法执行请求
consumer->GetOneInstance(request, instance)
如何基于 polaris-cpp 客户端完成一个服务发现的程序
5.1.3 - 动态路由
引入依赖
参考文档:依赖引入
初始化 polaris.yaml
你需要在项目的根路径下创建一个 polaris.yaml 文件用于初始化 polaris-cpp SDK。polaris.yaml配置详细
SDK实例构建
当初始化好 polaris.yaml 文件之后,你可以直接使用 include polaris/consumer.h, 使用polaris::ConsumerApi::CreateWithDefaultFile() 方法进行构造一个 ConsumerApi SDK 实例
#include "polaris/consumer.h"
int main(int argc, char** argv) {
consumer_ = std::unique_ptr<polaris::ConsumerApi>(polaris::ConsumerApi::CreateWithDefaultFile());
}
服务路由
GetInstances
每次获取一批可用服务提供者实例,该方法会执行路由流程。
该方法默认会过滤掉不健康、隔离、权重为0、被熔断的实例。
执行路由流程的条件
- 配置了 GetInstancesRequest.SourceService.Metadata 属性,会触发自定义路由流程
- 设置了 GetInstancesRequest.Metadata 属性,会触发元数据路由流程
/// @brief 获取批量服务实例请求
class GetInstancesRequest : Noncopyable {
public:
/// @brief 构造获取批量服务实例请求
/// @param service_key 命名空间和服务名
explicit GetInstancesRequest(const ServiceKey& service_key);
/// @brief 设置服务路由时否包含不健康的服务实例。可选,默认不包含
/// @note 即使设置不包含的情况下仍然可能降级返回不健康实例
void SetIncludeUnhealthyInstances(bool include_unhealthy_instances);
/// @brief 设置服务路由时是否包含熔断的服务实例。可选,默认不包含。
/// @note 即使设置不包含的情况下仍然可能降级返回熔断实例
void SetIncludeCircuitBreakInstances(bool include_circuit_breaker_instances);
/// @brief 设置是否跳过服务路由。可选,默认不跳过服务路由
void SetSkipRouteFilter(bool skip_route_filter);
/// @brief 设置源服务信息,用于服务路由计算。可选
void SetSourceService(const ServiceInfo& source_service);
/// @brief 设置元数据,用于元数据路由
void SetMetadata(std::map<std::string, std::string>& metadata);
/// @brief 设置元数据路由匹配失败时的降级策略,默认不降级
void SetMetadataFailover(MetadataFailoverType metadata_failover_type);
};
// 调用该方法执行请求
consumer->GetInstances(request, instance)
如果当前 GetInstancesRequest 还不支持 AddArgument 方法,同时服务端版本 >= 1.12.0,SourceService.Metadata 对应的 key 名称如下:
- 路径: $path
- 方法: $method
- 请求头: $header.{标签键}
- 请求参数: $query.{标签键}
- 请求COOKIE: $cookie.{标签键}
- 主调IP: $caller_ip
- 自定义: {标签键}
如何基于 polaris-cpp 客户端完成一个服务路由的程序
5.1.4 - 负载均衡
引入依赖
参考文档:依赖引入
初始化 polaris.yaml
你需要在项目的根路径下创建一个 polaris.yaml 文件用于初始化 polaris-cpp SDK。polaris.yaml配置详细
SDK实例构建
当初始化好 polaris.yaml 文件之后,你可以直接使用 include polaris/consumer.h, 使用polaris::ConsumerApi::CreateWithDefaultFile() 方法进行构造一个 ConsumerApi SDK 实例
#include "polaris/consumer.h"
int main(int argc, char** argv) {
consumer_ = std::unique_ptr<polaris::ConsumerApi>(polaris::ConsumerApi::CreateWithDefaultFile());
}
服务路由
GetOneInstance
每次获取一批可用服务提供者实例,该方法会执行路由流程。
该方法默认会过滤掉不健康、隔离、权重为0、被熔断的实例。
执行路由流程的条件
- 配置了 GetInstancesRequest.SourceService.Metadata 属性,会触发自定义路由流程
- 设置了 GetInstancesRequest.Metadata 属性,会触发元数据路由流程
/// @brief 获取单个服务实例请求
class GetOneInstanceRequest : Noncopyable {
public:
/// @brief 构建获取单个服务实例请求对象
/// @param service_key 命名空间和服务名
explicit GetOneInstanceRequest(const ServiceKey& service_key);
/// @brief 设置hash key,用于一致性哈希负载均衡算法选择服务实例。其他负载均衡算法不用设置
void SetHashKey(uint64_t hash_key);
/// @brief 设置 hash 字符串, sdk 会用 hash_string 算出一个 uint64_t
/// 的哈希值用于一致性哈希负载均衡算法选择服务实例。其他负载均衡算法不用设置
void SetHashString(const std::string& hash_string);
/// @brief 设置负载均衡类型。可选,默认使用配置文件中设置的类型
/// LoadBalanceType可取值如下:
/// - kLoadBalanceTypeWeightedRandom // 权重随机
/// - kLoadBalanceTypeRingHash // 一致性hash负载均衡
/// - kLoadBalanceTypeMaglevHash // 一致性Hash: maglev算法
/// - kLoadBalanceTypeL5CstHash // 兼容L5的一致性Hash
/// - kLoadBalanceTypeSimpleHash // hash_key%总实例数 选择服务实例
/// - kLoadBalanceTypeDefaultConfig // 使用全局配置的负载均衡算法,默认值
void SetLoadBalanceType(LoadBalanceType load_balance_type);
/// @brief 设置用于重试的实例数。可选,默认不返回用于重试的实例
/// @note 第一个实例由负载均衡器给出,外加backup_instance_num个实例,实例不重复,但不保证数量
/// 内部的一致性环hash负载均衡返回实例后方相邻的实例,其他返回随机实例
/// 从GetOneInstance的InstancesResponse获取实例
/// @param backup_instance_num 重试(备份)实例数
void SetBackupInstanceNum(uint32_t backup_instance_num);
/// @param replicate_index 副本索引,默认为0表示当前hash实例本身
/// 大于0表示从hash实例后面的第几个副本
void SetReplicateIndex(int replicate_index);
};
// 调用该方法执行请求
consumer->GetOneInstance(request, instance)
如何基于 polaris-cpp 客户端完成一个负载均衡的程序
5.1.5 - 节点熔断
引入依赖
参考文档:依赖引入
初始化 polaris.yaml
你需要在项目的根路径下创建一个 polaris.yaml 文件用于初始化 polaris-go SDK。polaris.yaml配置详细
SDK实例构建
当初始化好 polaris.yaml 文件之后,你可以直接使用 include polaris/consumer.h, 使用polaris::ProviderApi::CreateWithDefaultFile() 方法进行构造一个 ProviderAPI SDK 实例
#include "polaris/consumer.h"
int main(int argc, char** argv) {
consumer_ = std::unique_ptr<polaris::ConsumerApi>(polaris::ConsumerApi::CreateWithDefaultFile());
}
上报调用情况
/// @brief 服务实例调用结果上报
class ServiceCallResult : Noncopyable {
public:
/// @brief 设置服务实例的服务名
void SetServiceName(const std::string& service_name);
/// @brief 设置服务实例的命名空间
void SetServiceNamespace(const std::string& service_namespace);
/// @brief 设置服务实例ID
void SetInstanceId(const std::string& instance_id);
/// @brief 设置服务实例Host和Port,可选,如果设置了服务实例ID,则这个可不设置,优先使用服务实例ID
/// @param host 服务实例Host
/// @param port 服务实例Port
void SetInstanceHostAndPort(const std::string& host, int port);
/// @brief 设置调用返回状态码
void SetRetStatus(CallRetStatus ret_status);
/// @brief 设置调用返回码。可选,用于支持根据返回码实现自己的插件
void SetRetCode(int ret_code);
/// @brief 设置服务实例调用时延
void SetDelay(uint64_t delay);
/// @brief 设置主调服务ServiceKey
void SetSource(const ServiceKey& source);
/// @brief 设置被调服务labels信息
void SetLabels(const std::map<std::string, std::string>& labels);
};
上报请求调用结果
你在根据请求调用情况对 ServiceCallResult 结构体完成初始化后,只需要调用 ConsumerAPI.UpdateServiceCallResult 方法即可完成请求调用结果上报。SDK 内部会根据上报的调用结果信息,对实例进行信息统计并计算是否需要对实例进行熔断
consumer_->UpdateServiceCallResult(result)
如何基于 polaris-go 客户端完成一个节点熔断的程序
5.1.6 - 访问限流
引入依赖
参考文档:依赖引入
初始化 polaris.yaml
你需要在项目的根路径下创建一个 polaris.yaml 文件用于初始化 polaris-cpp SDK。polaris.yaml配置详细
SDK实例构建
当初始化好 polaris.yaml 文件之后,你可以直接使用 include polaris/limit.h, 使用polaris::LimitApi::CreateWithDefaultFile() 方法进行构造一个 LimitApi SDK 实例
#include "polaris/limit.h"
int main(int argc, char** argv) {
polaris::LimitApi* limit_api = polaris::LimitApi::CreateWithDefaultFile();
}
请求配额
/// @brief 限流配额请求
class QuotaRequest {
public:
/// @brief 设置服务命名空间
void SetServiceNamespace(const std::string& service_namespace);
/// @brief 设置服务名
void SetServiceName(const std::string& service_name);
/// @brief 设置标签用于选择限流配置
void SetLabels(const std::map<std::string, std::string>& labels);
/// @brief 设置请求需要分配的配额数量,可选,默认为1
void SetAcquireAmount(int amount);
/// @brief 设置请求超时时间,可选,单位ms,默认1000ms
void SetTimeout(uint64_t timeout);
/// @brief 设置请求所属的接口名,可选
void SetMethod(const std::string& method);
};
如果当前 QuotaRequest 还不支持 AddArgument 方法,同时服务端版本 >= 1.11.0,SetLabels 对应的 key 名称如下:
- 路径: $path
- 方法: $method
- 请求头: $header.{标签键}
- 请求参数: $query.{标签键}
- 主调服务: $caller_service
- 主调IP: $caller_ip
- 自定义: {标签键}
发起请求配额申请
你在接收到请求之后对 QuotaRequest 结构体完成初始化后,只需要调用 LimitAPI.GetQuota 方法即可完成本次请求配额的申请。
ret = limit_api->GetQuota(quota_request, response)
对于请求配额结果的结构体如下。
/// @brief 配额获取结果
enum QuotaResultCode {
kQuotaResultOk = 0, // 配额正常
kQuotaResultLimited, // 配额被限流
kQuotaResultWait // 需求需要等待重试
};
/// @brief 配额分配信息,sidecar模式下暂时不支持获取这些信息
struct QuotaResultInfo {
int64_t left_quota_; // 剩余配额
int64_t all_quota_; // 配置的配额
uint64_t duration_; // 配置周期
bool is_degrade_; // 是否降级
};
/// @brief 限流配额应答
class QuotaResponse {
public:
/// @brief 获取限流配额结果
QuotaResultCode GetResultCode() const;
/// @brief 获取配额分配信息
const QuotaResultInfo& GetQuotaResultInfo() const;
/// @brief 请求需要获取多长时间才能使用配额
uint64_t GetWaitTime() const;
};
分布式限流使用
如果要使用分布式限流,请先确保已经部署了北极星分布式限流 server
部署完后确认北极星控制台存在服务 命名空间: Polaris, 服务名: polaris.limiter。
确认完毕后,调整 polaris.yaml 配置文件,在控制台配置分布式限流规则,SDK 仍然使用 ret = limit_api->GetQuota(quota_request, response) 即可。
# 描述:限流相关配置
rateLimiter:
# 分布式限流时用于发现限流服务器,当规则中未配置限流集群时使用该配置
rateLimitCluster:
# 限流服务器集群所在命名空间
namespace: Polaris
# 限流服务器集群名字
service: polaris.limiter
如何基于 polaris-cpp 客户端完成一个服务限流的程序
5.1.7 - 二次寻址
引入依赖
参考文档:依赖引入
初始化 polaris.yaml
你需要在项目的根路径下创建一个 polaris.yaml 文件用于初始化 polaris-cpp SDK。polaris.yaml配置详细
修改 polaris.yaml 开启二次寻址
global:
#描述系统相关配置
system:
# 服务发现集群,用于二次寻址,非二次寻址场景无需配置
discoverCluster:
namespace: Polaris
service: polaris.discover
# 可选:服务刷新间隔
refreshInterval: 10m
# 健康检查集群,用于二次寻址,非二次寻址场景无需配置
healthCheckCluster:
namespace: Polaris
service: polaris.healthcheck
# 可选:服务刷新间隔
refreshInterval: 10m
5.2 - 使用 L5Agent
环境准备
部署polaris
如果已经部署好了polaris,可忽略这一步。
polaris支持在kubernetes环境中进行部署,注意必须保证暴露HTTP端口为8090,gRPC端口为8091。具体部署方案请参考:
开启服务端的 L5 接入能力
编辑 polaris-server.yaml 配置文件
# apiserver配置
apiservers:
...
# - name: service-l5
# option:
# listenIP: 0.0.0.0
# listenPort: 7779
# clusterName: cl5.discover
将相关注释移除
# apiserver配置
apiservers:
...
- name: service-l5
option:
listenIP: 0.0.0.0
listenPort: 7779
clusterName: cl5.discover
重启 polaris-server
bash tool/stop.sh
bash tool/start.sh
bash tool/stop.cmd
bash tool/start.cmd
修改 L5Agent 配置
修改 L5Agent 安装目录下的 conf/l5_config.ini 配置文件
[L5CONFIG]
ServerIp={北极星服务端IP}
ServerPort=7779
修改完上述配置之后,重启 L5Agent。在重启前需要删除 /data/L5Backup/l5server_list.backup
验证
SID 规范以及注意
- L5 SDI 的格式:ModID:CmdID
- 强烈建议用户命名空间选择 default 或者 Production,ModID 取值范围为: [2, 192,000,000]
- 如果用户确实有需要使用其他命名空间,请按照以下方式进行其他命名空间的换算:ModID 数值右移6位,如果结果 >= 3000001,则需要计算 ModID & 63 的结果值,根据结果值对应的命名空间信息如下,否则会出现L5寻址失败的问题:
{ 1: "Production", 2: "Development", 3: "Pre-release", 4: "Test", 5: "Polaris", 6: "default", }
创建测试服务以及SID
由于 l5api 仅支持访问 L5 SID,因此访问非 L5 SID 格式的服务名,需要创建 CL5 SID 格式的服务别名指向该服务
执行
➜ bin ./L5GetRoute1 192002625 487373 3
ip is :127.0.0.1 port is : 8091, usec=153,avg_usec=153=========================
ip is :127.0.0.1 port is : 8091, usec=2,avg_usec=77=========================
ip is :127.0.0.1 port is : 8091, usec=111,avg_usec=88=========================
6 - K8s 和网格代理
6.1 - 安装 Polaris Controller
k8s controller的作用
北极星提供K8s controller的机制,可以安装在k8s集群中,通过接收集群内k8s apiserver的事件回调,将K8s Service以及POD注册成北极星的服务以及实例。
安装说明
k8s controller包含以下组件:
- polaris-controller:北极星controller服务端,主要是安装在k8s集群上,提供回调接口供k8s controller manager进行调用。
开始安装
部署包下载
到polaris-controller的下载页面,根据您这边的 kubernetes 版本号(版本号 <= 1.21.x,选择k8s1.21.zip;版本号 >= 1.22.x,选择k8s1.22.zip),下载最新版本polaris-controller安装包。
部署包安装
安装前,需确保 kubectl 命令已经加入环境变量Path中,并且可以访问 kubernetes 的 APIServer。
以polaris-controller-release_${version}.k8s1.21.zip为例:
解压并进入部署包:
unzip polaris-controller-release_${version}.k8s1.21.zip
cd polaris-controller-release_${version}.k8s1.21
查询用户token,由于controller需要直接访问polaris的控制台OpenAPI,因此需要填写token。
- 打开北极星控制台,选择用户->用户列表->选择polaris用户->查看token,即可获取到token。
修改variables.txt文件,填写polaris的地址(只填IP或者域名,无需端口),如果在同一个集群中,则可以填写集群内域名,同时需要填写上一步所查询到的token
#polaris地址,只填IP或者域名,无需端口
POLARIS_HOST:polaris.polaris-system
#polaris的用户token
POLARIS_TOKEN:4azbewS+pdXvrMG1PtYV3SrcLxjmYd0IVNaX9oYziQygRnKzjcSbxl+Reg7zYQC1gRrGiLzmMY+w+aCxOYI=
执行安装部署。
./install.sh
安装后验证
安装成功后,可以在k8s集群中,polaris-system命名空间,看到polaris-controller的statefulset已经部署完成。
同时,打开北极星的控制台,可以看到k8s上面的service已经被自动同步到北极星上。
6.2 - K8s 服务同步
支持两种 K8s Service 同步模式:
- all:全量同步服务。将 K8s Service 全部同步到北极星。
- demand:按需同步服务。默认不会将 K8s Service 同步到北极星,需要在 Namespace 或者 Service 上添加北极星的 annotation。
北极星支持跨 K8s 集群的服务发现和治理,多个 K8s 集群的 Service 可以同步到一个北极星集群,同步规则如下:
- K8s Namespace 和 Service 名称作为北极星的命名空间名称
- 如果多个 K8s 集群存在相同的 Namespace 和 Service,全部 Pod 同步到一个北极星服务中
- polaris-controller 在北极星服务实例上添加 clusterName 标签,用于区分来自不同 K8s 集群的服务实例
- 如果存在多个 K8s Service 同步到一个北极星服务的情况,每个 K8s 集群的 polaris-controller 需要配置不同的 clusterName
注解
| 注解名称 | 注解描述 |
|---|---|
| polarismesh.cn/sync | 是否同步这个服务到 polarismesh。true 同步,false 不同步,默认不同步 |
| polarismesh.cn/aliasService | 把 k8s service 同步到 polarismesh 时,同时创建的服务别名的名字 |
| polarismesh.cn/aliasNamespace | 创建的别名所在的命名空间,配合 polarismesh.cn/aliasService 使用 |
使用指南
全量同步服务
以全量同步服务的模式启动 polaris-controller,将 K8s Service 全部同步到北极星,则 polaris-controller 的启动配置如下:
polaris-controller 启动配置文件:configmap.yaml
apiVersion: v1
kind: ConfigMap
data:
mesh: |-
...
serviceSync
mode: "all"
...
按需同步服务
以按需同步服务的模式启动 polaris-controller,默认不会将 K8s Service 同步到北极星,则 polaris-controller 的启动配置如下:
polaris-controller 启动配置文件:configmap.yaml
apiVersion: v1
kind: ConfigMap
data:
mesh: |-
...
serviceSync
mode: "demand"
...
如果需要将某个 Namespace 中的全部 Service 同步到北极星,请在 Namespace 上添加北极星的 annotation,配置方式如下:
apiVersion: v1
kind: Namespace
metadata:
name: default
annotations:
polarismesh.cn/sync: "true"
如果需要将某个 Service 同步到北极星,请在 Service 上添加北极星的 annotation,配置方式如下:
apiVersion: v1
kind: Service
metadata:
namespace: default
name: test
annotations:
polarismesh.cn/sync: "true"
如果需要将某个 Namespace 中的 Service同步到北极星并且排除某个 Service,配置方式如下:
apiVersion: v1
kind: Namespace
metadata:
name: default
annotations:
polarismesh.cn/sync: "true"
---
apiVersion: v1
kind: Service
metadata:
namespace: default
name: test
annotations:
polarismesh.cn/sync: "false"
创建服务别名
北极星支持服务别名的功能,允许为一个服务设置一个或者多个服务别名,使用服务别名进行服务发现的效果等同使用服务名称进行服务发现的效果。
polaris-controller 将 K8s Service 同步到北极星的名称映射规则如下:
- K8s Namespace作为北极星的命名空间名称
- K8s Service作为北极星的服务名称
如果需要在 Service 同步到北极星时,为其创建一个服务别名,配置方式如下:
apiVersion: v1
kind: Service
metadata:
namespace: default
name: test
annotations:
polarismesh.cn/aliasNamespace: aliasDefault
polarismesh.cn/aliasService: aliasTest
6.3 - K8s 配置同步(Beta)
提示
该文章仅适用于北极星服务端版本 >= 1.18.0, polaris-controller 版本 >= 1.7.0
支持两种 K8s ConfigMap 同步模式:
- all:全量同步配置。将 K8s ConfigMap 全部同步到北极星。
- demand:按需同步配置。默认不会将 K8s ConfigMap 同步到北极星,需要在 Namespace 或者 ConfigMap 上添加北极星的 annotation。
注解
| 注解名称 | 注解描述 |
|---|---|
| polarismesh.cn/sync | 是否同步这个配置到 polarismesh。true 同步,false 不同步,默认不同步 |
使用指南
controller 配置解析
configSync:
# 是否开启配置同步
enable: true
# 北极星服务端地址
serverAddress: #POLARIS_HOST#
# 北极星开启鉴权时需要配置
accessToken: #POLARIS_TOKEN#
# 是否开启删除操作,即允许删除 ConfigMap 或者北极星上的配置文件
allowDelete: false
# 配置同步方向: kubernetesToPolaris|polarisToKubernetes|both
# kubernetesToPolaris: 只能将 ConfigMap 同步到北极星中
# polarisToKubernetes: 只能将北极星配置文件中带有 internal-sync-to-kubernetes: true 标签的配置文件同步到 ConfigMap
# both: 上述两种同时开启
syncDirection: both
defaultGroup: "#CLUSTER_NAME#"
全量同步服务
以全量同步配置的模式启动 polaris-controller,将 K8s ConfigMap 全部同步到北极星,则 polaris-controller 的启动配置如下:
polaris-controller 启动配置文件:configmap.yaml
apiVersion: v1
kind: ConfigMap
data:
mesh: |-
...
configSync
mode: "all"
...
按需同步配置
以按需同步配置的模式启动 polaris-controller,默认不会将 K8s ConfigMap 同步到北极星,则 polaris-controller 的启动配置如下:
polaris-controller 启动配置文件:configmap.yaml
apiVersion: v1
kind: ConfigMap
data:
mesh: |-
...
configSync
mode: "demand"
...
如果需要将某个 Namespace 中的全部 ConfigMap 同步到北极星,请在 Namespace 上添加北极星的 annotation,配置方式如下:
apiVersion: v1
kind: Namespace
metadata:
name: default
annotations:
polarismesh.cn/sync: "true"
如果需要将某个 ConfigMap 同步到北极星,请在 ConfigMap 上添加北极星的 annotation,配置方式如下:
apiVersion: v1
kind: ConfigMap
metadata:
namespace: default
name: test
annotations:
polarismesh.cn/sync: "true"
如果需要将某个 Namespace 中的 ConfigMap 同步到北极星并且排除某个 ConfigMap,配置方式如下:
apiVersion: v1
kind: Namespace
metadata:
name: default
annotations:
polarismesh.cn/sync: "true"
---
apiVersion: v1
kind: ConfigMap
metadata:
namespace: default
name: test
annotations:
polarismesh.cn/sync: "false"
6.4 - Envoy 网格接入
注意:当前此接入方案处于实验阶段,请勿在生产环境使用
在 Polaris 的服务网格方案中,Polaris 是您的控制平面,Envoy Sidecar 代理是您的数据平面。当前
-
服务数据同步:
polaris-controller安装在用户的Kubernetes集群中,可以同步集群上的 Namespace,Service,Endpoints 等资源到polaris中,同时polaris-controller提供了Envoy Sidecar注入器功能,可以轻松地将Envoy Sidecar注入到您的 Kubernetes Pod 中,Envoy Sidecar 会自动去 Polaris 同步服务信息。 -
规则数据下发:
polaris控制面通过XDS v3标准协议与 envoy 进行交互,支持官方开源的 envoy 直接接入,当前支持的 envoy 版本为 1.26.2
环境准备
部署polaris
如果已经部署好了polaris,可忽略这一步。
polaris支持在kubernetes环境中进行部署,注意必须保证暴露HTTP端口为8090,gRPC端口为8091。具体部署方案请参考:
部署 polaris-controller
快速接入
服务调用关系说明
启用 sidecar 自动注入功能
-
创建命名空间
bookinfo:kubectl create namespace bookinfo -
为
bookinfo命名空间启用注入:
kubectl label namespace bookinfo polaris-injection=enabled
使用一下命令来验证 bookinfo 命名空间是否已经正确启用:
kubectl get namespace -L polaris-injection
此时应该返回:
NAME STATUS AGE POLARIS-INJECTION
bookinfo Active 3d2h enabled
启用 Envoy 按需加载机制
- polaris-server 需要 >= 1.18.0-beta 版本
- polaris-controller 需要 >= 1.7.0-beta 版本
在 POD 中添加以下 annonations sidecar.polarismesh.cn/openOnDemand: true 即可启用 Envoy 的按需加载
apiVersion: v1
kind: Pod
metadata:
name: annotations-demo
annotations:
sidecar.polarismesh.cn/openOnDemand: "true"
部署样例
-
下载样例部署文件:bookinfo
-
执行部署:
kubectl create -f bookinfo.yaml -
查看容器注入是否注入成功
启动自动注入后,polaris-controller 会将 Envoy Sidecar、Polaris Sidecar 容器注入到在此命名空间下创建的 pod 中。
可以看到运行起来的 pod 均包含三个容器,其中第一个容器是用户的业务容器,另外两个容器是由 Polaris Controller 注入器注入的 Envoy Sidecar 容器和 Polaris Sidecar 容器。您可以通过下面的命令来获取有关 pod 的更多信息:
kubectl describe pods -l app=productpage --namespace=bookinfo
此时应返回:
... ...
Init Containers:
# polaris-bootstrap-writer 产生 Envoy 的 Bootstrap 配置
polaris-bootstrap-writer:
... ...
# istio-init 为 envoy sidecar 设置流量拦截
istio-init:
... ...
Containers:
# demo 的业务容器
productpage:
... ...
# Envoy 是代理流量的容器
envoy:
... ...
- 打开productpage界面
通过productpage暴露的地址,可以访问productpage的主界面,进入Normal User或者TestUser后,可以看到(红、黑、无)三种形态的星星,代表demo已经部署成功。
使用服务治理能力
流量调度
北极星网格支持根据http请求的头部字段进行路由,支持通过path, header, query这3种类型的属性来进行路由。
- 使用场景
demo 项目中,productpage 会访问 reviews 服务,reviews 服务共有三个实例,三个实例分别部署了三个版本(会显示红、黑、无三种颜色的星星),需要保证特定的灰度用户(用户名为jason),请求到特定版本的 reviews 服务。
- 配置路由规则
为 reviews 服务创建路由规则。将请求中 header 包含字段 end-user=jason 的请求,路由到 version=v2 的服务实例中。同时再创建一条路由规则,指定标签键值为任意请求,路由到 version=v1 的服务实例中。
路由规则的标签填写格式要求:
- 对于Path:标签KEY需要填写 $path
- 对于Header:标签KEY需要带上前缀 $header,如 $header.end-user
- 对于Query:标签KEY需要带上前缀 $query,如 $query.end-user
- 验证路由是否生效
未登陆时,刷新 productpage 的页面,可以看到只返回没有颜色的星星(version=v1)。当使用 jason 登陆后,productpage 请求 reviews 时,会带上 header,end-user=jason,此时再刷新 productpage 页面,发现只会显示黑色的星星,即上面 version=v2 的实例。
访问限流
- polaris-server 需要 >= 1.17.3 版本
- polaris-controller 需要 >= 1.6.0 版本
- 在envoy接入的场景中,受XDS协议的限制,当前限流标签仅支持以下两个。
- 请求头(HEADER)
- 请求参数(QUERY)
-
使用场景: demo项目中,为 detail 服务设置流量限制,对于jason用户的请求,设置访问的频率为5/m,其余请求不做限制。
-
设置限流规则: 指定请求中 header 包含字段 end-user=jason 的请求,设置限流规则为5/m,限流类型为分布式限流。
说明: 详细的限流规则匹配及使用指南可参考:访问限流 -
验证限流是否生效: 未登陆时,多次刷新界面,不会出现错误。以jason用户身份登陆,一分钟刷新超过5次,detail 界面出现限流的错误信息。
mTLS
北极星网络支持服务间的mTLS认证及加密通讯,提供三种不同的服务粒度模式供用户选择:
| 模式 | 解释 |
|---|---|
| Permissive | 宽容模式,服务接受纯文本/mTLS服务调用;发起服务调用时,根据对端接受状况自动选择发起mTLS或纯文本服务调用 |
| Strict | 严格模式,服务仅接受/发起mTLS服务调用 |
| None | 无加密模式(为默认选项),服务仅接受/发起纯文本服务调用 |
启用方式
只需要在服务的metadata中加入键为polarismesh.cn/tls-mode的label即可开启该功能,可选的值为strict,permissive,none,无此label时或者值错误时,默认为无加密的none模式。
使用示例
部署polaris-security
polaris-security是北极星的证书机构,负责签发证书以供服务使用,是开启双向TLS功能的必要组件。
- 下载polaris-security
- 将示例证书/密钥加载为k8s secret:
./deploy/load-certs-into-k8s.sh - 验证secret加载成功:
kubectl get secrets -n polaris-system - 使用Helm部署
polaris-security,cd deploy/helm && helm install polaris-security . - 验证polaris-security部署成功:
kubectl get po -n polaris-system | grep polaris-security
部署mTLS版bookinfo示例
- 下载样例部署文件:mTLS版bookinfo
- 执行部署:
kubectl create -f bookinfo.yaml
mTLS版bookinfo在配置文件中使用polarismesh.cn/tls-mode的label为不同的服务启用了各自的双向TLS模式,部署完成后服务调用图如下所示:
效果验证
-
Strict模式验证 由于
Reviews V3服务使用了None模式,它将向Ratings服务发起纯文本请求,而Ratings服务使用了Strict模式,仅接受mTLS服务调用,因此Reviews V3到Ratings之间的服务调用总会失败。
因此,使用浏览器访问部署好的ProductPage,无论怎么刷新都无法看到红色的星星评级。 -
mTLS 验证 使用 Wireshark 抓包验证 mTLS 启用,如下图:
可以看到 Server 向 Client 提供证书后,要求 Client 提供自身证书,验证通过后方可开始加密数据通信。
相关链接
6.5 - DNS 接入
技术原理
在 Polaris 的 DNS 服务发现接入方案中,Polaris 是您的控制平面,Polaris Sidecar 作为本地 DNS 服务器实现服务发现以及动态路由。
Kubernetes 场景
- polaris-server: 北极星服务端,处理服务注册以及服务发现请求。
- polaris-controller: 完成 polaris-sidecar 容器注入到业务 POD 中,并下发 iptables 指令拦截业务容器的 DNS 请求,将其转发到 polaris-sidecar 中
- polaris-sidecar: 作为本地 DNS 服务器,将 DNS 域名解析为北极星中的服务,实现服务发现。
虚拟机场景
- polaris-server: 北极星服务端,处理服务注册以及服务发现请求。
- polaris-sidecar: 作为本地 DNS 服务器,将 DNS 域名解析为北极星中的服务,实现服务发现。
配置解读
虚拟机
- polaris-sidecar.yaml 内容和配置介绍如下:
bind: 0.0.0.0 # DNS 服务器监听IP
port: 53 # DNS 服务器监听端口
namespace: default # polaris-sidecar 所在的命名空间
polaris:
addresses:
- ${POLARIS_ADDRESS} # Polaris Server访问地址, 示例:127.0.0.1:8091
location:
providers:
- type: local # 当前仅支持local插件
options:
region: ${REGION} # 地址位置信息,可设置环境变量REGION或直接赋值
zone: ${ZONE} # 地址位置信息,可设置环境变量ZONE或直接赋值
campus: ${CAMPUS} # 地址位置信息,可设置环境变量CAMPUS或直接赋值
nearby_match_level: campus # 就近路由匹配范围
recurse: # 递归解析,当 polaris-sidecar 自己无法解析域名时,会转发给上一级 DNS 服务器继续解析
enable: true
timeoutSec: 1
resolvers: # DNS 解析插件
- name: dnsagent # DNS 代理插件
enable: true # 插件是否启用
dns_ttl: 10 # dns 记录的客户端 TTL
suffix: "." # 决定哪些域名解析会被 polaris-sidecar 解析,默认为全部域名,示例:".abc"
option:
route_labels: "key: value" # 主调方的静态标签信息,用于服务路由, 示例: "key1:value1,key2:value2"
容器
- dnsagent在k8s环境下,在主调方的部署 yaml 中支持如下配置,说明和示例如下
- 路由配置:主调方的静态标签信息,key 为 env, value 为 dev;
- 递归配置:开启递归解析,请求下一个 nameserver 的超时时间为 5 秒;
- dns代理解析配置:解析的后缀为.dns-test,客户端 DNS 解析记录TTL 为 3 秒;
- 就近路由配置:地理信息为 region为huanan,zone 为ap-guangzhou,campus 为ap-guangzhou-6,就近路由匹配范围为 campus
spec:
template:
metadata:
labels:
env: dev
annotations:
polarismesh.cn/sidecarConfig: |
{
"recurse": {
"enabled": true,
"timeout": 5
},
"dns": {
"suffix": ".dns-test",
"ttl": 3
},
"location": {
"region": "huanan",
"zone": "ap-guangzhou",
"campus": "ap-guangzhou-6",
"match_level": "campus"
}
}
......
快速接入
基于 DNS 的北极星服务发现接入支持虚拟机以及 kubernetes 两种部署环境。您可以根据实际部署场景选择其中一种接入方式。
虚拟机接入
部署 polaris
如果已经部署好了 polaris,可忽略这一步。
安装 polaris-sidecar
-
虚拟机安装过程需要使用 root 用户或者具有超级管理员权限的用户来执行,并且确保 53(udp/tcp)端口没有被占用。
-
需要从 Releases 下载最新版本的安装包。
-
上传安装包到虚拟机环境中,并进行解压,进入解压后的目录。
unzip polaris-sidecar-release_$version.$os.$arch.zip
修改 polaris-sidecar 配置
-
修改 polaris.yaml,写入部署好的北极星服务端的地址,端口号使用8091(GRPC端口)。
-
进入解压后的目录,执行 tool/start.sh 进行启动,然后执行 tool/p.sh 查看进程是否启动成功。
# bash tool/start.sh # bash ./tool/p.sh root 15318 1 0 Jan22 ? 00:07:50 ./polaris-sidecar start -
使用 root 权限修改 /etc/resolv.conf,在文件中添加 nameserver 127.0.0.1,并且添加到所有的 nameserver 记录前面,如下:
; generated by /usr/sbin/dhclient-script nameserver 127.0.0.1 nameserver x.x.x.x
验证
使用格式为<service>.<namespace>的域名进行访问,预期可以获得服务下某个实例的 IP 地址。
➜ dig polaris.checker.polaris
...
;; ANSWER SECTION:
polaris.checker.polaris. 10 IN AAAA ::ffff:127.0.0.1
...
到这里,在虚拟机环境下通过 DNS 接入北极星的服务发现就完成了。
Kubernetes 接入
部署 polaris
如果已经部署好了 polaris,可忽略这一步。
部署 polaris-controller
开启 polaris-sidecar 注入
-
方式一: 通过label 命令为某个 kubernetes 命名空间启用 polaris-sidecar 注入:
# 为某个 kubernetes 命名空间开启 polaris sidecar 的注入 kubectl label namespace ${kubernetes namespace} polaris-injection=enabled # 设置注入的 polaris sidecar 以 dns 模式运行 kubectl label namespace ${kubernetes namespace} polaris-sidecar-mode=dns -
方式二:通过 kubectl apply -f ns.yaml 创建命名空间
# k8s命名空间部署yaml-命名空间下pod默认注入sidecar apiVersion: v1 kind: Namespace metadata: name: dns-test labels: # 往pod中注入polaris sidecar polaris-injection: enabled # sidecar类型为dns polaris-sidecar-mode: dns
验证
-
下载样例部署文件
-
执行部署:
kubectl create -f deployment.yaml -
查看容器注入是否注入成功,启动自动注入后,
polaris-controller会将Polaris Sidecar容器注入到在此命名空间下创建的 pod 中。可以看到运行起来的 pod 均包含两个容器,其中第一个容器是用户的业务容器,第二个容器是由 Polaris Controller 注入器注入的 Polaris Sidecar 容器。您可以通过下面的命令来获取有关 pod 的更多信息:kubectl describe pods -l k8s-app=polaris-dns-provider --namespace=default -
进入验证 POD, 执行 curl 命令
kubectl exec -it polaris-dns-consumer-xxx -n default -- /bin/bash curl http://echoserver.default:10000/echo
使用高级功能
在使用高级功能时,先创建一个测试服务,用于接下来的功能测试
使用就近路由
可以通过设置环境变量,指定 polaris-sidecar 实例所处的地理位置信息,当 polaris-sidecar 执行 DNS 服务发现时,会根据自身的地域信息,对目标服务实例进行就近匹配。
假定一个场景:
- 存在以下三个地域
- region=region-1、zone=zone-1、campus=campus-1
- region=region-2、zone=zone-2、campus=campus-2
- region=region-3、zone=zone-3、campus=campus-3
- polaris-sidecar 如果处于 region=region-1、zone=zone-1、campus=campus-1,则优先选择相同地域的实例
使用方式
- 设置地域信息环境变量
export REGION=${ REGION 信息 } export ZONE=${ ZONE 信息 } export CAMPUS=${ CAMPUS 信息 } - 重启 polaris-sidecar
bash tool/stop.sh bash tool/start.sh
-
调整主调的 annotation,配置 sidecarConfig 里面的 location 信息
... spec: template: metadata: annotations: polarismesh.cn/sidecarConfig: | { "location": { "region": "region-1", "zone": "zone-1", "campus": "campus-1", "match_level": "campus" } } ... -
重建 POD
kubectl delete pod {POD 名称} --namespace {命名空间}
验证
执行 dig 命令验证
# 地域信息分别为 region=region-1、zone=zone-1、campus=campus-1
➜ dig test.echoserver.default
...
;; ANSWER SECTION:
test.echoserver.default. 10 IN A 1.1.1.1
...
# 地域信息分别为 region=region-2、zone=zone-2、campus=campus-2
➜ dig test.echoserver.default
...
;; ANSWER SECTION:
test.echoserver.default. 10 IN A 2.2.2.2
...
# 地域信息分别为 region=region-3、zone=zone-3、campus=campus-3
➜ dig test.echoserver.default
...
;; ANSWER SECTION:
test.echoserver.default. 10 IN A 3.3.3.3
...
使用动态路由
假定一个场景:
- 希望 env 为 dev 的请求,路由到 env 标签为 dev 的实例上
- 希望 env 为 pre 的请求,路由到 env 标签为 pre 的实例上
- 其他则路由到 env 标签为 prod 的实例上
- 当前 DNS 服务发现仅支持静态标签动态路由,暂不支持请求级别的动态路由
- 动态路由相关规则配置请参考: 控制台使用-动态路由
使用方式
- 调整 polaris-sidecar 配置文件
... resolvers: - name: dnsagent ... option: route_labels: "env:dev" - 重启 polaris-sidecar
bash tool/stop.sh bash tool/start.sh
- 调整主调的静态标签信息
... spec: template: metadata: labels: env: dev ... - 重建 POD
kubectl delete pod {POD 名称} --namespace {命名空间}
验证
执行 dig 命令验证
# 设置 route_labels: "env: dev"
➜ dig test.echoserver.default
...
;; ANSWER SECTION:
test.echoserver.default. 10 IN A 1.1.1.1
...
# 设置 route_labels: "env: pre"
➜ dig test.echoserver.default
...
;; ANSWER SECTION:
test.echoserver.default. 10 IN A 2.2.2.2
...
# 设置 route_labels: ""
➜ dig test.echoserver.default
...
;; ANSWER SECTION:
test.echoserver.default. 10 IN A 3.3.3.3
...
6.6 - JavaAgent 接入
提示
该文章仅适用于北极星服务端版本 >= 1.18.0, polaris-controller 版本 >= 1.7.0
技术原理
在 Polaris 的 JavaAgent 接入方案中,Polaris 是您的控制平面,Polaris JavaAgent 将北极星的服务治理能力通过字节码增强的方式,让业务应用无需任何代码改造即可享受到北极星的服务治理体验。
Kubernetes 场景
- polaris-server: 北极星服务端,处理服务注册以及服务发现请求。
- polaris-controller: 完成 polaris-javaagent 容器的注入以及在业务 POD 中无侵入的开启 Java Agent 的能力。
- polaris-javaagent-init: 负责将 polaris-javaagent 物料下载到业务 Container 中,同时初始化 Java Agent 所需要的配置信息。
注入Javaagent所依赖的注解信息
| 注解名称 | 注解描述 |
|---|---|
| polarismesh.cn/javaagentVersion | 需要注入的Javaagent版本号,对应是polaris-java-agent的release版本号 |
| polarismesh.cn/javaagentFrameworkName | 应用所使用的服务框架的名称,比如spring-cloud |
| polarismesh.cn/javaagentFrameworkVersion | 应用所使用的服务框架的版本,一般写的是大版本,比如hoxton, 2020, 2021 |
| polarismesh.cn/javaagentConfig | 用户自定义的JavaAgent配置,不填写的配置则使用默认配置,格式为JSON |
java-agent的configmap默认配置文件可以参考:javaagent-configmap.yaml
环境准备
部署polaris
如果已经部署好了polaris,可忽略这一步。
polaris支持在kubernetes环境中进行部署,注意必须保证暴露HTTP端口为8090,gRPC端口为8091。具体部署方案请参考:
部署 polaris-controller
快速接入
服务调用关系说明
启用 POD 注入功能
创建命名空间 javaagent
kubectl create namespace javaagent
为 javaagent 命名空间启用注入:
kubectl label namespace javaagent polaris-injection=enabled
使用一下命令来验证 javaagent 命名空间是否已经正确启用:
kubectl get namespace -L polaris-injection
此时应该返回:
NAME STATUS AGE POLARIS-INJECTION
javaagent Active 3d2h enabled
启用 JavaAgent 自动注入
- polaris-controller 需要 >= 1.7.0 版本
在 POD 中添加以下 annonations 即可
apiVersion: v1
kind: Pod
metadata:
name: annotations-demo
annotations:
polarismesh.cn/javaagent: "true"
polarismesh.cn/javaagentVersion: "{填写 polaris-java-agent 的版本}"
polarismesh.cn/javaagentFrameworkName: "spring-cloud"
polarismesh.cn/javaagentFrameworkVersion: "hoxton|2020|2021 选择对应的版本填入"
查看 JavaAgent 是否注入成功
使用一下命令来验证 javaagent 命名空间是否已经正确启用:
kubectl describe pod {目标业务POD名称} -n {javaagent}
查看服务是否注册到北极星
通过日志确定
在应用启动日志中,可以搜索"[Bootstrap] javaagent inject successfully",出现该日志证明agent注入初始化成功。
然后在启动日志中,搜索"[BootStrap] plugin 插件ID has been loading",代表插件已经加载完毕。
查看北极星控制台确认
验证限流功能
设置限流规则
调用接口触发限流
验证路由功能
设置路由规则
不携带特定参数
携带特定参数
7 - 网关
7.1 - 使用 Nginx
kubernetes环境使用
部署polaris
如果已经部署好了polaris,可忽略这一步。
polaris支持在kubernetes环境中进行部署,注意必须保证暴露HTTP端口为8090,gRPC端口为8091。具体部署方案请参考:
访问限流
-
部署polaris-limiter:注意,如果使用的是1.12之前版本的polaris单机版,则需要额外部署polaris-limiter,作为分布式限流的集中式token-server。部署方法可参考:polaris-limiter
-
获取样例:下载最新版本的nginx-gateway的release,获取对应版本的源码包:Source code (zip)。
-
部署文件说明:以1.1.0-beta.0为例,源码包名称为:nginx-gateway-1.1.0-beta.0.zip,解压后,部署文件为examples/ratelimit/nginx.yaml,里面包含有如下环境变量,用户可以按照自己的需要进行修改。
| 变量名 | 默认值 | 说明 |
|---|---|---|
| polaris_address | polaris.polaris-system:8091 | 北极星服务端地址,8091为GRPC端口 |
| polaris_nginx_namespace | default | 网关服务所在的命名空间 |
| polaris_nginx_service | nginx-gateway | 网关服务所在的服务名,用于查找并关联限流规则 |
| polaris_nginx_ratelimit_enable | true | 是否启用限流功能 |
- 部署样例:以1.1.0-beta.0为例,源码包名称为:nginx-gateway-1.1.0-beta.0.zip
unzip nginx-gateway-1.1.0-beta.0.zip
cd nginx-gateway-1.1.0-beta.0
kubectl apply -f examples/ratelimit/nginx.yaml
- 配置限流规则
在北极星控制台新建一个限流规则,服务名和命名空间分别选择nginx-gateway以及default,设置根据http header(user=1000)进行流量限制。
- 验证限流效果
通过postman,在http请求中带上头信息:user:1000,一分钟超过5次调用,会返回限流错误。
虚拟机环境使用
部署polaris
如果已经部署好了polaris,可忽略这一步。
polaris支持在linux虚拟机环境中进行部署,注意必须保证暴露HTTP端口为8090,gRPC端口为8091。具体部署方案请参考:
安装nginx网关
-
下载安装包:可以在GITHUB的版本页面下载最新的虚拟机安装包,当前只提供基于ubuntu-latest编译的虚拟机安装包,如需其他版本,可以通过源码编译的方式来进行打包。版本下载地址:release
-
解压安装包:以nginx-gateway-release-1.1.0-beta.0.linux.x86_64.tar.gz为例。
tar xf nginx-gateway-release-1.1.0-alpha.6.linux.x86_64.tar.gz
cd nginx-gateway-release-1.1.0-alpha.6.linux.x86_64
- 修改端口号(可选):nginx默认端口号为80,如需修改端口号,可以通过编辑conf/nginx.conf配置文件进行修改。
http {
server {
listen 80; #这里修改成希望监听的端口号
}
}
- 添加环境变量(可选):可通过添加环境变量的方式,指定nginx-gateway对应的参数设置。环境变量说明。
| 变量名 | 默认值 | 说明 |
|---|---|---|
| polaris_address | polaris.polaris-system:8091 | 北极星服务端地址,8091为GRPC端口 |
| polaris_nginx_namespace | default | 网关服务所在的命名空间 |
| polaris_nginx_service | nginx-gateway | 网关服务所在的服务名,用于查找并关联限流规则 |
| polaris_nginx_ratelimit_enable | true | 是否启用限流功能 |
-
重启nginx
cd nginx-gateway-release-*/sbin bash stop.sh bash start.sh
其他资料
- 如果需要编译Nginx网关,可以参考:nginx-gateway
7.2 - 使用 Envoy
部署polaris
kubernetes环境使用
如果已经部署好了polaris,可忽略这一步。
polaris支持在kubernetes环境中进行部署,注意必须保证暴露HTTP端口为8090,gRPC端口为8091。具体部署方案请参考:
虚拟机环境使用
如果已经部署好了polaris,可忽略这一步。
polaris支持在linux虚拟机环境中进行部署,注意必须保证暴露HTTP端口为8090,gRPC端口为8091。具体部署方案请参考:
Envoy Gateway 启动配置
node:
# Envoy 的 node 配置必须遵守以下规则
id: "gateway~${envoy gateway 网关服务所在的命名空间}/${UUID}~${envoy 节点IP}"
metadata:
gateway_service: ${envoy gateway 网关服务名称}
gateway_namespace: ${envoy gateway 网关服务所在的命名空间}
dynamic_resources:
ads_config:
api_type: GRPC
transport_api_version: V3
grpc_services:
- google_grpc:
target_uri: ${北极星服务端IP}:15010
stat_prefix: polarismesh
channel_args:
args:
grpc.http2.max_ping_strikes:
int_value: 0
grpc.keepalive_time_ms:
int_value: 10000
grpc.keepalive_timeout_ms:
int_value: 20000
- 当前推荐 envoy 版本为 envoyproxy/envoy-contrib:v1.21.4
- 必须在北极星创建 envoy gateway 的服务,其服务名为 ${node.metadata.gateway_service}, 所在命名空间为 ${node.metadata.gateway_namespace}
创建 Envoy Gateway 使用的路由规则
假定现在有两个服务 service-a 以及 service-b,希望 Envoy Gateway 能够按照以下规则路由到特定的服务
- 路由到 service-a
- 条件 1: http path 为 /api/v1/service-a
- 路由到 service-b
- 添加 1: http path 为 /api/v1/service-b
- Envoy Gateway 的路由规则中,请求匹配条件必须包含 路径,否则路由规则无法转为 Envoy Gateway 所需的 XDS 进行下发
那么需要按照下列步骤准备
准备 Envoy 启动配置
- 参考 Envoy Gateway 启动配置 创建 gateway_xds_test.yaml
# 这里只给出 node 节点部份的配置 node: id: "gateway~default/c962adc3-673e-4637-9ba8-969d755ef66a~127.0.0.1" cluster: "CLUSTER_NAME" metadata: gateway_service: EnvoyGateway gateway_namespace: default - 在北极星上创建服务,服务名为 EnvoyGateway, 所在命名空间为 default
创建路由到 service-a 的路由规则
创建路由到 service-b 的路由规则
运行 Envoy Gateway
docker run -it --rm -p 15001:15001 -p 15000:15000 -v $(pwd)/gateway_xds_test.yaml:/gateway_xds_test.yaml envoyproxy/envoy-contrib:v1.21.4 -c /gateway_xds_test.yaml
查看 Envoy Gateway 收到的 XDS 规则
进入 envoy 容器执行以下命令
curl http://127.0.0.1:15000/config_dump
如果 RoutesConfigDump 如下,则 XDS 规则获取成功
{
"@type":"type.googleapis.com/envoy.admin.v3.RoutesConfigDump",
"dynamic_route_configs":[
{
"version_info":"2023-04-01T01:06:47+08:00/9",
"route_config":{
"@type":"type.googleapis.com/envoy.config.route.v3.RouteConfiguration",
"name":"polaris-router",
"virtual_hosts":[
{
"name":"gateway-virtualhost",
"domains":[
"*"
],
"routes":[
{
"match":{
"path":"/api/v1/service-a"
},
"route":{
"weighted_clusters":{
"clusters":[
{
"name":"service-a",
"weight":100,
"metadata_match":{
"filter_metadata":{
"envoy.lb":{
"env":"prod"
}
}
}
}
],
"total_weight":100
}
}
},
{
"match":{
"path":"/api/v1/service-b"
},
"route":{
"weighted_clusters":{
"clusters":[
{
"name":"service-b",
"weight":100,
"metadata_match":{
"filter_metadata":{
"envoy.lb":{
"env":"prod"
}
}
}
}
],
"total_weight":100
}
}
},
{
"match":{
"prefix":"/"
},
"route":{
"cluster":"PassthroughCluster"
}
}
]
}
],
"validate_clusters":false
},
"last_updated":"2023-03-31T17:06:47.547Z"
}
]
}
请求验证
curl http://127.0.0.1:15001/api/v1/service-a
# 期望输出:I'm service-a
curl http://127.0.0.1:15001/api/v1/service-b
# 期望输出:I'm service-b
附录:Demo 程序
package main
import (
"io"
"log"
"net/http"
"os"
)
func main() {
handler := func(w http.ResponseWriter, req *http.Request) {
io.WriteString(w, "I'm "+os.Getenv("SERVICE_NAME"))
}
http.HandleFunc("/", handler)
log.Fatal(http.ListenAndServe(":"+os.Getenv("PORT"), nil))
}