惯性聚合 高效追踪和阅读你感兴趣的博客、新闻、科技资讯
阅读原文 在惯性聚合中打开

推荐订阅源

S
Securelist
Cyber Security Advisories - MS-ISAC
Cyber Security Advisories - MS-ISAC
WordPress大学
WordPress大学
OSCHINA 社区最新新闻
OSCHINA 社区最新新闻
T
Tailwind CSS Blog
V
V2EX
小众软件
小众软件
博客园 - 聂微东
H
Help Net Security
阮一峰的网络日志
阮一峰的网络日志
云风的 BLOG
云风的 BLOG
Blog — PlanetScale
Blog — PlanetScale
M
MIT News - Artificial intelligence
人人都是产品经理
人人都是产品经理
F
Fortinet All Blogs
S
Schneier on Security
Martin Fowler
Martin Fowler
MyScale Blog
MyScale Blog
Vercel News
Vercel News
freeCodeCamp Programming Tutorials: Python, JavaScript, Git & More
Google DeepMind News
Google DeepMind News
Google Online Security Blog
Google Online Security Blog
Webroot Blog
Webroot Blog
A
Arctic Wolf
量子位
博客园 - 叶小钗
I
Intezer
C
Check Point Blog
Cloudbric
Cloudbric
IT之家
IT之家
Last Week in AI
Last Week in AI
GbyAI
GbyAI
Attack and Defense Labs
Attack and Defense Labs
T
The Blog of Author Tim Ferriss
Y
Y Combinator Blog
Jina AI
Jina AI
K
KPMG report finds enterprise disconnect between AI and its ROI | CIO
T
Threat Research - Cisco Blogs
C
CERT Recently Published Vulnerability Notes
cs.CL updates on arXiv.org
cs.CL updates on arXiv.org
C
Cisco Blogs
J
Java Code Geeks
cs.CV updates on arXiv.org
cs.CV updates on arXiv.org
Engineering at Meta
Engineering at Meta
酷 壳 – CoolShell
酷 壳 – CoolShell
L
Lohrmann on Cybersecurity
有赞技术团队
有赞技术团队
Simon Willison's Weblog
Simon Willison's Weblog
The Register - Security
The Register - Security
T
Threatpost

ipfans's Blog

程序员的提示工程手册 AI 产品的破局之道:以人为本 使用 Go 开发 AI Agent的选择:Genkit for Go RAG 技术在实际工程中的应用:OpenAI 的最佳实践分享 从零学习 Hypothetical Document Embeddings (HyDE) - 2 从零学习 Hypothetical Document Embeddings (HyDE) - 1 No GIL Python 的冒险 使用 Ollama 快速部署本地开源大语言模型 使用子解释器运行Python并行应用 Twirp初相识 Twirp基本概念:Hooks和Interceptors 去年的一点小工作(1):从BFF谈起 Byebye 2022, Hello 2023 给hugo添加mermaid支持 一些实用工具列表 Go 1.17 泛型尝鲜 Go Web应用中常见的反模式 什么是事件建模Event Modeling? 构建属于你自己的dapr绑定组件
构建属于你自己的dapr服务发现
2021-05-09 · via ipfans's Blog

Featured image of post 构建属于你自己的dapr服务发现

写在最前: 这篇文章其实算是马后炮了,因为一直拖延症的问题,顺带过了一个五一假期,结果发现已经有社区贡献者提供了Consul的服务发现实现,于是本来写了一半的文章只能进行调整了。拖延症害人啊!几个草稿的文章看来要尽快赶出来了🤦‍♂️

上一篇文章中,我其实遗留了一个问题:如何定义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          string
		FactoryMethod 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