浅谈RPC协议

news2024/11/15 11:06:22

RPC协议

  • RPC简介
  • 为啥需要RPC
  • RPC的调用过程
  • gRPC
  • ProtoBuffer
  • gRPC实战

RPC简介

RPC(Remote Procedure Call Protocol)远程过程调用协议,目标就是让远程服务调用更加简单、透明。RPC 框架负责屏蔽底层的传输方式(TCP 或者 UDP)、序列化方式(XML/Json/ 二进制)和通信细节,服务调用者可以像调用本地接口一样调用远程的服务提供的接口,而不需要关心底层通信细节和调用过程。
在这里插入图片描述
其大致过程如上图所示。

为啥需要RPC

当我们的业务越来越多、应用也越来越多时,自然的,我们会发现有些功能已经不能简单划分开来或者划分不出来。我们平时写的项目大多数所有的模块都在一起,部署一台服务器上来,但是这也有几个问题:

  • 单台服务器的硬件资源有限,能够承受的并发量并不高
  • 任意模块的修改,都会导致整个项目代码重写编译,有可能你你只修改了只行代码并且至少一个模块的,当然你肯定只想编译这一个模块的代码就行,但是事实上整个项目需要重新编译。
  • 系统当中有些模块属于CPU密集型,有些模块是I/O密集型的,造成各模块对硬件资源的需求不一样的.当我们把这些模块打包发在同一台机器上,我们就只能综合整个模块选择内存和CPU以及网路带宽,没有办法针对每个模块选择其合适的硬件资源。

此时可以将公共业务逻辑抽离出来以及将服务进行模块拆分,将之组成独立的服务 Service 应用,而原有的、新增的应用都可以与那些独立的 Service 应用 交互,以此来完成完整的业务功能,所以我们急需一种高效的应用程序之间的通讯手段来完成这种需求,RPC 大显身手的时候来了。
但是这也有一些我们需要思考的点:

  • 大软件的模块怎么进行划分,各个模块之间可能会实现大量重复的代码
  • 各个模块之间改怎么访问?这使用的就是RPC来实现。

RPC的调用过程

要让网络通信细节对使用者透明,我们需要对通信细节进行封装,我们先看下一个 RPC 调用的流程涉及到哪些通信细节:
在这里插入图片描述

  • 服务消费方(client)调用以本地调用方式调用服务;
  • client stub接收到调用后负责将方法、参数等组装成能够进行网络传输的消息体;
  • client stub找到服务地址,并将消息发送到服务端;
  • server stub收到消息后进行解码;
  • server stub根据解码结果调用本地的服务;
  • 本地服务执行并将结果返回给 server stub;
  • server stub将返回结果打包成消息并发送至消费方;
  • client stub接收到消息,并进行解码;
  • 服务消费方得到最终结果。

而RPC的目标就是要 2~8(上面的2-8) 这些步骤都封装起来,让用户对这些细节透:
在这里插入图片描述

gRPC

1.grpc 的相关概念

什么是gRPC? gRPC 是一个高性能、通用的开源 RPC 框架,其由 Google 2015 年主要面向移动应用开发并基于 HTTP/2 协议标准而设计,基于 ProtoBuf 序列化协议开发,且支持众多开发语言。
由于是开源框架,通信的双方可以进行二次开发,所以客户端和服务器端之间的通信会更加专注于业务层面的内容,减少了对由 gRPC 框架实现的底层通信的关注。

2.gRPC的特点

  • 跨语言使用,支持 C++、Java、Go、Python、Ruby、C#、Node.js、Android Java、Objective-C、PHP 等编程语言;
  • 基于 IDL 文件定义服务,通过 proto3 工具生成指定语言的数据结构、服务端接口以及客户端 Stub;
  • 通信协议基于标准的 HTTP/2 设计,支持双向流、消息头压缩、单 TCP 的多路复用、服务端推送等特性,这些特性使得 gRPC 在移动端设备上更加省电和节省网络流量;
  • 序列化支持 PB(Protocol Buffer)和 JSON,PB 是一种语言无关的高性 能序列化框架,基于 HTTP/2 + PB, 保障了 RPC 调用的高性能;

其交互过程大概如下:
在这里插入图片描述
1.交换机在开启 gRPC 功能后充当 gRPC 客户端的角色,采集服务器充当 gRPC 服务器角色;

2.交换机会根据订阅的事件构建对应数据的格式(GPB/JSON),通过 Protocol Buffers 进行编写 proto 文件,交换机与服务器建立 gRPC 通道,通过 gRPC 协议向服务器发送请求消息;

3.服务器收到请求消息后,服务器会通过 Protocol Buffers 解译 proto 文件,还原出最先定义好格式的数据结构,进行业务处理;

4.数据处理完后,服务器需要使用 Protocol Buffers 重编译应答数据,通过 gRPC 协议向交换机发送应答消息;

5.交换机收到应答消息后,结束本次的 gRPC 交互。

ProtoBuffer

ProtoBuffer 是一种更加灵活、高效的数据格式,与 XML、JSON 类似,在一些高性能且对响应速度有要求的数据传输场景非常适用。
ProtoBuffer 在 gRPC 的框架中主要有三个作用:

  • 定义数据结构和字段
  • 定义服务的接口以及生成客户端的Stub(个人理解就是一个客户端类)
  • 通过序列化和反序列化方式提升传输效率。

为什么 ProtoBuf 会提高传输效率呢?
我们知道使用 XML、JSON 进行数据编译时,数据文本格式更容易阅读,但进行数据交换时,设备就需要耗费大量的 CPU 在 I/O 动作上,自然会影响整个传输速率。
Protocol Buffers 不像前者,它会将字符串进行序列化后再进行传输,即二进制数据。在这里不详细说明,有兴趣的可以看博客的另外一篇博客.

为什么 ProtoBuf 会提高传输效率呢?

我们知道使用 XML、JSON 进行数据编译时,数据文本格式更容易阅读,但进行数据交换时,设备就需要耗费大量的 CPU 在 I/O 动作上,自然会影响整个传输速率。

Protocol Buffers 不像前者,它会将字符串进行序列化后再进行传输,即二进制数据
gRPC 能够做到跨平台,多语言,很大一部分得益于Protobuffer自动的编译器。前面提到的 proto 文件就是通过编译器进行编译的,proto 文件需要编译生成一个类似库文件,基于库文件才能真正开发数据应用。
具体用什么编程语言编译生成这个库文件呢?由于现网中负责网络设备和服务器设备的运维人员往往不是同一组人,运维人员可能会习惯使用不同的编程语言进行运维开发,那么 Protocol Buffers 其中一个优势就能发挥出来——跨语言。

gRPC实战

在这里博主选择go语言进行演示grpc的使用,其他铁子也可以自行选择提前语言进行使用。在使用grpc之前各位铁子要安装好这个protobuf。
安装grpc最核心的库

go get google.golang.org/grpc 

上面安装是安装了这个protocol的编译器,它可以生成各种语言因此除了这个编译器我们还需要配合各个语言的代码生成工具,对于golang来说我们叫做protoc-gen-go

go install google.golang.org/protobuf/cmd/protoc-gen-go@v1.28
go install google.golang.org/grpc/cmd/protoc-gen-go-grpc@v1.2

安装好之后我们就可以开始编写proto文件

syntax="proto3";
option go_package=".;service";//这部分内容是关于生成的go代码,在那个目录的包中,service代表生成的go文件的package是service

message  HelloRequest{
     bytes requestName=1;
}
message  HelloResponse{
     bytes responseMsg=1;
}
service SayHello{
  rpc SayHello(HelloRequest)returns(HelloResponse);
}

编写完成proto文件之后我们开始使用这个命令生成代码

protoc --go_out=. hello.proto  
protoc --go-grpc_out=. hello.proto 

在这里插入图片描述
下面我们开始编写客户端的代码

package main

import (
	"context"
	"errors"
	"fmt"
	"google.golang.org/grpc"
	"google.golang.org/grpc/metadata"
	service "http/gRpc/server/proto"
	"net"
)

type server struct {
	*service.UnimplementedSayHelloServer //包含定义的sayHello方法的结构体
}

func (s *server) SayHello(ctx context.Context, req *service.HelloRequest) (*service.HelloResponse, error) {
	//获取源数据信息
	md, ok := metadata.FromIncomingContext(ctx)
	if !ok {
		return nil, errors.New("未传输token")
	}
	var appId string
	var appKey string
	if v, ok := md["appid"]; ok {
		appId = v[0]
	}

	if v, ok := md["appkey"]; ok {
		appKey = v[0]
	}
	fmt.Println("the appkey is" + appKey)
	//这里应该要去数据库里面查询,用户id appid
	if appId != "ksy" || appKey != "122" {
		return nil, errors.New("错误" + appKey + appId)
	}

	return &service.HelloResponse{
		ResponseMsg: []byte(req.RequestName),
	}, nil
}

func Test() {
	//开启监听
	listen, err := net.Listen("tcp", "127.0.0.1:8909")
	if err != nil {
		panic(err)
	}
	//创建grpc服务器
	grpcServer := grpc.NewServer()

	//注册进来,在grpc 服务端当中注册我们编写的服务
	service.RegisterSayHelloServer(grpcServer, &server{})

	//启动服务
	if err := grpcServer.Serve(listen); err != nil {
		panic(err)
	}
}

func main() {
	Test()
}

这个客户端对应代码

package main

import (
	"context"
	"fmt"
	"google.golang.org/grpc"
	"google.golang.org/grpc/credentials/insecure"
	service "http/gRpc/server/proto"
)

func Test() {
	//链接server端,此处禁用安全链接
	conn, err := grpc.Dial(":8909", grpc.WithTransportCredentials(insecure.NewCredentials()))
	if err != nil {
		panic(err)
	}
	defer conn.Close()

	//建立链接
	client := service.NewSayHelloClient(conn)
	//发起远程过程调用
	resp, err := client.SayHello(context.Background(), &service.HelloRequest{RequestName: []byte("ksy")})
	fmt.Println(resp)
}

type ClientTokenAuth struct {
	
}

// GetRequestMetadata 重写接口
func (c *ClientTokenAuth) GetRequestMetadata(ctx context.Context, uri ...string) (map[string]string, error) {
	return map[string]string{
		"appid":  "ksy",
		"appKey": "122",
	}, nil
}

func (c *ClientTokenAuth) RequireTransportSecurity() bool {
	//不开启安全传输
	return false
}

// TestToke token认证
func TestToke() {
	var opts []grpc.DialOption//选项
	opts = append(opts, grpc.WithTransportCredentials(insecure.NewCredentials()))
	opts = append(opts, grpc.WithPerRPCCredentials(new(ClientTokenAuth)))
	conn, err := grpc.Dial(":8909", opts...)
	if err != nil {
		panic(err)
	}
	defer conn.Close()
	//建立链接
	client := service.NewSayHelloClient(conn)
	//发起远程过程调用
	resp, err := client.SayHello(context.Background(), &service.HelloRequest{RequestName: []byte("ksy")})
	fmt.Println(err)
	fmt.Println(resp)
}
func main() {
	TestToke()
}

下面我们可以把客户端和服务端启动起来,就可以进行通信了。

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

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

相关文章

【数据结构】从树到二叉树

目录 ​编辑 一. 前言 二. 树的概念及结构----凉拌海带 2.1 什么是树 2.2 树的基本术语 2.3 树的表示 2.4 树在实际生活中的应用 二. 二叉树的概念及结构----扬州炒饭 2.1 什么是二叉树 2.2 二叉树两种特殊形式 2.3 二叉树的性质 2.4 二叉树的存储结构 三. 链式二叉树基本操…

MySQL之DQL万字解析(涵盖所有查询!!!)

今日金句 生活中有80%的痛苦是来自上班, 但如果不上班,就会有100%的痛苦来自没钱 文章目录 前言一、基础查询1.1 语法1.2 实例 二、条件查询2.1 语法2.2 条件查询实例2.3 模糊查询实例 三 、排序查询3.1 语法3.2 实例 四 、聚合函数4.1 概念4.2 聚合函…

css:鼠标经过el-dropdown 组件上会出现一个蓝色的小框

问题描述 效果如下,原以为是浏览器的bug,升级后就好了,没想到一直有这个问题 页面刷新后,鼠标经过el-dropdown 组件上会出现一个蓝色的小框 原因 浏览器默认有一个样式,加了一个边框 :focus-visible {outline: -we…

应用层:客户-服务器方式(C/S)、对等方式(P2P)

1.应用层:客户-服务器方式和对等方式 笔记来源: 湖科大教书匠:客户-服务器方式和对等方式 声明:该学习笔记来自湖科大教书匠,笔记仅做学习参考 开发一种新的网络应用首先要考虑的问题就是网络应用程序在各种端系统上的…

git no matching host key type found. Their offer: ssh-rsa

本地生成ssh,并配置了服务器SSH Public Keys 问题 拉去远程代码报错 git no matching host key type found. Their offer: ssh-rsa (base) tangsiqitangsiqideMacBook-Pro VDI % git clone "ssh://tangsiqireview.archeros.cn:29418/ArcherDT/vdi-server&…

通用登录模块(解决多端开发登录策略不同的问题)

文章目录 1、目前登录接口2、问题分析3、解决方案4、使用场景 现在有一个场景,就是需要做登录,但是我们不确定现在移动端的同学做几端,可能会有 手机号登录、账号密码登录、qq登录、微信登录、PC端登录、网页端登录。这些登录的具体实现肯定…

Go语言基础知识(一):基础介绍

一、简介 Go 语言又称 Golang,由 Google 公司于 2009 年发布,近几年伴随着云计算、微服务、分布式的发展而迅速崛起,跻身主流编程语言之列,和 Java 类似,它是一门静态的、强类型的、编译型编程语言,为并发…

python_day2

猜数字-while循环 import randomnum random.randint(1, 10) while True:x int(input("输入&#xff1a;"))if x > num:print("大了")elif x < num:print("小了")else:print("猜对了")break打印九九乘法表-while循环 i 1 wh…

mysql中desc的两种用法---1、查询表结构和降序

Mysql中DESC的两种用法 1、查询表结构 语法&#xff1a; desc table_name&#xff1b; PS&#xff1a;此处desc是describe的缩写&#xff0c;用法&#xff1a; desc 表名/查询语句 2、降序 语法&#xff1a; select * from 表 order by 字段 desc select ename,sal from e…

华为Harmony应用开发初探

HarmonyOS是一款面向万物互联时代的、全新的分布式操作系统。在传统的单设备系统能力基础上,HarmonyOS提出了基于同一套系统能力、适配多种终端形态的分布式理念,能够支持手机、平板、智能穿戴、智慧屏、车机等多种终端设备,提供全场景(移动办公、运动健康、社交通信、媒体…

VectorCAST软件安装

一、VectorCAST的安装 在 Windows 平台&#xff0c;安装文件是一个压缩文件&#xff08;zip 文件&#xff09;&#xff0c;请将其解压缩&#xff0c;解压缩后&#xff0c;找到 setup.exe&#xff0c; 双击运行&#xff0c;打开软件安装界面&#xff0c;之后在此界面点击 Next&…

利用python绘制二三维曲面和矢量流线图

为了实现不同数据的可视化&#xff0c;最近研究了python环境下的可视化方案&#xff0c;为后续的流体运动仿真模拟做好储备&#xff0c;由于python处理数据的便利性&#xff0c;导致目前很多后端处理或者可视化成图操作都在python中实现&#xff0c;比如前端是vue&#xff0c;加…

全国时尚CIO峰会丨实在智能:“数字员工”成企业数字化关键纽带

时尚&#xff0c;是不断演进的艺术。“中国时尚行业转型高峰论坛暨时尚行业CIO夏季峰会”作为时尚界的重要盛事&#xff0c;已经成为业界领袖、品牌大咖与创新者们的汇聚之地。近日&#xff0c;以“数智极智未来&#xff1a;新纪元 新生命”为主题的第八届时尚行业盛会在广东佛…

Linux驱动开发:Linux内核启动流程详解

前言&#xff1a;Linux 内核同样作为 Linux 驱动开发的 “三巨头” 之一&#xff0c;Linux 内核的启动流程要比 uboot 复杂的多&#xff0c;涉及到的内容也更多。但秉持着 “知其然知其所以然” 的学习态度&#xff0c;作者将给读者朋友大致的过一遍 Linux 内核的启动流程。(考…

Jmeter的常用设置(二)

文章目录 前言一、察看结果树响应结果是乱码_解决方法 方法一&#xff1a;在察看结果树之前添加 后置处理器 中的 “BeanShell PostProcessor” 来动态修改结果处理编码方法二&#xff1a;在配置文件中修改二、使用步骤 1.引入库2.读入数据总结 前言 接口测试中遇到的各种问题…

VN积分法卷径计算

卷径计算的其他方法请参看专栏的相关文章,链接如下: 卷径计算(V/N法)_RXXW_Dor的博客-CSDN博客卷径计算(厚度累计法/膜厚叠加法)_RXXW_Dor的博客-CSDN博客卷径计算的截面积法请参看下面的文章链接:卷径计算详解(通过卷绕的膜长和膜厚进行计算)_RXXW_Dor的博客-CSDN博客有关…

高清视频如何转成gif动画?手把手教你在线转换高清gif

说到gif动图相信大家并不陌生&#xff0c;随着gif表情包越来越火爆&#xff0c;大家也不满足于收藏转载别人的表情包了。都开始自己制作gif表情包了&#xff0c;那么&#xff0c;如何将视频转换成高清gif呢&#xff1f;很简单&#xff0c;使用GIF中文网的视频转gif&#xff08;…

Protobuf类型定义

"都甩掉吧&#xff0c;我们的世界一定会更美好&#xff01;其他不重要&#xff01;" 前面呢&#xff0c;我们讲了如何在Linux环境下安装Protobuf所需的库&#xff0c;那么本篇的着眼点在于Protobuf的编写以及语法规则。 什么是proto3? ProtocolBuffers语⾔版本3&am…

CClink IE转Modbus TCP网关连接三菱FX5U PLC

远创智控YC-CCLKIE-TCP 是自主研发的一款 CCLINK IE FIELD BASIC 从站功能的通讯网关。该产品主要功能是将各种 MODBUS-TCP 设备接入到 CCLINK IE FIELD BASIC 网络中。 远创智控YC-CCLKIE-TCP网关连接到 CCLINK IE FIELD BASIC 总线中做为从站使用&#xff0c;连接到 MODBUS-T…

[MMDetection]COCO数据集可视化验证

在使用MMDetection训练之前&#xff0c;需要对图像进行可视化验证&#xff0c;验证数据和标签是否对齐。 # 数据集可视化 import os import matplotlib.pyplot as plt from PIL import Imageoriginal_images [] images [] texts [] plt.figure(figsize(16,12))image_paths …