作者:邓正威
背景概述
什么是 Polaris
Polaris 是腾讯开源的服务治理平台,致力于解决分布式和微服务架构中的服务管理、流量管理、配置管理、故障容错和可观测性问题,针对不同的技术栈和环境提供服务治理的标准方案和最佳实践。
什么是 dubbogo
dubbogo 是一款高性能 Go 语言微服务 RPC 框架,在 Dubbo 多语言生态中扮演重要角色,是编写 Go 语言微服务的最佳选择之一。开发者可以使用 dubbogo 框架高效地编写 RPC 服务,并支持与dubbogo 、gRPC 服务跨语言互通;并且 dubbogo 本身提供的丰富服务治理特性,可以实现诸如服务发现、负载均衡、流量调度等服务治理诉求。
为什么要对接
分布式和微服务架构中的服务管理、流量管理、配置管理、故障容错和可观测性问题,如何去解决、选用什么组件来解决、组件之间是否会存在冲突等等,相信已经让不少开发者难以招架。在 dubbogo 用户中,需要解决这些微服务架构中的问题,通常都会部署以下组件
- Nacos(Zookeeper):解决服务管理、配置管理以及元数据管理
- Sentinel:解决流量管理、故障容错
- Prometheus、Skywalking:解决可观测性
可以发现,要解决这些问题不得不部署多个组件,并且每个组件都有各自的管控平台,数据联动性差,难以有一个全局的视角让用户可以很好的管理微服务。
Polaris 是一支持多语言多框架的云原生服务治理平台,具备服务管理、流量管理、故障容错、配置管理和可观测性五大功能,用户不需要在为选择什么组件而操心,直接在 Polaris 享受一站式服务治理平台所带来的便利。为此, Polaris 社区和 dubbogo 社区合作,将 Polaris 服务治理能力,与 dubbogo 框架相结合,便于 Go 应用开发者快速低门槛的进行微服务开发。
如何对接 Polaris
Polaris 有统一控制面和标准,数据面提供多语言sdk的实现给框架做集成。服务管理、流量管理、故障容错、配置管理和可观测性五大功能可直接通过 Polaris 的数据面直接接入,各个语言框架无需重复实现,统一了各个语言以及框架的服务治理能力。
因此,要完成 dubbo 与Polaris的集成,只需要使用 Polaris 提供的数据面 Polaris-Go SDK,通过 dubbogo 的 Extension 机制进行注入,无需额外进行服务治理逻辑的开发。
技术架构
Polaris 通过实现 dubbogo 相关 Extension 插件,完成了功能的注入,用户只需要在配置中进行功能开启即可使用,无需进行代码改造。
从用户数据流的维度,当用户在 dubbogo 中启用 Polaris 的服务治理能力后,业务流量实际处理流程如下:
从架构分层的维度,北极星 SDK,插件,与 dubbogo 之间通过以下方式进行整合:
- 基于 Registry/ServiceDiscovery 的 dubbogo 扩展点,引入 Polaris 的服务注册能力
- 基于 Registry/ServiceDiscovery 的 dubbogo 扩展点,引入 Polaris 的服务发现能力
- 基于 PriorityRouter 的 dubbogo 扩展点,引入 Polaris 的动态路由能力
- 基于 TpsLimiter 的 dubbogo 扩展点,引入 Polaris 的访问限流能力
如何使用
当前 dubbogo 与 Polaris 服务治理能力对接情况(基于 dubbogo v3.0.4-rc1 版本)
服务注册
当前 Polaris 已实现了 dubbogo 原生的服务注册扩展点,因此原本的 dubbogo 服务注册逻辑不需要进行任何调整,只需要在 dubbogo.yaml 配置文件中新增 protocol 为 polaris 的注册中心配置即可。
业务代码(dubbogo 原生使用方式)
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.yaml 配置文件
dubbo:
registries:
polaris-1:
protocol: polaris
address: ${北极星服务端IP}:8091
调整完 dubbogo.yam 配置文件后,启动服务,可以在北极星控制台直接观察到服务实例
服务发现
dubbogo 在进行服务调用时,会先通过 Polaris Registry 的 Extension 获取到服务的实例列表,然后转换为 dubbogo invoker,最终完成 dubbogo 服务调用。
当前 Polaris 已实现了 dubbogo 原生的服务发现扩展点,因此原本的 dubbogo 服务调用无需调整业务代码,仅需要在 dubbogo.yaml 中新增 protocol 为 polaris 的注册中心配置即可。
业务代码(dubbogo 原生使用方式)
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.yaml 配置
dubbo:
registries:
polaris-1:
protocol: polaris
address: ${北极星服务端IP}:8091
动态路由
动态路由可以实现基于 dubbo 的请求消息内容来对请求调度到不同的实例分组,比如将带了某些 user 标签的请求调度到灰度分组。
当前支持针对 dubbo 消息的以下内容进行路由调度:
假定一个场景,希望 uid 为 user-1 的请求,路由到版本为 2.0.0 的实例上,其他则路由到版本为 1.0.0 的实例上,那可以为 dubbogo 服务设置两条路由规则。
注意:在使用 PolarisMesh 的动态路由能力时,需要先启用 PolarisMesh 在 dubbogo 中的注册发现功能
业务代码(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)
}
}
测试路由规则
兜底路由规则
访问限流
访问限流可以实现基于 dubbo 的请求消息内容来对请求进行访问限流,比如对 dubbogo 中的 GetUser 方法,对请求参数 Name 为 Alex 的请求进行限流,速率为 10/s。
当前支持针对 dubbo 消息的以下内容进行路由调度:
限流规则
在 Polaris 配置限流规则后,需要在 dubbogo 中启用 Polaris 的 TpsLimiter,具体开启配置参考如下
注意:在使用 PolarisMesh 的动态路由能力时,需要先启用 PolarisMesh 在 dubbogo 中的注册发现功能
业务代码
func (s *Service) Test() {
var successCount, failCount int64
for i := 0; i < 10; i++ {
time.Sleep(50 * time.Millisecond)
// 服务提供者会根据请求参数 User.Name 的值来进行限流
if user, err := userProvider.GetUser(context.TODO(), &User{Name: "Alex03"}); err != nil {
failCount++
logger.Infof("error: %v\n", err)
} else {
successCount++
logger.Infof("response: %v\n", user)
}
}
logger.Infof("successCount=%v, failCount=%v\n", successCount, failCount)
}
dubbogo.yaml 配置文件
dubbo:
...
provider:
services:
UserProvider:
interface: org.apache.dubbo.UserProvider.Test
tps.limiter: polaris-limit # 配置 tps.limiter 为 polaris-limiter 即可
未来规划
当前 Polaris 的服务注册发现、动态路由、访问限流三大能力已经和 dubbogo 做了集成,后续 PolarisMesh 社区会继续和 dubbogo 社区进行合作,将 Polaris 的服务熔断、节点熔断、可观测性以及配置中心的能力融入到 dubbogo 中,让用户能够在 dubbogo 中使用 Polaris 一站式的服务治理功能。
除了能在 dubbogo上使用 Polaris 的一站式服务治理能力外,Polaris 社区还提供了 其他语言框架的接入,因此相关开发者也能够享受到 Polaris 一站式服务治理带来的技术红利。
附录
Polaris 项目:
https://github.com/polarismesh/polaris
dubbogo 项目:
https://github.com/apache/dubbo-go
dubbogo polaris example:
https://github.com/apache/dubbo-go-samples/tree/master/polaris
北极星服务注册文档:
北极星访问限流文档:
北极星服务路由文档:
作者:
邓正威:apache/dubbo-go committer
廖春涛(春少):PolarisMesh 社区 PMC,apache/dubbo-go committer
赵新(花名 于雨):dubbogo 社区负责人
微信或钉钉扫描下方对应二维码,立刻进群交流~