gRPC之grpc resolver

1、grpc resolver

当我们的服务刚刚成型时,可能一个服务只有一台实例,这时候client要建立grpc连接很简单,只需要指定server

的ip就可以了。但是,当服务成熟了,业务量大了,这个时候,一个实例就就不够用了,我们需要部署一个服务集

群。一个集群有很多实例,且可以随时的扩容,部分实例出现了故障也没关系,这样就提升了服务的处理能力和稳

定性,但是也带来一个问题,grpc的client,如何和这个集群里的server建立连接?

这个问题可以一分为二,第一个问题:如何根据服务名称,返回实例的ip?这个问题有很多种解决方案,我们可以

使用一些成熟的服务发现组件,例如consul或者zookeeper,也可以我们自己实现一个解析服务器;第二个问题,

如何将我们选择的服务解析方式应用到grpc的连接建立中去?这个也不难,因为grpc的resolver,就是帮我们解决

这个问题的,本篇,我们就来探讨一下,grpc的resolver是如何使用的。

1.1 proto编写和编译

syntax = "proto3";
package helloworld;
option go_package = "./;helloworld";service Greeter {rpc SayHello (HelloRequest) returns (HelloReply) {}
}message HelloRequest {string name = 1;
}message HelloReply {string message = 1;
}
$ protoc -I . --go_out=plugins=grpc:. ./helloword.proto

1.2 服务端编写

这里需要编写两个服务端:

package mainimport ("context"pb "demo/pb""google.golang.org/grpc""log""net"
)const (port = ":50051"
)type server struct {pb.UnimplementedGreeterServer
}func (s *server) SayHello(ctx context.Context, in *pb.HelloRequest) (*pb.HelloReply, error) {// 打印客户端传入HelloRequest请求的Name参数log.Printf("Received: %v", in.GetName())// 将name参数作为返回值,返回给客户端return &pb.HelloReply{Message: "Service1: Hello " + in.GetName()}, nil
}// main方法 函数开始执行的地方
func main() {// 调用标准库,监听50051端口的tcp连接lis, err := net.Listen("tcp", port)if err != nil {log.Fatalf("failed to listen: %v", err)}log.Println("listen: ", port)// 创建grpc服务s := grpc.NewServer()// 将server对象,也就是实现SayHello方法的对象,与grpc服务绑定pb.RegisterGreeterServer(s, &server{})// grpc服务开始接收访问50051端口的tcp连接数据if err := s.Serve(lis); err != nil {log.Fatalf("failed to serve: %v", err)}
}
package mainimport ("context"pb "demo/pb""google.golang.org/grpc""log""net"
)const (port2 = ":50052"
)type server2 struct {pb.UnimplementedGreeterServer
}func (s *server2) SayHello(ctx context.Context, in *pb.HelloRequest) (*pb.HelloReply, error) {// 打印客户端传入HelloRequest请求的Name参数log.Printf("Received: %v", in.GetName())// 将name参数作为返回值,返回给客户端return &pb.HelloReply{Message: "Service2: Hello " + in.GetName()}, nil
}// main方法 函数开始执行的地方
func main() {// 调用标准库,监听50052端口的tcp连接lis, err := net.Listen("tcp", port2)if err != nil {log.Fatalf("failed to listen: %v", err)}log.Println("listen: ",port2)//创建grpc服务s := grpc.NewServer()//将server对象,也就是实现SayHello方法的对象,与grpc服务绑定pb.RegisterGreeterServer(s, &server2{})// grpc服务开始接收访问50052端口的tcp连接数据if err := s.Serve(lis); err != nil {log.Fatalf("failed to serve: %v", err)}
}

1.3 客户端编写

package mainimport ("context"pb "demo/pb""google.golang.org/grpc""google.golang.org/grpc/resolver""log""time"
)// 全局注册Scheme为myservice的Resolver Build
func init() {resolver.Register(&myServiceBuilder{})
}type myServiceBuilder struct {
}func (*myServiceBuilder) Scheme() string {return "myservice"
}// 创建Resolver实例
func (*myServiceBuilder) Build(target resolver.Target, cc resolver.ClientConn, opts resolver.BuildOptions) (resolver.Resolver, error) {r := &myServiceResolver{target: target,cc:     cc,}r.start()return r, nil
}type myServiceResolver struct {target resolver.Targetcc     resolver.ClientConn
}// 根据target不同,解析出不同的端口
func (r *myServiceResolver) start() {if r.target.Endpoint() == "abc" {r.cc.UpdateState(resolver.State{Addresses: []resolver.Address{{Addr: ":50051"}}})} else if r.target.Endpoint() == "efg" {r.cc.UpdateState(resolver.State{Addresses: []resolver.Address{{Addr: ":50052"}}})}
}// 再次解析使用的解析方式不变
func (r *myServiceResolver) ResolveNow(o resolver.ResolveNowOptions) {r.start()
}func (*myServiceResolver) Close() {}const (address1 = "myservice:///abc"address2 = "myservice:///efg"
)func main() {// myservice:///abc// 访问服务端address,创建连接conn,地址格式myservice:///abcconn, err := grpc.Dial(address1, grpc.WithInsecure(), grpc.WithBlock())if err != nil {log.Fatalf("did not connect: %v", err)}defer conn.Close()c := pb.NewGreeterClient(conn)// 设置客户端访问超时时间1秒ctx, cancel := context.WithTimeout(context.Background(), time.Second)defer cancel()// 客户端调用服务端 SayHello 请求,传入Name 为 "world", 返回值为服务端返回参数r, err := c.SayHello(ctx, &pb.HelloRequest{Name: "world"})if err != nil {log.Fatalf("could not greet: %v", err)}// 根据服务端处理逻辑,返回值也为"world"log.Printf("Greeting: %s", r.GetMessage())// myservice:///efgconn2, err2 := grpc.Dial(address2, grpc.WithInsecure(), grpc.WithBlock())if err2 != nil {log.Fatalf("did not connect: %v", err)}defer conn2.Close()c2 := pb.NewGreeterClient(conn2)// 设置客户端访问超时时间1秒ctx2, cancel2 := context.WithTimeout(context.Background(), time.Second)defer cancel2()// 客户端调用服务端 SayHello 请求,传入Name 为 "world", 返回值为服务端返回参数r2, err2 := c2.SayHello(ctx2, &pb.HelloRequest{Name: "world"})if err2 != nil {log.Fatalf("could not greet: %v", err2)}// 根据服务端处理逻辑,返回值也为"world"log.Printf("Greeting: %s", r2.GetMessage())
}

1.4 测试

[root@zsx demo]# go run server/server1.go
2023/02/17 14:18:06 listen:  :50051
2023/02/17 14:18:32 Received: world
[root@zsx demo]# go run server/server2.go
2023/02/17 14:18:17 listen:  :50052
2023/02/17 14:18:32 Received: world
[root@zsx demo]# go run client/client.go
2023/02/17 14:18:32 Greeting: Service1: Hello world
2023/02/17 14:18:32 Greeting: Service2: Hello world
# 项目结构
$ tree demo/
demo/
├── client
│   └── client.go
├── go.mod
├── go.sum
├── pb
│   ├── helloword.pb.go
│   └── helloword.proto
└── server├── server1.go└── server2.go3 directories, 7 files

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

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

相关文章

linux测试固态硬盘读写速度,在 Linux 上检测 IDE/SATA SSD 硬盘的传输速度

你知道你的硬盘在 Linux 下传输有多快吗?不打开电脑的机箱或者机柜,你知道它运行在 SATA I (150 MB/s) 、 SATA II (300 MB/s) 还是 SATA III (6.0Gb/s) 呢?你能够使用 hdparm 和 dd 命令来检测你的硬盘速度。它为各种硬盘的 ioctls 提供了命…

stl标准模板库_C ++标准模板库(STL)中的array :: fill()

stl标准模板库fill() is a member function of "array container", which sets a given value to all array elements. It can also be used to set the value to other of containers also. Value type should be same as container type. fill()是“数组容器”的成…

Opencv——批量处理同一文件夹下的图片(解决savedfilename = dest + filenames[i].substr(len)问题)

文章目录前言一、完整代码二、实现效果前言 第一份代码实现了批量修改同一文件夹下图片的尺寸,有其他需求时仅需修改处理部分的代码以及文件夹路径。 第二份代码实现了批量截取同一文件夹下每张图片的ROI区域作为结果保存,注意截取后按下enter键才会跳到…

linux统计文件目录及其文件个数

linux下统计目录及其子目录的文件的个数 查看某目录下文件的个数 ls -l |grep "^-"|wc -l或find ./company -type f | wc -l 查看某目录下文件的个数,包括子目录里的。 ls -lR|grep "^-"|wc -l查看某文件夹下目录的个数,包括子目录里…

处理文件、摄像头和图形用户界面

1、基本I/O脚本 1.1 读/写图像文件 import numpy import cv2#利用二维Numpy数组简单创建一个黑色的正方形图像 img numpy.zeros((3,3),dtypenumpy.uint8) img #结果为:array([[0, 0, 0],[0, 0, 0],[0, 0, 0]], dtypeuint8)img.shape#结果为:(3, 3)###…

linux桌面天气,Ubuntu 14.10中安装和配置天气应用

对于操作系统平台而言,有各种小插件功能方便用户日常应用。在Ubuntu桌面中提供天气信息的功能,可以使用Unity Dash和桌面应用来获得相关信息,比如Typhoon。但对于用户而言,可以提供快速查询天气状况和温度数据,并且只需…

使用ACE_SOCK_SEQPACK_Association获取socket连接的本地及远程IP端口信息

int connect(const std::string& ip, int port){ ACE_INET_Addr portAddr(port, ip.c_str()); ACE_SOCK_Connector connector; ACE_SOCK_Stream peer; if (-1 connector.connect(peer, portAddr)) { std::cout << "连接服务器(" <&…

linux批处理操作系统_批处理操作系统

linux批处理操作系统批处理操作系统 (Batch Processing Operating System) When we are working in an environment there is a restriction of making use of computer resources effectively and improvement in the programmers output. When we are working with tapes a l…

STL容器及其简单应用(stack、priority_queue、vector、deuqe、list、map/multimap、set/multiset)

目录前言【1】stack操作以及应用stack的几个核心接口利用stack完成进制转换【2】priority_queue操作以及应用priority_queue的几个核心接口利用priority_queue完成合并果子问题【3】vector操作以及应用vector的几个核心接口利用vector完成随机排序【4】deuqe(双向队列)操作以及…

Android SAX API: XmlResourceParser及其扩展应用

XmlResourceParser继承了2个接口&#xff1a;AttributeSet和XmlPullParser。其中XmlPullParser定义了Android SAX框架。跟Java 的SAX API相比&#xff0c;XmlPullParser令人难以置信地简单。 一、使用XmlResourceParser读取资源束中的xml 资源束是应用程序编译后的应用程序包…

linux fdisk 磁盘空间使用率,linux查看磁盘剩余空间以及cpu使用情况

1、查看CPU个数cat /proc/cpuinfo | grep "physical id" | uniqtop可以实时的查看cpu的使用情况2、查看CPU核数cat /proc/cpuinfo | grep "cpu cores" | uniq3、查看CPU型号cat /proc/cpuinfo | grep model name |uniq4、查看内存cat /proc/meminfo | grep…

c语言 函数的参数传递示例_restder()函数,带有C ++中的示例

c语言 函数的参数传递示例C restder()函数 (C remainder() function) remainder() function is a library function of cmath header, it is used to calculate the remainder (IEC 60559), it accepts two parameters (numerator and denominator) and returns the remainder…

jquery validation-jquery的验证框架 详解(1)

jquery validation验证框架是一款非常优秀的客户端数据验证框架。我们在日常的项目中都会应用得到。今天开始我们会分两到三个个阶段 详细的了解这款插件 至于这款插件是多么的优秀&#xff0c;怎么个描述法 我这里就不详细述说。大家可以在接下来的时间里接触并且感觉它的强大…

已知一个掺杂了多个数字字符的中文名拼音,去掉所有数字字符之后,形式为“名”+空格+“姓”;并且名和姓的首字母大写,其他小写,要求输出姓名全拼,且全为小写。(后附详细样例说明)

已知一个掺杂了多个数字字符的中文名拼音&#xff0c;去掉所有数字字符之后&#xff0c;形式为“名”空格“姓”&#xff1b;并且名和姓的首字母大写&#xff0c;其他小写&#xff0c;要求输出姓名全拼&#xff0c;且全为小写。&#xff08;后附详细样例说明&#xff09; 【输入…

【视觉项目】【day2】8.21号实验记录(手机固定高度15cm拍摄+直方图均衡化+模板匹配,模板12个,测试28个,效果十分差)

目录均衡化代码模板图片按照大小排序总代码测试效果新思路由于模板匹配是像素之间的比对&#xff0c;所以不同光照下的像素灰度值也会不同 所以在比对之前&#xff0c;我们需要对测试图和模板图进行直方图均衡化&#xff0c;这一步可以先实现。 今天将采用批量处理的方式&#…

c语言 函数的参数传递示例_isgreater()函数以及C ++中的示例

c语言 函数的参数传递示例C isgreater()函数 (C isgreater() function) isgreater() function is a library function of cmath header, it is used to check whether the given first value is greater than the second value. It accepts two values (float, double or long…

在一个风景秀丽的小镇,一天早上,有N名晨跑爱好者(编号1~N)沿着优雅的江边景观道朝同一方向进行晨跑

【问题描述】 在一个风景秀丽的小镇&#xff0c;一天早上&#xff0c;有N名晨跑爱好者(编号1~N)沿着优雅的江边景观道朝同一方向进行晨跑&#xff0c;第i名跑者从位置si处起跑&#xff0c;且其速度为Vi。换句话说&#xff0c;对所有的实数t≥0&#xff0c;在时刻t时第i名跑者的…

linux内核测试,Linux内核测试的生命周期

内核持续集成(CKI)项目旨在防止错误进入 Linux 内核。在 Linux 内核的持续集成测试 一文中&#xff0c;我介绍了 内核持续集成Continuous Kernel Integration(CKI)项目及其使命&#xff1a;改变内核开发人员和维护人员的工作方式。本文深入探讨了该项目的某些技术方面&#xff…

Linux下动态库使用小结

1. 静态库和动态库的基本概念 静态库&#xff0c;是在可执行程序连接时就已经加入到执行码中&#xff0c;在物理上成为执行程序的一部分&#xff1b;使用静态库编译的程序运行时无需该库文件支持&#xff0c;哪里都可以用&#xff0c;但是生成的可执行文件较大。动态库&#xf…

【视觉项目】【day3】8.22号实验记录(利用canny检测之后的来进行模板匹配)

【day3】8.22号实验记录&#xff08;几乎没干正事的一天&#xff0c;利用canny检测之后的来进行模板匹配&#xff09; 今天没搞代码&#xff0c;主要是问研究生学长工业摄像头的接法的&#xff0c;学长也不知道&#xff0c;明天问问老师。。。 晚上搞了一下canny之后的模板匹配…