RPC

概念

RPC(Remote Procedure Call)远程过程调用。是一种通过网络向远程计算机请求服务信息,但又不需要了解底层网络技术的通信方式。就是像调用本地服务一样调用远程服务。

RPC采用客户端/服务端的模式,通过request-reponse消息模式实现。

实现步骤

RPC的主要实现步骤如下(加粗部分为rpc框架要实现的步骤):

  • 客户端发起本地连接请求连接服务端的服务;
  • 客户端程序句柄(stub)负责将客户端请求的消息序列化成二进制消息;
  • 客户端通过网络模块将消息发送至服务端;
  • 服务端程序句柄(stub)将收到的消息进行反序列化;
  • 服务端程序句柄(stub)根据解析后的方法调用本地服务;
  • 服务端上的服务处理完成后将消息发送至程序句柄(stub);
  • 服务端程序句柄(stub)将消息序列化成二进制消息;
  • 服务端通过网络模块将消息发送至客户端;
  • 客户端程序句柄(stub)将消息反序列化;
  • 客户端程序句柄(stub)根据解析后的方法调用本地服务;

实现原理

RPC 架构主要包括三部分:

  • 服务注册中心(Registry),负责将本地服务发布成远程服务,管理远程服务,提供给服务消费者使用,主要用于实现负载均衡和故障切换。
  • RPC Server,服务提供者,提供服务接口定义与服务实现类,服务提供者启动后主动向服务注册中心(Registry)注册机器IP、端口以及提供的服务列表;
  • RPC Client,服务消费者,通过远程代理对象调用远程服务,启动时向服务注册中心(Registry)获取服务提供方地址列表。

优缺点

优点

  • 对于使用者来说,简单高效,无需关心底层逻辑,仅调用接口即可;
  • 主流的rpc框架(如Dubbo、grpc、Hessian等)跨语言支持;

缺点

  • 开发难度大;
  • 异常处理困难

Stub

Stub是一段用于转换参数的代码。

为什么使用存根(Stub)?

rpc调用中,服务端提供方法和接口实现,客户端调用方法。但往往客户端和服务端位于不同的服务器上,主要有以下差异:

  • 编码不同。例如一端是GBK,另一端是UTF-8;
  • 大小端不同;
  • 编译语言不同。例如一段是c++,另一端是java;
  • 内存布局不同;
  • 尾款不同。有32/64位之分;

存根(Stub)选取一种中间形式,让两端的数据都可以正确可逆的与中间数据进行转换。常用的中间数据类型包括:纯字符串、XML、JSON、protobuf。

HTTP协议

从RPC的实现中可以看出,RPC的通信需要底层网络协议的支持,HTTP是一种比较好的实现方式。

概念

HTTP(HyperText Transfer Protocol)超文本传输协议,是一个双向协议,可以用来传输文字、图片、音视频等数据。

HTTP协议在3.0版本之前是基于TCP的,3.0版本底层改成了UDP。

HTTP/1.0

优点

  • 简单,报文的格式为header+body;
  • 灵活、易于扩展;
  • 应用广泛、跨平台;

缺点

  • 无状态;
  • 明文传输;
  • 不安全(后续HTTPS做了相关方面的修复);

HTTP/1.1

优点

  • 支持tcp长连接,改善了HTTP/1.0短连接造成的开销;
  • 支持管道(pipeline)网络传输;

缺点

  • 请求 / 响应头部(Header)未压缩,首部信息越多延迟越大;
  • 无请求优先级控制;
  • 服务器按请求顺序响应,会造成队头阻塞;
  • 请求只能从客户端开始,服务端被动响应;

HTTP/2.0

优点

  • 头部压缩;
  • 二进制格式。头信息和数据体都是二进制,统称为帧:头信息帧和数据帧;
  • 数据流;
  • 多路复用。一个连接中并发处理多个请求和响应;
  • 服务器推送。服务器可以主动向客户端发送消息

缺点

  • 多个请求复用一个TCP连接,一旦发生丢包,就会阻塞住所有的 HTTP 请求;

HTTP/3.0

优点

  • 底层协议改为UDP。基于UDP的QUIC协议可以实现类似TCP的可靠性传输,QUIC是一个在UDP之上的伪TCP+TLS+HTTP/2的多路复用协议;

GRPC-WEB

gRPC-Web是一个JavaScript客户端库,使Web应用程序能够直接与后端gRPC服务通信,而不需要HTTP服务器充当中介。

关于详细的grpc-web可以查看:

ProtoBuf

概念

protobuf(protocol buffer)一种用于序列化结构数据的工具,用于数据的存储和交换。是开源的一种数据格式,适合高性能,对响应速度有要求的数据传输场景。因为protobuf是二进制数据格式,需要编码和解码。

序列化和反序列化

在前面介绍rpc实现步骤时讲到,客户端或服务端的程序句柄(stub)在接收自身服务的消息后,会将消息进行序列化,在接收网络模块发送的消息后,会将数据进行反序列化。

  • 序列化:将结构数据或者对象转换成能够用于存储和传输的格式;
  • 反序列化:将序列化后的数据还原为结构数据和对象;
为什么要进行序列化和反序列化?
  • 减少存储空间;
  • 方便网络传输;
  • 可以在进程间传递对象;

特点

  • 使用二进制数据交换格式;
  • 使用扩展名为.proto的文件定义存储类的内容;
  • 使用自己的编译器protoc;

优点

  • 数据压缩性高;
  • 传输速度快;
  • 序列化速度快;
  • 简单、可扩展性高、加密性好;
  • 跨平台、跨语言、可扩展性强;

安装protoc

1)下载通用编译器

下载地址:https://github.com/protocolbuffers/protobuf/releases

下载21.7-win64版本即可。

2)添加至环境变量

3)安装go专用的protoc的生成器

go get github.com/golang/protobuf/protoc-gen-go

安装时会出现一些报错,解决方案可参考:https://blog.csdn.net/www_dong/article/details/127149660

示例

1)创建.proto文件

// 当前proto的版本
syntax = "proto3";// 格式: option go_package= "path;name";
// path: 指定生成文件的存放地址
// name: 生成的go文件所属的文件名
option go_package = "../service";// 指定文件从生成出来的package
package service;// 传输的对象
message User {string username = 1;int32 age = 2;
}

2)编译生成user.pb.go文件

执行命令

protoc --go_out=./ user.proto

如图所示,成功生成user.pb.go文件。

3)测试

测试程序main.go如下:

package mainimport ("fmt""service"
)func main() {user := &service.User{Username: "dong",Age:      18,}// 序列化marshal, err := proto.Marshal(user)if err != nil {panic(err)}// 反序列化newUser := &service.User{}err := proto.Unmarshal(marshal, newUser)if err != nil {panic(err)}fmt.Println(newUser.String())
}

程序执行结果如下:

proto文件

message

message是定义一个消息类型的关键字。

字段规则

requried: 消息体中必填字段,不设置会导致解码异常;optional: 消息体中的可选字段;repeated: 消息体中可重复的字段,重复的值的顺序会被保留;

示例:

.proto中定义类型如下:

message User {optional string passwd = 3;repeated string address = 4;
}

生成的go文件中的定义如下:

// 传输的对象
type User struct {state         protoimpl.MessageStatesizeCache     protoimpl.SizeCacheunknownFields protoimpl.UnknownFieldsPasswd   *string  `protobuf:"bytes,3,opt,name=passwd,proto3,oneof" json:"passwd,omitempty"`Address  []string `protobuf:"bytes,4,rep,name=address,proto3" json:"address,omitempty"`
}

字段映射

默认值

类型 默认值
bool false
整型 0
string “”
enum 第一个枚举元素的值,默认值为0
message DEFAULT_INSTANCE

标识号

在消息体的定义中,每个字段都必须要有一个唯一的标识号,标识号的范围是[0, 2^29-1]。

// 传输的对象
message User {string username = 1;int32 age = 2;optional string passwd = 3;repeated string address = 4;
}

嵌套消息

message Student
{message BoyStudent {string name = 1;int32 age = 2;repeated int32 height = 3;}repeated BoyStudent boy = 1;
}
message StudentMsg
{Student.BoyStudent boy = 1;
}

定义接口

service AccessService {// rpc 服务的函数名 (传入参数) 返回 (返回参数)rpc ListDevices(ListRequest) returns (ListResponse);
}

gRPC

概念

概念

gRPC是由开发的一个高性能、通用的开源RPC框架,主要面向移动应用开发且基于HTTP/2协议标准而设计,同时支持大多数流行的编程语言。

理念

定义一个服务,指定其能被远程调用的方法(包括参数和返回类型),在服务端实现这个接口,并运行一个gRPC服务器来处理客户端调用。客户端拥有一个存根能够保存像服务端一样的方法。

框架

安装

1)查看GOPATH的路径

go env

2)下载grpc源码

cd $GOPATHmkdir -p src/google.golang.orgcd src/google.golang.org/git clone https://github.com/grpc/grpc-gomv grpc-go grpc

3)下载grpc依赖1

cd $GOPATHmkdir -p src/golang.org/xcd src/golang.org/x/git clone https://github.com/golang/net
git clone https://github.com/golang/text

4)下载grpc依赖2

cd $GOPATHcd src/google.golang.org/git clone https://github.com/google/go-genprotomv go-genproto genproto

依赖需要下载完整,否则使用时报错!!!

实例

1)创建.proto文件

syntax = "proto3";option go_package="../service";package service;message ProductRequest {int32 prod_id = 1;
}message ProductReponse {int32 prod_stock = 1;
}// 定义接口
service ProdService {rpc GetProductStock(ProductRequest) returns(ProductReponse);
}

2)编译.proto文件

// 指定grpc插件
protoc --go_out=plugins=grpc:./ Product.proto

3)创建接口实现文件

// product.gopackage serviceimport "context"var ProductService = &productService{}type productService struct {}// 接口实现
func (p *productService) GetProductStock(context context.Context, request *ProductRequest) (*ProductReponse, error) {stock := p.GetStockById(request.ProdId)return &ProductReponse{ProdStock: stock}, nil
}func (p *productService) GetStockById(id int32) int32 {return 100
}

4)创建服务端

// grpc_server.gopackage mainimport ("service""google.golang.org/grpc""net""log""fmt"
)func main() {// 创建rpc实例rpcServer := grpc.NewServer()// 服务注册service.RegisterProdServiceServer(rpcServer, service.ProductService)// 启动监听listener, err := net.Listen("tcp", ":8800")if err != nil {log.Fatal("启动监听失败", err)}// 启动服务err = rpcServer.Serve(listener)if err != nil {log.Fatal("启动服务失败", err)}fmt.Println("启动服务成功")
}

5)创建客户端

// grpc_client.gopackage mainimport ("google.golang.org/grpc""google.golang.org/grpc/credentials/insecure""log""service""context""fmt"
)func main() {// 创建连接conn, err := grpc.Dial(target:":8800", grpc.WithTransportCredentials(insecure.NewCredentials()))if err != nil {log.Fatal("服务端连接失败: ", err)}// 退出时关闭连接defer conn.Close()// 创建客户端实例productServiceClient := service.NewProdServiceClient(conn)// 方法请求resq, err := productServiceClient.GetProductStock(context.Background(), &service.ProductRequest{ProdId: 233})if err != nil {log.Fatal("调用gRPC方法失败: ", err)} fmt.Println("调用gRPC方法成功, ProdStock = ", resq.ProdStock)
}

6)测试

启动grpc_server,开始监听。

go run grpc_server.go

启动grpc_client,连接成功。

go run grpc_client.go

打印如下:

7)工程目录

部分参考:

rpc介绍:http://wjhsh.net/GreenForestQuan-p-11543779.html

HTTP协议:https://blog.csdn.net/qq_34827674/article/details/104732605

grpc-web:https://www.cncf.io/blog/2018/10/24/grpc-web-is-going-ga/

Protobuf官网:https://developers.google.com/protocol-buffers/docs/proto3

gRPC官网:https://grpc.io

grpc介绍(一)——rpc、protobuf和grpc相关推荐

  1. Wireshark Protobuf 和 gRPC 内置解析器使用介绍

    Wireshark Protobuf 和 gRPC 内置解析器使用介绍 目录 Wireshark Protobuf 和 gRPC 内置解析器使用介绍 1. 主要功能 2. 示例中使用的.proto文件 ...

  2. 深入理解gRPC(一):gRPC介绍

    背景 随着微服务架构和云原生架构的出现,传统的单体应用程序被分解为一组细粒度的.自治的和面向业务能力的"微服务",网络通信链路的数量激增,进程间(或服务间/应用程序间)通信技术也因 ...

  3. go语言rpc,grpc介绍

    目录 rpc RPC调用 net/rpc RPC over HTTP 和 RESTful server client RPC over TCP 和 RESTful server client 序列化/ ...

  4. gRPC创建Java RPC服务

    1.说明 本文介绍使用gRPC创建Java版本的RPC服务, 包括通过.proto文件生成Java代码的方法, 以及服务端和客户端代码使用示例. 2.创建生成代码工程 创建Maven工程,grpc-c ...

  5. go grpc压缩_跟我学 gRPC—1. gRPC 及相关介绍

    Go语言中文网,致力于每日分享编码.开源等知识,欢迎关注我,会有意想不到的收获! 项目地址:https://github.com/EDDYCJY/go-grpc-example 作为开篇章,将会介绍 ...

  6. 漫谈grpc 4:grpc和其他rpc框架的横向对比,到底好在哪里?

    1,什么是grpc gRpc 是一个高性能.开源和通用的 RPC 框架,面向移动和 HTTP/2 设计.目前提供 C.Java 和 Go 语言版本,分别是:grpc, grpc-java, grpc- ...

  7. java rpc 框架 常用_常用的RPC架构系列---gRPC

    gRPC是谷歌的一个高性能,开源的高性能 RPC 框架,gRPC面向移动和HTTP/2设计.gRPC隐藏了底层的实现细节,包括序列化(json,xml),数据传输(TCP,HTTP,UDP),反序列化 ...

  8. grpc 报错 rpc: the client connection is closing

    grpc 报错 rpc: the client connection is closing 第一次写golang微服务,也是第一次接触gprc,底层原理还不太了解,盲猜跟openFeign差不多生成代 ...

  9. gRPC(2)- PHP使用gRPC

    PHP使用GRPC 前言 下载Protoc 编写proto文件 代码实现 准备 服务端服务实现 客户端请求实现 前言 在上节已经介绍了GRPC,不了解GRPC的可以先看下. 本文将讲述PHP如何使用G ...

最新文章

  1. 变量相关命令(env,export,set,read, array, declare)
  2. 启动子级时出错_【本音知识】弹钢琴时如何背谱?
  3. UVA11992不错的线段树段更新
  4. iOS设计模式——MVC(Model-View-Controller)
  5. 从代码到 Docker、Kubernetes、Istio、Knative……,或许是时候重新思考从代码到云的编程了...
  6. Kali Linux 网络扫描秘籍 第六章 拒绝服务(一)
  7. 向Excle中插入多个表
  8. DXUT框架剖析(13)
  9. Momentum(动量/冲量)的理解及应用
  10. HTML中视频的压缩方式,快速将视频压缩到最小的技巧!
  11. 前端纯CSS导入otf字体包
  12. 七剑下天山,独领自动化测试技术
  13. BAT疯狂抢人, AI应届博士生年薪201万, 网友: 转行来得及吗???
  14. arduino 328P的BootLoader
  15. js阿拉伯数字转中文汉字小写 支持到12位
  16. mysql 轨迹数据存储_基于Tablestore实现海量运动轨迹数据存储
  17. 黑镜.潘达斯奈基 高清中字
  18. 世界上第一台计算机内存容量,29、世界上第一台电子计算机ENIAC诞生于.doc
  19. Android系统的编舞者Choreographer
  20. Android Camera 四 Camera HAL 分析

热门文章

  1. 中华英才网爬虫程序解析(4)-分布式爬虫redis
  2. 2020北京考研英语一80+经验
  3. CRC校验原理的完整学习
  4. 小程序:Thu May 05 2022 11:03:00 GMT+0800 (中国标准时间) 渲染层错误
  5. 2022-07-10 第七小组 闫馨月 学习笔记
  6. redis-删除所有key
  7. 时间序列预测基础教程系列(14)_如何判断时间序列数据是否是平稳的(Python)
  8. 理解 OpenStack + Ceph (3):Ceph RBD 接口和工具 [Ceph RBD API and Tools]
  9. MODIS NDVI下载处理 MOD13A1, win10
  10. tomcat 7.0