java如何通过grpc连接etcd_grpc通过 etcd 实现服务发现与注册-源码分析

介绍

下面介绍 jupiter-0.2.7 版本中 grpc 通过 etcd 实现服务发现与注册。

服务发现与注册的实现解析

服务注册

服务注册的流程图:

aa9954741884a9b2f487a3950eded019.png

etcd的服务注册代码模块在 jupiter/pkg/registry/etcdv3 中。

下面让我们来看看实际的代码

// Registry register/unregister service

// registry impl should control rpc timeout

type Registry interface {

RegisterService(context.Context, *server.ServiceInfo) error

UnregisterService(context.Context, *server.ServiceInfo) error

ListServices(context.Context, string, string) ([]*server.ServiceInfo, error)

WatchServices(context.Context, string, string) (chan Endpoints, error)

io.Closer

}

复制代码

在 pkg/registry/registry.go 中定义了注册服务对象的接口。不同的服务只要实现了这些接口,jupiter 就能使用。

首先我们来看看注册方法

// RegisterService register service to registry

func (reg *etcdv3Registry) RegisterService(ctx context.Context, info *server.ServiceInfo) error {

err := reg.registerBiz(ctx, info)

...

}

// 业务信息注册

func (reg *etcdv3Registry) registerBiz(ctx context.Context, info *server.ServiceInfo) error {

...

// 提交信息到 etcd

_, err := reg.client.Put(readCtx, key, val, opOptions...)

...

}

复制代码

这里主要的部分是 reg.client.Put()  将服务信息提交到 etcd 中。其中的租约机制我会在之后单独写一篇文章介绍。这里主要还是关注如何注册。

源码中还有个 registerMetric() 方法,这个方法的目的是将服务信息在提交到etcd的 prometheus 前缀目录下,用于服务监控,用的也是 client.Put() 方法。这里具体就不展示代码了,感兴趣的同学可以去源码库中查看。

服务退出

// 删除服务

func (reg *etcdv3Registry) unregister(ctx context.Context, key string) error {

...

// 删除服务信息

_, err := reg.client.Delete(ctx, key)

...

}

复制代码

这里通过 client.Delete()  方法将服务信息从 etcd 中删除掉。

获取服务列表

// ListServices list service registered in registry with name `name`

func (reg *etcdv3Registry) ListServices(ctx context.Context, name string, scheme string) (services []*server.ServiceInfo, err error) {

// 服务信息key的前缀

target := fmt.Sprintf("/%s/%s/providers/%s://", reg.Prefix, name, scheme)

// 获取相关前缀的所有信息

getResp, getErr := reg.client.Get(ctx, target, clientv3.WithPrefix())

...

}

复制代码

通过 client.Get()  方法获取到相同前缀的服务信息。

服务信息变动监控

// WatchServices watch service change event, then return address list

func (reg *etcdv3Registry) WatchServices(ctx context.Context, name string, scheme string) (chan registry.Endpoints, error) {

prefix := fmt.Sprintf("/%s/%s/", reg.Prefix, name)

// 通过etcd客户端创建一个监控通道

watch, err := reg.client.WatchPrefix(context.Background(), prefix)

if err != nil {

return nil, err

}

...

xgo.Go(func() {

// 不断接收etcd发送过来的变动事件

for event := range watch.C() {

switch event.Type {

case mvccpb.PUT:

updateAddrList(al, prefix, scheme, event.Kv)

case mvccpb.DELETE:

deleteAddrList(al, prefix, scheme, event.Kv)

}

out := al.DeepCopy()

fmt.Printf("al => %p\n", al.Nodes)

fmt.Printf("snapshot => %p\n", out.Nodes)

select {

// 将更新后的服务信息发送出去,接收方是 resolver

case addresses

default:

xlog.Warnf("invalid")

}

}

})

// 返回一个地址通道,用于传递

return addresses, nil

}

复制代码

WatchServices()  方法主要是监控信息的变动事件,并将变动后的服务信息重新返回给 resolver。具体思路是通过 etcdClient.Watch()  方法创建一个监控通道,然后放入一个 goroutine来不断接收 etcd 推送过来的事件,维护本地的服务信息,并通过 resolver 最终返回到 grpclb 负载均衡器进行服务地址信息的更新。

服务发现

服务发现流程图:

641249cd61c3b251db846a33a07a9362.png

grpc 的 resolver 模块定义了两个接口

// Builder creates a resolver that will be used to watch name resolution updates.

type Builder interface {

Build(target Target, cc ClientConn, opts BuildOptions) (Resolver, error)

Scheme() string

}

// Resolver watches for the updates on the specified target.

// Updates include address updates and service config updates.

type Resolver interface {

ResolveNow(ResolveNowOptions)

Close()

}

复制代码

首先我们来看看 Builder 接口的具体实现

type baseBuilder struct {

name string

reg  registry.Registry

}

// Build ...

func (b *baseBuilder) Build(target resolver.Target, cc resolver.ClientConn, opts resolver.BuildOptions) (resolver.Resolver, error) {

endpoints, err := b.reg.WatchServices(context.Background(), target.Endpoint, "grpc")

if err != nil {

return nil, err

}

var stop = make(chan struct{})

xgo.Go(func() {

for {

select {

case endpoint :=

var state = resolver.State{

Addresses: make([]resolver.Address, 0),

...

}

for _, node := range endpoint.Nodes {

...

state.Addresses = append(state.Addresses, address)

}

cc.UpdateState(state)

case

return

}

}

})

return &baseResolver{

stop: stop,

}, nil

}

复制代码

这里Build 方法主要是通过 Registry 模块获得监控服务通道,然后将更新的服务信息再更新到 grpcClient 中去,保证 grpcClient 的负载均衡器的服务地址永远都是最新的。

如何将Builder的具体实现注册到 grpc 中

import "google.golang.org/grpc/resolver"

// Register ...

func Register(name string, reg registry.Registry) {

resolver.Register(&baseBuilder{

name: name,

reg:  reg,

})

}

复制代码

将 Registry模块注入到 Builder 对象中,然后注入到 grpc 的 resolver 模块中去。这样 grpcClient 在实际运行中就会调用 etcd 的服务发现功能了。

grpc 如何使用服务与发现的源码解析

这里在介绍一下jupiter框架在实际项目中如何使用服务发现与注册。

服务注册

func (app *Application) startServers() error {

var eg errgroup.Group

// start multi servers

for _, s := range app.servers {

s := s

eg.Go(func() (err error) {

_ = app.registerer.RegisterService(context.TODO(), s.Info())

defer app.registerer.UnregisterService(context.TODO(), s.Info())

...

})

}

return eg.Wait()

}

eng := engine.NewEngine()

eng.SetRegistry(compound_registry.New(

etcdv3_registry.StdConfig("default").Build(),

))

复制代码

在框架的 Application 模块中已经实现了服务的自动注册与删除。一般使用框架时不需要再调用。项目使用中只需要在创建 Application 对象时,将注册中心信息注入即可。

服务发现

// 服务发现需要初始化,拿到etcd中服务的信息

func (eng *Engine) initResolver() error {

resolver.Register("etcd", etcdv3.StdConfig("default").Build())

return nil

}

复制代码

服务发现也是类型的将注册中心信息注入即可。

文章系列

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/343869.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

视频光端机各种视频接口的传输距离是多少?

视频光端机将1到多路的模拟视频信号通过各种编码转换成光信号通过光纤介质进行远距离传输。那么,对于视频光端机的各种视频接口以及传输距离你是否详细了解过呢?接下来我们就跟随飞畅科技的小编一起来看看吧! 一、视频信号接口  1.监控视频…

[渝粤教育] 中国地质大学 面向对象程序设计 复习题

《面向对象程序设计》模拟题 一.单选题 1.如果一个类中包含纯虚函数则该类称为(). A.抽象类 B.虚基类 C.派生类 D.子类 2.在类中将show声明为不带返回值的纯虚函数则正确的写法是(). A.virtual void show()0; B.virtual show()0; C.virtual void show(); D.void show()0 virtu…

spring jms 事务_Spring JMS:处理事务中的消息

spring jms 事务1.引言 这篇文章将向您展示使用JMS异步接收消息期间使用者执行过程中的错误如何导致消息丢失。 然后,我将解释如何使用本地事务解决此问题。 您还将看到这种解决方案在某些情况下可能导致消息重复(例如,当它将消息保存到数据…

[渝粤教育] 西南科技大学 智能交通系统 在线考试复习资料

智能交通系统——在线考试复习资料 一、单选题 1.运用多种方式将路线优化结果告知用户的过程称为( )。 A.数据挖掘 B.路线诱导 C.模式识别 D.预测分析 2.( )是根据国家现行财税制度和借个体系,分析、计算投资者或项目直接发生的财务效益和费用,编制财务报表,计算评价指标,考察…

php 脏数据,使用 PHP Masked Package 屏蔽敏感数据

Fuko \ Masked 是 Kaloyan Tsvetkov 的一个小型 PHP 库,用于通过用编辑后的元素替换列入黑名单的元素来屏蔽敏感数据。以下是 软件包 readme 的基本用法示例:use Fuko\Masked\Protect;//隐藏$secret_key var中的值Protect::hideValue($secret_key);//隐藏…

视频数据复用光端机故障排除方法

数字光端机是一种通过数字电路控制光信号,使用类似于0、1代码来实现光通信的机器,广泛应用于光纤通信等领域。那么,我们在使用数据光端机的时候,如果遇到故障该如何来解决呢?接下来我们就跟随飞畅科技的小编一起来详细…

[渝粤教育] 西南科技大学 电子商务原理及应用 在线考试复习资料(1)

电子商务原理及应用——在线考试复习资料 一、单选题 1.( )接受商家的送货要求,将商品送到消费者手中。 A.邮局 B.快递公司 C.送货公司 D.物流中心 2.卓越属于( )类型的B2C电子商务企业: A.经营着离线商店的零售商 B.没有离线商店的虚拟零售企业 C.商品制造商 D.网络交易服务公…

使用AWS Lambda,S3和AWS CloudFront进行动态内容缓存

快速提供内容对于任何网站或应用程序具有更好的客户体验至关重要。 如果您将网站或应用程序托管在AWS Cloud中,那么无论从何处访问应用程序,都可以以较低的延迟快速提供内容。 AWS提供了CloudFront服务,用于将内容缓存在每个用户地理位置本地…

[渝粤教育] 西南科技大学 组织行为学 在线考试复习资料

组织行为学——在线考试复习资料 一、单选题 1.( )是指一个团队的综合情绪控制调节能力。 A.团队学习 B.团队情商 C.团队成员角色 D.团队创建 2.在沟通过程中,由信息发送者选择来向接收者传送信息的媒介物,叫( )。 A.编码 B.解码 C.反馈 D.通道 3.组织风俗属于组织文化的( )。…

php获取页面指定内容,php获取页面指定标签内容的实现代码分享

php获取页面指定标签内容的实现代码分享可以匹配任意可闭合带id标签header ( "Content-type: text/html; charsetutf-8" );/** 参数说明: $tag_id:所要获取的元素Tag Id $url:所要获取页面的Url $tag:所要获取的标签 $data*/function getWebTag($tag_id, $url false…

数据光端机设备性能指标介绍

作为安防监控工程,设备的可靠性应该是第一考虑要素。而数据光端机设备的可靠性是设备厂商在产品设计时就必需考虑的,但是,有些厂商可能会因为某些原因而不愿做或不知道怎么做这方面的工作,在这里着重从工程的角度简单地讨论以下问…

[渝粤教育] 西南科技大学 行政法学与行政诉讼法学 在线考试复习资料(1)

行政法学与行政诉讼法学——在线考试复习资料 一、单选题 1.某省工商局与税务局联名对某公司作出处罚,吊销其营业执照,罚款100万元。该公司提起复议,复议机关是( ) A.国家工商总局 B.国家税务总局 C.国务院 D.省政府 2.行政相对人对下列行为不能申请行政复议的是哪一种?( ) A…

光电转换器有什么作用?光纤收发器如何保养?

光电转换器可以使原来的快速以太网平滑升级,并能充分保护用户原来的网络资源,它也可以称为光纤收发器。光电转换器可以实现交换机和计算机之间的互联,也可以作为传输中继,还可以进行单多模转换。光纤收发器在应用过程中&#xff0…

php中id如何与删除关联,ThinkPHP查询语句与关联查询用法实例

这篇文章主要介绍了ThinkPHP查询语句与关联查询用法,以实例的形式常见的查询方法,包括数组作为查询条件及对象方式来查询等技巧,需要的朋友可以参考下本文实例讲述了ThinkPHP查询语句与关联查询用法。分享给大家供大家参考。具体如下:在thinkphp框架页面中我们可以直…

[渝粤教育] 西南科技大学 货币银行学 在线考试复习资料

货币银行学——在线考试复习资料 一、单选题 1.最严重的恶性通货膨胀的最终结果是( )。 A.突发性的商品抢购 B.挤兑银行 C.货币制度崩溃 D.投机盛行 2.凯恩斯的货币需求函数非常重视( )。 A.恒久收入的作用 B.货币供应量的作用 C.利率的作用 D.汇率的作用 3.下列西方的中央银…

latex段落悬挂缩进_使用正则表达式在Java中悬挂缩进段落

latex段落悬挂缩进这篇文章显示了如何使用正则表达式将缩进的长段落挂起。 该方法将考虑单词边界,这意味着它不会破坏缩进单词。 为了说明此问题,请考虑以下示例: 近年来,人们越来越努力从自然语言文本中提取实体之间的关系。 在…

【渝粤教育】电大中专会计电算化 (2)作业 题库

1下列有关会计电算化狭义概念的说法正确的是()。 A以会计理论为主体的电子信息技术在会计工作中的应用 B与实现电算化有关的所有工作 C以电子计算机为主体的电子信息技术在会计工作中的应用 D与实现电算化有关的主要工作 错误 正确答案:左边查询 学生答案&#xff1…

光纤模块与光纤收发器的区别

随着科技的发展,城市信息化速度的加快,对于通信技术的要求越来越高,光纤以其传输速度快、距离远、安全稳定、抗干扰、扩容便捷等优点越来越成为人们在通讯敷设时的首选。我们经常看到在建筑智能化项目中的远距离数据传输需求,基本…

html中输出PHP的下拉列表,html中关于下拉列表select的图文代码详解

HTML中的下拉列表:Html代码VolvoSaabOpelAudi其中select是显示一个下拉列表(drop down list)出来,option是下拉列表中的项目(item),而option的文本内容(text content)是下拉列表项目中显示到页面上的值,value是真正需要提交到服务…

【渝粤教育】电大中专学前儿童语言教育 (2)作业 题库

作业视频教务托管,壹叁路路贰陆陆壹〇肆〇 认为儿童天生就有学习语言能力且体现在一种语言获得装置(LAD)中的教育家是( )。 A.皮亚杰 B.乔姆斯基 C.伍顿 D.斯金纳 错误 正确答案:左边查询 学生答案:未作答 2.语言是( )…