1 - 使用 Go SDK

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

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

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

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

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

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
}

相关示例工程代码

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)

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 - 使用 dubbogo

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.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.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 - 访问限流

当前支持针对 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 开展

3 - 使用 gRPC-Go

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

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

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

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

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