Go网络编程-RPC程序设计

gRPC 通信

RPC 介绍

RPC, Remote Procedure Call,远程过程调用。与 HTTP 一致,也是应用层协议。该协议的目标是实现:调用远程过程(方法、函数)就如调用本地方法一致。

如图所示:

说明:

  • ServiceA 需要调用 ServiceB 的 FuncOnB 函数,对于 ServiceA 来说 FuncOnB 就是远程过程

  • RPC 的目的是让 ServiceA 可以像调用 ServiceA 本地的函数一样调用远程函数 FuncOnB,也就是 ServieA 上代码层面使用:serviceB.FuncOnB() 即可完成调用

  • RPC 是 C/S 模式,调用方为 Client,远程方为 Server

  • RPC 把整体的调用过程,数据打包、网络请求等,封装完毕,在 C、S 两端的 Stub 中。Stub(代码存根)

  • 调用流程如下

    1. ServiceA 将调回需求告知 Client Sub

    2. Client Sub 将调用目标(Call ID)、参数数据(params)等调用信息进行打包(序列化),并将打包好的调用信息通过网络传输给 Server Sub

    3. Server Sub 将根据调用信息,调用相应过程。期间涉及到数据的拆包(反序列化)等操作。

    4. 远程过程 FuncOnB 运行,并得到结果,将结果告知 Server Sub

    5. Server Sub 将结果打包,并传输回给 Client Sub

    6. Client Sub 将结果拆包,把最终函数调用的结果告知 ServiceA

以上就是典型 RPC 的流程。

RPC 协议没有对网络层做规范,那也就意味着具体的 RPC 实现可以基于 TCP,也可以基于其他协议,例如 HTTP,UDP 等。RPC 也没有对数据传输格式做规范,也就是逻辑层面,传输 JSON、Text、protobuf 都可以。这些都要看具体的 RPC 产品的实现。广泛使用的 RPC 产品有 gRPC,Thrift 等。

gRPC 介绍

gPRC 官网(https://grpc.io/)上的 Slogan 是:A high performance, open source universal RPC framework。就是:一个高性能、开源的通用 RPC 框架。

支持多数主流语言:C#、C++、Dart、Go、Java、Kotlin、Node、Objective-C、PHP、Python、Ruby。其中 Go 支持 Windows, Linux, Mac 上的 Go 1.13+ 版本。

gRPC 是一个 Google 开源的高性能远程过程调用 (RPC) 框架,可以在任何环境中运行。它可以通过对负载平衡、跟踪、健康检查和身份验证的可插拔支持有效地连接数据中心内和跨数据中心的服务。它也适用于分布式计算的最后一步,将设备、移动应用程序和浏览器与后端服务接。

在 gRPC 中,客户端应用程序可以直接调用不同机器上的服务器应用程序的方法,就像它是本地对象一样,使您更容易创建分布式应用程序和服务。与许多 RPC 系统一样,gRPC 基于定义服务的思想,指定可以远程调用的方法及其参数和返回类型。在服务端,服务端实现这个接口并运行一个 gRPC 服务器来处理客户端调用。在客户端,客户端有一个存根(在某些语言中仅称为客户端),它提供与服务器相同的方法。

技术上,gRPC 基于 HTTP/2 通信,采用 Protocol Buffers 作数据序列化。

准备 gRPC 环境

使用 gRPC 需要:

  • Go

  • Protocol Buffer 编译器,protoc,推荐版本3

  • Go Plugin,用于 Protocol Buffer 编译器

安装 protoc:

可以使用 yum 或 apt 包管理器安装,但通常版本会比较滞后。因此更建议使用预编译的二进制安装。

下载地址:

 https://github.com/protocolbuffers/protobuf/releases

基于系统和版本找到合适的二进制下载并安装。

CentOS 演示:

 # 下载特定版本,当前(2022年08月)最新 21.4$ curl -LO https://github.com/protocolbuffers/protobuf/releases/download/v21.4/protoc-21.4-linux-x86_64.zip# 解压到特定目录$ sudo unzip protoc-21.4-linux-x86_64.zip -d /usr/local# 如果特定目录中的bin不在环境变量 path 中,手动加入 path​# 测试安装结果,注意版本应该是 3.x$ protoc --versionlibprotoc 3.21.4

Win 演示,下载,解压到指定目录,在 CMD 中运行:

 # 解压到指定目录即可,要保证 protoc/bin 位于环境变量 path 中,可以随处调用> protoc.exe --versionlibprotoc 3.21.4​

安装 Go Plugin:

 # 下载特定版本,当前(2022年08月)最新 v1.28.1> go install google.golang.org/protobuf/cmd/protoc-gen-go@latest# 下载特定版本,当前(2022年08月)最新 v1.2.0> go install google.golang.org/grpc/cmd/protoc-gen-go-grpc@latest# 安装完毕后,要保证 $GOPATH/bin 位于环境变量 path 中​# 测试安装结果> protoc-gen-go --versionprotoc-gen-go.exe v1.28.1> protoc-gen-go-grpc --versionprotoc-gen-go-grpc 1.2.0
Protocol Buffer 的基础使用

默认情况下,gRPC 使用 Protocol Buffers,这是 Google 用于序列化结构化数据的成熟开源机制(尽管它可以与 JSON 等其他数据格式一起使用)。

Protocol Buffers 的文档:https://developers.google.com/protocol-buffers/docs/overview

使用 Protocol Buffers 的基本步骤是:

  1. 使用 protocol buffers 语法定义消息,消息是用于传递的数据

  2. 使用 protocol buffers 语法定义服务,服务是 RPC 方法的集合,来使用消息

  3. 使用 Protocol Buffer编 译工具 protoc 来编译,生成对应语言的代码,例如 Go 的代码

使用 Protocol Buffers 的第一步是在 .proto 文件中定义序列化的数据的结构,.proto 文件是普通的文本文件。Protocol Buffers 数据被结构化为消息,其中每条消息都是一个小的信息逻辑记录,包含一系列称为字段的 name-value 对。

除了核心内容外,.proto 文件还需要指定语法版本,目前主流的也是最新的 proto3 版本。在 .proto 文件的开头指定。

一个简单的产品信息示例:

product.proto

 syntax = "proto3";​// 定义 Product 消息message Product {string name = 1;int64 id = 2;bool is_sale = 3;}

第二步是在 .proto 文件中定义 gRPC 服务,将 RPC 方法参数和返回类型指定为 Protocol Buffers 消息,继续编辑 product.proto :

 syntax = "proto3";​// 为了生成 go 代码,需要增加 go_package 属性,表示代码所在的包。protoc 会基于包构建目录option go_package = "./proto-codes";​// 定义 ProductInfo 消息message ProductInfoResponse {string name = 1;int64 int64 = 2;bool is_sale = 3;}​// rpc 方法 ProductInfo 需要的参数消息message ProductInfoRequest {int64 int64 = 1;}​// 定义 Product 服务service Product {// 获取产品信息rpc ProductInfo (ProductInfoRequest) returns (ProductInfoResponse) {}}

第三步是使用 protoc 工具将 .proto 定义的消息和包含 rpc 方法的服务编译为目标语言的代码,我们选择 Go 代码。

 $ protoc --go_out=. --go-grpc_out=. product.proto# --go_out *.pb.go 目录# --go-grpc_out *_grpc.pb.go 目录

其中:

  • *.pb.go 包含消息类型的定义和操作的相关代码

  • *_grpc.pb.go 包含客户端和服务端的相关代码

生成的代码主要是结构上的封装,在继续使用时,还需要继续充实业务逻辑。

基于 gRPC 的服务间通信示例

示例说明,存在两个服务,订单服务和产品服务。其中:

  • 订单服务提供 HTTP 接口,用于完成订单查询。订单中包含产品信息,要利用 grpc 从产品服务获取产品信息

  • 产品服务提供 grpc 接口,用于响应微服务内部产品信息查询

本例中,对于 grpc 来说,产品服务为服务端、订单服务为客户端。

同时不考虑其他业务逻辑,例如产品服务也需要对外提供 http 接口等,仅在乎 grpc 的通信示例。同时不考虑服务发现和网关等。

image.png

编码实现:

一:基于之前定义的 .proto 文件生成 pb.go 文件

注意,客户端和服务端,都需要使用生成的 pb.go 文件

二:实现订单服务

orderService/httpService.go

 package main​import ("context""encoding/json""flag""fmt""google.golang.org/grpc""google.golang.org/grpc/credentials/insecure""log""net/http""orderService/protos/codes""time")​var (// 目标 grpc 服务器地址gRPCAddr = flag.String("grpc", "localhost:50051", "the address to connect to")// http 命令行参数addr = flag.String("addr", "127.0.0.1", "The Address for listen. Default is 127.0.0.1")port = flag.Int("port", 8080, "The Port for listen. Default is 8080."))​func main() {flag.Parse()// 连接 grpc 服务器conn, err := grpc.Dial(*gRPCAddr, grpc.WithTransportCredentials(insecure.NewCredentials()))if err != nil {log.Fatalf("did not connect: %v", err)}defer conn.Close()// 实例化 grpc 客户端c := codes.NewProductClient(conn)​// 定义业务逻辑服务,假设为产品服务service := http.NewServeMux()service.HandleFunc("/orders", func(writer http.ResponseWriter, request *http.Request) {// 调用 grpc 方法,完成对服务器资源请求ctx, cancel := context.WithTimeout(context.Background(), time.Second)defer cancel()r, err := c.ProductInfo(ctx, &codes.ProductInfoRequest{Int64: 42,})if err != nil {log.Fatalln(err)}​resp := struct {ID       int                          `json:"id"`Quantity int                          `json:"quantity"`Products []*codes.ProductInfoResponse `json:"products"`}{9527, 1,[]*codes.ProductInfoResponse{r,},}respJson, err := json.Marshal(resp)if err != nil {log.Fatalln(err)}writer.Header().Set("Content-Type", "application/json")_, err = fmt.Fprintf(writer, "%s", string(respJson))if err != nil {log.Fatalln(err)}})​// 启动监听address := fmt.Sprintf("%s:%d", *addr, *port)fmt.Printf("Order service is listening on %s.\n", address)log.Fatalln(http.ListenAndServe(address, service))}

三,实现产品服务

productService/grpcService.go

package mainimport ("context""flag""fmt""google.golang.org/grpc""log""net""productService/protos/compiles"
)//grpc 监听端口
var port = flag.Int("port", 50051, "The server port")// ProductServer 实现 UnimplementedProductServer
type ProductServer struct {compiles.UnimplementedProductServer
}func (ProductServer) ProductInfo(ctx context.Context, pr *compiles.ProductInfoRequest) (*compiles.ProductInfoResponse, error) {return &compiles.ProductInfoResponse{Name:   "马士兵 Go 云原生",Int64:  42,IsSale: true,}, nil
}func main() {flag.Parse()//设置 tcp 监听器lis, err := net.Listen("tcp", fmt.Sprintf(":%d", *port))if err != nil {log.Fatalf("failed to listen: %v", err)}// 新建 grpc Servers := grpc.NewServer()// 将 ProductServer 注册到 grpc Server 中compiles.RegisterProductServer(s, ProductServer{})log.Printf("server listening at %v", lis.Addr())// 启动监听if err := s.Serve(lis); err != nil {log.Fatalf("failed to serve: %v", err)}
}

测试,访问 order 的 http 接口。获取订单信息中,包含产品信息。

gRPC 核心概念

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

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

相关文章

windows下安装启动运行MinIO

MinIO服务器本身是采用Go语言开发的; 编程操作MinIO服务器的客户端有很多: Go,Python,Java,.NET,JavaScript,Haskell,C 官方文档:https://min.io/docs/minio/linux/dev…

MySQL下载安装使用教程图文教程(超详细)

「作者简介」:冬奥会网络安全中国代表队,CSDN Top100,就职奇安信多年,以实战工作为基础著作 《网络安全自学教程》,适合基础薄弱的同学系统化的学习网络安全,用最短的时间掌握最核心的技术。 这一章节我们使…

Jenkins-zookeeper-docker-xxljob-rancher

文章目录 Jenkins实战1 新建任务需要的配置pipeline Zookeeper基础 Docker基础实操windows11 docker mysql DockerhouseDockerhubxxl-Job基础实战 Rancher基础思考 实战1 Rancher的某个namespace的scale为0 Jenkins 实战 1 新建任务需要的配置pipeline 该代码是Jenkinsfile&…

版本控制工具

版本控制工具是用于记录代码文件变化历史、方便查阅特定版本修改情况的系统,一般分为集中式和分布式两种。以下是一些常见的版本控制工具: 集中式版本控制工具 Subversion(SVN) 简介:Subversion是一种集中式版本控制…

《基于 CDC、Spark Streaming、Kafka 实现患者指标采集》

📢 大家好,我是 【战神刘玉栋】,有10多年的研发经验,致力于前后端技术栈的知识沉淀和传播。 💗 🌻 CSDN入驻不久,希望大家多多支持,后续会继续提升文章质量,绝不滥竽充数…

如何获得Cesium的TileSet并设置本地服务器的Url

一.总体思路 首先使用管理者获得TileSet,通过JSON文件读写,调用对应的Cesium内部提供的函数。 UE5中Json文件的读取与解析 - 知乎 (zhihu.com) 不太了解JSON的可以学习这个。 二.具体实现 1.创建Actor,并且 如何获得Cesium的TileSet,设置本地Url 一…

实现了一个心理测试的小程序,微信小程序学习使用问题总结

1. 如何在跳转页面中传递参数 ,在 onLoad 方法中通过 options 接收 2. radio 如何获取选中的值? bindchange 方法 参数e, e.detail.value 。 如果想要获取其他属性,使用data-xx 指定,然后 e.target.dataset.xx 获取。 3. 不刷…

全国媒体邀约,主流媒体到场出席采访报道

传媒如春雨,润物细无声,大家好,我是51媒体网胡老师。 全国媒体邀约,确保主流媒体到场出席采访报道,可以带来一系列的好处,这些好处不仅能够增强活动的可见度,还能对品牌或组织的长期形象产生积…

将iPad 作为Windows电脑副屏的几种方法(二)

将iPad 作为Windows电脑副屏的几种方法(二) 1. 前言2. EV 扩展屏2.1 概述2.2 下载、安装、连接教程2.3 遇到的问题和解决方法2.3.1 平板连接不上电脑 3. Twomon SE3.1 概述3.2 下载安装教程 4. 多屏中心(GlideX)4.1 概述4.2 下载安…

基于FPGA的多路选择器

目录 一、组合逻辑 二、多路选择器简介: 三、实战演练 摘要:本实验设计并实现了一个简单的多路选择器,文章后附工程代码 一、组合逻辑 组合逻辑是VerilogHDL设计中的一个重要组成部分。从电路本质上讲,组合逻辑电路的特点是输…

数据结构(单链表算法题)

1.删除链表中等于给定值 val 的所有节点。 OJ链接 typedef struct ListNode ListNode;struct ListNode {int val;struct ListNode* next; };struct ListNode* removeElements(struct ListNode* head, int val) {//创建新链表ListNode* newhead, *newtail;newhead newtail N…

verilog bug记录——正点原子spi_drive存在的问题

verilog bug记录——正点原子spi_drive存在的问题 问题概述代码修改—spi_drive.v遗留问题 问题概述 因为项目需求,需要利用spi对flash进行擦除和写入操作,所使用的开发板是正电原子的达芬奇开发板,我事先往Flash里面存了两个bit&#xff0c…

全国产服务器主板:搭载飞腾FT2000+/64处理器的高性能加固服务器

近期很多朋友咨询全国产化的服务器主板。搭载的是飞腾FT-2000/64的全国产化服务器主板。他的主要特点是:①丰富的PCIe、千兆以太网、SATA接口,可用作数据处理、存储、通信服务器;②​​​​​​​板载独立显示芯片,对外HDMI/VGA/L…

DP(6) | 完全背包 | Java | LeetCode 322, 179, 139 做题总结

322. 零钱兑换 我的错误答案 class Solution {public int coinChange(int[] coins, int amount) {int[][]dp new int [coins.length][amount1];for(int j0; j<amount; j) {if(coins[0] j){dp[0][coins[0]] 1;}}for(int i1; i<coins.length; i) {for(int j0; j<am…

vue3前端开发-小兔鲜项目-图片懒加载的自定义标签

vue3前端开发-小兔鲜项目-图片懒加载的自定义标签&#xff01;很多大型网站&#xff0c;因为首页面渲染的内容太多了&#xff0c;然而有些用户&#xff0c;可能在顶部就发现了自己感兴趣的内容&#xff0c;直接就点击跳转去了其他页面&#xff0c;因此&#xff0c;完全没有必要…

神经网络之多层感知机

目录 一、全连接层&#xff1a;二、单层感知机概念&#xff1a;三、多层感知机概念&#xff1a; 一、全连接层&#xff1a; 在神经网络中&#xff0c;全连接层就是每个神经元都与上一层的所有神经元相连接&#xff0c;即每个神经元都接收上一层所有神经元的输入&#xff0c;并…

【面试题】数据结构:堆排序的排序思想?

堆排序的排序思想&#xff1f; 堆排序是一种高效的排序算法&#xff0c;其基本思想是利用堆这种数据结构来实现排序。堆是一种特殊的完全二叉树&#xff0c;通常用数组来表示。堆排序的基本步骤如下&#xff1a; 1. 构建初始堆&#xff1a; 将待排序的数组转换成一个最大堆&a…

【JavaEE】volatile + final + wait-notify + join + park-unpark 相关原理

本文基于jdk8 本文所讲的一些原理都是在多线程中经常使用的内容。 参考&#xff1a;黑马程序员深入学习Java并发编程&#xff0c;JUC并发编程全套教程_哔哩哔哩_bilibili 目录 volatile原理 Java内存模型(JMM) 可见性&有序性 双重检查锁应用 final原理 设置final变量…

GPT-4o大语言模型优化、本地私有化部署、从0-1搭建、智能体构建

原文链接&#xff1a;GPT-4o大语言模型优化、本地私有化部署、从0-1搭建、智能体构建https://mp.weixin.qq.com/s?__bizMzUzNTczMDMxMg&mid2247608565&idx3&snd4e9d447efd82e8dd8192f7573886dab&chksmfa826912cdf5e00414e01626b52bab83a96199a6bf69cbbef7f7fe…

学习日志:java线程

文章目录 前言一、线程和进程线程与进程的关系 二、Java 线程和操作系统的线程JDK 1.2 之前JDK 1.2 及以后用户线程和内核线程 三、创建线程四、线程的生命周期和状态五、线程的上下文切换六、Thread#sleep() 方法和Object#wait() 方法 前言 这里总结线程的一些概念。 一、线程…