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

返回本页常规视图.

文档

了解北极星的应用场景和架构原理,学习怎么部署、使用和扩展北极星。

1 - 北极星是什么

介绍北极星的基础知识、功能特性和接入方式,让您对北极星有全面的了解。

1.1 - 简介

介绍北极星的背景、架构、功能,方便用户了解北极星能解决什么问题

北极星是腾讯开源的服务治理平台,致力于解决分布式和微服务架构中的服务管理、流量管理、配置管理、故障容错和可观测性问题,针对不同的技术栈和环境提供服务治理的标准方案和最佳实践。下面介绍北极星的应用场景、功能特性、系统组件和常见问题。

背景

应用架构经历了从单体到分布式服务或者微服务的演进,但是演进并不是替代,每种架构各有优劣。

单体架构

单体架构的全部代码都在一个应用里,适合小型业务系统的研发。如果应用的复杂度低,单体架构易于开发、测试、部署和伸缩。但是,随着功能模块和研发人员的增加,单体架构面临众多问题:

  • 故障扩散:如果某些功能模块发生异常,可能影响其他的功能模块。

  • 扩展性差:只能扩展整个应用,不能单独扩展某些热点功能,存在资源浪费。

  • 迭代效率低:不同功能无法独立迭代,任何改动都影响整个应用,增加开发、测试和发布成本。

  • 技术栈单一:全部功能只能采用相同的技术栈开发,引入新技术和升级新版本的难度太大。

微服务架构

对于中型以上规模的业务系统来说,更适合采用分布式服务架构,例如:微信支付这种超大型系统涉及上百个功能模块和上千名研发人员,采用单体架构简直是个灾难。因此,需要将不同的功能拆成分布式服务,每个服务由少量研发人员独立维护。

分布式服务可以解决单体架构的问题,但是用起来并不容易,需要配套的基础设施:

  • 本地函数调用变成远程服务调用,需要高效的网络请求框架。

  • 网络请求需要解决服务寻址、故障容错和各种应用场景中的流量调度问题。

  • 应用数量大幅增加,需要 CICD 流水线和发布平台简化应用的测试和运维工作。

微服务和分布式服务没有本质的区别,微服务更强调服务的粒度要细。在落地过程中,服务的粒度其实没有绝对的标准,要从实际问题出发选择合理方案,不要盲目追求微服务。

北极星致力于打造一个支持多语言、多框架的服务治理平台,帮助用户解决分布式服务或者微服务架构中的服务管理、流量管理、配置管理、故障容错和可观测性问题。

北极星具备哪些功能

北极星具备服务管理、流量管理、故障容错、配置管理和可观测性五大功能:

  • 服务管理:包含服务发现、服务注册、健康检查和元数据管理。

    • 服务发现:支持 HTTP、SDK 和 DNS 服务发现方式。
    • 服务注册:支持 HTTP、SDK、控制台操作和 K8s 服务注册方式。
    • 健康检查:支持服务实例上报心跳,通过心跳判断实例是否健康,及时剔除异常实例。
    • 元数据管理:支持在服务和实例上配置协议、版本和位置等标签,实现动态路由等功能。
  • 流量管理:包含动态路由、负载均衡和访问限流。

    • 动态路由:支持自定义路由策略,将服务的部分请求路由到部分实例,用于灰度发布等应用场景。
    • 负载均衡:支持权重轮训、权重随机和权重一致性 Hash 等负载均衡算法。
    • 访问限流:支持本地和分布式两种模式,被限流的请求支持排队和自定义响应。
  • 故障容错:包含服务熔断和节点熔断。

    • 服务熔断:对服务或者接口进行熔断,如果服务或者接口发生熔断,返回自定义响应。
    • 节点熔断:对服务实例进行熔断,不会将请求路由到熔断的服务实例,降低请求失败率。
    • 主动探测:服务和节点熔断除了被动探测,还支持主动探测,进一步降低请求失败率。
  • 配置管理:包含配置变更、配置校验、版本管理和灰度发布等功能。

  • 可观测性:提供业务流量、系统事件和操作记录等监控视图。

北极星的功能需要控制面和数据面配合实现:

  • 控制面:负责服务和配置数据的管理和下发,负责流量管理和熔断降级策略的管理和下发。

  • 数据面:负责全部服务发现和治理功能的客户端实现,采用插件化设计,支持按需加载和使用。

数据面功能分为三个部分:

  • 服务作为被调:当一个服务被其他服务调用时,可以使用服务注册、上报心跳、访问限流和访问鉴权功能。

  • 服务作为主调:当一个服务调用其他服务时,可以使用服务发现、动态路由、负载均衡和熔断降级功能。

  • 公共部分:支持拉取配置数据和上报监控数据。

北极星包含哪些组件

北极星的系统组件分为控制台、控制面和数据面三个部分:

  • 控制台:提供简单易用的管理页面,支持用户和权限管理。

  • 控制面:包含核心组件 Polaris 和可选的功能组件,核心组件可以满足绝大部分业务需求,可选的功能组件按需部署。

  • 数据面:提供多语言 SDK、开发框架、Java Agent 和网格代理四种形态的实现,满足不同的业务场景和开发模式,支持异构服务的互联互通和统一治理。

控制面组件:

  • Polaris:支持各种形态的数据面接入,支持服务和配置数据的管理和下发,支持流量管理和熔断降级策略的管理和下发,可以覆盖服务注册中心、服务网格控制面和配置中心的功能。

  • Polaris Controller:可选的功能组件,支持 K8s 服务同步和网格代理注入。K8s 服务同步将 K8s 服务按需同步到北极星,用户不需要在应用程序里显式地注册服务。网格代理注入按需在应用程序 Pod 里注入北极星 Sidecar,以流量代理的方式实现服务发现和治理功能。

数据面组件:

  • SDK:北极星提供轻量级的多语言 SDK,使用方法和绝大部分客户端软件类似,用户在应用程序里引入北极星 SDK。这种数据面形态以无流量代理的方式实现服务发现和治理功能,没有额外的性能和资源损耗,不会增加现网运维和问题定位的成本。

  • 开发框架:北极星 SDK 可以被集成到开发框架内部,如果用户使用开发框架,不需要显式地引入北极星 SDK。对于 Spring Cloud、Dubbo 和 gRPC 等开发框架,北极星提供可以无缝集成的依赖包。另外,go-micro、go-kratos、go-zero、GoFrame 和 CloudWeGo 等开发框架社区也提供北极星插件。

  • Java Agent:对于 Spring Cloud 和 Dubbo 等 Java 开发框架,北极星支持 Java 生态常用的 Agent 接入模式。用户只需要在应用程序的启动命令中引入 Polaris Java Agent,即可将北极星的服务发现和治理功能引入应用程序,不需要改动任何代码和配置文件。

  • 网格代理:北极星网格代理在应用程序 Pod 里注入 Polaris Sidecar 和 Proxy,前者通过劫持 DNS 解析将请求转到后者,后者通过流量代理实现服务发现和治理功能。这种数据面形态适合性能和资源损耗不敏感的业务,要求业务具备网格代理的运维能力。

常见问题

腾讯业务都在使用北极星吗?

北极星是腾讯内部协同共建的新一代服务发现和治理平台,已整合和替代 L5 等名字服务和负载均衡系统。截止2021年底,超过90%的业务部门使用北极星,接入节点数量超过千万。

北极星开源版和内部版相同吗?

开源版和内部版的主体功能和代码相同,但是部署架构不同。开源版提供单机和集群两种部署架构,集群架构支持百万级的节点接入。内部版通过插件的方式实现了更为复杂的部署架构,支持千万级的节点接入。

北极星和 TARS 是什么关系?

北极星和 TARS 都是腾讯在微服务领域的重点开源项目。曾经,腾讯内部存在多套服务开发框架、注册中心和治理组件,使用不同开发框架的服务难以互相调用和统一管理。为了解决这个问题,腾讯内部协同共建了北极星,整合了服务注册中心和治理组件,TARS 内部版的开发框架部分已接入北极星。北极星和 TARS 开源社区也会尝试更多合作。

1.2 - 功能特性

介绍北极星的主要核心功能的概念及原理

1.2.1 - 服务管理

服务注册

服务注册指的是被调方按照服务模型将自身的服务数据注册到北极星,以供主调方进行服务发现。

服务数据主要包括以下部分:

  • 服务名:服务的唯一标识,区分大小写。
  • 服务元数据:服务的标签信息,KV格式,可对服务进行分类,可用于过滤。
  • 服务实例:提供服务的节点列表,以IP:PORT的方式提供。
  • 服务实例元数据:服务实例的标签信息,KV格式,通常用于描述节点的集群、版本等,用于后续流量治理等操作。

服务注册的方式

北极星支持以下4种服务注册方式:

通过SDK注册

北极星提供了多语言SDK,服务可以通过集成SDK,调用registerInstance接口完成服务注册。

通过服务框架注册

服务框架会提供通用的服务注册接口,供应用在拉起的时候,自动往注册中心注册。

北极星对主流的服务框架(SpringCloud,Dubbo,gRPC)做了适配,用户无需修改业务逻辑代码,只需引入北极星的框架扩展库,即可实现自动注册。

通过k8s同步的方式注册

用户通过k8s部署服务,并注册为k8s的service,北极星通过controller的机制,从k8s中将service和endpoint信息同步到北极星,完成服务注册。

通过OpenAPI注册

北极星控制面提供基于Rest标准的OpenAPI,用户可通过OpenAPI完成服务注册的操作。

服务发现

服务发现指的主调方是根据服务名标识,拉取服务实例列表,以供后续进行服务调用的操作。

服务发现的方式

北极星支持以下4种方式进行服务发现:

通过SDK进行服务发现

北极星提供了多语言SDK,SDK通过ConsumerAPI提供3个接口进行服务发现:

  • getAllInstances:获取服务下全量的服务实例列表,不做任何过滤。
  • getHealthyInstances:获取服务下健康的服务实例列表,只包含健康实例,不包含被熔断、不健康、隔离、权重为0的实例。
  • getOneInstances:针对健康的服务实例列表,进行动态路由和负载均衡,返回单个可用的服务实例。

通过服务框架进行服务发现

服务框架会提供通用的服务发现接口,应用在RPC之前,会自动进行服务发现,获取到可用的实例进行RPC调用。

北极星对主流的服务框架(SpringCloud,Dubbo,gRPC)做了适配,用户无需修改业务逻辑代码,只需引入北极星的框架扩展库,即可实现自动发现。

使用DNS进行服务发现

北极星通过polaris-sidecar提供DNS功能,用户程序可以通过DNS域名访问的方式,实现无侵入的服务发现。

使用OpenAPI服务发现

北极星控制面提供基于Rest标准的OpenAPI,用户可通过OpenAPI完成服务发现的操作。

健康检查

健康检查提供了一种机制,使得控制面可以在一定时间段内,感知服务实例出现异常,从而将异常节点剔除,并通知给所有的消费者。健康检查支持以下实现形式:

心跳上报

服务实例持续上报心跳给控制面,并与控制面约定TTL的时间段,控制面检查服务实例的心跳上报时间点,当发现当前时间相比实例最后一次上报时间已经超过3*TTL,就将实例标记为不健康,并通知给该服务的消费者。

心跳上报

1.2.2 - 流量管理

动态路由

通常一个服务包含多个实例。在简单场景下,每个实例是对等的,通过负载均衡组件访问任意一个即可。

但是,在绝大部分场景下,每个实例具有逻辑属性和物理属性:

  • 逻辑属性:版本、协议、业务Set、特性环境等。北极星允许用户为每个实例设置自定义标签
  • 物理属性:地理位置。比如实例所属的地域-城市-园区的位置信息。

对于某个服务的全部实例,可以根据逻辑和物理属性将其划分成为多个分组或者集群,如下图所示:

服务主调方/消费者发送请求,客户端根据请求和主调方节点属性,将不同节点的不同请求路由到不同实例分组或者集群。

串联式路由插件

北极星动态路由组件采用插件化、可配置的方式实现。北极星默认内置以下路由插件:

  • 前置路由插件:默认在插件链的最前面执行,用于剔除隔离和权重为0的实例。
  • 规则路由插件:按照控制台配置的路由规则,根据用户请求参数执行路由规则进行服务实例的过滤。
  • 元数据路由插件:直接根据传入的实例元数据对服务实例进行过滤。
  • 就近路由插件:根据应用自身所属的地域信息,与实例的地域信息进行匹配,筛选出就近的服务实例。
  • 后置路由插件:剔除健康状态异常和故障熔断的实例。如果被剔除的节点数超过一定比例,返回前一个插件的筛选结果,防止因网络分区原因导致的误剔除。

当调用GetOneInstance接口时,会调用路由插件,执行动态路由进行实例筛选,执行流程如下图所示:

插件链中路由插件的执行顺序可以由用户自行编排,同时用户也可以定制自己的路由插件。

负载均衡

从满足本次转发要求的服务实例集中, 通过一定的均衡策略,选取一个实例返回给主调方,供主调方进行服务请求发送。

分类

负载均衡策略一般分为2类:

无状态负载均衡

无状态负载均衡策略,主要特点是每次负载均衡获取到的结果是由具体的负载均衡算法决定。目的是让负载均匀的分发到后端节点。

主要负载均衡策略包括:权重随机,权重轮询等

对于无状态的业务逻辑,为了保证后端节点能够均衡分配请求,此时应该选择权重随机负载均衡策略

有状态负载均衡

有状态负载均衡策略,除了要达到让负载均衡分散到节点的目标以外,还需要实现将同一对象的请求分发到同一个节点。例如业务场景需要将同一个用户的全部请求发送到后端同一个节点处理的情况。

主要负载均衡策略是一致性hash

算法

权重随机

权重随机负载均衡策略,利用区间算法,基于伪随机因子取模的方式选择对应服务实例。

对于有状态的业务逻辑(比如通过用户ID或者请求ID进行hash分区的),为了保证同key请求能够持续命中同一个物理节点,此时应该选择一致性hash负载均衡策略。

权重一致性hash(ringhash算法)

该负载均衡策略基于ketama环算法,每一个服务实例会按照权重分裂成若干个虚拟节点。虚拟节点通过取hash值的方式,映射到长度为2^32的hash环中。

发起查询时,北极星会基于用户传入的hashKey,计算出具体的hash值,然后到环中寻找hash值刚刚好大于传入数据hash值的虚拟节点,并返回其对应的服务实例

权重一致性hash(maglev算法)

该负载均衡策略基于maglev算法(https://static.googleusercontent.com/media/research.google.com/en//pubs/archive/44824.pdf)进行节点分配。

首先为实例集创建一个长度为质数65537的向量表,算法根据节点的权重,将向量表进行填充,直到向量表全部被节点所占满。取节点时则根据用户传值的hashValue取摸的方式,返回对应下标的节点。

算法优点:由于是直接取模寻址,因此算法性能相比ketama环要高(官方数据是在256K个插槽的情况下,性能是5X到10X的差距)。

算法缺点:当节点下线后,导致迁移的节点数量相比ketama环要多(官方数据为迁移节点数量是ketama的两倍)

权重设计

北极星的每个服务实例,都可以设置权重,请求会根据权重,按比例进行分配。权重分为静态权重和动态权重两类:

静态权重

用户可以通过界面配置或者实例注册的方式,调整服务实例的权重,由控制面推送给所有的数据面生效。

动态权重

数据面在运行过程中,定时上报负载数据给控制面,目前支持capacity&used两个指标, 被调方定时(一般2s)上报两个指标的数值到控制面,控制面根据负载信息,调整权重数据。主调方定时拉取最新的权重数据,实时更新以前的静态权重字段,复用老的weightrandom算法。

访问限流

限流能力是高并发系统中,对于服务提供方的一种保护手段。通过限流功能,我们可以通过控制QPS的方式,以避免被瞬时的流量高峰冲垮,从而保障系统的高可用性。

访问限流主要有如下两个应用场景:

  • 过载保护:保护业务不被突发流量打垮
  • 业务防刷:防止恶意用户发送过多流量影响其他正常用户

北极星为被调端服务提供2种类型的访问限流能力:

单机限流:针对单个被调实例的级别的限流,流量限额只针对当前被调实例生效,不共享。

分布式限流:针对服务下所有实例级别的限流,多个服务实例共享同一个全局流量限额。

两种限流模式如何选择?

  • 单机限流:一般适用于保护服务自身不被打垮,按照每个服务集群单机的容量来计算配额。
  • 分布式限流:一般适用于保护第三方服务或者公共服务(比如保护数据库);或者是在网关层进行限流,对通过网关接入的后端服务进行保护。

访问鉴权

访问鉴权包含以下3部分功能:

  • 认证:检验服务调用双方的身份真实性
  • 加密:对服务调用通讯数据进行加密
  • 鉴权:校验请求是否有访问服务接口的权限

访问鉴权可以有效地保护服务调用过程,防止中间人攻击、敏感数据泄露、数据越权访问等问题。

整体架构

Polaris支持使用mTLS来对服务调用进行认证与加密,整体架构如下所示:

  • polaris-security是Polaris的安全组件,在mTLS场景下,它支持作为中间证书签发机构(Intermediate Certificate Authority)使用。
  • Polaris Controller监测到用户服务启用mTLS功能后,会向Pod内自动注入所有启用mTLS功能需要的环境。
  • Polaris xDS Server会给启用mTLS的服务对应的Envoy sidecar下发相应的额外配置。
  • Polaris Sidecar中会额外启动mTLS agent组件,通过Unix Domain Socket通讯向Envoy提供SDS(Secret Discovery Service)能力。
  • mTLS agent组件会自动生成服务使用的身份证书及私钥,并自动进行轮转(rotate)。
  • 每当身份证书接近过期时,mTLS会向polaris-security发送CSR(证书签名请求)来进行更新。

证书签名及轮转原理

启动阶段

  • 用户启用mTLS功能之前,需要先在k8s集群中部署两个secret
  • polaris-security会读取polaris-security-secret,并为自身签发service certificate,用于在TLS握手中自证身份。
  • mTLS agent会读取polaris-sidecar-secret,用于TLS握手中验证polaris-security的身份。

证书签名

  • mTLS agent向polaris-security发起TLS保护的certificate signing request,polaris-security会提供自身的service certiface给mTLS agent验证。
  • 成功后,polaris-security从请求的header中提取出mTLS agent的Service Account Token,并使用Token Review请求的方式发送给Kubernetes API Server进行验证。
  • 验证成功后,正式进入证书签名流程,polaris-security会按CSR中的参数要求,使用CA私钥加密摘要,并将所有材料整合成已签名的证书,连同证书链一起返回给mTLS Agent。
  • mTLS Agent可以使用返回的材料来提供SDS服务,已签名的证书可以用作证明workload的身份;证书链可以用作验证对端workload的身份。

证书轮转

  • mTLS agent的Rotater类会负责证书轮转,它其实就是一个定时任务执行器,每隔一定时间间隔就会执行一次CSR发送任务,并根据返回结果更新SDS材料,请求失败则会自动重试。
  • 轮转时间间隔默认值为30分钟,证书TTL默认值为1小时,自动重试间隔默认为1秒。
  • polaris-security是一个无状态的组件,可以进行适当的水平扩展来保证高可用。

mTLS实现原理

Polaris提供三种不同的服务粒度模式供用户选择:

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

sidecar注入

  • mTLS的开关是用户服务的metadata中的polarismesh.cn/tls-mode键对应的label
  • 服务注册回调时,Polaris Controller的injector发现上述label的值为strict或permissve时,就会渲染出额外的注入配置:挂载secret及uds路径、开启iptables入流量拦截、为polaris-bootstrap-writer设置特殊的环境变量等。
  • polaris-bootstrap-writer检测到mTLS相关的环境变量被设置后,会使用一份mTLS专用的Envoy配置模版来进行渲染,这份模版中设置了sds的相关配置与特殊的node metadata,polaris控制面就是使用这个特殊的metadata来区分服务网格中的各个服务是否启用mTLS功能。

xDS

  • polaris控制面在给各个Envoy sidecar下发配置时,会根据node metadata中的mTLS相关信息来决定下发哪种配置。
  • 对于permissve模式,下发的listener会加入一个TLS Inspector filter配置,TLS Inspector能根据请求的头几字节自动判断这是纯文本请求或是mTLS请求,然后进行不同处理;下发的cluster会加入一个额外的Match条件,在对端endpoint拥有acceptMTLS metadata时,会使用tls transport socket,否则就使用默认的raw buffer transport socket。
  • 对于strict模式,下发的listener仅接受mTLS服务调用;而下发的cluster仅会使用tls transport socket来连接对端endpoint。

1.2.3 - 熔断降级

熔断降级

故障熔断,指的是当下游因过载或者BUG等原因,出现请求错误后,为了防止故障级联扩散导致整个链路出现异常,从而对请求进行拒绝或者重试的一种机制。

熔断模型

熔断模型的设计遵循业界标准的熔断器模型设计。熔断器有3类状态:

  • 关闭:所有请求皆可访问下游资源,无任何限制。
  • 打开:限制访问下游资源的请求,不允许任何请求的访问。
  • 半开:限制访问下游资源的请求,只允许部分请求达到下游。

熔断场景

熔断一般会发生在以下场景下:

硬件环境出现故障

服务在运营过程中,因为一些不可抗力的因素,可能会出现机器故障、机器重启、机房断电、网络中断等问题。通过熔断机制,对服务实例或者机房分组的快速熔断,可以避免业务请求持续失败。

版本上线引入BUG

版本新特性开发上线后,因为漏测等原因,某些分支触发了BUG,导致部分的业务逻辑出现故障。常见的是部分方法在遇到某些入参的时候,会出现进程报错或者高负载的问题,影响其他方法的请求处理。通过熔断机制,将故障方法进行屏蔽,可以避免其他业务请求受到影响。

服务出现过载

因为路由不均或者峰值流量的到来,导致被调服务出现了高负载,导致请求的时延增大,成功率降低。通过熔断机制,合理的拒绝一部分请求,可以降低服务负载,恢复正常的运行状态。

熔断级别

接口级熔断

应用与服务之间的调用都是针对接口进行调用,为避免调用故障接口导致业务整体时延较大,加剧后端的压力。用户可以设置熔断规则,按照整个服务或者服务下某个接口的粒度设置熔断阈值,并统计在调用过程中的错误率时延等数据,达到阈值后会进行熔断(熔断器打开)。熔断后,访问该服务或特定接口的请求都会返回失败或者走降级逻辑。

接口级熔断生效在接口调用前,主调服务访问接口前需要判断接口的熔断状态。

实例级熔断

一般用于远程服务调用(RPC)的场景,针对某个节点或者分组(具备相同标签的节点集)设置熔断阈值,实例级熔断往往按照具体的服务实例进行熔断统计,并统计在调用过程中的错误率时延等数据,达到阈值后会进行熔断。熔断后,该实例会被屏蔽,不会有请求路由进来,直到恢复。

接口级熔断生效在接口调用中,在负载均衡过程中完成对熔断状态实例的剔除。

触发熔断条件

连续错误数熔断

请求调用时,统计周期内,出现连续错误数目超过阈值之后,资源进入熔断状态。

错误率熔断

熔断器按照滑窗对请求总数及成功数进行统计,并汇总时间段内的总错误率,一旦超过阈值,资源进入熔断状态。

错误判断条件

系统需要通过错误请求的统计来判断是否需要触发熔断,请求的错误一般会表现出以下2个方面的特性:

返回的状态码

对于标准协议的请求,比如HTTP Response,常见的5XX等状态码,代表着后端出现异常(比如数据库异常)导致业务请求失败。

时延

对于交易系统等对时延比较敏感的系统,当出现后端数据库等负载过高的情况,导致部分请求可以正常处理,但是时延普遍过高,此时仍可认为这部分请求是失败请求,触发熔断处理。

熔断恢复

当资源的错误请求统计达到一定阈值后,资源会进入熔断状态,在接下来的一段时间内,该资源将会被屏蔽(不会有请求路由到该资源),渡过屏蔽期后,资源会进入半开状态,此时系统会放少部分业务请求给该资源,并记录请求的处理结果。假如请求全部处理成功,则资源恢复成功(熔断器关闭),取消屏蔽并正常处理业务请求。

但是,假如业务请求扔存在处理失败,则该资源会重新进入熔断状态,继续保持隔离。

如何使用

1.2.4 - 配置管理

配置中心

流程设计

客户端视角

应用启动时,同步从服务端拉取一次配置,获取最新的配置内容。

把第一步拉取到的所有的配置文件生成 ListVersion> 的数据 ,并向服务端发送订阅配置请求,请求内容为 ListVersion>。

当收到配置文件的推送消息时,向服务端拉取最新的配置文件。

配置服务端视角

先检查客户端 ListVersion> 的请求里是否存在 File 版本号落后,如果存在,则立马响应 File -> NewVersion 内容给客户端。

如果客户端配置文件版本号都是最新的,则在内存里维护 File -> List 的数据结构并 Hold 请求 30s。如果 30s 内有配置文件发布,则立马响应请求,返回 File -> NewVersion 给所有客户端。

发布推送配置简化流程

用户在界面点击发布按钮,服务端更新数据库里配置发布表的数据。配置发布表的核心字段:file, version, content, mtime

每个北极星服务端实例,都会定时1s扫描配置发布表,根据 mtime 捞出最近 1s 内变更过的数据

北极星服务端实例扫描到最新变更的数据之后

  • 重新加载内存缓存
  • 向内存里的消息发布管道里写入一条消息

推送协程从消息发布管道里获取到消息,并消费消息。通过 File -> List 信息,获取所有订阅配置文件的客户端信息,并响应客户端 Hold 的请求。

1.3 - 接入方式

介绍如何使用北极星数据面组件快速接入并使用北极星的功能

1.3.1 - 使用 SDK

功能简介

北极星网格提供多语言 SDK 作为高性能接入方式:

以插件化和配置化的方式实现服务发现和治理功能:

  • 被调方功能:服务注册、上报心跳、限流
  • 主调方功能:服务发现、动态路由、负载均衡、熔断降级
  • 观测性功能:服务调用、熔断降级和限流的监控统计

接口说明

被调方功能接口

Register

功能:注册服务实例
描述:将实例注册到某个服务下,实例信息包含地址和元数据

Deregister

功能:反注册服务实例
描述:将某个服务下的实例反注册
Heartbeat

功能:上报心跳
描述:如果在注册服务实例时,开启服务端健康检查功能,需要定期上报心跳到服务端,不然服务实例状态异常
GetLimitQuota

功能:获取请求处理配额
描述:如果使用限流功能,在每次处理请求之前,获取请求处理配额。若有配额,则处理请求,否则拒绝处理请求

主调方功能接口

GetAllInstances

功能:获取全部实例
描述:获取注册到某个服务下的全部实例,包含健康、异常和隔离的实例。本接口只使用服务发现功能模块
GetOneInstance

功能:获取一个可用实例
描述:在每次服务调用之前,获取一个可用实例。本接口使用服务发现、动态路由、负载均衡和熔断降级功能模块
备注:几个功能模块采用插件化设计,默认插件配置适用于基本场景,可以根据业务场景调整插件配置

UpdateServiceCallResult

功能:上报服务调用结果
描述:在每次服务调用之后,上报本次服务调用的结果。服务调用结果用于熔断降级和监控统计

接口使用说明

服务被调方

// 在应用启动阶段,注册服务实例
Register(namespace, service, instance)

// 如果使用服务端健康检查功能,在应用运行阶段,需要定期上报心跳到服务端
{
    Heartbeat(namespace, service, instance)
}

// 如果使用限流功能,在每次处理请求之前,获取请求处理配额
{
    if( GetLimitQuota(limiter) ) {
        Handle(request)
    } else {
        Refuse(request)
    }
}

// 在应用停止阶段,反注册服务实例
Deregister(namespace, service, instance)

服务主调方

// 发起一次服务调用
{
    // 获取本次服务调用的实例
    instance = GetOneInstance(namespace, service)

    // 发起服务调用
    response = ServiceCall(instance.address, request)

    // 上报本次服务调用的结果
    UpdateServiceCallResult(instance.id, response.code, response.delay)
}

快速入门示例

各语言 SDK 的快速入门示例:

Java语言

Go语言

C++语言

PHP语言

1.3.2 - 使用开发框架

功能简介

北极星 SDK 可以被集成到开发框架内部,如果用户使用开发框架,不需要显式地引入北极星 SDK,只需要依赖北极星相关的框架插件即可接入北极星。

当前支持以下框架的扩展接入:

开发框架如何集成北极星

北极星会基于服务框架原生的扩展接口之上,封装北极星的多语言SDK,接入北极星服务端实现服务发现、服务治理、配置管理等能力。

下图是SpringCloud框架集成的示意图,北极星只对原生的SpringCloud接口进行扩展,业务逻辑不感知这部分扩展,只需要通过修改POM引入相关的扩展依赖即可。

<dependencies>
  <!-- 示例:引入spring-cloud-starter-tencent-polaris-discovery插件,即可接入北极星服务注册发现功能-->
  <dependency>
     <groupId>com.tencent.cloud</groupId>
     <artifactId>spring-cloud-starter-tencent-polaris-discovery</artifactId>
  </dependency>
</dependencies>

1.3.3 - 使用 Java Agent

功能简介

对于Java应用,北极星 SDK 可以被通过字节码注入的方式,集成到开发框架内部,如果用户使用开发框架,不需要显式地引入北极星 SDK,只需要在启动时,通过-javaagent的指令加载使用JavaAgent,即可无缝接入北极星。

当前支持以下框架的JavaAgent扩展:

JavaAgent如何集成北极星

北极星会通过字节码注入的方式,将北极星的SDK,作为插件注入到服务框架原生的扩展接口之上,从而接入北极星服务端实现服务发现、服务治理、配置管理等能力。

用户无需修改POM,只需要在启动Java程序时,加入javaagent的JVM启动参数就可以。

java -javaagent:polaris-java-agent-bootstrap-${version}.jar -jar xxx.jar

1.3.4 - 使用 K8s 和网格代理

介绍北极星如何实现 K8s 服务注册和网格代理接入,以及它们的应用场景。

随着容器化的普及,越来越多用户使用 K8s 部署应用,北极星支持 K8s 服务注册和健康检查。另外,Linkerd 和 Istio 等服务网格通过流量劫持的方式实现大部分服务治理功能,北极星也支持这种接入方式。

K8s服务同步

架构原理

北极星提供polaris-controller,基于kubernetes的controller机制,监听service&pod事件,将K8s Namespace, Service以及Endpoint,实时同步成北极星对应的命名空间、服务、服务实例列表。

用户无需依赖任何SDK及框架,即可实现基于POD的服务实例注册、反注册和健康检查。

应用场景

北极星是一个计算与存储分离的系统,具备极强的可扩展性,一个北极星集群可以支持多个k8s集群同时接入。接入到同一个北极星的集群的多个k8s集群中的应用,可以共享同一份服务数据,实现集群间的无感知调用。

网格代理

架构原理

北极星支持Proxy网格模式,envoy数据面可以直接接入北极星控制面实现服务发现和治理。北极星支持自动注入envoy代理,用户程序无需做任何改动,即可实现自动往POD中注入envoy。

应用场景

北极星提供了多种框架的适配插件,可以支持当下比较流行的proxyless网格模式的接入。SpringCloud、Dubbo的应用可以零改造接入服务网格,共享统一的服务治理模型,与使用Envoy代理的应用无缝互通。

2 - 使用指南

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

2.1 - 服务端安装

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

控制台

新建服务

进入服务列表页面,点击【新建】按钮,确认是否可以新建服务。新建服务成功表示安装成功

新建服务

2.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 - 控制台使用

2.2.1 - 命名空间

命名空间列表

通过浏览器输入http://127.0.0.1:8080(127.0.0.1可换成服务端实际安装的IP地址),打开Polaris控制台。

在侧边栏点击命名空间,进入命名空间列表页:

创建命名空间

点击新建按钮,在弹出对话框中填入命名空间全局唯一名称,即可完成命名空间的创建。

创建命名空间字段说明:

字段名 含义 必选/可选
名称 命名空间名称,全局唯一 必选
描述 命名空间描述 可选

2.2.2 - 注册中心

2.2.2.1 - 服务列表

服务

服务列表

在侧边栏点击服务,进入服务列表页,列表各字段含义如下:

创建服务

点击新建按钮,在弹出来的对话框填入命名空间和服务名(同一命名空间下需唯一)等必填信息,即可完成服务的创建。

创建服务字段说明:

字段名 含义 必选/可选
服务名 服务标识,同一命名空间下唯一 必选
命名空间 服务所属的命名空间 必选
部门 服务所在的部门信息,可选 可选
业务 服务所在的业务信息,可选 可选
开启就近访问 是否开启就近访问,开启的话,SDK会自动筛选就近实例 可选,默认关闭
服务标签 服务上的KV标签,仅用于控制台及OpenAPI查询过滤 可选
描述 服务的描述信息 可选

服务实例

服务实例列表

在控制台点击具体服务名,进入服务实例列表页。

创建实例

点击新建按钮,在弹出来的对话框填入实例IP和端口(同一服务下IP和端口组合需唯一),即可完成服务实例的创建。

创建服务实例字段说明:

字段名 含义 必选/可选
实例IP 服务实例的IP,可填入多个,用换行分割 必选
端口 服务实例的端口,可填入多个,用换行分割 必选
权重 服务实例的权重,可控制流量的相对百分比,权重为0则不会有流量 可选,默认100
协议 服务实例端口协议信息 可选
版本 服务实例的版本信息 可选
实例标签 服务实例的KV标签信息,用于路由过滤 可选
地域信息 Region(大区),Zone(可用区),Campus(机房),3级地域信息 可选
健康状态 设置实例健康状态,仅当不开启健康检查时有效 可选
开启健康检查 设置是否开启健康检查,开启健康检查后,由控制面负责健康状态的变更 可选
是否隔离 设置实例是否隔离,实例隔离后则不会有流量 可选

2.2.2.2 - 服务可见性

2.2.3 - 服务网格

2.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.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.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.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.2.4 - 配置中心

2.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.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.2.4.3 - 配置加密

设计

客户端:

  • 客户端本地生成一对公钥和私钥,请求配置文件时携带公钥参数,服务端使用客户端发来的公钥作为KEK(密钥加密密钥)对配置文件的DEK进行加密,然后返回客户端配置密文和DEK密文,客户端收到后用私钥解密DEK密文得到DEK明文,再用DEK解密配置密文。
  • 客户端解密流程

控制台:

  • 创建加密配置: 创建配置接口增加是否加密参数,如果需要加密,服务端生成数据加密密钥DEK,加密配置文件,保存配置文件密文到配置文件表,保存DEK和配置创建人配置文件的标签表。

  • 查看加密配置: 用户在有读权限的前提下,请求获取配置文件,如果配置文件是加密的,服务端额外校验请求人是否为创建人,如果是则使用DEK解密配置文件后返回;如果不是则只返回配置文件密文。

  • 控制台创建读取流程

如何启用配置加密

  • 在新增配置文件中,点击配置加密的开关按钮

  • 确认开启配置加密后,选择期望的配置加密算法

  • 正常填写配置内容并发布

  • 客户端接口获取到的文件内容是加密的

当前支持的客户端版本

2.2.4.4 - 配置灰度

功能描述

在使用配置中心对业务集群配置进行集中管理时,如果对某个配置项进行了修改,配置中心会将新的配置下发到所有监听该配置文件的业务进程中。业务进程接受到新的配置后会将新的配置覆盖当前的旧配置从而完成配置生效。由于配置是下发到所有客户端,一旦配置值修改不符合预期,将影响整个业务集群。

因此,在需要对配置进行编辑后下发到业务机器时,推荐先进行灰度发布。灰度发布是指在修改配置需要发布时,根据一定的规则选择一小部份机器,将修改后的配置先下发到这些机器中进行小范围验证。待业务确认无问题时,再将配置进行全量下发。如果在灰度发布期间发现问题,可以立即停止灰度发布。

如何使用

  • 编辑完配置文件后,点击灰度发布

  • 在弹出的框中,填写客户端灰度标签信息

  • 点击下一步,完成提交,便可看到处于灰度发布中的配置

2.2.5 - 权限控制

2.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.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变更

如何创建鉴权策略

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

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

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

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

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

创建命名空间

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

创建服务

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

2.3 - Java 应用开发

2.3.1 - 使用 Java SDK

2.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 客户端完成一个服务发现的程序

2.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 客户端完成一个服务路由的程序

2.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 客户端完成一个服务负载均衡的程序

2.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协议,由于服务开启了鉴权,因此探测时需要传入鉴权头。

注意:主动探测的规则,服务名可以选择全部服务,则规则针对全部服务生效。如果需要针对只接口进行探测,则可以在接口字段中填入对应的接口名。

在熔断规则中开启主动探测

需要在熔断规则中开启探测,这样才可以把探测结果用于熔断。

2.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 客户端完成一个服务限流的程序

2.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);

相关示例工程代码

2.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)

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

2.3.2 - 使用 Spring Cloud

2.3.3 - 使用 Spring Boot

2.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 开展。

2.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"
    }
}'

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

2.3.4 - 使用 Dubbo

2.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 版本的接入,最新版本为 0.2.0-3.2.7

引入依赖

<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

结果验证

服务注册样例可以参考:

2.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 版本的接入,最新版本为 0.2.0-3.2.7

引入依赖

在 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 指定服务的命名空间
token string 指定用户token

结果验证

服务接口定义

服务契约名称格式样例

"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"
        }
    ]
}

2.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 版本的接入,最新版本为 0.2.0-3.2.7

引入依赖

首先,动态路由需要依赖以下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的请求消息内容来对请求调度到不同的实例分组,比如将带了某些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 个工程。

2.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 版本的接入,最新版本为 0.2.0-3.2.7

引入依赖

首先,动态路由需要依赖以下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>

配置北极星注册中心地址

接下来,需要添加北极星 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个工程,代表的是主调端和被调端,限流行为工作在被调端。

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 版本的接入,最新版本为 0.2.0-3.2.7

引入依赖

首先,熔断降级需要依赖以下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>

配置北极星注册中心地址

接下来,需要添加北极星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}

2.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 版本的接入,最新版本为 0.2.0-3.2.7

引入依赖

在 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

2.3.5 - 使用 gRPC-Java

2.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 完成一个服务注册的程序

2.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 完成一个服务发现的程序

2.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 开展

2.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 开展

2.4 - Go 应用开发

2.4.1 - 使用 Go SDK

2.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 客户端完成一个服务发现的程序

2.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 客户端完成一个动态路由的程序

2.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 客户端完成一个负载均衡的程序

2.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地址

2.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 客户端完成一个节点熔断的程序

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

相关示例工程代码

2.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)

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

2.4.2 - 使用 dubbogo

2.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 开展

2.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 开展

2.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 开展

2.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 开展

2.4.3 - 使用 gRPC-Go

2.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 完成一个服务注册的程序

2.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 完成一个服务发现的程序

2.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 开展

2.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})

2.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 开展

2.5 - C++ 应用开发

2.5.1 - 使用 C++ SDK

2.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",
    ],

2.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 客户端完成一个服务发现的程序

2.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 客户端完成一个服务路由的程序

2.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 客户端完成一个负载均衡的程序

2.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 客户端完成一个节点熔断的程序

2.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 客户端完成一个服务限流的程序

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

2.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=========================

2.6 - K8s 和网格代理

2.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已经被自动同步到北极星上。

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

2.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"

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

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

2.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",代表插件已经加载完毕。

查看北极星控制台确认

验证限流功能

设置限流规则

调用接口触发限流

验证路由功能

设置路由规则

不携带特定参数

携带特定参数

2.7 - 网关

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

其他资料

2.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))
}

3 - 最佳实践

介绍如何使用北极星解决分布式和微服务架构中的常见问题,输出最佳实践文档和样例。

3.1 - 灰度发布

3.1.1 - 蓝绿发布

什么是蓝绿发布

蓝绿部署是一种应用发布模式,可将用户流量从先前版本的应用或微服务全量转移到新版本中(两者均保持在生产环境中运行)。

旧版本可以称为蓝色环境,而新版本则可称为绿色环境。一旦生产流量从蓝色完全转移到绿色,蓝色就可以在回滚或退出生产的情况下保持待机,也可以更新成为下次更新的模板。

蓝绿发布的适用场景

  • 机器资源有富余或者可以按需分配
  • 单体应用、调用复杂度不高的业务系统
  • 对用户体验具备一定的容忍度

北极星如何支持蓝绿发布

蓝绿发布需要依赖几个关键的技术点:

  • 流量入口侧需要支持按百分比进行流量切换,并对灰度流量进行染色(打上灰度标签)。
  • 微服务框架需要支持灰度标签的透传。
  • 服务治理中心支持灰度流量只路由到灰度版本的服务中,非灰度流量只路由到原版本服务中 。

北极星提供以下功能,支持蓝绿发布:

  • 网关直通微服务:北极星支持直接打通网关到微服务的链路(支持主流网关Envoy/Kong/Nginx/Spring Cloud Gateway),网关侧可以直接将流量打通到微服务的节点/POD,无需通过ClusterIP来中转。
  • 提供自定义路由能力,支持流量按标签(版本等)进行路由。
  • 微服务框架SpringCloudTencent,以及流量代理Envoy支持流量标签透传能力。

北极星支持Spring Cloud Tencent以及服务网格(Envoy)的方式接入使用蓝绿发布的能力。

前置条件

部署polaris

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

polaris支持在kubernetes环境中进行部署,注意必须保证暴露HTTP端口为8090,gRPC端口为8091。具体部署方案请参考:

阶段一:实例打标

Spring Cloud Tencent 接入

打标实例版本号

Spring Cloud Tencent支持通过以下2种方式进行实例的版本号打标:

  • 方式一:配置文件

在服务实例的配置文件中添加配置,如在 bootstrap.yml 添加如下所示即可:

spring:
  cloud:
    tencent:
      metadata:
        content:
          version: 2.0.0
  • 方式二:环境变量

在服务实例所在的操作系统中添加环境变量也可进行打标,例如:SCT_METADATA_CONTENT_version=2.0.0

打标灰度标签透传

由于Spring Cloud默认不会对所有的请求标签进行透传,因此需要增加Spring Cloud透传标识,可以通过添加环境变量SCT_PROTOCOL_CONTENT_TRANSITIVE_HEADER=gray的方式,进行灰度标识gray:true的透传。

Envoy Proxy 接入

应用需要基于K8S进行部署,才可以使用Envoy Proxy的接入模式。

实例的版本标签需要通过POD标签的方式打入,然后在部署过程中,北极星的controller会自动把POD标签同步到北极星。

可以在K8S的部署配置中,在template配置中,添加labels的方式完成版本打标。可参考这里的部署配置:微服务部署配置

spec:
  template:
    metadata:
      labels:
        app: user
        version: 2.0.0

阶段二:部署应用

Spring Cloud Tencent 接入

支持虚拟机、Docker Composer、K8S等多种部署模式,注意需要保证业务进程与北极星服务的网络连通性。

Envoy Proxy 接入

只支持K8S的部署模式,同时,为了实现POD标签的自动同步,以及Envoy Proxy的自动注入,需要预先部署K8s Controller组件。具体部署方案请参考:

阶段三:网关路由&染色

网关作为流量入口,配置网关路由的目标主要是为了可以将流量按比例进行切分到不同版本的微服务中去,同时通过流量打标的方式,将路由到新版本的请求,在Header上打入gray:true的标签,便于后续微服务按照标签进行路由。

用户可以使用任意对接了北极星服务发现的网关进行操作(Envoy, Nginx, Kong等),这里给出Envoy的VirtualHost路由配置,便于大家理解,具体配置可以参考LDS配置

virtual_hosts:
- name: local_service
domains:
- "*"
routes:              
- match:
	prefix: "/"
  route:
	weighted_clusters:
	  total_weight: 100
	  clusters:
	  - name: user
		weight: 80
		metadata_match:
		  filter_metadata:
			envoy.lb:
			  version: 1.0.0
	  - name: user
		weight: 20
		request_headers_to_add:
		- header:
			key: gray
			value: "true"
		metadata_match:
		  filter_metadata:
			envoy.lb:
			  version: 2.0.0   

阶段四:微服务路由

通过配置微服务路由,目标是使得对于灰度流量的调用,都只在新版本的服务分组中进行。

打开北极星控制台,通过点击侧边栏:动态路由->自定义规则页面,配置自定义路由规则,规则可配置对命名空间下全部服务生效。

  • 配置灰度规则,使得header中带有gray:true灰度标签的流量都只流向version=2.0.0的分组:

  • 配置兜底规则,使得不带灰度标签的流量都只流向version=1.0.0的分组:

阶段五:观察监控并查看流量的灰度过程

通过北极星的可观测性能力,可以准确看到不同分组的流量切换的过程,以及服务调用成功率,等到所有流量都切换到新版本分组以及没有失败请求,代表灰度完成。

阶段六:灰度完成的收尾动作

灰度完成后,需要做以下事情:

  • 对老版本分组的实例进行缩容下线
  • 删除网关的路由规则
  • 在北极星控制台删除自定义路由规则

一键部署体验

北极星提供了一键部署demo,可以通过一键部署demo快速体验蓝绿发布。详细请参考:

3.1.2 - 金丝雀发布

什么是金丝雀发布

金丝雀发布是已经将新版本应用部署到生产环境了,然后根据一定的特征,一般是用户ID、用户地域、用户类型等不同维度,允许部分用户使用部署到生产环境上的新版本应用。这个过程中,通过观察新版本的表现(比如成功率、时延、负载等),以判断新版本是否符合预期。

金丝雀发布的适用场景

  • 用户体验不能中断的业务
  • 微服务业务的独立服务的特性变更

北极星如何支持金丝雀发布

金丝雀发布需要依赖几个关键的技术点:

  • 微服务框架需要支持灰度标签的透传。
  • 服务治理中心支持将灰度用户的流量只路由到灰度版本的服务中,其他流量只路由到原版本服务中 。

北极星提供以下功能,支持金丝雀发布:

  • 提供自定义路由能力,支持流量按标签(版本等)进行路由。
  • 微服务框架SpringCloudTencent,以及流量代理Envoy支持流量标签透传能力。

北极星支持Spring Cloud Tencent以及服务网格(Envoy)的方式接入使用金丝雀发布的能力。

前置条件

部署polaris

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

polaris支持在kubernetes环境中进行部署,注意必须保证暴露HTTP端口为8090,gRPC端口为8091。具体部署方案请参考:

阶段一:实例打标

Spring Cloud Tencent 接入

打标实例版本号

Spring Cloud Tencent支持通过以下2种方式进行实例的版本号打标:

  • 方式一:配置文件

在服务实例的配置文件中添加配置,如在 bootstrap.yml 添加如下所示即可:

spring:
  cloud:
    tencent:
      metadata:
        content:
          version: 2.0.0
  • 方式二:环境变量

在服务实例所在的操作系统中添加环境变量也可进行打标,例如:SCT_METADATA_CONTENT_version=2.0.0

打标灰度标签透传

由于Spring Cloud默认不会对所有的请求标签进行透传,因此需要增加Spring Cloud透传标识,可以通过添加环境变量SCT_PROTOCOL_CONTENT_TRANSITIVE_HEADER=gray的方式,进行灰度标识gray:true的透传。

Envoy Proxy 接入

应用需要基于K8S进行部署,才可以使用Envoy Proxy的接入模式。

实例的版本标签需要通过POD标签的方式打入,然后在部署过程中,北极星的controller会自动把POD标签同步到北极星。

可以在K8S的部署配置中,在template配置中,添加labels的方式完成版本打标。可参考这里的部署配置:微服务部署配置

spec:
  template:
    metadata:
      labels:
        app: user
        version: 2.0.0

阶段二:部署应用

Spring Cloud Tencent 接入

支持虚拟机、Docker Composer、K8S等多种部署模式,注意需要保证业务进程与北极星服务的网络连通性。

Envoy Proxy 接入

只支持K8S的部署模式,同时,为了实现POD标签的自动同步,以及Envoy Proxy的自动注入,需要预先部署北极星的Controller组件(polaris-controller)。具体部署方案请参考:

阶段三:微服务路由

通过配置微服务路由,目标是使得对于灰度流量的调用,都只在新版本的服务分组中进行。

打开北极星控制台,通过点击侧边栏:动态路由->自定义规则页面,配置自定义路由规则,规则只对credit服务生效。

  • 配置灰度规则,使得header中带有gray:true灰度标签的流量都只流向version=2.0.0的分组:

  • 配置兜底规则,使得不带灰度标签的流量都流向其他版本分组:

阶段四:观察监控并查看流量的灰度过程

通过北极星的可观测性能力,可以准确看到不同分组的流量切换的过程,以及服务调用成功率,等到灰度分组相关指标没有问题,代表灰度验证完成。

阶段五:灰度完成的收尾动作

灰度验证完成后,需要做以下事情:

  • 对老版本分组的实例进行滚动升级到新版本
  • 在北极星控制台删除自定义路由规则

一键部署体验

北极星提供了一键部署demo,可以通过一键部署demo快速体验蓝绿发布。详细请参考:

3.1.3 - 全链路灰度-场景1

什么是全链路灰度

微服务架构下,有些开发需求,微服务调用链路上的多个微服务同时发生了改动,通常每个微服务都会有灰度环境或分组来接收灰度流量。此时希望通过进入上游灰度环境的流量,也能进入下游灰度的环境中,确保1个请求始终在灰度环境中传递。

全链路灰度适用场景

  • 用户体验不能中断的业务。
  • 微服务业务的存在关联关系的多个微服务的特性变更。

全链路灰度的实现方案

可以基于域名分离的方式实现全链路灰度,通过不同的域名区分灰度环境和稳定环境。用户的请求通过灰度域名访问到灰度版本的服务,通过稳定域名访问到稳定版本的服务。

灰度请求通过灰度域名接入到网关,网关通过域名识别到灰度请求后,将请求优先路由到灰度版本的服务,并通过请求头的方式进行灰度染色。后续微服务之间,服务框架通过请求头识别到灰度请求,会优先将请求路由到灰度版本服务,如果寻址不到灰度版本,则路由到稳定版本服务。

前置条件

部署polaris

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

polaris支持在kubernetes环境中进行部署,注意必须保证暴露HTTP端口为8090,gRPC端口为8091。具体部署方案请参考:

阶段一:实例打标

Spring Cloud Tencent 接入

打标实例版本号

Spring Cloud Tencent支持通过以下2种方式进行实例的版本号打标:

  • 方式一:配置文件

在服务实例的配置文件中添加配置,如在 bootstrap.yml 添加如下所示即可:

spring:
  cloud:
    tencent:
      metadata:
        content:
          version: 2.0.0
  • 方式二:环境变量

在服务实例所在的操作系统中添加环境变量也可进行打标,例如:SCT_METADATA_CONTENT_version=2.0.0

打标灰度标签透传

由于Spring Cloud默认不会对所有的请求标签进行透传,因此需要增加Spring Cloud透传标识,可以通过添加环境变量SCT_TRAFFIC_CONTENT_RAW_TRANSHEADERS=gray的方式,进行灰度标识gray:true的透传。

Envoy Proxy 接入

应用需要基于K8S进行部署,才可以使用Envoy Proxy的接入模式。

实例的版本标签需要通过POD标签的方式打入,然后在部署过程中,北极星的controller会自动把POD标签同步到北极星。

可以在K8S的部署配置中,在template配置中,添加labels的方式完成版本打标。可参考这里的部署配置:微服务部署配置

spec:
  template:
    metadata:
      labels:
        app: user
        version: 2.0.0

阶段二:部署应用

Spring Cloud Tencent 接入

支持虚拟机、Docker Composer、K8S等多种部署模式,注意需要保证业务进程与北极星服务的网络连通性。

Envoy Proxy 接入

只支持K8S的部署模式,同时,为了实现POD标签的自动同步,以及Envoy Proxy的自动注入,需要预先部署北极星的Controller组件(polaris-controller)。具体部署方案请参考:

阶段三:网关路由&染色

网关作为流量入口,配置网关路由的目标主要是为了可以将通过灰度域名接入的流量,导入到灰度版本的下游微服务上,同时通过流量打标的方式,将路由到灰度版本的请求,在Header上打入gray:true的标签,便于后续微服务按照标签进行路由。

配置域名切流量的规则

用户可以使用任意对接了北极星服务发现的网关进行操作(Envoy, Nginx, Kong等),这里给出Envoy的VirtualHost路由配置,便于大家理解,具体配置可以参考LDS配置

virtual_hosts:
- name: local_service
  domains:
  - "*"
  routes:              
  - match:
	  prefix: "/"
    route:
	  weighted_clusters:
	    total_weight: 100
	    clusters:
	    - name: user
		  weight: 80
		  metadata_match:
		    filter_metadata:
			  envoy.lb:
			    version: 1.0.0
	    - name: user
		  weight: 20
		  request_headers_to_add:
		  - header:
			  key: gray
			  value: "true"
		  metadata_match:
		    filter_metadata:
			  envoy.lb:
			    version: 2.0.0

阶段四:微服务路由

通过配置微服务路由,目标是使得对于灰度流量的调用,都只在新版本的服务分组中进行。

打开北极星控制台,通过点击侧边栏:动态路由->自定义规则页面,配置自定义路由规则,规则可配置对命名空间下全部服务生效。

  • 配置灰度规则,使得header中带有gray:true灰度标签的流量都只流向version=2.0.0的分组:

  • 配置兜底规则,使得不带灰度标签的流量都只流向version=1.0.0的分组:

阶段五:观察监控并查看流量的灰度过程

通过北极星的可观测性能力,可以准确看到不同分组的流量切换的过程,以及服务调用成功率,等到所有流量都切换到新版本分组以及没有失败请求,代表灰度完成。

阶段六:灰度完成的收尾动作

灰度完成后,需要做以下事情:

  • 对老版本分组的实例进行缩容下线
  • 删除网关的路由规则
  • 在北极星控制台删除自定义路由规则

一键部署体验

北极星提供了一键部署demo,可以通过一键部署demo快速体验蓝绿发布。详细请参考:

3.1.4 - 全链路灰度-场景2

什么是全链路灰度

微服务架构下,有些开发需求,微服务调用链路上的多个微服务同时发生了改动,通常每个微服务都会有灰度环境或分组来接收灰度流量。此时希望通过进入上游灰度环境的流量,也能进入下游灰度的环境中,确保1个请求始终在灰度环境中传递。

全链路灰度适用场景

  • 用户体验不能中断的业务。
  • 微服务业务的存在关联关系的多个微服务的特性变更。

全链路灰度的实现方案

灰度环境和稳定环境对外只暴露一个域名,系统基于特定的请求标识(UID等)识别到灰度请求,并将灰度请求优化路由到灰度环境。

针对UID=2000的请求进行灰度,灰度请求接入到网关后,网关通过特定UID识别到灰度请求后,将请求优先路由到灰度版本的服务,并将UID透传到下一跳服务中。后续微服务之间,服务框架通过UID识别到灰度请求,会优先将请求路由到灰度版本服务,如果寻址不到灰度版本,则路由到稳定版本服务,UID的请求头会随着微服务调用每一级进行透传。

前置条件

部署polaris

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

polaris支持在kubernetes环境中进行部署,注意必须保证暴露HTTP端口为8090,gRPC端口为8091。具体部署方案请参考:

阶段一:实例打标

Spring Cloud Tencent 接入

打标实例版本号

Spring Cloud Tencent支持通过以下2种方式进行实例的版本号打标:

  • 方式一:配置文件

在服务实例的配置文件中添加配置,如在 bootstrap.yml 添加如下所示即可:

spring:
  cloud:
    tencent:
      metadata:
        content:
          version: 2.0.0
  • 方式二:环境变量

在服务实例所在的操作系统中添加环境变量也可进行打标,例如:SCT_METADATA_CONTENT_version=2.0.0

打标灰度标签透传

由于Spring Cloud默认不会对所有的请求标签进行透传,因此需要增加Spring Cloud透传标识,可以通过添加环境变量SCT_TRAFFIC_CONTENT_RAW_TRANSHEADERS=uid的方式,进行灰度标识uid:200的透传。

Envoy Proxy 接入

应用需要基于K8S进行部署,才可以使用Envoy Proxy的接入模式。

实例的版本标签需要通过POD标签的方式打入,然后在部署过程中,北极星的controller会自动把POD标签同步到北极星。

可以在K8S的部署配置中,在template配置中,添加labels的方式完成版本打标。可参考这里的部署配置:微服务部署配置

spec:
  template:
    metadata:
      labels:
        app: user
        version: 2.0.0

阶段二:部署应用

Spring Cloud Tencent 接入

支持虚拟机、Docker Composer、K8S等多种部署模式,注意需要保证业务进程与北极星服务的网络连通性。

Envoy Proxy 接入

只支持K8S的部署模式,同时,为了实现POD标签的自动同步,以及Envoy Proxy的自动注入,需要预先部署北极星的Controller组件(polaris-controller)。具体部署方案请参考:

阶段三:网关路由&染色

网关作为流量入口,配置网关路由的目标主要是为了可以将灰度用户的请求,路由灰度版本的微服务中去。

按标签切流量

用户可以使用任意对接了北极星服务发现的网关进行操作(Envoy, Nginx, Kong等),这里给出Envoy的VirtualHost路由配置,便于大家理解,具体配置可以参考LDS配置

virtual_hosts:
- name: gray_service
  domains:
	- base.service.com
  routes:
	- match:
		prefix: /
		headers:
		  - name: uid
			exact_match: '200'
	  route:
		cluster: user
		metadata_match:
		  filter_metadata:
			envoy.lb:
			  version: v2.0.0
	  request_headers_to_add:
		- header:
			key: gray
			value: 'true'
	- match:
		prefix: /
	  route:
		cluster: user
		metadata_match:
		  filter_metadata:
			envoy.lb:
			  version: v1.0.0     

阶段四:微服务路由

通过配置微服务路由,目标是使得对于灰度流量的调用,都只在新版本的服务分组中进行。

打开北极星控制台,通过点击侧边栏:动态路由->自定义规则页面,配置自定义路由规则,规则可配置对命名空间下全部服务生效。

  • 配置灰度规则,使得header中带有uid:200灰度标签的流量都只流向version=2.0.0的分组:

  • 配置兜底规则,使得不带灰度标签的流量都只流向version=1.0.0的分组:

阶段五:观察监控并查看流量的灰度过程

通过北极星的可观测性能力,可以准确看到不同分组的流量切换的过程,以及服务调用成功率,等到所有流量都切换到新版本分组以及没有失败请求,代表灰度完成。

阶段六:灰度完成的收尾动作

灰度完成后,需要做以下事情:

  • 对老版本分组的实例进行缩容下线
  • 删除网关的路由规则
  • 在北极星控制台删除自定义路由规则

一键部署体验

北极星提供了一键部署demo,可以通过一键部署demo快速体验蓝绿发布。详细请参考:

3.2 - 测试环境路由

3.2.1 - 概述

背景介绍

在实际的开发过程中,一个微服务架构系统下的不同微服务可能是由多个团队进行开发与维护的,每个团队只需关注所属的一个或多个微服务,而各个团队维护的微服务之间可能存在相互调用关系。如果一个团队在开发其所属的微服务,调试的时候需要验证完整的微服务调用链路。此时需要依赖其他团队的微服务,如何部署开发联调环境就会遇到以下问题:

  1. 如果所有团队都使用同一套开发联调环境,那么一个团队的测试微服务实例无法正常运行时,会影响其他依赖该微服务的应用也无法正常运行。
  2. 如果每个团队有单独的一套开发联调环境,那么每个团队不仅需要维护自己环境的微服务应用,还需要维护其他团队环境的自身所属微服务应用,效率大大降低。同时,每个团队都需要部署完整的一套微服务架构应用,成本也随着团队数的增加而大大上升。

此时可以使用测试环境路由的架构来帮助部署一套运维简单且成本较低开发联调环境。

什么是测试环境路由

测试环境路由是一种基于服务路由的环境治理策略,核心是维护一个稳定的基线环境作为基础环境,测试环境仅需要部署需要变更的微服务以构成特性环境。部署完成多测试环境后,开发者可以通过一定的路由规则方式,将测试请求打到不同的测试环境,如果测试环境没有相应的微服务处理链路上的请求,那么会降级到基线环境处理。因此,开发者需要将开发新测试的微服务部署到对应的测试环境,而不需要更新或不属于开发者管理的微服务则复用基线环境的服务,完成对应测试环境的测试。

由此可见,多测试环境有两个基础概念,即基线环境和特性环境。

基础概念

基线环境

基线环境(Baseline Environment)是完整稳定的基础环境,是作为同类型下其他环境流量通路的一个兜底可用环境,用户应该尽量保证基线环境的完整性、稳定性。

测试环境

测试环境(Feature Environment)是一种临时环境,仅可能为开发/测试环境类型,测试环境不需要部署全链路完整的服务,而是仅部署本次有变更的服务,其他服务通过服务路由的方式复用基线环境服务资源。

实现原理

方案总览

测试环境路由的样例实现以下图为例,一共有两个测试环境以及一个基线环境。流量从端到端会依次经过以下组件:App -> 网关 -> 用户中心 -> 积分中心 -> 活动中心。

为了达到测试环境路由的能力,开发工作需要做三件事情:

  1. 服务实例染色(标识实例属于哪个测试环境)
  2. 流量染色(标识请求应该被转发到哪个测试环境)
  3. 服务路由 a. 网关根据请求的目标测试环境标签转发到对应的目标测试环境的用户中心. b. 服务调用时,优先转发到同测试环境下的目标服务实例,如果同测试环境下没有服务实例则转发到基线环境.

以下三小节,将会详细介绍这三部分的原理。

服务实例染色

在多测试环境的场景中,需要对每个测试环境部署的实例进行区分,因此需要在实例上打类似于“featureenv=测试环境名”的标签,例如以下几种实践场景:

  1. 应用实例的配置文件中表明其环境信息。
  2. 把实例标签放到机器上的某一个配置文件里,例如 /etc/metadata。
  3. 应用启动时,调用公司的 CMDB 接口获取元信息。

流量染色

流量染色即为每个请求打上目标测试环境标签,路由转发时根据请求标签匹配请求。而流量染色可以分为以下几种方式:

  • 静态染色

静态染色所有经过当前实例的请求都带上当前实例的标签信息。例如经过 env=f1 的实例的请求都携带 env=f1 的标签信息。

  • 动态染色

静态染色是把服务实例的某些标签作为请求标签,服务实例标签相对静态,应用启动后初始化一次之后就不再变更。但是在实际的应用场景下,不同的请求往往需要设置不同的标签信息。此时则需要通过动态染色的能力。因此需要按照一定的规则或逻辑,为每个请求动态生成标签信息。

元数据路由

北极星提供了非常完善的服务治理能力,上层的服务框架基于北极星原生 SDK 就能快速实现强大的服务治理能力。在多测试环境场景下主要用到了元数据路由插件,此插件核心能力是根据请求的标签完全匹配服务实例的标签。

操作指引

具体操作指引按照染色的方式,分为以下三种,可以跳转到对应的文档详细查看:

3.2.2 - 客户端染色

流程简介

如概述所言,测试环境路由的开发工作分为三个阶段:

  • 阶段一:实例打标。在多测试环境的场景中,需要对每个测试环境部署的实例进行区分,因此需要在实例上打类似标识实例测试环境类别的标签。
  • 阶段二:部署应用。
  • 阶段三:流量染色。流量染色即为每个请求打上目标测试环境标签,路由转发时根据请求标签匹配请求。

如下图所示,开发者给每个环境的应用实例进行打标(如 featureenv=f1 ),标明其所在的环境类型。阶段二部署业务应用。阶段三中,开发者在请求头添加相应的流量标签,即可完成测试环境路由。

操作指引

阶段一

微服务框架服务注册场景

Spring Cloud Tencent 框架接入

Spring Cloud Tencent 中的 spring-cloud-tencent-featureenv-plugin 模块闭环了测试环境路由全部能力,所有服务只需要添加该依赖即可引入测试环境路由能力。spring-cloud-tencent-featureenv-plugin 默认以 featureenv 标签作为匹配标签,用户也可以通过系统内置的 system-feature-env-router-label=custom_feature_env_key 标签来指定测试环境路由使用的标签键。以下三种方式以默认的 featureenv 作为示例。设置方式详情参考Spring Cloud Tencent 元数据使用说明

  • 方式一:配置文件

在服务实例的配置文件中添加配置,如在 bootstrap.yml 添加如下所示即可:

spring:
  cloud:
    tencent:
      metadata:
        content:
          featureenv: f1  # f1 替换为测试环境名称
  • 方式二:环境变量

在服务实例所在的操作系统中添加环境变量也可进行打标,例如:SCT_METADATA_CONTENT_featureenv=f1

  • 方式三:SPI 方式 自定义实现 InstanceMetadataProvider#getMetadata() 方法的返回值里里包含 featureenv 即可。

注意:基线环境部署的服务实例不需要设置 featureenv 标签,表明其不属于任何测试环境,才可在请求没有匹配到对应测试环境的时候,匹配到基线环境。

kubernetes服务注册场景

北极星提供了polaris-controller,支持直接将pod labels同步为北极星上面的实例标签。

  • 在集群中安装polaris-controller,安装方式可参考:安装指南
  • 创建deployment的时候,通过template配置,指定pod的标签信息,详细参考:标签指定
apiVersion: apps/v1
kind: Deployment
metadata:
  name: nginx-deployment
  labels:
    app: nginx
spec:
  replicas: 3
  selector:
    matchLabels:
      app: nginx
  template:
    metadata:
      labels:
        app: nginx
    spec:
      containers:
      - name: nginx
        image: nginx:1.14.2
        ports:
        - containerPort: 80

做完上面2步后,polaris-controller默认会对集群中的服务数据进行全量同步,而pod中的labels也会同步为北极星的实例标签。

阶段二

在 VM 或者容器中部署业务应用,需要保证业务应用与北极星服务治理中心的网络连通性。

阶段三

开发者在客户端发出的 HTTP 请求里,新增 X-Polaris-Metadata-Transitive-featureenv=f1 请求头即可实现流量染色。

请求头 X-Polaris-Metadata-Transitive-featureenv=f1 是按照北极星定义的请求头格式设置的,其中 X-Polaris-Metadata-Transitive- 是北极星需要读取请求头的前缀,例子中的 featureenv 为实际的键值对的key,f1 为实际的键值对的value。

原理解析

  • 标签筛选:用户传入的env=f1,spring cloud tencent会基于从北极星发现的实例数据,筛选出匹配env=f1的实例,并进行服务调用。

  • 标签透传:在微服务的调用链路中,spring cloud tencent框架会将用户的请求标签逐级往下透传,使得每一层调用都可以优先调度都env=f1的实例上。

3.2.3 - 网关动态染色

流程简介

如概述所言,测试环境路由的开发工作分为三个阶段:

  • 阶段一:实例打标。在多测试环境的场景中,需要对每个测试环境部署的实例进行区分,因此需要在实例上打类似标识实例测试环境类别的标签。
  • 阶段二:部署应用。
  • 阶段三:流量染色。流量染色即为每个请求打上目标测试环境标签,路由转发时根据请求标签匹配请求。

如下图所示,开发者给每个环境的应用实例进行打标(如 featureenv=f1 ),标明其所在的环境类型。阶段二部署业务应用。阶段三中,开发者在网关添加动态流量染色规则来给每个请求添加相应的流量标签,即可完成测试环境路由。

操作指引

阶段一

微服务框架服务注册场景

Spring Cloud Tencent 框架接入

Spring Cloud Tencent 中的 spring-cloud-tencent-featureenv-plugin 模块闭环了测试环境路由全部能力,所有服务只需要添加该依赖即可引入测试环境路由能力。spring-cloud-tencent-featureenv-plugin 默认以 featureenv 标签作为匹配标签,用户也可以通过系统内置的 system-feature-env-router-label=custom_feature_env_key 标签来指定测试环境路由使用的标签键。以下三种方式以默认的 featureenv 作为示例。设置方式详情参考Spring Cloud Tencent 元数据使用说明

  • 方式一:配置文件

在服务实例的配置文件中添加配置,如在 bootstrap.yml 添加如下所示即可:

spring:
  cloud:
    tencent:
      metadata:
        content:
          featureenv: f1  # f1 替换为测试环境名称
  • 方式二:环境变量

在服务实例所在的操作系统中添加环境变量也可进行打标,例如:SCT_METADATA_CONTENT_featureenv=f1

  • 方式三:SPI 方式 自定义实现 InstanceMetadataProvider#getMetadata() 方法的返回值里里包含 featureenv 即可。

注意:基线环境部署的服务实例不需要设置 featureenv 标签,表明其不属于任何测试环境,才可在请求没有匹配到对应测试环境的时候,匹配到基线环境。

kubernetes服务注册场景

北极星提供了polaris-controller,支持直接将pod labels同步为北极星上面的实例标签。

  • 在集群中安装polaris-controller,安装方式可参考:安装指南
  • 创建deployment的时候,通过template配置,指定pod的标签信息,详细参考:标签指定
apiVersion: apps/v1
kind: Deployment
metadata:
  name: nginx-deployment
  labels:
    app: nginx
spec:
  replicas: 3
  selector:
    matchLabels:
      app: nginx
  template:
    metadata:
      labels:
        app: nginx
    spec:
      containers:
      - name: nginx
        image: nginx:1.14.2
        ports:
        - containerPort: 80

做完上面2步后,polaris-controller默认会对集群中的服务数据进行全量同步,而pod中的labels也会同步为北极星的实例标签。

阶段二

在 VM 或者容器中部署业务应用,需要保证业务应用与北极星服务治理中心的网络连通性。

阶段三

网关动态染色是开发者配置一定的染色规则,让流量经过网关时自动染色。例如上图红框内所示,把 uid=1 用户的请求都转发到 f1 环境,把 uid=0 用户的请求都转发到 f2 环境。具体的流程是开发者在北极星的页面上添加类似如下图所示的染色规则,然后网关根据染色规则在 HTTP 请求里,新增 X-Polaris-Metadata-Transitive-featureenv=f1 请求头即可实现流量染色。

请求头 X-Polaris-Metadata-Transitive-featureenv=f1 是按照北极星定义的请求头格式设置的,其中 X-Polaris-Metadata-Transitive- 是北极星需要读取请求头的前缀,例子中的 featureenv 为实际的键值对的key,f1 为实际的键值对的value。

操作步骤:

  1. 创建配置文件 rule/staining.json

  1. 编辑 rule/staining.json 并应用SCG染色模板(SCG染色模版将在1.11.0版本提供,目前仅支持自定义编写)。

  1. 保存并发布,该规则配置将下发到对应的SCG应用,后续 HTTP 请求将按照规则进行染色,并根据染色标签路由到不同的测试环境,以实现测试环境路由。

模版里的样例配置的含义是,在 HTTP 请求的参数中拿到 uid 字段,如果等于(EQUAL10001,那么就在经过的 HTTP 请求的头部自动打上 X-Polaris-Metadata-Transitive-featureenv=feature1 的数据标签。更加详细的规则配置说明如下所示:

配置项 配置项说明 类型 备注
rules 动态染色规则列表 list
conditions 规则匹配条件列表 list
conditions内项 规则匹配条件 map
conditions内项.key 规则匹配条件原始值 string ${http.query.xxx}
${http.header.xxx}
${http.cookie.xxx}
${http.method}
${http.uri}
conditions内项.values 规则匹配条件目标值列表 list
conditions内项.operation 规则匹配条件操作符 string EQUALS
NOT_EQUALS
IN
NOT_IN
REGEX
BLANK
NOT_BLANK
labels 染色标签列表 list
labels内项 染色标签 map
labels内项.key 染色标签key string
labels内项.value 染色标签value list

Spring Cloud Tencent 实现方式

Spring Cloud Tencent 通过实现 Spring Cloud Gateway 的 GlobalFilter 来实现流量染色插件,开发者只需要添加 spring-cloud-tencent-gateway-plugin 依赖,并在配置文件打开如下所示的染色插件开关即可引入流量染色能力。spring-cloud-tencent-gateway-plugin 插件会默认读取北极星配置中心内的 rule/staining.json 配置作为动态染色规则。

spring-cloud-tencent-gateway-plugin 配置列表:

配置项Key 默认值 是否必填 配置项说明
spring.cloud.tencent.plugin.scg.enabled true 是否开启网关插件
spring.cloud.tencent.plugin.scg.staining false 是否开启网关染色
spring.cloud.tencent.plugin.scg.staining.rule-staining.enabled true 是否开启网关动态规则染色
spring.cloud.tencent.plugin.scg.staining.rule-staining.namespace ${spring.cloud.tencent.namespace:default} 网关动态规则命名空间
spring.cloud.tencent.plugin.scg.staining.rule-staining.group ${spring.application.name:spring-cloud-gateway} 网关动态规则配置分组
spring.cloud.tencent.plugin.scg.staining.rule-staining.fileName rule/staining.json 网关动态规则文件名

3.2.4 - 网关静态染色

流程简介

如概述所言,测试环境路由的开发工作分为三个阶段:

  • 阶段一:实例打标。在多测试环境的场景中,需要对每个测试环境部署的实例进行区分,因此需要在实例上打类似标识实例测试环境类别的标签。
  • 阶段二:部署应用。
  • 阶段三:流量染色。流量染色即为每个请求打上目标测试环境标签,路由转发时根据请求标签匹配请求。

如下图所示,开发者给每个环境的应用实例进行打标(如 featureenv=f1 ),标明其所在的环境类型。阶段二部署业务应用。阶段三中,开发者在各个环境的网关添加向请求头插入流量标签的插件,即可完成测试环境路由。

操作指引

阶段一

微服务框架服务注册场景

Spring Cloud Tencent 框架接入

Spring Cloud Tencent 中的 spring-cloud-tencent-featureenv-plugin 模块闭环了测试环境路由全部能力,所有服务只需要添加该依赖即可引入测试环境路由能力。spring-cloud-tencent-featureenv-plugin 默认以 featureenv 标签作为匹配标签,用户也可以通过系统内置的 system-feature-env-router-label=custom_feature_env_key 标签来指定测试环境路由使用的标签键。以下三种方式以默认的 featureenv 作为示例。设置方式详情参考Spring Cloud Tencent 元数据使用说明

  • 方式一:配置文件

在服务实例的配置文件中添加配置,如在 bootstrap.yml 添加如下所示即可:

spring:
  cloud:
    tencent:
      metadata:
        content:
          featureenv: f1  # f1 替换为测试环境名称
  • 方式二:环境变量

在服务实例所在的操作系统中添加环境变量也可进行打标,例如:SCT_METADATA_CONTENT_featureenv=f1

  • 方式三:SPI 方式 自定义实现 InstanceMetadataProvider#getMetadata() 方法的返回值里里包含 featureenv 即可。

注意:基线环境部署的服务实例不需要设置 featureenv 标签,表明其不属于任何测试环境,才可在请求没有匹配到对应测试环境的时候,匹配到基线环境。

kubernetes服务注册场景

北极星提供了polaris-controller,支持直接将pod labels同步为北极星上面的实例标签。

  • 在集群中安装polaris-controller,安装方式可参考:安装指南
  • 创建deployment的时候,通过template配置,指定pod的标签信息,详细参考:标签指定
apiVersion: apps/v1
kind: Deployment
metadata:
  name: nginx-deployment
  labels:
    app: nginx
spec:
  replicas: 3
  selector:
    matchLabels:
      app: nginx
  template:
    metadata:
      labels:
        app: nginx
    spec:
      containers:
      - name: nginx
        image: nginx:1.14.2
        ports:
        - containerPort: 80

做完上面2步后,polaris-controller默认会对集群中的服务数据进行全量同步,而pod中的labels也会同步为北极星的实例标签。

阶段二

在 VM 或者容器中部署业务应用,需要保证业务应用与北极星服务治理中心的网络连通性。

阶段三

往请求中加入固定的 Header 是网关最常见的插件,如上图所示。可以在每个环境部署一个网关,所有经过网关的请求都增加 X-Polaris-Metadata-Transitive-featureenv=f1 请求头(其中,f1替换为对应的测试环境标签)即可。

请求头 X-Polaris-Metadata-Transitive-featureenv=f1 是按照北极星定义的请求头格式设置的,其中 X-Polaris-Metadata-Transitive- 是北极星需要读取请求头的前缀,例子中的 featureenv 为实际的键值对的key,f1 为实际的键值对的value。

Spring Cloud Tencent 静态染色

在 Spring Cloud 项目中,可以利用 Spring Cloud Gateway 提供的一些方式来帮助实现流量的静态染色,如下所示。所有经过该网关的流量,都在经过的 HTTP 请求的头部自动打上 X-Polaris-Metadata-Transitive-featureenv=f1 的数据标签。

  1. 配置文件方式添加 HTTP 请求头部

开发者可以在配置文件中,为每一个需要进行流量染色的服务,添加 Spring Cloud Gateway 提供的内置 filter 规则来实现流量染色的 HTTP 请求头部的添加。

spring:
  cloud:
    gateway:
      routes:
      - id: add_request_header_route
        uri: lb://NAME_OF_SERVICE
        filters:
        - AddRequestHeader=X-Polaris-Metadata-Transitive-featureenv, f1

具体文档参考:The AddRequestHeader GatewayFilter Factory

  1. 代码方式添加 HTTP 请求头部

开发者也可以实现 Spring Cloud Gateway 提供的 GlobalFilter 接口,直接为所有经过网关应用的请求添加流量染色的 HTTP 请求头部。

@Component
public class CustomGlobalFilter implements GlobalFilter {
	@Override
	public Mono<Void> filter(ServerWebExchange exchange, GatewayFilterChain chain) {
		// get request builder
		ServerHttpRequest.Builder builder = exchange.getRequest().mutate();

		try {
			builder.header("X-Polaris-Metadata-Transitive-featureenv", URLEncoder.encode("f1", UTF_8));
		}
		catch (UnsupportedEncodingException e) {
			builder.header("X-Polaris-Metadata-Transitive-featureenv", "f1");
		}

		return chain.filter(exchange.mutate().request(builder.build()).build());
	}
}

3.3 - K8s 相关实践

3.3.1 - 跨集群服务注册

提示

  • 该文章仅适用于不同 Kubernetes 集群间的 POD 可 IP 直连

背景及架构

北极星支持对接多k8s集群,不同集群的服务注册同一个北极星服务端,可以实现多集群之间的直通POD负载均衡,可以解决使用K8S的CLUSTER IP负载均衡模式下会出现的长连接负载不均等问题。

北极星服务端只部署一套,不同的k8s集群中的POD,通过集群内的k8s controller,将POD信息同步到北极星,同时将集群名作为服务实例的标签注册上去,便于用户进行查找以及按集群就近路由。

部署k8s controller

k8s controller需要部署到k8s的集群中,可以参考以下文档进行部署:k8s controller部署指南

配置集群名

k8s controller默认会以default集群名进行部署,我们需要修改成实际的集群名。

  • 修改配置文件集群名

打开polaris-controller的安装包(非源码包),找到configmap.yaml这个文件,并且在文件中,将clusterName的值修改成实际的集群名称

    # k8s集群名,需要修改成实际的集群名称
    clusterName: "default" 

修改完毕后,通过kubectl apply -f configmap.yaml,将配置重新发布。

  • 重启controller

找到polaris-controller的部署路径,一般在polaris-system命名空间下,将controller的POD重启

  • 观察北极星控制台

打开北极星控制台,找到对应通过的服务名,进入实例列表,确认POD IP是否已经带入clusterName的标签信息。

3.4 - 存量服务迁移

3.4.1 - Eureka 迁移方案

服务迁移

原理说明

北极星对Eureka的API进行了全兼容,因此,业务可以把北极星集群作为一个Eureka节点,加入到Eureka原来的集群中,基于Eureka原生的同步协议进行新老注册中心的服务数据双向同步。

在这种迁移模式下, 用户可逐渐、分批次的将老集群中的eureka升级成北极星,升级过程对数据面不感知。新应用(使用Spring Cloud Tencent或其他北极星客户端),和存量应用(仍然使用Spring Cloud Netflix或者其他Eureka客户端),都可以接入到北极星完成注册发现,无需代码修改。

启动迁移

*** 安装北极星集群版 ***

需要先安装北极星集群版,可参考 集群版安装

*** 迁移相关的参数说明 ***

北极星通过eureka-apiserver实现了与开源标准eureka接口全兼容,用户如果对eureka进行了一些定制,需要手动调整eurekaeureka-apiserver的相关参数。

所有的eureka相关的参数都在polaris.yaml中,在apiservers.option下面进行配置:

参数名 含义 示例
listenIP eureka兼容的服务端监听IP 0.0.0.0
listenPort eureka兼容的服务端监听端口 8761
namespace 通过eureka接口注册及发现的服务节点的命名空间,由于eureka本身没有命名空间的概念,所以针对eureka的服务管理操作必须在北极星某个命名空间下进行 default
refreshInterval 全量服务实例缓存的刷新间隔,单位秒 10
deltaExpireInterval 增量实例缓存的刷新间隔,单位秒 60
peersToReplicate 需要进行复制的对端eureka服务端节点列表 - 9.15.15.5:8761
customValues 自定义配置,用户如果对eureka服务端进行了定制并影响了参数,则可以把相关的参数填上,比如定制了dataCenterInfo,则可以将新的dci信息填入,北极星服务端会按照配置的信息进行下发 见" 定制dataCenterInfo"

*** 往北极星服务端添加eureka地址 ***

  • 进入北极星集群中的其中一个节点,找到polaris.yaml配置文件,在apiservers.service-eureka.option下面,添加eureka服务端地址信息,用于做数据复制:
apiservers:
  - name: service-eureka
    option:
      ... // 其他配置
      peersToReplicate: // eureka服务端节点的地址列表
      - <eureka1 IP>:<eureka1 port>
      - <eureka2 IP>:<eureka2 port>
  • 重启北极星服务端。

*** 往eureka服务端添加北极星服务端地址 ***

  • 修改eureka服务端的配置,将北极星其中一个节点的地址,加入到原有的eureka集群中。
eureka:
  client:
    serviceUrl:
      defaultZone: http://<北极星服务端IP>:8761/eureka/
  • 重启Eureka服务端。

*** 定制dataCenterInfo ***

如果用户对eureka-server进行了定制,比如定制了<dataCenterInfo class="com.netflix.appinfo.AmazonInfo">,那么可以在北极星把这个配置项加入,即可下发带有定制后的DCI相关的服务数据。

apiservers:
  - name: service-eureka
    option:
      ... // 其他配置
      customValues:
        dataCenterInfoClass: "com.netflix.appinfo.AmazonInfo"
        dataCenterInfoName: "myOwn"

迁移完成

配置好迁移后,可以在北极星控制台能同时查看到注册在eureka的实例,以及注册到北极星的实例,相互之间可以正常访问。

从eureka同步到北极星的服务实例,会打入internal-eureka-replicate:true的标签。

3.4.2 - Nacos 迁移方案

3.4.2.1 - 协议兼容(推荐)

提示

本章节仅适用于北极星服务端版本 >= 1.18.0

概述

如果你希望使用 Polaris 代替 Nacos 作为新的注册中心,Polaris 提供了协议兼容的方式,用户仅需要更改程序中的 nacos-client 的服务端接入地址即可。

准备Polaris服务端

需要预先安装好Polaris服务端,安装方式可参考:集群版安装

注册发现

Nacos 服务名和北极星服务名映射关系

Nacos 字段 Nacos 字段值 北极星字段 北极星字段值描述
namespace 默认命名空间/非默认命名空间ID namespace default/命名空间名称
group DEFAULT_GROUP service 作为服务名的前缀
service DEFAULT_GROUP service 作为服务名的后缀,${group}__${service} 为最终的北极星服务名, 如果 group == DEFAULT_GROUP,则服务名为 ${service}
cluster DEFAULT instance.metadata 作为实例标签的一部份, 实例标签 key 为 internal-nacos-cluster

原生 Nacos-Client

Properties properties = new Properties();
properties.put(PropertyKeyConst.SERVER_ADDR, "北极星服务端IP:8848");
properties.put(PropertyKeyConst.NAMESPACE, "北极星命名空间名称");
properties.put(PropertyKeyConst.USERNAME, "可任意值");
properties.put(PropertyKeyConst.PASSWORD, "北极星用户/用户组的资源访问凭据 Token");

// 创建注册发现客户端
NamingService namingService = NacosFactory.createNamingService(properties);

Spring Cloud Alibaba

spring.cloud.nacos.username="可任意值"
spring.cloud.nacos.password="北极星用户/用户组的资源访问凭据 Token"
spring.cloud.nacos.discovery.server-addr="北极星服务端IP:8848"
spring.cloud.nacos.discovery.namespace="北极星命名空间名称"

Dubbo

dubbo
 registry
   address: nacos://北极星服务端IP:8848?username=可任意值&password=北极星用户/用户组的资源访问凭据 Token
   parameters.namespace: 北极星命名空间名称
  metadata-report
    address: nacos://北极星服务端IP:8848

配置管理

Nacos 配置信息和北极星配置信息映射关系

Nacos 字段 Nacos 字段值 北极星字段 北极星字段值描述
namespace 默认命名空间/非默认命名空间ID namespace default/命名空间名称
group DEFAULT_GROUP group 北极星配置分组名称
dataId application.yaml file_name 北极星配置文件名称

原生 Nacos-Client

Properties properties = new Properties();
properties.put(PropertyKeyConst.SERVER_ADDR, "北极星服务端IP:8848");
properties.put(PropertyKeyConst.NAMESPACE, "北极星命名空间名称");
properties.put(PropertyKeyConst.USERNAME, "可任意值");
properties.put(PropertyKeyConst.PASSWORD, "北极星用户/用户组的资源访问凭据 Token");

// 注册配置客户端
ConfigService configService = new NacosConfigService(properties);

Spring Cloud Alibaba

spring.cloud.nacos.username="可任意值"
spring.cloud.nacos.password="北极星用户/用户组的资源访问凭据 Token"
spring.cloud.nacos.config.namespace="北极星命名空间名称"
spring.cloud.nacos.config.server-addr="北极星服务端IP:8848"
spring.cloud.nacos.config.group="北极星配置分组名称"

Dubbo

dubbo
  config-center
    address: nacos://北极星服务端IP:8848

3.4.2.2 - 配置迁移

概述

如果你希望使用 Polaris 代替 Nacos 作为新的配置中心,Polaris 提供 polaris-sync方案:通过 server-to-server 的迁移方式,将 Nacos 的配置迁移至 Polaris。

准备Polaris服务端

需要预先安装好Polaris服务端,安装方式可参考:集群版安装

准备 polaris-sync

需要下载 polaris-sync 的最新 release 版本:下载地址

下载完之后,将 polaris-sync-server-${version}.zip 进行解压

wget https://github.com/polarismesh/polaris-sync/releases/download/${version}/polaris-sync-server-${version}.zip

unzip polaris-sync-server-${version}.zip

完成上述步骤之后,进入 polaris-sync-server-${version}/conf 目录,可以看到两个配置文件,这里只需要关注 sync-config.json

➜  conf tree
.
├── sync-config.json      # 配置同步任务配置文件
└── sync-registry.json   # 服务同步任务配置文件

sync-config.json 配置

sync-config.json 是服务同步任务的配置文件,polaris-sync 启动之后会自动加载该配置文件,从中获取服务数据同步任务配置信息,并根据该信息创建对应的服务同步任务执行。

sync-config.json 配置文件的格式是 json,其配置内容主要由以下四个对象组成

  • tasks: 数组形式,定义的服务数据同步任务信息,即设置服务数据从那个源注册中心同步到目标注册中心
  • methods: 数组形式,定义服务数据同步的方式,当前支持 PULL 模式以及 WATCH 模式
  • health_check: 对象形式,定义是否需要对源注册中心以及目标注册中心进行健康检查,探测注册中心是否存活
  • report: 对象形式,定义 polaris-sync 在同步过程中产生的指标数据上报的目标位置

这里我们对 tasks 配置参数解析

参数 key 类型 名称 示例|
name string 同步任务 ID,唯一标识 nacos-to-polaris
enable bool 同步任务是否开启 true
source object 源配置中心信息 NULL
source.name string 源注册中心实例别名 nacos
source.type string 注册中心类型 nacos
source.server object 源配置中心服务端信息 NULL
source.server.addresses []string 注册中心接入地址 [“127.0.0.1:8848”]
source.server.user string 注册中心用户信息 nacos
source.server.password string 注册中心用户密码信息 nacos
source.server.token string 注册中心用户访问凭据 token token-123
source.db object 源配置中心数据库信息 NULL
source.db.jdbc_url string 数据库 jdbc 信息 jdbc:mysql://127.0.0.1:3306/nacos
source.db.username string 数据库账户 nacos
source.db.password string 配置数据库账户密码 nacos
destination object 目标配置中心信息 NULL
destination.name string 目标配置中心实例别名 nacos
destination.type string 目标配置中心类型 nacos
destination.server object 目标配置中心服务端信息 NULL
destination.server.addresses []string 目标配置中心接入地址 [“127.0.0.1:8848”]
destination.server.user string 目标配置中心用户信息 nacos
destination.server.password string 目标配置中心用户密码信息 nacos
destination.server.token string 目标配置中心用户访问凭据 token token-123
destination.db object 目标配置中心数据库信息 NULL
destination.db.jdbc_url string 数据库 jdbc 信息 jdbc:mysql://127.0.0.1:3306/nacos
destination.db.username string 数据库账户 nacos
destination.db.password string 配置数据库账户密码 nacos
match []object 设置待同步的配置数据匹配规则 [{}]
match[${index}].namespace string 待同步的服务命名空间的 namespace
match[${index}].config_group string 待同步的配置分组 config_group

这里你可以参考 sync-config.json 的样例配置,根据你的实际情况进行调整 tasks 对象即可,examples/sync-config.json

启动 polaris-sync

完成 sync-config.json 的配置之后,启动 polaris-sync 执行配置数据同步

➜ cd polaris-sync-server-0.3.0-beta

➜ bash bin/start.sh

验证

  • 启动 polaris-sync 之后,查看日志 loggers/polaris-sync.log 观察到有以下日志则同步任务正常运行
[Polaris] success to send post http://127.0.0.1:8090/config/v1/configfiles/release, method POST
  • 登陆 nacos 控制台以及 polaris 控制台,查看配置是否同步到了 Polaris,以及在 Nacos 新增配置后,在 Polaris 控制台也能够实时看到。

何时结束

当你的所有应用均默认从 Polaris 拉取配置后,则可以关闭 polaris-sync 进程结束配置数据同步,然后便可以关停 Nacos 服务。至此完成配置数据从 Nacos 迁移至 Polaris。

3.4.2.3 - 服务迁移

概述

如果你希望使用 Polaris 代替 Nacos 作为新的注册中心,Polaris 提供了两种服务迁移的方式

  • polaris-sync方案:提供server-to-server的迁移方式,支持多语言应用的迁移,需额外部署polaris-sync迁移工具
  • 双注册双发现方案:提供JavaAgent的迁移方式,用户代码无感的方式完成服务迁移,仅支持Java应用,无需额外部署polaris-sync迁移工具

在执行服务数据从一个注册中心迁移至另一个注册中心的过程中,往往需要双向访问:

  • 迁移到新注册中心的服务,需要访问未迁移的服务。
  • 未迁移至新注册中心的服务,需要访问已迁移的服务。

当前 Polaris 提供的两种服务迁移方式均能够满足该要求,接下来你可以通过以下内容了解如何通过服务数据同步或者多注册多发现进行服务迁移。

准备Polaris服务端

需要预先安装好Polaris服务端,安装方式可参考:集群版安装

服务数据同步

polaris-sync 提供server-to-server的迁移方式,支持 Nacos 和 Polaris 进行服务数据双向同步。你可以按照以下步骤编写 polaris-sync 服务迁移的任务配置。从而实现将服务数据从 Nacos 平稳的迁移至 Polaris。

准备 polaris-sync

需要下载 polaris-sync 的最新 release 版本:下载地址

下载完之后,将 polaris-sync-server-${version}.zip 进行解压

wget https://github.com/polarismesh/polaris-sync/releases/download/${version}/polaris-sync-server-${version}.zip

unzip polaris-sync-server-${version}.zip

完成上述步骤之后,进入 polaris-sync-server-${version}/conf 目录,可以看到两个配置文件,这里只需要关注 sync-registry.json

➜  conf tree
.
├── sync-config.json
└── sync-registry.json

sync-registry.json 配置

sync-registry.json 是服务同步任务的配置文件,polaris-sync 启动之后会自动加载该配置文件,从中获取服务数据同步任务配置信息,并根据该信息创建对应的服务同步任务执行。

sync-registry.json 配置文件的格式是 json,其配置内容主要由以下四个对象组成

  • tasks: 数组形式,定义的服务数据同步任务信息,即设置服务数据从那个源注册中心同步到目标注册中心
  • methods: 数组形式,定义服务数据同步的方式,当前支持 PULL 模式以及 WATCH 模式
  • health_check: 对象形式,定义是否需要对源注册中心以及目标注册中心进行健康检查,探测注册中心是否存活
  • report: 对象形式,定义 polaris-sync 在同步过程中产生的指标数据上报的目标位置

这里我们对 tasks 配置参数解析

参数 key 类型 名称 示例|
name string 同步任务 ID,唯一标识 nacos-to-polaris
enable bool 同步任务是否开启 true
source object 源注册中心信息 NULL
source.name string 源注册中心实例别名 nacos
source.type string 注册中心类型 nacos
source.addresses []string 注册中心接入地址 [“127.0.0.1:8848”]
source.user string 注册中心用户信息 nacos
source.password string 注册中心用户密码信息 nacos
source.token string 注册中心用户访问凭据 token token-123
destination object 目标注册中心信息 NULL
destination.name string 目标注册中心实例别名 nacos
destination.type string 注册中心类型 nacos
destination.addresses []string 目标注册中心接入地址 [“127.0.0.1:8848”]
destination.user string 目标注册中心用户信息 nacos
destination.password string 目标注册中心用户密码信息 nacos
destination.token string 目标注册中心用户访问凭据 token token-123
match []object 设置待同步的服务数据匹配规则 [{}]
match[${index}].namespace string 待同步的服务命名空间的 namespace
match[${index}].service string 待同步的服务名称 service

这里你可以参考 sync-registry.json 的样例配置,根据你的实际情况进行调整 tasks 对象即可,examples/sync-registry.json

启动 polaris-sync

完成 sync-registry.json 的配置之后,启动 polaris-sync 执行服务数据同步

➜ cd polaris-sync-server-0.3.0-beta

➜ bash bin/start.sh

验证

  • 启动 polaris-sync 之后,查看日志 loggers/polaris-sync.log 观察到有以下日志则同步任务正常运行
[LOG] success to watch for service cn.polarismesh.polaris.sync.core.tasks.
[Core][Pull]prepare to update from registry source-nacos, type NACOS, service service='nacos.test.3'}, group default, instances []
[Core][Watch]prepare to update service Service{namespace='default',  default instances []
[Core][Watch]prepare to update service Service{namespace='default',  default instances []
[Polaris] service not found to discover service Service='nacos.test.3'} to http://127.0.0.1:8090/v1/Discover
[Polaris] service not found to discover service Service{namespace='default', service='nacos.test.3'} to http://127.0.0.1:8090/v1/Discover
  • 登陆 nacos 控制台以及 polaris 控制台,查看服务以及服务下的实例是否同步成功,实例能够稳定维持健康状态。

何时结束

当你的所有应用均默认注册到 Polaris 之后,则可以关闭 polaris-sync 进程结束服务数据同步,然后便可以关停 Nacos 服务。至此完成服务数据从 Nacos 迁移至 Polaris。

多注册多发现

Polaris 提供 JavaAgent 的迁移方式,无需额外部署 polaris-sync 迁移工具,仅支持 Java 应用的迁移

准备 polaris-java-agent

需要下载 polaris-java-agent 的最新 release 版本:下载地址

下载完之后,将 polaris-sync-server-${version}.zip 进行解压

wget https://github.com/polarismesh/polaris-java-agent/releases/download/${version}/polaris-java-agent-${version}.zip

unzip polaris-java-agent-${version}.zip

完成上述步骤之后,进入 polaris-java-agent-${version} 目录,先看下目录结构

➜  polaris-java-agent-1.3.0-beta tree
.
├── conf
│   └── plugin
│       └── springcloud2021
│           └── application.properties           # Spring Cloud Java Agent 的插件配置
├── plugins
│   └── spring-cloud-2021-plugin-1.3.0-beta.jar  # Spring Cloud 2021 的 Java Agent 插件支持
└── polaris-agent-core-bootstrap.jar			 # Polaris Java Agent 主程序

编辑 application.properties

# 配置服务名称
spring.application.name=${服务名称信息}
# 开启 polaris java agent 的服务注册发现能力
spring.cloud.discovery.enabled=true
# 设置北极星注册中心地址
spring.cloud.polaris.address=grpc\://127.0.0.1\:8091
# 设置注册的命名空间信息
#  注意:
#   1. 如果需要开启多注册能力,需要确保已经在 Polaris 上创建了原本应用在 Nacos 的命名空间
#   2. 北极星的默认命名空间 default 等同于 nacos 的默认命名空间
spring.cloud.polaris.namespace=default
# 开启双注册双发现到 nacos
spring.cloud.nacos.enabled=true
# 设置 nacos 服务注册中心的地址
spring.cloud.nacos.discovery.server-addr=127.0.0.1\:8848
# 设置 nacos 的账户信息
spring.cloud.nacos.username=nacos
spring.cloud.nacos.password=nacos
# 是否开启从 nacos 拉取服务实例信息
spring.cloud.nacos.discovery.enabled=true
# 是否开启将服务注册到 nacos
spring.cloud.nacos.discovery.register=true

重启业务进程

重启业务进程时,需要设置 -javaagent 参数指定为 Polaris Java Agent 才能启用多注册多发现能力。

java -javaagent:xxx/polaris-agent-core-bootstrap.jar -jar {你的 Java 程序名称}.jar

验证

登陆 nacos 控制台以及 polaris 控制台,查看业务进程是否同时注册到 Nacos 以及 Polaris,并且实例均处于健康状态。

何时结束

当你的所有应用均通过 Polaris Java Agent 完成双注册双发现之后,可以通过调整 application.properties,设置 spring.cloud.nacos.enabled=false 禁止注册到 Nacos,或者调整业务进程逻辑使得默认注册到 Polaris,再逐步重启相关业务进程即可。

4 - 参考文档

北极星相关的参考文档,包含版本信息、接口文档、测试报告和开发者文档等。

4.1 - 版本信息

4.1.1 - 版本升级指南

服务端与控制台版本对应表

北极星服务端北极星控制台 版本的对应关系

Polaris-Server Version Polaris-Console Version
v1.18.x v1.15.0
v1.17.3~v1.17.8 v1.14.4
v1.17.2 v1.14.0
v1.17.0~v1.17.1 v1.13.x
v1.16.x v1.13.x
v1.15.x v1.12.x
v1.14.x v1.11.x
v1.13.x v1.10.x
v1.12.x v1.9.x
v1.11.x v1.8.x
v1.10.0 v1.7.3
v1.9.0 v1.6.1
v1.8.0 v1.6.0
v1.7.0 v1.5.8
v1.6.0 v1.4.0
v1.5.0 v1.3.2
v1.4.0 v1.3.1
v1.3.2 v1.3.1
v1.3.1 v1.3.0
v1.3.0 v1.2.1
v1.2.2 v1.2.1
v1.2.1 v1.2.1
v1.2.0 v1.2.0
v1.0.0 v1.0.0

1.10.x 版本升级至 1.11.x

polaris-server 升级

polaris-console 升级

  • 覆盖安装 polaris-console

1.11.x 版本升级至 1.12.x

polaris-server 升级

polaris-console 升级

  • 覆盖安装 polaris-console

1.12.x 版本升级至 1.13.x

polaris-server 升级

polaris-console 升级

  • 覆盖安装 polaris-console

1.13.x 版本升级至 1.14.x

polaris-server 升级

polaris-console 升级

  • 覆盖安装 polaris-console

1.14.x 版本升级至 1.15.x

polaris-server 升级

polaris-console 升级

  • 覆盖安装 polaris-console

1.15.x 版本升级至 1.16.x

polaris-server 升级

polaris-console 升级

  • 覆盖安装 polaris-console

1.16.x 版本升级至 1.17.2

polaris-server 升级

polaris-console 升级

  • 覆盖安装 polaris-console

1.17.2 版本升级至 1.17.8

polaris-server 升级

polaris-console 升级

  • 覆盖安装 polaris-console

1.17.8 版本升级至 1.18.0

polaris-server 升级

polaris-console 升级

  • 覆盖安装 polaris-console

升级注意事项

  • polaris-console 更新之后需要刷新浏览器缓存,避免升级 polaris-console 后浏览器还缓存前端页面文件信息,从而无法体验新的前端交互

4.1.2 - Pre-Release v1.18.0

下载地址

特性说明

Nacos客户端协议全功能版本兼容

在 1.18.0 版本中,社区正式将 apiserver-nacos 插件纳入官方默认插件,并完善了 nacos1.x/nacos2.x 的客户端功能特性兼容。用户无需替换自己的 nacos-client 依赖,只需更换接入地址即可接入北极星的注册发现以及配置管理。

  • nacos1.x
    • 注册发现
      • 实例注册
      • 服务发现
      • 心跳上报
      • 基于 UDP 的服务端主动推送
    • 配置管理
      • 配置发布
      • 配置查询
      • 配置监听
  • nacos2.x
    • 注册发现
      • 实例注册
      • 服务发现
      • 基于 gRPC 长连接的实例信息维护
      • 基于 gRPC 的服务端主动推送
    • 配置管理
      • 配置发布
      • 配置查询
      • 配置监听
apiservers:
  - name: service-nacos
    option:
      listenIP: "0.0.0.0"
      # nacos http 协议监听端口,grpc 端口默认在该基础上 +1000
      listenPort: 8848
      # 设置 nacos 默认命名空间对应 Polaris 命名空间信息
      defaultNamespace: default
      connLimit:
        openConnLimit: false
        maxConnPerHost: 128
        maxConnLimit: 10240

支持 Mesh Sidecar 场景下的 Cluster/Endpoint 按需加载

Sidecar Mesh 场景下,每个 Sidecar 进程都会收到 xDS Server 推送下来的全量服务数据。假设一个 Workload-1 他仅仅调用了 Service-1/Service-2 两个服务,但是大部份的 xDS Server 都会将全量的 Service 推送给 Workload-1 的 Sidecar。这样子带来的后果就是每个 Sidecar 的内存、资源消耗会随着服务量级的增长而增长。

为了解决上述问题。社区在 1.18.0 版本中实现了 Envoy xDS 中的 OCDS 能力。默认只推送全量的 VHDS 到 Sidecar 中,Cluster/Endpoint 资源根据实际请求进行按需加载。

同时我们也优化了服务端关于 xDS 规则生成的内存占用,不再使用 envoy go-control-plane 中的 SnapshotCache 实现,而是选择了 LinearCache,根据每类 xDS 资源的生成特点进行存放在不同的 LinearCache 中,尽可能将公共的 xDS 资源只生成一份,其余的需要按照 mtls、odcds 场景的规则则各自存在对应的 LinearCache 中。

  • 需要搭配 polaris-controller v1.7.0 版本一起使用
  • 由于当前 Envoy 的按需加载能力,当 On-Demand VHDS 和 On-Demand Cluster 同时启用时存在 BUG,因此目前仅实现了 On-Demand Cluster 的能力,待和 Envoy 社区推进解决该 BUG 后用户可享受真正的 Envoy 按需加载能力,社区 issue

支持 Mesh Sidecar 场景下的分布式限流

在 1.18.0 版本中,我们针对 Mesh Sidecar 的场景,支持将 Polaris 的分布式限流通过由 Polaris-Sidecar 组件实现的 RLS 提供给 Envoy 的限流 Filter,使得用户在 Mesh 场景下可以享受 Polaris 的分布式限流能力

配置中心支持灰度发布

为了让用户有更好的配置中心使用体验,社区在 v1.18.0 版本中支持配置灰度能力,当前灰度能力支持用户自定义客户端标签进行灰度控制下发;针对存量老版本客户端仅支持根据客户端IP进行灰度控制台下发。

polaris-go 配置客户端标签

global:
  serverConnector:
    addresses:
      - 127.0.0.1:8091
  client:
    labels:
      ${label_key}: ${label_value}

polaris-java

开发中…

配置中心和 Kubernetes ConfigMap 无缝打通

当前通过 polaris-controller 组件将 Kubernetes 上的 Service 信息同步至北极星中,用户便可以针对 Kubernetes 上的 POD 进行相应的服务治理。但是对于 ConfigMap 这一配置资源的管理却还是只能停留在 Kubernetes;假如北极星能够接管用户的 ConfigMap 管理,用户只需要在北极星控制台上进行配置文件创建、发布即可将配置同步到 ConfigMap 中那么用户还能够享受到配置审计、发布历史、配置回滚等增强功能。因此在 1.18.0 版本中我们支持了北极星和 Kubernetes ConfigMap 资源的数据打通能力,用户只需要部署 polaris-controller 1.7.0 版本即可,相关使用文档参考 K8s 配置同步

版本变化

特性

  • [PR #1174] feat:support push envoy rls filter xds
  • [PR #1175] feat(xds): add OutlierDetection and HealthCheck
  • [PR #1215] 服务端支持流量无损停机
  • [PR #1237] feat: allow empty db password
  • [PR #1253] feat:envoy ratelimit action suppoer all spec label & add hds feature
  • [PR #1271] 配置中心支持灰度发布
  • [PR #1276] refactor:优化xds生成逻辑 & 合并社区 nacosserver 插件
  • [PR #1285] feat:新增配置控制是否允许自动创建服务
  • [PR #1304] feat:xdsv3 support envoy odcds

优化

  • [PR #1170] refactor:Adjust xds rule build
  • [PR #1179] refactor: remove the template code used by map to improve code readability
  • [PR #1232] refactor:statis log add traffic direction info
  • [PR #1235] in order to improve the processing of service discovery QPS when using api-http server
  • [PR #1250] 增强eureka delta api的稳定性
  • [PR #1283] 无效请求不需要上报prometheus

测试覆盖

  • [PR #1309] test:add unit test for service visible feature

BUG 修复

  • [PR #1162] 调整与Eureka实例的状态兼容逻辑
  • [PR #1173] 单机版为用户关联用户组时,会默认勾选所有用户组
  • [PR #1184] 修复通过服务别名拉取时,服务信息为源服务信息问题
  • [PR #1188] 用户组token鉴权bug修复;用户名校验规则修改:允许包含英文句号
  • [PR #1192] 修复batchConfig批量注销实例配置问题
  • [PR #1196] 修复心跳上报写redis异常时未将异常结果返回问题
  • [PR #1197] 修复熔断/探测规则更新绑定服务信息后缓存遗留脏数据
  • [PR #1201] 修复 arm64 环境无法使用 docker image
  • [PR #1212] 修复清理软删除实例时没有同步清理 instance_metadata 以及 health_check 表的数据
  • [PR #1213] 修复xDS 生成 cacheKey 时缺失 gatewayService
  • [PR #1233] fix: Dockerfile 8761 port duplicate
  • [PR #1240] fix typo: firtstUpdate -> firstUpdate
  • [PR #1273] 解决配置中心标签 value 和 key 相同的问题
  • [PR #1281] fix release_history search bug
  • [PR #1287] fix:修复checkLeader任务卡住 & 修复nacos2.x逻辑兼容问题
  • [PR #1291] fix: statis plugin will happen nil pointer dereference on item
  • [PR #1301] 入口流量匹配规则缺失

New Contributors

Full Changelog: https://github.com/polarismesh/polaris/compare/v1.17.8...v1.18.0

参与 PolarisMesh 社区

欢迎大家使用体验、Star、Fork、Issue,也欢迎大家参与 PolarisMesh 开源共建!

仓库地址:https://github.com/polarismesh/polaris

项目文档: https://polarismesh.cn/#/

往期发布:https://github.com/polarismesh/polaris/releases

4.1.3 - Release v1.17.8

下载地址

特性说明

支持 Mesh Sidecar 场景下的单机限流

在 1.17.3 版本中,我们针对 Mesh Sidecar 的场景,支持将 Polaris 的单机限流规则 Spec 通过 Envoy XDS 的格式进行下发给 Sidecar,使得用户在 Mesh 场景下可以享受 Polaris 的限流能力

配置中心支持配置回滚、撤回发布

为了让用户有更好的配置中心使用体验,社区在 v1.17.3 版本中支持了配置回滚、撤回某个配置版本发布的能力。当前仅支持通过服务端 OpenAPI 进行操作,前端 UI 支持会在下一个版本中对外放出。

关闭服务端自注册的心跳上报

修改服务端配置

bootstrap:
  # Register as Arctic Star Service
  polaris_service:
    # disable_heartbeat disable polaris_server node run heartbeat action to keep lease polaris_service
    disable_heartbeat: true

版本变化

特性

  • [PR 1174] feat:support push envoy rls filter xds
  • [PR 1175] feat(xds): add OutlierDetection and HealthCheck
  • [PR 1187] [Refactor] 配置中心重构+支持配置回滚/撤回发布

优化

  • [PR 1162] 调整与Eureka实例的状态兼容逻辑
  • [PR 1170] refactor:Adjust xds rule build
  • [PR 1179] refactor: remove the template code used by map to improve code readability
  • [PR 1202] refactor:配置文件缓存逻辑重构

BUG 修复

  • [PR 1173] 单机版为用户关联用户组时,会默认勾选所有用户组
  • [PR 1184] 修复通过服务别名拉取时,服务信息为源服务信息问题
  • [PR 1188] 用户组token鉴权bug修复;用户名校验规则修改:允许包含英文句号
  • [PR 1192] 修复batchConfig批量注销实例配置问题
  • [PR 1196] 修复心跳上报写redis异常时未将异常结果返回问题
  • [PR 1208] 修复熔断/探测规则更新绑定服务信息后缓存遗留脏数据
  • [PR 1212] 修复清理软删除实例时没有同步清理 instance_metadata 以及 health_check 表的数据
  • [PR 1213] 修复xDS 生成 cacheKey 时缺失 gatewayService
  • [PR 1201] 修复 arm64 环境无法使用 docker image 问题

New Contributors

Full Changelog: https://github.com/polarismesh/polaris/compare/v1.17.2...v1.17.5

参与 PolarisMesh 社区

欢迎大家使用体验、Star、Fork、Issue,也欢迎大家参与 PolarisMesh 开源共建!

仓库地址:https://github.com/polarismesh/polaris

项目文档: https://polarismesh.cn/#/

往期发布:https://github.com/polarismesh/polaris/releases

4.1.4 - Release v1.17.2

下载地址

特性说明

配置文件支持加密

配置文件中经常会涉及一些敏感信息,例如帐号密码等参数。这时需对这些敏感信息进行加密,提供信息安全性。因此在 1.17.2 版本中配置中心正式支持配置加密功能,进一步提升配置中心的功能完备性。具体使用文档参考 配置加密

启用该能力的配置文件示例

plugin:
  crypto:
    entries:
      # 配置加密功能中,服务端提供的加密算法插件配置
      - name: AES

支持集群部署不依赖 Redis 能力正式发布

在 1.17.2 中社区正式提供北极星集群部署的去 redis 组件的集群部署方案,方便用户快速搭建北极星,减低使用北极星的成本。

启用该能力的配置文件示例

healthcheck:
  open: true
  service: polaris.checker
  slotNum: 30
  minCheckInterval: 1s
  maxCheckInterval: 30s
  clientReportInterval: 120s
  batch:
    heartbeat:
      open: true
      queueSize: 10240
      waitTime: 32ms
      maxBatchCount: 32
      concurrency: 64
  checkers:
    - name: heartbeatLeader

北极星存储层支持 Postgresql (实验性)

在 1.17.2 中, 社区开发者 @bingxindan 带了存储层基于 postgresql 的支持, 可通过引入 store-postgresql 插件自编译开启存储层使用 postgresql 的特性。

北极星协议层支持 Nacos 2.x 注册发现 (实验性)

在 1.17.2 中, 社区开发者 @chatless 带了协议层对 nacos2.x 的支持, 可通过引入 apiserver-nacos 插件自编译开启协议层支持 nacos2.x 客户端接入的特性。

What’s Changed

Feature

  • [PR #1124] Support configuration encryption function
  • [PR #1126] 解耦AuthServer,将功能拆解到UserOperator及StrategyOperator
  • [PR #1135] Add support for config upsert and publish

Enhancement

  • [PR #1131] Support sending the last heartbeat health time of the instance to the data plane
  • [PR #1137] Optimize store layer error code return and instance query cache
  • [PR #1141] docs(update): 完善OpenAPI swagger 文档
  • [PR #1147] optimize the code style of the configuration center

BugFix

  • [PR #1143] fix:hotfix remove user mobile and email
  • [PR #1144] doc:CircuitBreakerStore文档注释错误
  • [PR #1151] Fix the failure of the metrics function after restarting the container
  • [PR #1155] The server nil panic problem after the health check function is turned off

New Contributors

Full Changelog: https://github.com/polarismesh/polaris/compare/v1.17.1...v1.17.2

参与 PolarisMesh 社区

欢迎大家使用体验、Star、Fork、Issue,也欢迎大家参与 PolarisMesh 开源共建!

仓库地址:https://github.com/polarismesh/polaris

项目文档: https://polarismesh.cn/#/

往期发布:https://github.com/polarismesh/polaris/releases

4.1.5 - Release v1.17.0

下载地址

特性说明

支持集群部署不依赖 Redis(BETA)

为了减低中小公司在部署北极星时需要维护 redis 以及 mysql 组件所带来的运维工作量,在 1.17.0 中我们提供北极星集群部署的去 redis 组件的集群部署方案,方便用户快速搭建北极星,减低使用北极星的成本。

启用该能力的配置文件示例

healthcheck:
  open: true
  service: polaris.checker
  slotNum: 30
  minCheckInterval: 1s
  maxCheckInterval: 30s
  clientReportInterval: 120s
  batch:
    heartbeat:
      open: true
      queueSize: 10240
      waitTime: 32ms
      maxBatchCount: 32
      concurrency: 64
  checkers:
    - name: heartbeatLeader

XDS 规则下发时支持服务别名

通过北极星的服务别名机制,支持将服务别名一并通过 XDS 的格式进行下发,解决 XDS 跨命名空间资源下发的问题

What’s Changed

Feature

  • PR #1068 eureka注册发现支持命名空间隔离
  • PR #1070 feat:support service alias from xds
  • PR #1082 feat:support heartbeat without redis in cluster

Enhancement

  • PR #1056 refactor admin job execute interval config
  • PR #1063 refactor: maintain rename to admin
  • PR #1065 refactor: service governance rule not bind service instance
  • PR #1066 支持根据实例ID获取实例列表
  • PR #1079 添加windows启动停止脚本
  • PR #1081 GetInstances接口过滤条件为可选
  • PR #1086 修复高并发场景下鉴权CheckPermission方法导致内存溢出问题
  • PR #1099 add CleanDeletedClients admin-job

BugFix

  • PR #1057 修复有子目录的配置文件无法导入问题
  • PR #1060 fix:限流规则disable查询条件失效
  • PR #1076 fix:http 客户端接口鉴权行为保持和gRPC一致
  • PR #1085 Fix prometheus.yml bug
  • PR #1102 fix: remove standalone docker exec not exist shell

Test

  • PR #1062 test: add polaris.checker health check unit test

New Contributors

Full Changelog: https://github.com/polarismesh/polaris/compare/v1.16.4...v1.17.0

参与 PolarisMesh 社区

欢迎大家使用体验、Star、Fork、Issue,也欢迎大家参与 PolarisMesh 开源共建!

仓库地址:https://github.com/polarismesh/polaris

项目文档: https://polarismesh.cn/#/

往期发布:https://github.com/polarismesh/polaris/releases

4.1.6 - Release v1.16.0

下载地址

特性说明

更完善的服务调用监控

在 polaris 1.16.0 版本前,缺乏服务调用之间的流量指标展示分析,因此服务间调用的流量情况对用户来说就是一个黑盒,同时,用户也无法判断在北极星平台配置的流量治理规则,在服务调用时是否执行,以及执行的结果是否符合预期:

  • 缺少服务间调用请求的响应时耗统计信息。
  • 缺少服务间调用请求的响应码分布情况。
  • 缺少接口级、实例级的服务间调用请求指标。

基于以上几点,在 polaris v1.16.0 版本中,我们针对服务间调用的核心指标重新进行设计,并且优化了相关指标在控制台的展示试图,进一步方便用户观察微服务运行期间服务调用的流量情况:

  • 提供服务间调用响应的耗时统计,支持最大、最小、均值、P95以及P99的查询,支持按照服务、接口、实例进行筛选查看。
  • 提供服务间调用响应码的分布情况,支持按照服务、接口、实例进行筛选查看。
  • 提供服务间调用的主调实例以及被调实例的指标查看。

控制台预览

  • 服务调用兼容概览

  • 服务调用详细

里程碑规划

polaris 下个版本将围绕易用性以及稳定性进行迭代,预计在5月初推出,计划提供下列功能:

集群化部署去redis

为了减低中小公司在部署北极星时需要维护 redis 以及 mysql 组件所带来的运维工作量,社区将提供北极星集群部署的去 redis 组件的集群部署方案,方便用户快速搭建北极星,减低使用北极星的成本。

XDS协议支持下发跨命名空间的服务数据

当前北极星的 XDS 协议不支持下发跨命名空间的服务数据,社区会先通过北极星的服务别名机制,支持将服务别名一并已XDS的格式进行下发,通过服务别名的方式解决XDS跨命名空间资源下发的问题;后续社区也会进一步调研Envoy的按需加载的能力,从而更优雅的解决这一使用问题。

参与 PolarisMesh 社区

欢迎大家使用体验、Star、Fork、Issue,也欢迎大家参与 PolarisMesh 开源共建!

仓库地址:https://github.com/polarismesh/polaris

项目文档: https://polarismesh.cn/#/

往期发布:https://github.com/polarismesh/polaris/releases

4.1.7 - Release v1.15.0

下载地址

特性说明

更完善的服务注册配置监控

在 polaris 1.15.0 版本前,北极星的可观测性指标较少,用户难以观察北极星服务端运行时的一些指标信息:

  • 缺少服务端针对请求的响应时耗统计信息
  • 缺少服务端响应的错误码分布情况
  • 缺少服务数、实例数的统计,无法感知不同状态实例总数的一个变化情况

基于以上几点,在 polaris v1.15.0 版本中,我们针对服务端的几个核心指标进行上报并展示在控制台,方便用户观察北极星服务端运行时情况:

  • 提供服务端响应的耗时统计,支持最大、最小、均值、P95以及P99的查询,支持按照接口、服务端节点进行筛选查看
  • 提供服务端响应码的分布情况,支持按照接口、服务端节点进行筛选查看
  • 提供服务数统计情况,用户可以查看到服务总数、在线服务数、异常服务数、离线服务数的变化曲线
  • 提供实例数统计情况,用户可以查看到实例总数、在线实例数、异常实例数、隔离实例数的变化曲线
  • 提供配置分组、配置文件、已发布配置文件的数量变化曲线

控制台预览

  • 概览页面

  • 服务和配置统计

  • 服务端请求统计

里程碑规划

polaris 下个版本将继续围绕易用性、可观测性以及稳定性进行迭代,预计在4月初推出,计划提供下列功能:

服务调用监控

  • 支持更详细的业务服务之间的流量调用监控
  • 查看每个服务的调用数、QPS、响应延迟、成功率、错误码
  • 查看服务调用数的情况:成功数、失败数、被限流请求数、被熔断请求数

参与 PolarisMesh 社区

欢迎大家使用体验、Star、Fork、Issue,也欢迎大家参与 PolarisMesh 开源共建!

仓库地址:https://github.com/polarismesh/polaris

项目文档: https://polarismesh.cn/#/

往期发布:https://github.com/polarismesh/polaris/releases

4.1.8 - Release v1.14.0

下载地址

特性说明

更完善的熔断治理规则

在 polaris 1.14.0 版本前,熔断规则的易用性存在不好的地方。

  • 仅支持节点级熔断。
  • 熔断条件支持不够丰富,仅支持错误率和错误数。
  • 无法根据用户自定义错误码以及响应延迟进行熔断。
  • 主动探测规则无法配置。

基于以上几点,在 polaris v1.14.0 版本中,我们针对熔断规则的 spec 以及配置交互做了优化,解决了上述几个问题,当前用户可以根据自己的场景配置更加灵活的熔断规则:

  • 支持服务级、接口级以及节点级的熔断规则配置。
  • 支持时延、错误码的错误判断条件,用户可自行组合判断条件。
  • 支持配置熔断恢复条件。
  • 支持配置主动探测规则,与业务调用合并判断决定是否关闭熔断状态。

支持查看服务端连接数

  • 社区用户在使用过程中,在升级服务端版本或者变更接入信息等场景中,发现无法观察北极星服务端中的客户端连接数量情况。因此在 polaris 控制台中我们新增北极星服务端自身的一些指标监控:

  • 查看当前链接到北极星服务端的 SDK 实例连接数量

  • 查看当前北极星服务端的服务发现链接数

  • 查看当前北极星服务端的配置获取连接数

控制台预览

  • 服务熔断配置

  • 节点熔断配置

  • 主动探测配置

  • 服务端链接数查看

里程碑规划

polaris 下个版本将继续围绕易用性、可观测性以及稳定性进行迭代,预计在 3 月初推出,计划提供下列功能:

注册配置监控

  • 支持更详细的北极星服务端请求数、响应延迟等指标监控图标。
  • 支持提供服务数、实例数、配置数等指标监控图标。

更易用的路由规则

  • 调整路由规则配置的交互以及规则定义,降低用户对于路由规则配置的理解以及上手成本。

配置导入导出

  • 支持命名空间级别、配置分组级别的配置导入导出能力,提升用户对于配置中心的使用体验。

参与 PolarisMesh 社区

欢迎大家使用体验、Star、Fork、Issue,也欢迎大家参与 PolarisMesh 开源共建!

仓库地址:https://github.com/polarismesh/polaris

项目文档: https://polarismesh.cn/#/

往期发布:https://github.com/polarismesh/polaris/releases

4.1.9 - Release v1.13.0

下载地址

版本信息

polaris-server

Features

Enhancement

Plugins

Install

BugFix

Test

New Contributors

Full Changelog: 点击链接查看

4.1.10 - Release v1.12.0

下载地址

版本信息

polaris-server

功能优化

  • [PR #642、#676] 北极星自定义路由功能优化

  • [PR #687] 支持 xdsv3 协议下发规则时输出debug日志

  • [PR #627] 北极星OpenAPI支持Swagger2.0

Bug修复

  • [PR #650] 修复错误码 i18n 可能导致的空指针问题
  • [PR #659] 限流规则匹配标签无法完全删除的问题
  • [PR #661] 修复限流用例失败问题
  • [PR #673] 修复eureka协议中心跳错误的处理
  • [PR #684] 修复自定义路由v1转v2的id漂移问题
  • [PR #693] 修复v2路由规则对于v1路由规则兼容逻辑

安装优化

  • [PR #690] 单机版本支持部署 polaris-limiter 分布式限流server
  • [PR #724] 修复helm部署包中polaris-console.yaml配置不对问题

新贡献者

Full Changelog: 点击链接查看

polaris-console

功能优化

  • [PR #86] 优化服务实例新增/编辑表单
  • [PR #91] Console 使用 Json Web Token 代替用户资源访问凭据,避免浏览器泄露用户Token
  • [PR #99] 支持配置中心配置文件编辑页面全屏编辑
  • [PR #102] beta能力 提供Swagger UI 供加载Polaris Server的OpenAPI 接口, 访问北极星控制台地址(127.0.0.1:8080/apidocs)即可
  • [PR #110] 新建/编辑服务优化标签交互

Bug修复

  • [PR #92] 修复编辑服务实例时不展示服务实例的地理位置信息数据
  • [PR #98] 修复服务可观测性指标聚合查询语句不正确问题

配置变动

polaris-server.yaml

北极星的自注册服务只保留 polaris.checker ,其他自注册服务被移除

# server启动引导配置
bootstrap:
  # 注册为北极星服务
  polaris_service:
    # probe_address: ##DB_ADDR##
    enable_register: true
    isolated: false
    services:
      - name: polaris.checker
        protocols:
          - service-grpc

升级步骤

注意:升级步骤仅针对部署了北极星集群版本

之前已经安装过北极星集群

北极星服务端升级操作
执行 SQL 升级动作
  • 登陆北极星的MySQL存储实例
  • 执行以下 SQL 增量脚本
mysql -u $db_user -p $db_pwd -h $db_host < store/sqldb/scripts/delta/v1_11_0-v1_12_0.sql
北极星控制台升级操作

更新 polaris-console.yaml

logger:
  RotateOutputPath: log/polaris-console.log
  RotationMaxSize: 500
  RotationMaxAge: 30
  RotationMaxBackups: 100
  level: info
webServer:
  mode: "release"
  listenIP: "0.0.0.0"
  listenPort: 8080
  jwt:
    secretKey: "polarismesh@2021"
    expired: 1800
  namingV1URL: "/naming/v1" # 本次 v1.9.0 版本变动
  namingV2URL: "/naming/v2" # 本次 v1.9.0 版本变动
  authURL: "/core/v1"
  configURL: "/config/v1"
  monitorURL: "/api/v1"
  webPath: "web/dist/"
polarisServer:
  address: "{北极星服务端IP}:8090"
monitorServer:
  address: "127.0.0.1:9090"
oaAuthority:
  enableOAAuth: false
hrData:
  enableHrData: false

4.1.11 - Release v1.11.0

下载地址

版本信息

polaris-server

功能优化

  • [PR #532] 支持配置某些服务在控制台列表进行隐藏
  • [PR #526] 支持配置模版功能(UI交互暂未支持)
  • [PR #552] 新限流后台功能 & UI 交互优化
  • [PR #550] 服务端报错支持 i18n
  • [PR #553] 配置中心代码结构调整

Bug修复

  • [ISSUE #520] 服务注册后,没有做任何操作但是实例的修改时间会发生变化

安装优化

  • [PR #530] 调整 docker 镜像 tag 的发布规则

代码测试

  • [PR #509] 单元测试 & 集成测试添加MySQL存储测试场景
  • [PR #542] 优化整体的集成测试 & 单元测试
  • [PR #548] 单元测试 & 集成测试添加Redis存储测试场景

新贡献者

Full Changelog: https://github.com/polarismesh/polaris/compare/v1.10.0...v1.11.1

polaris-console

功能优化

  • [PR #66] 创建配置文件时,文件的格式自动从文件名中识别
  • [PR #66] 调整创建配置文件页面 Card body 的高度,尽可能充满整个浏览器
  • [PR #86] 优化服务实例新增/编辑表单

Bug修复

  • [PR #95] 修复前端删除熔断规则最后一条时没有触发熔断规则解绑

升级步骤

注意:升级步骤仅针对部署了北极星集群版本

之前已经安装过北极星集群

执行 SQL 升级动作
  • 登陆北极星的MySQL存储实例
  • 执行以下 SQL 增量脚本
mysql -u $db_user -p $db_pwd -h $db_host < store/sqldb/scripts/delta/v1_8_0-v1_11_0.sql

4.2 - 接口文档

4.2.1 - Open API

4.2.2 - 错误码

错误码 描述
200000 执行成功
200001 服务发现数据无变化
200002 数据没有变化, 无需更新
400000 请求错误
400001 请求解析失败
400002 空请求
400003 批量数据超过限制
400004 服务发现资源非法
400100 请求ID非法
400101 用户名非法
400102 用户token非法
400103 参数非法
400104 查询实例参数为空
400105 查询实例, 需要服务或命名空间或主机作为参数
400110 命名空间名称非法
400111 命名空间拥有人非法
400112 命名空间token非法
400120 服务名称非法
400121 服务拥有人非法
400122 服务token非法
400123 服务元数据非法
400124 服务端口非法
400125 服务所属业务非法
400126 服务所属部门非法
400127 服务cmdb非法
400128 服务备注非法
400129 服务别名备注非法
400130 实例ID非法
400131 实例Host非法
400132 实例端口非法
400133 实例别名非法
400134 当前命名空间不运行创建sid类型别名
400135 服务别名拥有者非法
400136 实例协议非法
400137 实例版本非法
400138 实例逻辑集合非法
400139 实例隔离设置非法
400140 服务端未开启健康检查
400141 在已被禁用的实例上进行心跳
400142 心跳超限, 实例仅支持每秒1次心跳
400143 未找到心跳类型
400150 元数据长度过长或包含非法字符
400151 限频ID非法
400152 限频标签非法
400153 限频数量非法
400154 限流名称非法
400160 熔断ID非法
400161 熔断版本非法
400162 熔断名称非法
400163 熔断命名空间ID非法
400164 熔断所属人ID非法
400165 熔断token非法
400166 熔断所属业务非法
400167 熔断所属部门非法
400168 熔断备注非法
400170 服务有已存在的网格
400171 当前资源有已存在的网格
400172 网格参数非法
400180 平台ID非法
400181 平台名称非法
400182 平台域名非法
400183 平台qps非法
400184 平台token非法
400185 平台拥有人非法
400186 平台所属部们非法
400187 平台备注非法
400188 未找到平台
400190 限流ID非法
400191 限流qps非法
400192 限流标识非法
400201 资源已存在
400202 未找到资源
400203 当前命名空间存在服务,请先删除服务,再删除命名空间
400204 当前服务存在实例,请先删除实例,再删除服务
400205 当前服务存在路由规则,请先删除路由规则,再删除服务
400206 当前服务存在限流规则,请先删除限流规则,再删除服务
400207 存在已发布配置
400208 实例请求重复
400209 当前服务存在熔断规则,请先删除熔断规则,再删除服务
400210 当前服务存在服务别名,请先删除服务别名,再删除服务
400211 某些网格资源在当前命名空间已存在
400212 某些熔断在当前命名空间已存在
400213 服务已被某些网格订阅
400214 服务已存在限流配置
400215 用户已存在
400216 用户组已存在
400217 鉴权策略规则已存在
400218 主账户下还存在子账户,请先删除所有子账户,在删除主账户
400301 服务未找到
400302 路由未找到
400303 示例未找到
400304 服务别名未找到
400305 命名空间未找到
400306 未找到和当前服务别名关联的服务
400307 限流规则未找到
400308 熔断规则未找到
400309 主配置未找到
400310 标签配置未找到
400311 未找到标签或服务, 或者关系已存在
400312 用户未找到
400313 拥有人用户未找到
400314 用户组未找到
400315 鉴权策略规则未找到
400401 客户端API未开放
400402 不允许请求当前业务服务
400410 用户所有人非法
400411 用户ID非法
400412 用户密码非法
400420 用户组所有人的属性非法
400421 用户组ID非法
400430 鉴权策略规则拥有人非法
400431 鉴权策略规则名称非法
400432 鉴权策略ID非法
400440 鉴权策略用户主体类型非法
400501 服务别名不允许更新
400502 服务别名不允许创建实例
400503 服务别名不允许创建路由规则
400504 仅允许源服务可以创建别名
400505 服务别名不允许创建限流规则
400506 服务别名不允许绑定规则
400507 不允许不同的命名空间绑定同一规则
400508 不允许修改默认策略
400509 not allow modify main account default strategy
400700 路由规则ID非法
400701 路由规则类型非法,只支持 (RulePolicy,MetadataPolicy)
400702 路由名称非法
400703 路由优先级非法,只支持[0, 10]
400801 配置文件组名非法
400802 配置文件名称非法
400803 配置文件内容过长
400804 非法的配置文件格式,支持的格式有: json,xml,html,properties,text,yaml
400805 配置文件标签非法, 标签应该是成对的, 比如key1,value1,key2,value2, 并且key,value应是非空白字符
400806 监视配置文件格式非法
400807 无法找到配置文件
400808 配置模板名称非法
401000 未经授权
401001 权限不被允许
401002 鉴权token为空
401003 token已被禁用
401004 token不存在
403001 token验证异常
403002 角色操作异常
404001 无法找到主机的cmdb
409000 数据有冲突, 请再次重试
429001 你的实例请求过多
500000 执行异常
500001 存储层异常
500002 cmdb插件异常
500004 解析路由规则失败
500005 解析限频规则失败
500006 解析熔断规则失败
500007 心跳异常
500008 实例异步注册超时

4.3 - 测试报告

4.3.1 - 性能测试报告

测试方案

测试工具

使用开源的ghz工具进行压测。测试工具地址: ghz

测试规格

测试组网

客户端直接发送请求到北极星服务端:

  • 服务注册/反注册请求会对MySQL进行增删操作
  • 心跳上报请求会对Redis进行KV修改操作
  • 服务发现请求会对服务端缓存进行操作

准备动作

  • 下载polaris代码
git clone https://github.com/polarismesh/polaris.git
  • 打包proto
chmod 777 polaris/common/api/protoc/bin/* && cd polaris/common/api/v1/ && sh build.sh

测试结果

实例注册

测试数据

规格 TPS 平均RT(ms) 最大RT(ms) P99 RT(ms) 服务端CPU负载 MySQLCPU负载 Redis CPU负载
1C2G 2144 354.75 2450 379.92 64.68 90.54 1.40
2C4G 4563 448.183 2300 492.31 66.09 82.33 1.60
4C8G 13608 187.22 2380 210.53 76.37 86.14 2.39
8C16G 29457 79.01 2030 83.03 58.63 89.03 2.43
8C32G 35912 67.89 2500 75.35 63.02 87.31 2.43

测试命令

  • 执行(ghz命令与配置文件至于polaris/common/api/v1 目录下):
./ghz --config=./register_instance.json -c {并发数, eg 100} -x {持续执行时间, eg 60s}
  • 配置文件 register_instance.json 如下:
{
  // 实际执行时请把所有注释行删除
  // 请求总数
  "total": 1,
  // 并发数
  "concurrency": 1,
  "proto": "./grpcapi.proto",
  "call": "v1.PolarisGRPC.RegisterInstance",
  "data": {
    "id": "polaris-perf-test-1-ins-{{.RequestNumber}}",
    // 服务名称
    "service": "POLARIS-PERF-TEST-1",
    // 命名空间名称
    "namespace": "default",
    // 随机域名
    "host": "fakehost-{{randomString 8 }}.com",
    // 随机端口
    "port": "{{randomInt 1000 50000}}",
    "enable_health_check": true,
    "health_check": {
      "type": 1,
      "heartbeat": {
        "ttl": 3
      }
    },
    "healthy": true,
    "isolate": false,
    "ctime": "{{.TimestampUnix}}",
    "mtime": "{{.TimestampUnix}}"
  },
  // 北极星地址
  "host": "127.0.0.1:8091",
  "insecure": true
}

服务发现

测试数据

规格 TPS 平均RT(ms) 最大RT(ms) P99 RT(ms) 服务端CPU负载 MySQLCPU负载 Redis CPU负载
1C2G 12194 214.75 654.23 248.64 64.68 18.9 6.40
2C4G 27331 17.183 310.46 18.58 92.51 39.441 4.01
4C8G 46118 38.63 472.42 45.47 90.567 25 5.96
8C16G 80277 47.81 719 59.03 88 25.12 3.4
8C32G 116021 298.05 872.81 372.28 93.02 27.312 9

测试命令

  • 执行:
./ghz --config=./discover_instance.json -c {并发数, eg 100} -x {持续执行时间, eg 60s}
  • 配置文件 discover_instance.json 如下:
{
    "total":1,
    "concurrency":1,
    "proto":"./grpcapi.proto",
    "call":"v1.PolarisGRPC.Discover",
    "data":{
        "type": 1,
        "service": {
             // 服务名称
             "name": "PERF-1-TEST-SVCID-{{.WorkerID}}",
             // 命名空间名称
             "namespace":"default"
        }
    },
    // 北极星地址
    "host": "127.0.0.1:8091",
    "insecure":true
}

心跳上报

测试数据

规格 TPS 平均RT(ms) 最大RT(ms) P99 RT(ms) 服务端CPU负载 MySQLCPU负载 Redis CPU负载
1C2G 5094 155.31 564.95 161.84 92.68 36.34 50
2C4G 6419 421.73 342.65 492.31 87.41 40.134 41.241
4C8G 10417 41.47 840.14 50.96 90.124 31.2 23.576
8C16G 32092 70.83 639.47 77.83 89.412 34 30.66
8C32G 78077 219.42 371.58 242.79 90 35 32.39

测试命令

  • 执行:
./ghz --config=./heartbeat_instance.json -c {并发数, eg 100} -x {持续执行时间, eg 60s}
  • 配置文件 heartbeat_instance.json 如下:
{
  // 实际执行时请把所有注释行删除
  // 请求总数
  "total": 1,
  // 并发数
  "concurrency": 1,
  "proto": "./grpcapi.proto",
  "call": "v1.PolarisGRPC.Heartbeat",
  "data": {
    "id": "polaris-perf-test-1-ins-{{.RequestNumber}}",
    // 服务名称
    "service": "POLARIS-PERF-TEST-1",
    // 命名空间名称
    "namespace": "default",
    "healthy": true,
    "isolate": false,
    "mtime": "{{.TimestampUnix}}"
  },
  // 北极星地址
  "host": "127.0.0.1:8091",
  "insecure": true
}

实例反注册

测试数据

规格 TPS 平均RT(ms) 最大RT(ms) P99 RT(ms) 服务端CPU负载 MySQLCPU负载 Redis CPU负载
1C2G 903 573.75 797.03 682.78 45.42 91.54 2.4
2C4G 1485 448.18 621.231 391.07 69.241 82.33 3.8
4C8G 2959 57.59 389.36 88.25 67.51 93.1251 2.39
8C16G 8694 61.70 265.97 123.03 73.41 91.03 2.3
8C32G 14356 61.70 423.51 323.95 63.39 87.31 6.196

测试命令

  • 执行:
./ghz --config=./deregister_instance.json -c {并发数, eg 100} -x {持续执行时间, eg 60s}
  • 配置文件 deregister_instance.json 如下:
{
  // 实际执行时请把所有注释行删除
  // 请求总数
  "total": 1,
  // 并发数
  "concurrency": 1,
  "proto": "./grpcapi.proto",
  "call": "v1.PolarisGRPC.DeregisterInstance",
  "data": {
    "id": "polaris-perf-test-1-ins-{{.RequestNumber}}",
    // 服务名称
    "service": "POLARIS-PERF-TEST-1",
    // 命名空间名称
    "namespace": "default"
  },
   // 北极星地址
  "host": "127.0.0.1:8091",
  "insecure": true
}

结论

在长时间的压力测试下,不同规格的北极星集群均维持正常运行状态,集群可承载的实例容量从1k实例到10w实例,相关依赖组件的系统资源消耗也均在预期内,并未出现相关依赖组件高负载不可用现象。

  • 注册实例的TPS最高可达35912,符合接口预期
  • 服务发现的QPS最高可达116021,符合接口预期
  • 实例心跳的TPS最高可达78077,符合接口预期
  • 注销实例的TPS最高可达14356,符合接口预期

通过压测,不同规格的北极星集群可以稳定支撑服务实例数量均满足预期。

4.4 - 开发者文档

4.4.1 - 插件开发

4.4.1.1 - 开发规范

背景

北极星服务端整体都是一个插件化的设计,当前支持插件化的核心功能模块有

插件名称 插件定义文件
协议层 apiserver.go
存储层 store.go
资源鉴权 auth.go

除了这三个核心模块支持插件化之外,还有一些旁路功能,北极星也进行了插件化的设计

插件名称 插件定义文件
操作审计日志 plugin/history.go
服务实例事件 plugin/discoverevent.go
服务发现统计 plugin/discoverstatis.go
健康检查 plugin/healthchecker.go
接入层限流 plugin/ratelimit.go
配置管理 plugin/cmdb

无论是核心模块还是旁路功能模块,北极星服务端都对其进行了插件化的设计,可以快速的通过编写相关插件来扩展北极星的能力。譬如通过对协议层 apiserver 的扩展,北极星服务端快速支持了 http 以及 grpc 协议的接入,同时实现了 xds 协议以及 eureka 协议的接入。

那么如何根据北极星服务端提供的插件扩展点,来开发自己的插件呢?

如何编写插件

如何编写北极星服务端插件呢?这里我们以开发一个用于将服务实例事件上报到 Loki 的插件。

插件源码

初始化插件项目

  1. 创建插件项目文件夹

    mkdir polaris-server-plugin-${plugin-name}
    
  2. 进入第一步创建的文件夹:polaris-server-plugin-${plugin-name},执行 go mod init 命令

    go mod init ${module name}
    
  3. 进入第一步创建的文件夹:polaris-server-plugin-${plugin-name},创建项目的 README 文档来描述这个插件的使用

  4. 引入北极星服务端依赖

    go get github.com/polarismesh/polaris@${release version}
    

至此,一个北极星服务端插件项目就初始化完成了,接着就要开始进入我们的插件编写阶段。

插件编写

在编写插件前,我们需要先了解下,我们想要实现的插件定义是什么样的,因此这里我们要实现的是一个服务实例事件插件,因此来看下这个插件的定义

// Plugin 通用插件接口
type Plugin interface {
    // Name 插件名称,需要唯一
	Name() string
    // Initialize 初始化插件,插件自行解析 ConfigEntry 转为插件所需要的配置对象
	Initialize(c *ConfigEntry) error
    // Destroy 插件销毁
	Destroy() error
}

// DiscoverChannel is used to receive discover events from the agent
type DiscoverChannel interface {
	Plugin
	// PublishEvent 发布一个服务事件
	//  @param event 服务事件信息
	PublishEvent(event model.DiscoverEvent)
}

因此,我们的自定义服务实例事件插件就需要实现 Plugin 以及 DiscoverChannel 两个 interface,然后将上报 Loki 的动作在 PublishEvent 方法中进行完成。

至此,我们就可以开始编自定义插件,实现将 model.DiscoverEvent 信息写入到 Loki 中

插件注册

完成插件编写后,我们还需要主动将插件信息注册到北极星服务端中,这里北极星服务端利用了 golang 中的 init 机制来实现插件实例的注册。

因此,我们还需要在我们的插件代码中,添加下面的插件注册动作。

package loki

import "github.com/polarismesh/polaris/plugin"

func init() {
	d := &discoverEventLoki{}
	plugin.RegisterPlugin(d.Name(), d)
}

至此,一个自定义的服务实例事件插件的开发流程到这里就全部结束了。

如何使用插件

  1. 下载北极星服务端源码

    git clone https://github.com/polarismesh/polaris.git
    
  2. 进入 polaris 目录, 并切换到对应的版本 TAG

    cd polaris
    git checkout ${release version}
    
  3. 进入 polaris 目录,执行命令引入相关插件

    go get github.com/polaris-contrib/polaris-server-plugin-discoverevent-loki@{version}
    
  4. (可选)进入 polaris 目录,执行依赖整理

    go mod tidy -compat=1.17
    
  5. 编辑 polaris/plugin.go, 在 import 块中添加

    import (
         ...
           _ "github.com/polarismesh/polaris/plugin/discoverevent/loki" # 引入插件并触发插件的自动注册逻辑
    )
    
  6. 执行 build.sh 构建 polaris-server

4.4.1.2 - CMDB插件开发

背景

在进行服务发现发现时,我们都希望能够做到同机房、同地域的就近路由,以减少网络调用的延迟。而要做到就近路由,就必须知道主调节点和被调节点的地域信息,因此我们可以通过开发北极星服务端的 CMDB 插件,对接至自己的 CMDB 系统,从而填充每个实例的地域信息,以到达实现就近路由的目标。

为了方便快速的将北极星的 CMDB 扩展点对接至用户的 CMDB 系统,我们设计了一套通用的 CMDB OpenAPI,开发者只需要按照该 OpenAPI 实现一个 CMDB 查询服务端,即可将北极星快速对接到自己的 CMDB 系统中去。

协议定义

发起 CMDB 查询请求

METHOD: POST
HEADER: Authorization: 访问 Token // 可选

BODY
{
    "request_id": String,
    "page_no": Number,
    "page_size": Number // 固定,每次 100 拉取
}

CMDB Server 的返回响应

{
    "total": Number, // 总数
    "size": Number, // 当前放回条数
    "code": Number,
    "info": String,
    "data": [
        {
            "ip": "127.0.0.1",
            "type": "host", # 固定
            "region": {
                "name": String
            }
            "zone": {
                "name": String
            }
            "campus": {
                "name": String
            }

        }
    ]
}

服务端启用

修改 polaris-server.yaml 配置

# 插件配置
plugin:
  cmdb:
    name: memory
    option:
      url: "{ CMDB 查询服务端 OpenAPI 地址 }"
      interval: 60s

然后重启北极星服务端即可

4.4.2 - 指标监控

4.4.2.1 - 监控指标

服务端

指标

APIServer

指标名称 类型 说明 标签
client_total GAUGE SDK 实例数 polaris_server_instance
sdk_client_total GAUGE SDK 连接数 polaris_server_instance
discovery_conn_total GAUGE 注册发现连接数 polaris_server_instance
config_conn_total GAUGE 配置中心连接数 polaris_server_instance

服务注册

指标名称 类型 说明 标签
service_count GAUGE 服务数 namespace, polaris_server_instance
service_online_count GAUGE 在线服务数(服务下存在健康状态的实例) namespace, polaris_server_instance
service_abnormal_count GAUGE 异常服务数(服务下全为异常状态的实例) namespace, polaris_server_instance
service_offline_count GAUGE 离线服务数(服务下没有任何状态的实例) namespace, polaris_server_instance
instance_count GAUGE 实例数 namespace, service, polaris_server_instance
instance_online_count GAUGE 健康实例数 namespace, service, polaris_server_instance
instance_abnormal_count GAUGE 异常实例数 namespace, service, polaris_server_instance
instance_isolate_count GAUGE 隔离实例数 namespace, service, polaris_server_instance

配置中心

指标名称 类型 说明 标签
config_group_count GAUGE 配置分组数 namespace, polaris_server_instance
config_file_count GAUGE 配置文件数 namespace, group, polaris_server_instance
config_release_file_count GAUGE 已发布配置文件数 namespace, group, polaris_server_instance

响应耗时

指标名称 类型 说明 标签
client_rq_interval_count GAUGE 客户端请求数 api, protocol, err_code, polaris_server_instance
client_rq_timeout GAUGE 客户端请求总时延 api, protocol, err_code, polaris_server_instance
client_rq_timeout_min GAUGE 客户端请求最小时延 api, protocol, err_code, polaris_server_instance
client_rq_timeout_avg GAUGE 客户端请求平均时延 api, protocol, err_code, polaris_server_instance
client_rq_timeout_max GAUGE 客户端请求最大时延 api, protocol, err_code, polaris_server_instance

维度

维度名称 说明
polaris_server_instance PolarisSever节点IP
api 接口名称
protocol 接口层协议
err_code 错误码
namespace 命名空间
service 服务名
group 配置分组

4.5 - 相关产品对比

4.5.1 - 注册中心对比

北极星VS其他注册中心

特性 北极星 nacos 1.x nacos 2.x eureka consul
服务发现单机TPS 80277 13604 30680.48 6431 40027.91
服务注册单机TPS 29457 13257 26784.84 4793 4608.57
架构 AP AP/CP AP/CP AP CP
水平扩展 存算分离,支持水平扩展 存算合一,不支持水平扩展 存算合一,不支持水平扩展 存算合一,不支持水平扩展 存算合一,不支持水平扩展
健康检查 主动探测+客户端心跳 主动探测+客户端心跳 主动探测+客户端心跳/连接 客户端心跳 主动探测+客户端心跳
推空保护 支持 支持 支持 支持 不支持
可定制 插件化 插件化 插件化 插件化 不可定制
跨地域容灾 支持 不支持 不支持 不支持 支持

4.5.2 - 服务网格对比

北极星VS其他服务网格

特性 北极星 sentinel istio
Proxy模式接入 支持 支持 支持
Proxyless框架接入 支持 支持 不支持
多语言SDK 支持Go/Java/C++ 支持Go/Java 不支持
多测试环境路由 支持 不支持 支持
蓝绿发布 支持 不支持 支持
金丝雀发布 支持 不支持 支持
全链路灰度 支持 不支持 支持
A/B测试 支持 不支持 支持
就近访问 支持 不支持 支持
故障熔断 支持 支持 支持
单机限流 支持 支持 支持
分布式限流 支持单次、异步 支持单次 支持单次
限流维度 支持服务、接口、标签、调用关系、来源IP等维度 基于应用、资源、调用关系维度 服务、接口、标签维度
限流算法 直接拒绝、匀速排队 直接拒绝、匀速排队 直接拒绝
Token Server高可用 支持 不支持(需自己实现) 不支持(需自己实现)
可观测性 支持 支持 支持

4.6 - 常见问题

4.6.1 - 服务端相关

北极星集群版安装,初始化数据库发生 “Specified key ’name’ was too long; max key length is 767 bytes”

解决方案

  • 启用innodb_large_prefix参数能够取消对于索引中每列长度的限制(但是无法取消对于索引总长度的限制)
  • 启用innodb_large_prefix必须同时指定innodb_file_format=barracuda,innodb_file_per_table=true,并且建表的时候指定表的row_formatdynamic或者compressed(mysql 5.6中row_format默认值为compact)

4.6.2 - 客户端相关

北极星如何采集业务的服务调用监控信息

  • 北极星业务监控指标是由 Polaris SDK 直接和 Prometheus 服务端进行数据通信
  • Prometheus 感知 Polaris SDK 的方式借助了 Prometheus Service Discovery 能力,当选择 Polaris SDK 通过 Pull 模式上报监控数据时,北极星服务端能够感知到当前所有处于运行状态的 Polaris SDK 实例,然后通过 Prometheus Service Discovery 的方式通知到 Prometheus。

在北极星监控页面看不到服务调用指标

排查点 1: 客户端是否开启了相关监控上报的功能开关

监控功能开关如何开启请参考各语言客户端中的可观测性章节

排查点 2: 确认主调方是否有执行服务调用结果上报

  • 当前北极星的服务调用监控依赖主调方主动上报,因此需要确认业务应用的主调方 (Consumer) 是否引入了北极星相关客户端依赖,比如 Polaris Java、Polaris Go、Spring Cloud Tencent、DubboGo Polaris 等等
  • 如果用户是直接使用 Polaris Java、Polaris Go, 则需要自行调用 ConsumerAPI 中的 UpdateServiceCallResult 方法完成服务调用监控数据上报

排查点 3: 确认 prometheus、pushgateway 组件是否部署以及是否正常运行

  • 单机版安装包已经包括了 prometheus、pushgateway 组件, 开箱即用, 如果是虚拟机部署的, 当虚拟机重启时,需要自行启动每个相关组件进程。
  • 集群版安装时,用户需要自己部署生产可用的 prometheus、pushgateway 集群,请参考集群部署文-监控组件安装

排查点 4: prometheus 指标采集分为了两种: Pull 模式以及 Push 模式,需要根据自己的网络情况合理选择 pull 模式或者 push 模式

123