一文详解gRPC框架

news2024/11/19 13:34:33

目录

RPC框架简介

简介

各种序列化协议优缺点

gRPC调用模式

gRPC跟ProtocolBuffers的关系

ProtocolBuffers协议

gRPC桩代码生成

gRPC线程模型

gRPC分层

gRPC开发经验

官网及快速开始

常见状态码

适用场景

适用

不适用


手写简易RPC框架

Dubbo学习笔记

一文详解Netty架构及优势

HTTP、HTTPS的优劣及其与RPC和WebSocket的对比


RPC框架简介

简介

一个RPC框架的基本构成主要如下图:

常见的RPC框架有以下几种:

1、apache dubbo

提供了六大核心能力:面向接口代理的高性能RPC调用,智能容错和负载均衡,服务自动注册和发现,高度可扩展能力,运行期流量调度,可视化的服务治理与运维

文档 | Apache Dubbo

2、Mtransport

美团致力于将Mtransport定位成一组高性能、高可用的企业级RPC通信框架,现将已在公司广泛使用,成熟稳定的Mtransport进行开源,开源后总名称为OCTO-RPC,其中第一批包括Dorado(Java)、Whale(C++)两个语言版本。支持服务注册、服务发现、异步通信、负载均衡等功能。

美团分布式服务通信框架及服务治理系统OCTO - 程序员大本营

GitHub - Meituan-Dianping/octo-rpc: OCTO-RPC 是支持Java和C++的企业级通信框架,在RPC服务之上扩展了丰富的服务治理功能,为美团各业务线提供高效、统一的通信服务。

3、motan

motan是新浪微博开源的RPC框架,除了常规的点对点调用外,motan还提供服务治理功能,包括服务节点的自动发现、摘除、高可用和负载均衡等。Motan具有良好的扩展性,主要模块都提供了多种不同的实现,例如支持多种注册中心,支持多种rpc协议等

https://www.cnblogs.com/lovebean/p/10622166.html

https://github.com/weibocom/motan

4、thrift

Thrift是一种接口描述语言和二进制通讯协议,它被用来定义和创建跨语言的服务。它被当作一个远程过程调用框架来使用,是由Facebook为“大规模跨语言服务开发”而开发的。提供了全套RPC解决方案,包括序列化机制、传输层、并发处理框架等。

5、gRPC

gRPC是一款高性能开源通用的RPC框架,同时面向服务端跟移动端,基于HTTP/2协议设计。目前提供 C、Java 和 Go 语言版本。

dubbo

Mtransport

motan

thrift

gRPC

开发语言

java

java/c++

java

多语言

多语言

服务治理

支持

支持

支持

不支持

不支持

序列化框架

多框架

thrift

多框架

thfit

protobuf

服务注册发现

支持

支持

支持

不支持

不支持

管理中心

支持

支持

支持

不支持

不支持

各种序列化协议优缺点

Response对象↔二进制

1、JDK自带序列化  outputstream/inputstream

  • 缺点:

    • 无法跨语言

    • 序列化编码后的字节数组太大

    • 序列化耗时严重

2、fastJSON:文本型序列化框架,String和对象的转换,应用广泛。如果 RPC 框架选用 JSON 序列化,服务提供者与服务调用者之间传输的数据量要相对较小,否则将严重影响性能。

3、Hessian:支持跨语言,序列化后字节数适中,API 易用。是国内主流 rpc 框架:dubbo,motan 的默认序列化协议。

4、Google 的Protobuf:提起 Protostuff 不得不说到 Protobuf。Protobuf 可能更出名一些,因为其是 google 的亲儿子,grpc 框架便是使用 protobuf 作为序列化协议,虽然 protobuf 与语言无关平台无关,但需要使用特定的语法编写 .prpto 文件,然后静态编译,这带了一些复杂性。而 protostuff 实际是对 protobuf 的扩展,protostuff-runtime 模块继承了 protobuf 性能,且不需要预编译文件,但与此同时,也失去了跨语言的特性。所以 protostuff 的定位是一个 JAVA 序列化框架,其性能略优于 Hessian。tip :protostuff 反序列化时需用户自己初始化序列化后的对象,其只负责将该对象进行赋值。

5、Message pack

6、JBoss Marshalling(序列化包)

7、Kryo:专为 JAVA 定制的序列化协议,序列化后字节数少,利于网络传输。但不支持跨语言(或支持的代价比较大)。dubbox 扩展中支持了 kryo 序列化协议。

......

gRPC调用模式

gRPC支持定义四种类型的调用:

  • 一元RPC服务(unary RPCs): 客户端向服务端发送一次请求,服务端对请求作出一次响应,如同一次普通的函数调用

rpc SayHello(HelloRequest) returns (HelloResponse);
  • 服务端流式RPC服务:这种模式是客户端发起一次请求,服务端返回一段连续的数据流。典型例子是oneService中读取hive数据的方法定义,源源不断的读取hive表数据。

rpc LotsOfReplies(HelloRequest) returns (stream HelloResponse);
  • 客户端流式RPC服务: 与服务端数据流模式相反,这次是客户端源源不断的向服务端发送数据流,而在发送结束后,由服务端返回一个响应。

rpc LotsOfGreetings(stream HelloRequest) returns (HelloResponse);
  • 双向流式RPC服务: 服务端和客户端使用各自的读写流发送消息序列。两个读写流独立工作,因此客户端和服务端可以以任意顺序进行读写, 例如服务端可以等到客户端发送完所有的消息才开始向流中写响应消息,也可以每读取一条消息就写一条响应消息,或者其他的顺序组合。但是每个流中的消息顺序是有保证的。

rpc BidiHello(stream HelloRequest) returns (stream HelloResponse);

gRPC跟ProtocolBuffers的关系

protobuf全名是ProtocolBuffers,是谷歌推出的二进制序列化协议,提供IDL文件来定义各种类型的数据。目前整体协议版本是proto3,protobuf提供了从proto文件编译生成各个语言文件的功能。与此同时protobuf提供了丰富的插件机制,用户可以扩展生成的对应语言的文件,俗称桩代码生成。

ProtocolBuffers协议

syntax = "proto2";

package tutorial;

option java_multiple_files = true;
option java_package = "com.example.tutorial.protos";
option java_outer_classname = "AddressBookProtos";

message Person {
  optional string name = 1;
  optional int32 id = 2;
  optional string email = 3;

  enum PhoneType {
    MOBILE = 0;
    HOME = 1;
    WORK = 2;
  }

  message PhoneNumber {
    optional string number = 1;
    optional PhoneType type = 2 [default = HOME];
  }

  repeated PhoneNumber phones = 4;
}

message AddressBook {
  repeated Person people = 1;
}
----------------------------------------------------------------------
syntax = "proto3";

package com.kuaishou.infra.grpc.test;

option java_package = "com.kuaishou.demo";
option java_outer_classname = "Demo";
option java_multiple_files = true;

message TestRequest {
    string value = 1;
}

message TestResponse {
    string value = 1;
}

service TestService {
    rpc Test (TestRequest) returns (TestResponse);
    rpc TestDeadline (TestRequest) returns (TestResponse);
    rpc TestCost (TestRequest) returns (TestResponse);
    rpc TestEmpty (TestRequest) returns (TestResponse);
}

service TestStreamService {
    rpc Test (TestRequest) returns (stream TestResponse);
    rpc TestFailed (TestRequest) returns (stream TestResponse);
    rpc TestSlow (TestRequest) returns (stream TestResponse);
    rpc TestUpStream(stream TestRequest) returns (TestResponse);
    rpc TestUpStreamSlow(stream TestRequest) returns (TestResponse);
    rpc TestDuplex(stream TestRequest) returns (stream TestResponse);
    rpc TestOutboundFlowControl (TestRequest) returns (stream TestResponse);
}
  • proto文件路径:

    • proto文件本身所在路径:假设是kuaishou/demo;使用场景是当其他proto文件需要引入当前proto文件时依赖这个路径,形如 import "kuaishou/demo/demo.proto"。这样就可以使用文件内部定义的message了

    • proto文件内部package指定路径:com.kuaishou.infra.grpc.test;这个路径非常的核心,任何迁移或者修改proto文件的操作都不应该修改这个package路径,因为它决定了文件内部service的full path name。一旦发生变化就会造成在实际gRPC调用时找不到服务方法而抛异常(Unimplemented)

    • option参数指定java输出路径:com.kuaishou.demo;这个路径也比较核心,定义好之后也不要轻易修改,因为它决定了proto中message类的生成路径,如果修改会造成源码不兼容编译阻塞

  • proto文件输出样式

    • proto文件的名称,例如infra_demo.proto;在没指定2的前提下,会默认按照驼峰生成OuterClass,对于本例为InfraDemo.java;有意思的是当proto文件中的message跟默认生成java类名重名的时候,会在生成类名后面加上OuterClass,对于本例为InfraDemoOuterClass

    • option java_outer_classname = "Demo"如果指定此选项,则输出文件名称为指定名称Demo

    • option java_multiple_files = true:指定此选项proto文件中的message会生成独立的java文件,此选项定义好后也不要轻易修改,否则也会造成编译阻塞,推荐开启这个选项

gRPC桩代码生成

gRPC通过Protocol Buffers提供的Plugin机制来实现原生桩代码生成,Protobuf的插件化桩代码生成机制主体思想如下:

  • FileDescriptor 作为Plugin的输入参数,代表一个proto文件的描述

  • ServiceDescriptor代表一个service的描述符

  • MethodDescriptor代表一个service中方法的描述符,包括上面描述的四种MethodType

  • Printer作为输出写文件到对应路径

过程可以拆解为如下几个部分:

  • ServiceDescriptor、MethodDescriptor单例变量,出于性能考虑

  • ClientStub,主要包括三种:

  • XXXBlockingStub:官方已经弃用

  • XXXFutureStub:返回ListeningFuture,也是我们使用最多的方式

  • XXXStub:异步方式,业务通过StreamObserver回调来感知数据流转

  • XXXImplBase:服务实现基类

gRPC桩代码生成的扩展方式有两种:

  • 在原生桩代码生成之上做修改,需要修改c++文件重新编译构建

  • 直接利用Protocol Buffers提供的扩展机制自己生成全新的文件

gRPC线程模型

grpc基于http2.0传输协议进行数据传输,使用NIO线程模型实现服务远程调用:

  • client侧线程模型

    • Caller线程:业务当前线程

    • Worker线程(grpc-default-executor):请求处理与响应回调线程

    • IO线程(grpc-nio-worker-ELG):使用Netty的EventLoopGroup(ELG)

  • server侧线程模型

    • Worker线程(grpc-default-executor):Server启动时候指定

    • IO线程(grpc-nio-worker-ELG):使用Netty的ELG

gRPC分层

 

在gRPC中,客户端应用可以通过桩代码直接调用运行在另一台机器上的服务端应用的方法,就像客户端调用自己的本地方法一样。这一特性使得我们可以轻易构建分布式的应用和服务。

 

grpc中使用protobuf定义桩代码,通过protoc-gen-grpc-java插件生成java代码,同时protobuf支持自定义代码生成器。

  • JAVA业界主流实现方式

    • salesforce简介:https://en.wikipedia.org/wiki/Salesforce.com

    • salesforce提供工具包支持以JAVA方式来扩展protoc:GitHub - salesforce/grpc-java-contrib: Useful extensions for the grpc-java library

    • 参考实践:Watchers · salesforce/reactive-grpc · GitHub

    • https://itnext.io/customizing-grpc-generated-code-5909a2551ca1

gRPC开发经验

官网及快速开始

gRPC

Quick start | Java | gRPC

常见状态码

grpc/doc/statuscodes.md at master · grpc/grpc · GitHub

  • OK:代表请求成功执行

  • CANCELLED:请求被取消,通常是超时 or Deadline Exceed导致

  • UNKNOWN:通常是Server抛异常导致,一般Server业务执行抛异常非StatusException or RuntimeStatusException,所以gRPC内部会用UNKNOWN状态码进行处理

  • DEADLINE_EXCEEDED:客户端请求配置了withDeadlineAfter CallOption,双端都生效,服务端超时会取消请求,Client侧表现为收到这个状态码的RuntimeStatusException,也是我们最常见的异常

  • PERMISSION_DENIED:顾名思义,代表没有访问权限,可以对应HTTP的403,常见如IP白名单

  • UNAUTHENTICATED:gRPC特意用这个状态码代表没有授权的访问,通常是开启tls的服务

  • RESOURCE_EXAUSTED:代表服务端资源不足,如带宽,磁盘,连接数等等;业务也可以使用它来描述业务资源不足的情况

  • UNIMPLEMENTED:gRPC内部异常,请求的FullPath方法未实现,如果没有FallbackRegistry会抛这个状态码异常,通常可能是proto文件有不兼容改动

  • UNAVAILABLE:代表当前服务不可用,一般是暂时性问题,代表客户端可以通过重试来解决的情况

  • INTERNAL:gRPC内部严重错误,通常是有严重bug才会出现,业务不应该使用此状态码

适用场景

适用

  1. 对于给其他Team提供接口时,应该优先使用gRPC服务

  2. 对于消耗特定资源的(例如GPU/CPU/大内存资源),有特殊依赖的(比如运行环境需要依赖外部的ffmpeg等binary等),集中实现效率比较高的(比如某个业务集中到几台机器,可以使用大内存缓存等)

  3. 一些经常变化的业务逻辑,依赖很广泛,又需要实现可以收敛且能随时更新

  4. 其他需要做〔服务化〕的业务

不适用

  1. 不关心返回值的one-way调用或者异步请求,应该优先使用kafka

  2. 一些极高QPS,逻辑稳定,没有远程访问的本地实现

  3. 使用方为公司外部的服务(这类大概率需要暴露成http服务)

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

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

相关文章

【python】数据表转csv

文章目录 1 基本结构1.1 数据1.2 数据结构 2 代码3 tip 1 基本结构 1.1 数据 1.2 数据结构 2 代码 代码: import mysql.connector import csvdef getPerson():# 数据库初始化cnx mysql.connector.connect(userroot, passwordroot, databasetest)cursor cnx.cur…

IDEA启动tomcat控制台中文乱码问题

IntelliJ IDEA是很多程序员必备且在业界被公认为最好的Java开发工具,有很多小伙伴在安装完IDEA并且tomcat之后,启动tomcat会出现控制台中文乱码问题,如下图所示: 具体解决步骤: 一、修改当前 Web 项目 Tomcat Server…

SAP ALV批量修改列的数据

导语:最近在给ALV增加批量修改列的功能,需求是修改多列,以前经常自己画屏幕来实现,研究了一下,SAP有标准的函数,可以自动带出选择列的字段属性,搜索帮助等等,大大提高了便捷性。 函…

本地同步远程yum源,并保存到本地

1.修改本地/etc/yum.repos.d/内容为远程yum repo配置; # 1).备份原yum配置 mkdir -p /home/yum-bak && mv /etc/yum.repos.d/* /home/yum-bak/* # 2).修改目标yum配置 2.执行缓存,查看相关repoid是否正确 yum clean all …

QT学习笔记2--对象树

对象树 可以看到QWidet这几个类的父亲是QObject,在析构的时候是从下往上析构。 实例 创建类 验证的话,要先创建一个类,命名为pushbotton。 点击choose创建,类。 编写相关函数 构造函数 pushbotton::pushbotton(QWidget *pare…

华为云专家出品《深入理解边缘计算》电子书上线

华为开发者大会PaaS生态电子书推荐,助你成为了不起的开发者! 什么是边缘计算?边缘计算的应用场景有哪些? 华为云出品《深入理解边缘计算》电子书上线 带你系统理解云、边、端协同的相关原理 了解开源项目的源码分析流程 学成能…

【Python】字符串格式化前世今生

▒ 目录 ▒ 🛫 问题描述环境 1️⃣ 《%》方式格式化语法%后面的参数说明 2️⃣ str.format优点指定位置:参数可以不按顺序关键字参数列表索引对象数字格式化 3️⃣ f-string 语法语法示例格式化一个表达式转义符号格式化 datetime 对象 🛬 结…

C#传Bitmap到C++dll出现灰色图片的问题

如果直接将内存中的Bitmap 传给C,原图会失去颜色,如下: 代码如下: ImageCodecInfo jpgEncoder GetEncoder(ImageFormat.Jpeg);System.Drawing.Imaging.Encoder myEncoder System.Drawing.Imaging.Encoder.Quality;EncoderParameters myEncod…

给若依添加单元测试(二)

给若依添加单元测试 方案一(简单) 方案二(异常困难但企业开发一般用这个) 在 activity 子模块中添加单元测试 S1.在 src 目录下创建 test.java.MapperTests 文件 S2.将以下内容复制进去 import com.ruoyi.activity.Activity…

C#私有构造函数学习

私有构造函数是一种特殊的实例构造函数。 它通常用在只包含静态成员的类中。 如果类具有一个或多个私有构造函数而没有公共构造函数,则其他类(除嵌套类外)无法创建该类的实例。 如果类T只声明了私有实例构造函数,则在T的程序文本外…

java项目之留学生交流互动论坛网站ssm源码

风定落花生,歌声逐流水,大家好我是风歌,混迹在java圈的辛苦码农。今天要和大家聊的是一款基于springboot的留学生交流互动论坛网站。项目源码以及部署相关请联系风歌,文末附上联系信息 。 💕💕作者&#xf…

python编码中常见问题及解决方案

文章目录 1. 输入minVal和maxVal,将 minVal - maxVal 分成 N 等份,列表返回2. request 请求MP4视频URL时,如何获取视频大小3. 输出00,01,02或001,002,003等格式字符串 1. 输入minVal和maxVal&am…

UE5 Stride Warping Orientation Warping功能学习

在UE5的 Lyra Demo中,运用到了各类动画Warping(动画扭曲)技术,通过各类Warping节点在动画蓝图中的合理组织,可以有效的解决运动滑步问题,并为动画增添更多细节。 本文主要基于Animation Warping插件讲一下…

vue echarts k线图 标记点根据条件设置颜色

1. 数据格式{属性1, 属性2, 属性3, 属性4{属性4.1, 属性4.2, 属性4.3}} {symbol: circle, symbolSize: 0,xAxis: 2023-01-01 08:36:00, yAxis: 0.06968924, label: {fontStyle: normal, fontSize: 13, color: blue} } 2. 自定义局部function 拼装数据 // data 是 自定义标记点…

element-ui el-tree功能应用

1.目录节点搜索功能&#xff1a; <el-tree>:filter-node-method"filterNode"</el-tree>//添加监听watch: {search(val) {this.$refs.tree.filter(val)}},// 树搜索filterNode(value, data) {if (!value) return truereturn data.name.indexOf(value) ! -…

安装MySQL实现远程访问链接---无需本地访问

文章目录 1. 安装Mysql2. 安装phpMyAdmin3. 修改User 表4. 本地测试连接5. 安装cpolar6. 配置公网访问地址7. 固定连接公网地址 转载自cpolar极点云文章&#xff1a;群晖NAS 安装 MySQL远程访问连接 群晖安装MySQL具有高效、安全、可靠、灵活等优势&#xff0c;可以为用户提供一…

mysql索引之B+树

1.概述 提到B树就不得不提及二叉树&#xff0c;平衡二叉树和B树这三种数据结构了。B树就是从他们三个演化来的。众所周知B树是一种常见的数据结构&#xff0c;被广泛应用于数据库和文件系统等领域&#xff0c;B树的设计目标是保持树的平衡性&#xff0c;以提供稳定的性能&…

磐石呼叫中心系统经常被UDP攻击的解方法

语音系统经常被UDP攻击&#xff0c;UDP攻击是一种常见的网络攻击形式&#xff0c;经常针对语音、视频和在线游戏等实时传输数据的应用程序。攻击者使用大量的UDP数据包向目标服务器发送请求&#xff0c;导致服务器过载&#xff0c;使其无法处理有效的请求&#xff0c;从而导致服…

01-基本数据类型和注释

基本数据类型 使用编程语言进行编程时&#xff0c;需要用到各种变量来存储各种信息。变量保留的是它所存储的值的内存位置。这意味着&#xff0c;当您创建一个变量时&#xff0c;就会在内存中保留使用一些空间。 您可能需要存储各种数据类型&#xff08;比如字符型、整型、浮…

C++数据结构笔记(3)线性表的链式存储底层实现

本系列的帖子并不包含全部的基础知识&#xff0c;只挑一部分最核心的知识点总结&#xff0c;着重于具体的实现细节而并非理论的知识点总结&#xff0c;大家按需阅读学习。 链表的核心概念总结如下&#xff1a; 1.链式存储不需要连续的内存空间 2.链表由一系列的结点组成&…