作者:李俱顺
原文:https://www.4async.com/2021/05/building-your-own-dapr-service-discovery/
在上一篇文章中,我其实遗留了一个问题:如何定义dapr的服务发现呢?其实在后面阅读dapr的源码之后也前一篇文章的评论中提到了答案:目前dapr提供了内置两种服务发现模式:K8s模式和用于独立部署的mDNS模式。mDNS模式在某些网络环境下可能存在问题(比如跨机房),不过没有关系,dapr同时提供了可扩展能力,可以通过定义自主的服务发现能力扩展dapr的边界。
从 NameResolution 到 Resolver 接口
在 pkg/components/nameresolution/registry.go
文件中,dapr定义了一个 NameResolution
结构体用于服务注册和发现:
type (// NameResolution is a name resolution component definition.NameResolution struct {Name stringFactoryMethod func() nr.Resolver}// Registry handles registering and creating name resolution components.Registry interface {Register(components ...NameResolution)Create(name, version string) (nr.Resolver, error)}nameResolutionRegistry struct {resolvers map[string]func() nr.Resolver}
)
其中真正的服务解析则是依靠 components-contrib
中实现了 Resolver
接口的具体实现执行。
// Resolver is the interface of name resolver.
type Resolver interface {// Init initializes name resolver.Init(metadata Metadata) error// ResolveID resolves name to address.ResolveID(req ResolveRequest) (string, error)
}
其中 Init
会在 Runtime 初始化时被调用,而 ResolveID
则会在服务查询时调用。比如在 pkg/messaging/direct_messaging.go
的方法 getRemoteApp
中进行服务的解析:
func (d *directMessaging) getRemoteApp(appID string) (remoteApp, error) {id, namespace, err := d.requestAppIDAndNamespace(appID)if err != nil {return remoteApp{}, err}request := nr.ResolveRequest{ID: id, Namespace: namespace, Port: d.grpcPort}address, err := d.resolver.ResolveID(request)if err != nil {return remoteApp{}, err}return remoteApp{namespace: namespace,id: id,address: address,}, nil
}
当然,事实上这样并不完全足够,还需要把这个服务注册放入dapr支持的服务中去:
runtime.WithNameResolutions(nr_loader.New("mdns", func() nr.Resolver {return nr_mdns.NewResolver(logContrib)}),nr_loader.New("kubernetes", func() nr.Resolver {return nr_kubernetes.NewResolver(logContrib)}),nr_loader.New("consul", func() nr.Resolver {return nr_consul.NewResolver(logContrib)}),
),
上面的这些是设定的dpar目前支持的一些服务发现功能,而我们之前服务发现也一直使用的 Consul 实现,已经满足我们的需求了…????拖延症害人啊!
从原理到实现
上面提到了我们需要实现一个 Resolver
接口的实现,我们可以预见到我们大概会需要这么一个东西:
type resolver struct {}// NewResolver creates Consul name resolver.
func NewResolver() nr.Resolver// Init will configure component. It will also register service or validate client connection based on config
func (r *resolver) Init(metadata nr.Metadata) error // ResolveID resolves name to address via consul
func (r *resolver) ResolveID(req nr.ResolveRequest) (string, error)
接下来就需要一个 client *consul.Client
去实现服务的注册:
type resolver struct {client *consul.Client
}func (r *resolver) Init(metadata nr.Metadata) error {// ...if err := r.client.Agent().ServiceRegister(regData); err != nil {return fmt.Errorf("failed to register consul service: %w", err)}// ...
}
注册服务完成后,在调用具体的服务时,我们需要获取具体的服务地址:
func (r *resolver) ResolveID(req nr.ResolveRequest) (string, error) {// ...services, _, err := r.client.Health().Service(req.ID, "", true, cfg.QueryOptions)// ...
}
当然上面的演示代码只是部分核心功能代码,如果需要拓展更多的实现细节内容,需要查看具体的官方接收社区贡献的实现:components-contrib/nameresolution/consul
相关文章:
Dapr能否引领云原生中间件的未来?
云原生 | 阿里巴巴的Dapr实践与探索
Dapr | 云原生的抽象与实现
Dapr 可视化指南
Dapr 知多少 | 分布式应用运行时
Dapr 正式发布 1.0
Dapr 交通流量控制示例
Dapr是如何简化微服务的开发和部署
微软开源微服务运行时Dapr,赋能云原生应用开发
YARP实现Dapr服务调用的反向代理
Dapr微服务应用开发系列0:概述
Dapr微服务应用开发系列1:环境配置
Dapr微服务应用开发系列2:Hello World与SDK初接触
Dapr微服务应用开发系列3:服务调用构件块
Dapr微服务应用开发系列4:状态管理构件块
Dapr微服务应用开发系列5:发布订阅构建块
Windows环境下Dapr入门
云原生 | .NET 5 with Dapr 初体验
通过Dapr实现一个简单的基于.net的微服务电商系统
通过Dapr实现一个简单的基于.net的微服务电商系统(二)——通讯框架讲解
通过Dapr实现一个简单的基于.net的微服务电商系统(三)——一步一步教你如何撸Dapr
通过Dapr实现一个简单的基于.net的微服务电商系统(四)——一步一步教你如何撸Dapr之订阅发布
通过Dapr实现一个简单的基于.net的微服务电商系统(五)——一步一步教你如何撸Dapr之状态管理
通过Dapr实现一个简单的基于.net的微服务电商系统(六)——一步一步教你如何撸Dapr之Actor服务
通过Dapr实现一个简单的基于.net的微服务电商系统(七)——一步一步教你如何撸Dapr之服务限流
通过Dapr实现一个简单的基于.net的微服务电商系统(八)——一步一步教你如何撸Dapr之链路追踪
通过Dapr实现一个简单的基于.net的微服务电商系统(九)——一步一步教你如何撸Dapr之OAuth2授权
通过Dapr实现一个简单的基于.net的微服务电商系统(九)——一步一步教你如何撸Dapr之OAuth2授权-百度版
通过Dapr实现一个简单的基于.net的微服务电商系统(十)——一步一步教你如何撸Dapr之绑定
通过Dapr实现一个简单的基于.net的微服务电商系统(十一)——一步一步教你如何撸Dapr之自动扩/缩容
WebAssembly + Dapr = 下一代云原生运行时?
dapr 应用开发 | 环境配置
乘风破浪,.Net Core遇见Dapr,为云原生而生的分布式应用运行时
Dapr案例之高德 Serverless 平台建设及实践
在非容器(集群)环境下运行dapr