当前位置: 首页 > news >正文

gRPC之grpc resolver


title: gRPC之grpc resolver(二十)
date: 2023-01-27
top: 0
categories:

  • Go
  • gRPC
    tags:
  • Go
  • gRPC
    description: |

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

相关文章:

gRPC之grpc resolver

title: gRPC之grpc resolver(二十) date: 2023-01-27 top: 0 categories: GogRPC tags:GogRPC description: | 1、grpc resolver 当我们的服务刚刚成型时,可能一个服务只有一台实例,这时候client要建立grpc连接很简单,只需要指定server 的…...

NI Package Manager创建程序包

NI Package Manager创建程序包 要使用PackageManager创建程序包,即把相关的组件都放在一个目录下,使用命令行创建程序包。 程序包是一个压缩文件,包含要安装到目标位置的所有文件。Package Manager创建的程序包扩展名为.nipkg。可以使用Pack…...

C语言实现排序介绍

C语言学习都会学到排序算法&#xff0c;下面实现两个排序算法&#xff1a; #include <stdio.h>// 冒泡排序 void bubble_sort(int arr[], int n) {for (int i 0; i < n - 1; i) {for (int j 0; j < n - i - 1; j) {if (arr[j] > arr[j 1]) {int temp arr[j…...

64位ATT汇编语言使用bss段.skip指令储存字符,并使用系统调用输出字符

.global main .section .data .section .bss# 需要输出的字符数组&#xff0c;还没有初始化mystring: .skip 4 .section .text main:# 将mystring这个字符串的地址存入到rbx寄存器中leaq mystring,%rbx# 将a放入到mystring第一个字节里边movb $a,(%rbx)# 将地址往后边移动一个字…...

贝锐蒲公英路由器X4C如何远程访问NAS?

在目前网盘前路坎坷的情况下&#xff0c;私人云盘已然是一种新的趋势&#xff01;那自己打造一个私有云盘&#xff0c;是否需要高成本或是高门槛呢&#xff1f;其实并不用&#xff01;蒲公英针对个人玩家打造了全方位的私有云解决方案。 &#xff08;1&#xff09;入门级玩家只…...

Golang Context 的使用指南

Golang Context 的使用指南 1. 什么是 Context 在 Golang 中&#xff0c;Context 是一个用于跨 goroutine 传递数据、取消任务以及超时控制的标准库。它提供了一种从父 goroutine 向子 goroutine 传递请求或控制信息的机制&#xff0c;可以有效地管理和控制 goroutine 的生命…...

vue3使用西瓜播放器播放flv、hls、mp4视频

vue3使用西瓜播放器播放flv、hls、mp4视频 安装相关的插件 npm install xgplayer npminstall xgplayer-flv npm install xgplayer-hls npm install xgplayer-mp4 组件封装 <template><div :id"${playerId}" /> </template> <script setup la…...

【Promise12数据集】Promise12数据集介绍和预处理

【Segment Anything Model】做分割的专栏链接&#xff0c;欢迎来学习。 【博主微信】cvxiayixiao 本专栏为公开数据集的介绍和预处理&#xff0c;持续更新中。 要是只想把Promise12数据集的raw形式分割为png形式&#xff0c;快速导航&#xff0c;直接看2&#xff0c;4标题即可 …...

Qt设置整体背景颜色

this->setStyleSheet("border:none;background-color:white");...

Stream流常见操作

.stream() 常用方法 .forEach&#xff08;&#xff09; 该方法接收一个 Consumer 接口函数&#xff0c;会将每一个流元素交给该函数进行处理 .filter()&#xff1a;过滤 该接口接收一个 Predicate 函数式接口参数&#xff08;可以是一个Lambda或方法引用&#xff09;作为筛…...

INFINI Labs 产品更新 | 发布 Easysearch Java 客户端,Console 支持 SQL 查询等功能

近年来&#xff0c;日志管理平台越来越流行。使用日志管理平台可以实时地、统一地、方便地管理和查看日志&#xff0c;挖掘日志数据价值&#xff0c;驱动运维、运营&#xff0c;提升服务管理效率。 方案架构 Beats 是轻量级采集器&#xff0c;包括 Filebeat、Metricbeat 等。E…...

前端调试只会console.log()?

前言 相信大家在日常开发中调试代码是必不可少的步骤&#xff0c;毕竟谁也不能保证代码不出问题&#xff0c;总得debug一下&#xff0c;输出信息看看数据有没有问题。是不是习惯性console.log(‘XXX’)或者debugger呢。而JavaScript中的console对象提供了丰富的方法用于更灵活…...

CentOS Linux release 7.9.2009 (Core)中安装配置Tomcat

一、安装JDK 部分内容可以参考我这篇文章&#xff1a;Windows11与CentOS7下配置与检测JDK与Maven环境变量 中的 2.2 安装jdk-8u371-linux-x64.tar.gz和配置环境变量/etc/profile //1、安装redhat-lsb yum install -y redhat-lsb//2、查看系统版本信息 lsb_release -a //3、查…...

移动机器人路径规划(四)--- 考虑机器人模型下的运动规划KINODYNAMIC PATHFINDING

目录 1 动力学概念简介 2 State Lattice Planning 3 Boundary Value Problem 4 混合A*算法 Hybrid A* 5 Kinodynamic RRT* 1 动力学概念简介 一种生成机器人的运动同时受限制于运动学的约束&#xff08;避障&#xff09;以及动力学的约束&#xff08;在速度加速度力的约束…...

服务器数据恢复—VMware虚拟化下误操作导致服务器崩溃的数据恢复案例

服务器故障&分析&#xff1a; VMware虚拟化&#xff0c;vmfs文件系统&#xff0c;共3块磁盘。工作人员误操作将VMware虚拟化重装系统&#xff0c;服务器崩溃。 正常情况下&#xff0c;重装系统会导致文件系统元文件被覆盖。要恢复数据须找到重装系统前的文件系统残留信息并…...

微服务实战系列之Gateway

前言 人类世界自工业革命以来&#xff0c;无论从金融、货币、制度&#xff0c;还是科技、资源、社会各个方面&#xff0c;都发生了翻天覆地的变化。物质极大丰富&#xff0c;从而也推动了科技的极速发展。当计算机问世也仅仅不到80年&#xff0c;而如今我们的生活处处有它的影子…...

GZ038 物联网应用开发赛题第10套

2023年全国职业院校技能大赛 高职组 物联网应用开发 任 务 书 &#xff08;第10套卷&#xff09; 工位号&#xff1a;______________ 第一部分 竞赛须知 一、竞赛要求 1、正确使用工具&#xff0c;操作安全规范&#xff1b; 2、竞赛过程中如有异议&#xff0c;可向现场考…...

重生之我是一名程序员 35

哈喽啊大家晚上好&#xff01;今天给大家带来的知识很简单啊&#xff0c;所以今天呢给大家带来的是C语言中的另一个库函数——strlen。 首先&#xff0c;让我先给大家介绍一下它&#xff0c;strlen函数是C语言中的一个字符串处理函数&#xff0c;它用于计算一个字符串的长度&a…...

计算机毕业设计选题推荐-点餐微信小程序/安卓APP-项目实战

✨作者主页&#xff1a;IT毕设梦工厂✨ 个人简介&#xff1a;曾从事计算机专业培训教学&#xff0c;擅长Java、Python、微信小程序、Golang、安卓Android等项目实战。接项目定制开发、代码讲解、答辩教学、文档编写、降重等。 ☑文末获取源码☑ 精彩专栏推荐⬇⬇⬇ Java项目 Py…...

分享禁止Win10更新的两种方法

深恶痛绝 Windows更新简直就是毒瘤&#xff0c;总是在某些不需要的时候提示更新&#xff0c;而且关闭服务后总有办法重启。老是关不掉。 如果每次都是正常更新&#xff0c;好像也没啥所谓&#xff0c;但是总有那么一两次会蓝屏、黑屏、开不了机…… 52出品 下面是吾爱社区找…...

【OSG学习笔记】Day 18: 碰撞检测与物理交互

物理引擎&#xff08;Physics Engine&#xff09; 物理引擎 是一种通过计算机模拟物理规律&#xff08;如力学、碰撞、重力、流体动力学等&#xff09;的软件工具或库。 它的核心目标是在虚拟环境中逼真地模拟物体的运动和交互&#xff0c;广泛应用于 游戏开发、动画制作、虚…...

mongodb源码分析session执行handleRequest命令find过程

mongo/transport/service_state_machine.cpp已经分析startSession创建ASIOSession过程&#xff0c;并且验证connection是否超过限制ASIOSession和connection是循环接受客户端命令&#xff0c;把数据流转换成Message&#xff0c;状态转变流程是&#xff1a;State::Created 》 St…...

解锁数据库简洁之道:FastAPI与SQLModel实战指南

在构建现代Web应用程序时&#xff0c;与数据库的交互无疑是核心环节。虽然传统的数据库操作方式&#xff08;如直接编写SQL语句与psycopg2交互&#xff09;赋予了我们精细的控制权&#xff0c;但在面对日益复杂的业务逻辑和快速迭代的需求时&#xff0c;这种方式的开发效率和可…...

基于Uniapp开发HarmonyOS 5.0旅游应用技术实践

一、技术选型背景 1.跨平台优势 Uniapp采用Vue.js框架&#xff0c;支持"一次开发&#xff0c;多端部署"&#xff0c;可同步生成HarmonyOS、iOS、Android等多平台应用。 2.鸿蒙特性融合 HarmonyOS 5.0的分布式能力与原子化服务&#xff0c;为旅游应用带来&#xf…...

基础测试工具使用经验

背景 vtune&#xff0c;perf, nsight system等基础测试工具&#xff0c;都是用过的&#xff0c;但是没有记录&#xff0c;都逐渐忘了。所以写这篇博客总结记录一下&#xff0c;只要以后发现新的用法&#xff0c;就记得来编辑补充一下 perf 比较基础的用法&#xff1a; 先改这…...

OpenPrompt 和直接对提示词的嵌入向量进行训练有什么区别

OpenPrompt 和直接对提示词的嵌入向量进行训练有什么区别 直接训练提示词嵌入向量的核心区别 您提到的代码: prompt_embedding = initial_embedding.clone().requires_grad_(True) optimizer = torch.optim.Adam([prompt_embedding...

稳定币的深度剖析与展望

一、引言 在当今数字化浪潮席卷全球的时代&#xff0c;加密货币作为一种新兴的金融现象&#xff0c;正以前所未有的速度改变着我们对传统货币和金融体系的认知。然而&#xff0c;加密货币市场的高度波动性却成为了其广泛应用和普及的一大障碍。在这样的背景下&#xff0c;稳定…...

算法笔记2

1.字符串拼接最好用StringBuilder&#xff0c;不用String 2.创建List<>类型的数组并创建内存 List arr[] new ArrayList[26]; Arrays.setAll(arr, i -> new ArrayList<>()); 3.去掉首尾空格...

无人机侦测与反制技术的进展与应用

国家电网无人机侦测与反制技术的进展与应用 引言 随着无人机&#xff08;无人驾驶飞行器&#xff0c;UAV&#xff09;技术的快速发展&#xff0c;其在商业、娱乐和军事领域的广泛应用带来了新的安全挑战。特别是对于关键基础设施如电力系统&#xff0c;无人机的“黑飞”&…...

Java求职者面试指南:计算机基础与源码原理深度解析

Java求职者面试指南&#xff1a;计算机基础与源码原理深度解析 第一轮提问&#xff1a;基础概念问题 1. 请解释什么是进程和线程的区别&#xff1f; 面试官&#xff1a;进程是程序的一次执行过程&#xff0c;是系统进行资源分配和调度的基本单位&#xff1b;而线程是进程中的…...