这是本节的多页打印视图。 点击此处打印.

返回本页常规视图.

使用指南

介绍北极星控制台、控制面和数据面的使用方式,让您学会在不同的技术栈和环境中使用北极星。

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版本:

下载后需要进行解压,如果有需要自定义单机版相关组件的监听端口,需修改压缩包内的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

安装分布式限流组件

下载软件包:下载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"

安装分布式限流组件

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.dbpolaris.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} . 

检查安装

部署后可以通过以下命令观察到 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.typeLoadBalancer 则可以使用 polaris 的 service 的 EXTERNAL-IP:webPort 访问到北极星的页面。 如果您的k8s 集群不支持 LoadBalancer ,可以将 service.typeNodePort ,通过 nodeip:nodeport 访问。

配置项说明

参数名 参数解释
global.mode 集群类型,支持 cluterstandalone ,表示集群版和单机版
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"
    }
}'

可选 开启二次寻址

在大规模集群(百万级别服务)场景下,可对对北极星按照功能模块进行集群拆分,注册发现、健康检查、控制台操作划分为不同集群来进行处理,各集群相互独立,可按照请求量独立扩展。客户端通过埋点集群的二次寻址机制,为接口寻址到目标集群进行功能接口的调用。

二次寻址.png

服务端配置

注册发现集群的 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 插件

客户端的 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

服务配置

  • 在控制台上通过可视化的方式操作开关就近路由。

就近流程

route_nearby

初始化

  • 用户调用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 - 配置导入导出

导出配置文件

导航到配置分组,点击上方导出按钮弹出配置导出对话框。

选择要导出的配置文件所在命名空间。

提供两种导出形式:

  1. 全部导出:将命名空间中的配置分组全部导出

  1. 导出选中的配置分组:选择命名空间中的配置分组导出

选择完成后,点击提交按钮导出配置,配置文件会已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文件,修改完后执行以下命令进行重启polaris

    bash tool/stop.sh
    bash tool/start.sh
    

    bash 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变更

如何创建鉴权策略

  • 单击新建策略。填写策略基本信息,在角色栏可以选择需要授权用户或用户组,单击下一步选择授权的资源。

  • 在资源栏可选择北极星的资源类型,包括命名空间、服务等资源,主账号可对所有资源进行操作。

  • 单击下一步,进入预览界面,详细展示该策略涉及的用户、用户组以及资源。确认信息无误后,单击完成。

  • 主账号可在权限策略列表查阅现有的权限策略,可单击编辑进行授权或删除等操作。

新建资源如何选择可操作用户

创建命名空间

在命名空间页面中,点击新建,在弹出页面中,点击高级选择可以操作本资源的用户或者用户组。

创建服务

在服务列表页面中,点击新建,在弹出页面中,点击高级选择可以操作本资源的用户或者用户组。

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>

然后只需要在 标签中在添加 polaris-all 即可

<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、被熔断的实例。

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>

然后只需要在 标签中在添加 polaris-all 即可

<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 结构体后,只需要调用 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>

然后只需要在 标签中在添加 polaris-all 即可

<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();
    }
}

样例地址

Github地址

熔断单个接口

配置熔断规则

配置接口熔断规则,针对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();
    }
}

样例地址

Github地址

熔断单个实例

配置熔断规则

配置实例熔断规则,针对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>

然后只需要在 标签中在添加 polaris-all 即可

<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));
}

样例地址

Github地址

启用主动探测

业务往往会存在高峰期和低峰期,低峰期流量比较少,不足以触发熔断,会出现当部分实例出现数据不可达的问题时,没法及时发现,导致高峰期到来时出现故障。

主动探测可以解决这个问题,启用主动探测后,主调方会定时根据探测规则,对被调实例进行探测,探测结果可作为熔断的判断依据,可实现对故障资源的快速熔断。

配置主动探测规则

配置一个主动探测规则,对服务(名为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>

然后只需要在 标签中在添加 polaris-all 即可

<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 结构体后,只需要调用 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>

然后只需要在 标签中在添加 polaris-all 即可

<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>

然后只需要在 标签中在添加 polaris-all 即可

<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>

然后只需要在 标签中在添加 polaris-all 即可

<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 应用级注册发现 仅适用于北极星服务端版本 &gt;= 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 个工程。

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),字段格式

功能验证

针对 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}

代码中无需额外添加限流判断代码,插件会自动在被调端进行请求的限流计算和拦截。

最终限流效果

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个工程,代表的是主调端和被调端,限流行为工作在被调端。

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}

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 批量服务实例查询请求
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()

GetOneInstances

每次仅获取一个可用服务提供者实例,该方法会依次执行路由、负载均衡流程。

该方法默认会过滤掉不健康、隔离、权重为0、被熔断的实例。

// 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 结构体之后,只需要调用 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()

负载均衡请求

// ProcessRoutersRequest 执行负载均衡请求结构体
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)

样例地址

Github地址

熔断单个接口

配置熔断规则

配置接口熔断规则,针对 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)

样例地址

Github地址

熔断单个实例

配置熔断规则

配置实例熔断规则,针对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)

样例地址

Github地址

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 结构体完成初始化后,只需要调用 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 - 配置管理

引入依赖

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.7 - 可观测性

引入依赖

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.8 - 二次寻址

引入依赖

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}   # 如果北极星服务端开启了针对客户端的鉴权,则需要配置该参数

如何配置服务路由参数

dubbogo 中的 PolarisMesh PriorityRouter 扩展点实现,能够根据用户配置的服务路由规则,自动的从当前 RPC 调用上下文以及请求信息中识别出需要参与服务路由的请求标签信息。

假定一个场景:

  • 希望 uid 为 user-1 的请求,路由到 environment 标签为 pre 的实例上
  • 希望 uid 为 user-2 的请求,路由到 environment 标签为 dev 的实例上
  • 其他则路由到 environment 标签为 prod 的实例上,那可以为 dubbogo 服务设置三条路由规则。

  • 请求匹配规则为 请求参数(QUERY)
    • 标签来源: RPC 调用中方法的入参,即 Invoaction.Arguments()
    • 标签键规则
      • 方法仅有一个入参: param.$.${fieldName}, param. 为固定前缀,后面的表达式为标准的 JSONPath expressions,参考文档
      • 方法有多个参数: param[${index}].$.${fieldName}, param[${index}]. 为固定前缀,${index} 代表是方法入参中的第几个参数,下标起始位置从 0 开始;后面的表达式为标准的 JSONPath expressions,参考文档
  • 请求匹配规则为 请求头(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 即可

如何配置服务限流参数

dubbogo 中的 PolarisMesh TpsLimiter 扩展点实现,能够根据用户配置的限流规则,自动的从当前 RPC 调用上下文以及请求信息中识别出需要参与限流的请求标签信息。

比如对 dubbogo 中的 GetUser 方法,对请求参数 Name 为 Alex 的请求进行限流,速率为10/s。

  • 请求匹配规则为 请求参数(QUERY)
    • 标签来源: RPC 调用中方法的入参,即 Invoaction.Arguments()
    • 标签键规则
      • 方法仅有一个入参: param.$.${fieldName}, param. 为固定前缀,后面的表达式为标准的 JSONPath expressions,参考文档
      • 方法有多个参数: param[${index}].$.${fieldName}, param[${index}]. 为固定前缀,${index} 代表是方法入参中的第几个参数,下标起始位置从 0 开始;后面的表达式为标准的 JSONPath expressions,参考文档
  • 请求匹配规则为 请求头(HEADER):
    • 标签来源: RPC 调用的额外标签信息,即 Invoaction.Attachments()

验证

可根据 dubbogo example 开展

4.3 - 使用 gRPC-Go

4.3.1 - 服务注册

引入依赖

go get github.com/polarismesh/grpc-go-polaris-go@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方法

编译安装

下载源码

支持两种方式下载源码:

  1. 使用git clone源码然后切到最新的tag
  2. 直接在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库符号。该方案只支持业务链接北极星动态库时可用。

具体步骤如下:

  1. 到北极星源码根目录下执行rm -rf third_party/protobuf/build* 删除编译出来的protobuf库

  2. 修改北极星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"即可

  1. 在北极星根目录执行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、被熔断的实例。

/// @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、被熔断的实例。

/// @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、被熔断的实例。

/// @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)

如何基于 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());
}

服务路由

GetInstances

每次获取一批可用服务提供者实例,该方法会执行路由流程。

该方法默认会过滤掉不健康、隔离、权重为0、被熔断的实例。

/// @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 结构体完成初始化后,只需要调用 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 自动注入功能

  • 创建命名空间 bookinfokubectl 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 按需加载机制

在 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 SidecarPolaris 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种类型的属性来进行路由。

  1. 使用场景

demo 项目中,productpage 会访问 reviews 服务,reviews 服务共有三个实例,三个实例分别部署了三个版本(会显示红、黑、无三种颜色的星星),需要保证特定的灰度用户(用户名为jason),请求到特定版本的 reviews 服务。

  1. 配置路由规则

为 reviews 服务创建路由规则。将请求中 header 包含字段 end-user=jason 的请求,路由到 version=v2 的服务实例中。同时再创建一条路由规则,指定标签键值为任意请求,路由到 version=v1 的服务实例中。

路由规则的标签填写格式要求:

  • 对于Path:标签KEY需要填写 $path
  • 对于Header:标签KEY需要带上前缀 $header,如 $header.end-user
  • 对于Query:标签KEY需要带上前缀 $query,如 $query.end-user
  1. 验证路由是否生效

未登陆时,刷新 productpage 的页面,可以看到只返回没有颜色的星星(version=v1)。当使用 jason 登陆后,productpage 请求 reviews 时,会带上 header,end-user=jason,此时再刷新 productpage 页面,发现只会显示黑色的星星,即上面 version=v2 的实例。

访问限流

  1. 使用场景: demo项目中,为 detail 服务设置流量限制,对于jason用户的请求,设置访问的频率为5/m,其余请求不做限制。

  2. 设置限流规则: 指定请求中 header 包含字段 end-user=jason 的请求,设置限流规则为5/m,限流类型为分布式限流。

  3. 验证限流是否生效: 未登陆时,多次刷新界面,不会出现错误。以jason用户身份登陆,一分钟刷新超过5次,detail 界面出现限流的错误信息。

mTLS

北极星网络支持服务间的mTLS认证及加密通讯,提供三种不同的服务粒度模式供用户选择:

模式 解释
Permissive 宽容模式,服务接受纯文本/mTLS服务调用;发起服务调用时,根据对端接受状况自动选择发起mTLS或纯文本服务调用
Strict 严格模式,服务仅接受/发起mTLS服务调用
None 无加密模式(为默认选项),服务仅接受/发起纯文本服务调用

启用方式

只需要在服务的metadata中加入键为polarismesh.cn/tls-modelabel即可开启该功能,可选的值为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-modelabel为不同的服务启用了各自的双向TLS模式,部署完成后服务调用图如下所示:

效果验证

  1. Strict模式验证 由于Reviews V3服务使用了None模式,它将向Ratings服务发起纯文本请求,而Ratings服务使用了Strict模式,仅接受mTLS服务调用,因此Reviews V3Ratings之间的服务调用总会失败。
    因此,使用浏览器访问部署好的ProductPage,无论怎么刷新都无法看到红色的星星评级。

  2. mTLS 验证 使用 Wireshark 抓包验证 mTLS 启用,如下图:

可以看到 Server 向 Client 提供证书后,要求 Client 提供自身证书,验证通过后方可开始加密数据通信。

相关链接

Polaris

Polaris Controller

Polaris Demo

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 配置

bind: 0.0.0.0             # DNS 服务器监听IP
port: 53                  # DNS 服务器监听端口
namespace: default        # polaris-sidecar 所在的命名空间
recurse:                  # 递归解析,当 polaris-sidecar 自己无法解析域名时,会转发给上一级 DNS 服务器继续解析
  enable: false
  timeoutSec: 1
logger:                   # 日志配置
  output_paths:           # 标准输出打印
    - stdout
  error_output_paths:     # 错误日志通过标准错误输出打印
    - stderr
  rotate_output_path: logs/polaris-sidecar.log              # 日志持久化输出
  error_rotate_output_path: logs/polaris-sidecar-error.log  # 错误日志持久化输出
  rotation_max_size: 100            # 单个日志文件最大大小,单位 MB
  rotation_max_backups: 10          # 最多保存多少个日志文件
  rotation_max_age: 7               # 单个日志文件最大保存时间,单位天
  output_level: info                # 日志级别
resolvers:                          # DNS 解析插件
  - name: dnsagent                  # 普通的 DNS 解析
    dns_ttl: 10                     # dns 记录的 TTL
    enable: true                    # 插件是否启用
    suffix: "."                      # 决定哪些域名解析会先通过 polaris-sidecar,默认为全部域名,用户可以设置改配置来控制需要经过 polaris-sidecar 解析域名
    option: 
      route_labels: "key: value"    # 当前 polaris-sidecar 的静态标签信息,用于服务路由
  - name: meshproxy                 # 工作在 kubernetes 下的 mesh 模式
    dns_ttl: 120
    enable: false
    option:
      reload_interval_sec: 30       # 定时与北极星服务端进行同步服务列表
      dns_answer_ip: 10.4.4.4       # 返回给 envoy 的 IP 信息

polaris-go SDK 配置

global:
  serverConnector:
    addresses:
      - 127.0.0.1:8091      # 设置北极星服务端 gRPC 服务发现接入地址
  location:                 # 用于就近接入
    provider: env           # 默认从环境变量中读取地理位置信息

快速接入

基于 DNS 的北极星服务发现接入支持虚拟机以及 kubernetes 两种部署环境。您可以根据实际部署场景选择其中一种接入方式。

虚拟机接入

部署 polaris

如果已经部署好了 polaris,可忽略这一步。

安装 polaris-sidecar

  • 虚拟机安装过程需要使用 root 用户或者具有超级管理员权限的用户来执行,并且确保 53(udp/tcp)端口没有被占用。

  • 需要从 Releases 下载最新版本的安装包。

  • 上传安装包到虚拟机环境中,并进行解压,进入解压后的目录。

    unzip polaris-sidecar-release_$version.$os.$arch.zip
    
  • 修改 polaris.yaml,写入部署好的北极星服务端的地址,端口号使用8091(GRPC端口)。

    global:
      serverConnector:
        addresses:
          - {北极星服务端IP}:8091
    
  • 关闭系统自身的 dns resolve 进程

    # 关闭 systemd-resolved 进程
    systemctl stop systemd-resolved
    
    # 如果想恢复原本的 systemd-resolved,执行下面命令
    # systemctl start systemd-resolved
    
  • 进入解压后的目录,执行 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 注入

  • 为某个 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 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
    

使用高级功能

在使用高级功能时,先创建一个测试服务,用于接下来的功能测试

  • 创建测试服务 test.echoserver

使用就近路由

可以通过设置环境变量,指定 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 POLARIS_INSTANCE_REGION=${ REGION 信息 }
    export POLARIS_INSTANCE_ZONE=${ ZONE 信息 }
    export POLARIS_INSTANCE_CAMPUS=${ CAMPUS 信息 }
    
  • 重启 polaris-sidecar
    bash tool/stop.sh
    bash tool/start.sh
    

  • 调整 polaris-sidecar container 的 ENV 信息
    containers:
    - image: polarismesh/polaris-sidecar:${sidecar 的版本}
      name: polaris-sidecar
    ...
      env:
        - name: POLARIS_INSTANCE_REGION
          value: "{ REGION 信息 }"
        - name: POLARIS_INSTANCE_ZONE
          value: "{ ZONE 信息 }"
        - name: POLARIS_INSTANCE_CAMPUS
          value: "{ 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 的实例上

使用方式

  • 调整 polaris-sidecar 配置文件
    ...
    resolvers:
      - name: dnsagent
        ...
        option: 
          route_labels: "env:dev"
    
  • 重启 polaris-sidecar
    bash tool/stop.sh
    bash tool/start.sh
    

  • 调整 polaris-sidecar container 的 ENV 信息
    containers:
    - image: polarismesh/polaris-sidecar:${sidecar 的版本}
      name: polaris-sidecar
    ...
      env:
        - name: SIDECAR_DNS_ROUTE_LABELS
          value: "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 自动注入

在 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
    

其他资料

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 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 启动配置

  • 参考 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))
}