当前位置: 首页 > 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出品 下面是吾爱社区找…...

STM32F4基本定时器使用和原理详解

STM32F4基本定时器使用和原理详解 前言如何确定定时器挂载在哪条时钟线上配置及使用方法参数配置PrescalerCounter ModeCounter Periodauto-reload preloadTrigger Event Selection 中断配置生成的代码及使用方法初始化代码基本定时器触发DCA或者ADC的代码讲解中断代码定时启动…...

oracle与MySQL数据库之间数据同步的技术要点

Oracle与MySQL数据库之间的数据同步是一个涉及多个技术要点的复杂任务。由于Oracle和MySQL的架构差异&#xff0c;它们的数据同步要求既要保持数据的准确性和一致性&#xff0c;又要处理好性能问题。以下是一些主要的技术要点&#xff1a; 数据结构差异 数据类型差异&#xff…...

[10-3]软件I2C读写MPU6050 江协科技学习笔记(16个知识点)

1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16...

k8s业务程序联调工具-KtConnect

概述 原理 工具作用是建立了一个从本地到集群的单向VPN&#xff0c;根据VPN原理&#xff0c;打通两个内网必然需要借助一个公共中继节点&#xff0c;ktconnect工具巧妙的利用k8s原生的portforward能力&#xff0c;简化了建立连接的过程&#xff0c;apiserver间接起到了中继节…...

让回归模型不再被异常值“带跑偏“,MSE和Cauchy损失函数在噪声数据环境下的实战对比

在机器学习的回归分析中&#xff0c;损失函数的选择对模型性能具有决定性影响。均方误差&#xff08;MSE&#xff09;作为经典的损失函数&#xff0c;在处理干净数据时表现优异&#xff0c;但在面对包含异常值的噪声数据时&#xff0c;其对大误差的二次惩罚机制往往导致模型参数…...

莫兰迪高级灰总结计划简约商务通用PPT模版

莫兰迪高级灰总结计划简约商务通用PPT模版&#xff0c;莫兰迪调色板清新简约工作汇报PPT模版&#xff0c;莫兰迪时尚风极简设计PPT模版&#xff0c;大学生毕业论文答辩PPT模版&#xff0c;莫兰迪配色总结计划简约商务通用PPT模版&#xff0c;莫兰迪商务汇报PPT模版&#xff0c;…...

C#学习第29天:表达式树(Expression Trees)

目录 什么是表达式树&#xff1f; 核心概念 1.表达式树的构建 2. 表达式树与Lambda表达式 3.解析和访问表达式树 4.动态条件查询 表达式树的优势 1.动态构建查询 2.LINQ 提供程序支持&#xff1a; 3.性能优化 4.元数据处理 5.代码转换和重写 适用场景 代码复杂性…...

Caliper 负载(Workload)详细解析

Caliper 负载(Workload)详细解析 负载(Workload)是 Caliper 性能测试的核心部分,它定义了测试期间要执行的具体合约调用行为和交易模式。下面我将全面深入地讲解负载的各个方面。 一、负载模块基本结构 一个典型的负载模块(如 workload.js)包含以下基本结构: use strict;/…...

Python 实现 Web 静态服务器(HTTP 协议)

目录 一、在本地启动 HTTP 服务器1. Windows 下安装 node.js1&#xff09;下载安装包2&#xff09;配置环境变量3&#xff09;安装镜像4&#xff09;node.js 的常用命令 2. 安装 http-server 服务3. 使用 http-server 开启服务1&#xff09;使用 http-server2&#xff09;详解 …...

热门Chrome扩展程序存在明文传输风险,用户隐私安全受威胁

赛门铁克威胁猎手团队最新报告披露&#xff0c;数款拥有数百万活跃用户的Chrome扩展程序正在通过未加密的HTTP连接静默泄露用户敏感数据&#xff0c;严重威胁用户隐私安全。 知名扩展程序存在明文传输风险 尽管宣称提供安全浏览、数据分析或便捷界面等功能&#xff0c;但SEMR…...