gRPC 的原理 介绍带你从头了解gRPC

gRPC 的原理

什么是gRPC

gRPC的官方介绍是:gRPC是一个现代的、高性能、开源的和语言无关的通用 RPC 框架,基于 HTTP2 协议设计,序列化使用PB(Protocol Buffer),PB 是一种语言无关的高性能序列化框架,基于 HTTP2+PB 保证了的高性能。

好吧我知道对于一个初学者来说这并没有意义,首先我们需要提炼关键,来回答以下几个问题,从而真正明白gRPC到底是什么?

  1. gRPC 和 RPC 的区别
  2. HTTP2 协议是什么?基于他的设计是什么意思?
  3. 序列化PB(Protocol Buffer) 是什么?

gRPC 和RPC 的区别

RPC(Remote Procedure Call)是一种通过网络从远程计算机程序上请求服务,而不需要了解底层网络技术的协议。

gRPC是Google开发的一个RPC系统,它使用HTTP/2协议进行通信,并使用Protocol Buffers作为接口描述语言。

这使得gRPC比传统的RPC更加强大,可以支持流式请求和响应,以及其他复杂的交互模式。

总结:RPC 是一个框架,已经写好一些功能,但是并不适合谷歌的应用场景,在这个基础上 谷歌 对RPC 框架进行了迭代开发,形成了gRPC。

HTTP2 协议是什么?基于他的设计是什么意思?

HTTP/2是HTTP协议的第二个主要版本,它在性能优化、服务器推送、头信息压缩、协议复用等方面都有显著的改进。

基于HTTP/2的设计意味着gRPC在设计时充分利用了HTTP/2的这些特性,

例如,它可以在一个TCP连接上并行发送多个请求和响应,减少了网络延迟。

总结:http2 是一个通讯规定,基于http2 的协议设计是指在使用这个通讯规定上进行的程序软件设计。

gRPC 即是基于RPC协议又基于HTTP2协议,这两种协议怎么融合的?

在明确上述两种协议的具体内容之后,我们就可以回答这个问题了。在gRPC中RPC是它的业务逻辑基本框架,HTTP2 是它的通讯逻辑基本原理

从而我们可以理解这张图:
![[Pasted image 20231114145840.png]]

二进制序列化PB(Protocol Buffer) 是什么?

Protocol Buffers(简称PB)是Google开发的一种数据序列化协议(类似于XML、JSON、hessian)。

它能够将数据结构以高效和可扩展的格式进行序列化,可以用于网络通信和数据存储等场景。

上面的解释很绕,让我们先明确什么是序列化:简单点说:就是把信息按照固定格式组织起来,为的是解决不同系统、不同编程语言、不同平台之间的传输存储问题。

序列化是指将对象转换为可以在网络传输或存储中使用的格式,以便在需要时可以重新构造出原始对象。在序列化过程中,对象的状态被转换为字节流或其他可传输的形式,以便可以在不同的系统、编程语言或平台之间进行传输或存储。

序列化的主要目的是实现对象的持久化、跨网络传输和跨平台通信。通过序列化,可以将对象转换为字节流,然后可以将字节流保存到文件中、通过网络发送给其他系统,或者在不同的程序之间进行交互。在接收方,可以通过反序列化将字节流转换回原始对象,以便进行进一步的处理或使用。

常见的序列化格式包括JSON、XML和Protocol Buffers(Protobuf)等。不同的序列化格式具有不同的特点和适用场景,选择合适的序列化格式取决于具体的需求和使用环境。

怎么用呢?这里我们以PB为例:
Protocol Buffers(简称Protobuf)使用特定的语法和编译器来定义消息的结构和字段,然后通过编译器生成相应的代码,用于序列化和反序列化对象。

下面是使用C++代码的示例,展示了如何使用Protobuf进行对象的序列化和反序列化:

  1. 定义消息结构
    首先,需要使用Protobuf的语法定义消息的结构和字段。例如,创建一个名为Person的消息类型,包含nameage字段:

    syntax = "proto3";message Person {string name = 1;int32 age = 2;
    }
    
  2. 生成代码
    使用Protobuf的编译器将上述定义的消息结构编译为相应的代码。在C++中,可以使用protoc命令行工具进行编译:

    protoc --cpp_out=. person.proto
    

    这将生成person.pb.hperson.pb.cc两个文件,包含了用于序列化和反序列化Person消息的代码。

  3. 序列化对象
    在C++代码中,可以使用生成的代码来创建Person对象,并将其序列化为字节流:

    #include "person.pb.h"// 创建Person对象
    Person person;
    person.set_name("John");
    person.set_age(25);// 序列化为字节流
    std::string serialized_data;
    person.SerializeToString(&serialized_data);
    

    SerializeToString方法将Person对象序列化为一个字符串。

  4. 反序列化对象
    反之,可以将序列化的字节流反序列化为原始的Person对象:

    // 反序列化为Person对象
    Person deserialized_person;
    deserialized_person.ParseFromString(serialized_data);// 访问反序列化后的字段
    std::string name = deserialized_person.name();
    int age = deserialized_person.age();
    

    ParseFromString方法将字节流解析为Person对象,并可以通过访问相应的字段获取数据。

需要注意的是,上述示例中的代码是使用C++语言进行的,如果使用其他编程语言,操作步骤会有所不同,但基本原理是相似的。

gRPC的工作方式

在通过上述 的详细介绍之后,我们就可以介绍gRPC 的工作方式来说明什么是gRPC 了。
![[Pasted image 20231114151128.png]]
上图中使用的是c++和红宝石以及安卓开发三种语言、平台、系统都不同的实例间通讯,展示的是gRPC 的 通用性

![[Pasted image 20231114151324.png]]
上图是解释了信息在gRPC 中是怎样流转的。展示的是gRPC 的 序列化

为什么使用gRPC

gRPC 的原理

  1. 自由,开放:让所有人,所有平台都能使用,其实就是开源,跨平台,跨语言
  2. 协议可插拔:不同的服务可能需要使用不同的消息通信类型和编码机制,例如,JSON、XML和Thirft,所以协议应允许可插拔机制,还有负载均衡,服务发现,日志,监控等都支持可插拔机制
  3. 阻塞和非阻塞:支持客户端和服务器交换的消息序列的异步和同步处理。这对于在某些平台上扩展和处理至关重要
  4. 取消和超时:一次RPC操作可能是持久并且昂贵的,应该允许客户端设置取消RPC通信和对这次通信加上一个超时时间
  5. 拒绝:必须允许服务器通过在继续处理请求的同时拒绝新请求的到来并优雅地关闭。
  6. 流处理:存储系统依靠流和流控制来表达大型数据集,其他服务,如语音到文本或股票行情,依赖于流来表示与时间相关的消息序列
  7. 流控制:计算能力和网络容量在客户端和服务器之间通常是不平衡的。流控制允许更好的缓冲区管理,以及过度活跃的对等体提供对DOS的保护。
  8. 元数据交换:认证或跟踪等常见的跨领域问题依赖于不属于服务声明接口的数据交换。依赖于他们将这些特性演进到服务,暴露API来提供能力。
  9. 标准化状态码:客户端通常以有限的方式响应API调用返回的错误。应约束状态码名称空间,以使这些错误处理决策更加清晰。如果需要更丰富的特定领域的状态,则可以使用元数据交换机制来提供该状态。
  10. 互通性:报文协议(Wire Protocol)必须遵循普通互联网基础框架

gRPC 的一些特性

  1. gRPC基于服务的思想:定义一个服务,描述这个服务的方法以及入参出参,服务器端有这个服务的具体实现,客户端保有一个存根,提供与服务端相同的服务。

  2. gRPC默认采用protocol buffer作为IDL(Interface Description Lanage)接口描述语言,服务之间通信的数据序列化和反序列化也是基于protocol buffer的,因为protocol buffer的特殊性,所以gRPC框架是跨语言的通信框架(与编程语言无关性),也就是说用Java开发的基于gRPC的服务,可以用GoLang编程语言调用

  3. gRPC同时支持同步调用和异步调用,同步RPC调用时会一直阻塞直到服务端处理完成返回结果,异步RPC是客户端调用服务端时不等待服务段处理完成返回,而是服务端处理完成后主动回调客户端告诉客户端处理完成

  4. gRPC是基于http2协议实现的,http2协议提供了很多新的特性,并且在性能上也比http1提搞了许多,所以gRPC的性能是非常好的

  5. gRPC并没有直接实现负载均衡和服务发现的功能,但是已经提供了自己的设计思路。已经为命名解析和负载均衡提供了接口

  6. 基于http2协议的特性:gRPC允许定义如下四类服务方法

    1. 一元RPC:客户端发送一次请求,等待服务端响应结构,会话结束,就像一次普通的函数调用这样简单
    2. 服务端流式RPC:客户端发起一起请求,服务端会返回一个流,客户端会从流中读取一系列消息,直到没有结果为止
    3. 客户端流式RPC:客户端提供一个数据流并写入消息发给服务端,一旦客户端发送完毕,就等待服务器读取这些消息并返回应答
    4. 双向流式RPC:客户端和服务端都一个数据流,都可以通过各自的流进行读写数据,这两个流是相互独立的,客户端和服务端都可以按其希望的任意顺序独写

gRPC的使用场景

  • 低延迟,高度可扩展的分布式系统

  • 开发与云服务器通信的客户端

  • 设计一个准确,高效,且与语言无关的新协议时

  • 分层设计,以实现扩展,例如。身份验证,负载平衡,日志记录和监控等

  • 谷歌长期以来一直在gRPC中使用很多基础技术和概念。目前正在谷歌的几个云产品和谷歌面向外部的API中使用。Square,Netflix,CoreOS,Docker,CockroachDB,Cisco,Juniper Networks以及许多其他组织和个人也在使用它。

gRPC的数据封装和数据传输问题

这里我们主要介绍pb的工作方式,即怎样封装数据;

数据封装

gRPC 使用的是自己的封装方式 Protocol Buffer简称ProtoBuf,是Google开发的一种跨语言、跨平台、可扩展的用于序列化数据协议。

下面是一个protoBuf 的样例

// XXXX.proto
// rpc服务的类 service关键字, Test服务类名
service Test {
// rpc 关键字,rpc的接口
rpc HowRpcDefine (Request) returns (Response) ; // 定义一个RPC方法
}
// message 类,c++ class
message Request {
//类型 | 字段名字| 标号
int64 user_id = 1;
string name = 2;
}
message Response {
repeated int64 ids = 1; // repeated 表示数组
Value info = 2; // 可嵌套对象
map<int, Value> values = 3; // 可输出map映射
}
message Value {
bool is_man = 1;
int age = 2;
}

以上是一个使用样例,包含方法定义、入参、出参。可以看出有几个明确的特点:

  • 有明确的类型,支持的类型有多种
  • 每个field会有名字
  • 每个field有一个数字标号,一般按顺序排列(下文编解码会用到这个点)
  • 能表达数组、map映射等类型
  • 通过嵌套message可以表达复杂的对象
  • 方法、参数的定义落到一个.proto 文件中,依赖双方需要同时持有这个文件,并依此进行编解码
    protobuf作为一个以跨语言为目标的序列化方案,protobuf能做到多种语言以同一份proto文件作为约定,不用A语言写一份,B语言写一份,各个依赖的服务将proto文件原样拷贝一份即可。

但.proto文件并不是代码,不能执行,要想直接跨语言是不行的,必须得有对应语言的中间代码才行,中间代码要有以下能力:

  • 将message转成对象,例如C++里是class,golang里是struct,需要各自表达后,才能被理解
  • 需要有进行编解码的代码,能解码内容为自己语言的对象、能将对象编码为对应的数据

在完成数据封装之后,我们就准备好了将它传输出去,接下来就是数据传输了。

数据传输

grpc采用HTTP2.0,相对于HTTP1.0 在 更快的传输 和 更低的成本 两个目标上做了改进。有以下几个基本点:

  • HTTP2 未改变HTTP的语义(如GET/POST等),只是在传输上做了优化
  • 引入帧、流的概念,在TCP连接中,可以区分出多个request/response
  • 一个域名只会有一个TCP连接,借助帧、流可以实现多路复用,降低资源消耗
  • 引入二进制编码,降低header带来的空间占用
    HTTP1.1核心问题在于:在同一个TCP连接中,没办法区分response是属于哪个请求,一旦多个请求返回的文本内容混在一起,则没法区分数据归属于哪个请求,所以请求只能一个个串行排队发送。这直接
    导致了TCP资源的闲置。
    HTTP2为了解决这个问题,提出了 流 的概念,每一次请求对应一个流,有一个唯一ID,用来区分不同的请求。基于流的概念,进一步提出了 帧 ,一个请求的数据会被分成多个帧,方便进行数据分割传输,每个帧都唯一属于某一个流ID,将帧按照流ID进行分组,即可分离出不同的请求。这样同一个TCP连接中就可以同时并发多个请求,不同请求的帧数据可穿插在一起,根据流ID分组即可。HTTP2.0基于这种二进制协议的乱序模式 (Duplexing),直接解决了HTTP1.1的核心痛点,通过这种复用TCP连接的方式,不用再同时建多个连接,提升了TCP的利用效率。

总结
传输使用 http2 协议,是在tcp链接完成之后,再在应用层发送时的一个协议,通过流 ID 和 帧报文的两个概念 解决了传输拥塞的问题。我们将这种方式称之为 tcp链接复用

gRPC 的原理

什么是gRPC

gRPC的官方介绍是:gRPC是一个现代的、高性能、开源的和语言无关的通用 RPC 框架,基于 HTTP2 协议设计,序列化使用PB(Protocol Buffer),PB 是一种语言无关的高性能序列化框架,基于 HTTP2+PB 保证了的高性能。

好吧我知道对于一个初学者来说这并没有意义,首先我们需要提炼关键,来回答以下几个问题,从而真正明白gRPC到底是什么?

  1. gRPC 和 RPC 的区别
  2. HTTP2 协议是什么?基于他的设计是什么意思?
  3. 序列化PB(Protocol Buffer) 是什么?

gRPC 和RPC 的区别

RPC(Remote Procedure Call)是一种通过网络从远程计算机程序上请求服务,而不需要了解底层网络技术的协议。

gRPC是Google开发的一个RPC系统,它使用HTTP/2协议进行通信,并使用Protocol Buffers作为接口描述语言。

这使得gRPC比传统的RPC更加强大,可以支持流式请求和响应,以及其他复杂的交互模式。

总结:RPC 是一个框架,已经写好一些功能,但是并不适合谷歌的应用场景,在这个基础上 谷歌 对RPC 框架进行了迭代开发,形成了gRPC。

HTTP2 协议是什么?基于他的设计是什么意思?

HTTP/2是HTTP协议的第二个主要版本,它在性能优化、服务器推送、头信息压缩、协议复用等方面都有显著的改进。

基于HTTP/2的设计意味着gRPC在设计时充分利用了HTTP/2的这些特性,

例如,它可以在一个TCP连接上并行发送多个请求和响应,减少了网络延迟。

总结:http2 是一个通讯规定,基于http2 的协议设计是指在使用这个通讯规定上进行的程序软件设计。

gRPC 即是基于RPC协议又基于HTTP2协议,这两种协议怎么融合的?

在明确上述两种协议的具体内容之后,我们就可以回答这个问题了。在gRPC中RPC是它的业务逻辑基本框架,HTTP2 是它的通讯逻辑基本原理

从而我们可以理解这张图:
![[Pasted image 20231114145840.png]]

二进制序列化PB(Protocol Buffer) 是什么?

Protocol Buffers(简称PB)是Google开发的一种数据序列化协议(类似于XML、JSON、hessian)。

它能够将数据结构以高效和可扩展的格式进行序列化,可以用于网络通信和数据存储等场景。

上面的解释很绕,让我们先明确什么是序列化:简单点说:就是把信息按照固定格式组织起来,为的是解决不同系统、不同编程语言、不同平台之间的传输存储问题。

序列化是指将对象转换为可以在网络传输或存储中使用的格式,以便在需要时可以重新构造出原始对象。在序列化过程中,对象的状态被转换为字节流或其他可传输的形式,以便可以在不同的系统、编程语言或平台之间进行传输或存储。

序列化的主要目的是实现对象的持久化、跨网络传输和跨平台通信。通过序列化,可以将对象转换为字节流,然后可以将字节流保存到文件中、通过网络发送给其他系统,或者在不同的程序之间进行交互。在接收方,可以通过反序列化将字节流转换回原始对象,以便进行进一步的处理或使用。

常见的序列化格式包括JSON、XML和Protocol Buffers(Protobuf)等。不同的序列化格式具有不同的特点和适用场景,选择合适的序列化格式取决于具体的需求和使用环境。

怎么用呢?这里我们以PB为例:
Protocol Buffers(简称Protobuf)使用特定的语法和编译器来定义消息的结构和字段,然后通过编译器生成相应的代码,用于序列化和反序列化对象。

下面是使用C++代码的示例,展示了如何使用Protobuf进行对象的序列化和反序列化:

  1. 定义消息结构
    首先,需要使用Protobuf的语法定义消息的结构和字段。例如,创建一个名为Person的消息类型,包含nameage字段:

    syntax = "proto3";message Person {string name = 1;int32 age = 2;
    }
    
  2. 生成代码
    使用Protobuf的编译器将上述定义的消息结构编译为相应的代码。在C++中,可以使用protoc命令行工具进行编译:

    protoc --cpp_out=. person.proto
    

    这将生成person.pb.hperson.pb.cc两个文件,包含了用于序列化和反序列化Person消息的代码。

  3. 序列化对象
    在C++代码中,可以使用生成的代码来创建Person对象,并将其序列化为字节流:

    #include "person.pb.h"// 创建Person对象
    Person person;
    person.set_name("John");
    person.set_age(25);// 序列化为字节流
    std::string serialized_data;
    person.SerializeToString(&serialized_data);
    

    SerializeToString方法将Person对象序列化为一个字符串。

  4. 反序列化对象
    反之,可以将序列化的字节流反序列化为原始的Person对象:

    // 反序列化为Person对象
    Person deserialized_person;
    deserialized_person.ParseFromString(serialized_data);// 访问反序列化后的字段
    std::string name = deserialized_person.name();
    int age = deserialized_person.age();
    

    ParseFromString方法将字节流解析为Person对象,并可以通过访问相应的字段获取数据。

需要注意的是,上述示例中的代码是使用C++语言进行的,如果使用其他编程语言,操作步骤会有所不同,但基本原理是相似的。

gRPC的工作方式

在通过上述 的详细介绍之后,我们就可以介绍gRPC 的工作方式来说明什么是gRPC 了。
)
在这里插入图片描述

包浆老图

上图中使用的是c++和红宝石以及安卓开发三种语言、平台、系统都不同的实例间通讯,展示的是gRPC 的 通用性

![[Pasted image 20231114151324.png]]

上图是解释了信息在gRPC 中是怎样流转的。展示的是gRPC 的 序列化

为什么使用gRPC

gRPC 的原理

  1. 自由,开放:让所有人,所有平台都能使用,其实就是开源,跨平台,跨语言
  2. 协议可插拔:不同的服务可能需要使用不同的消息通信类型和编码机制,例如,JSON、XML和Thirft,所以协议应允许可插拔机制,还有负载均衡,服务发现,日志,监控等都支持可插拔机制
  3. 阻塞和非阻塞:支持客户端和服务器交换的消息序列的异步和同步处理。这对于在某些平台上扩展和处理至关重要
  4. 取消和超时:一次RPC操作可能是持久并且昂贵的,应该允许客户端设置取消RPC通信和对这次通信加上一个超时时间
  5. 拒绝:必须允许服务器通过在继续处理请求的同时拒绝新请求的到来并优雅地关闭。
  6. 流处理:存储系统依靠流和流控制来表达大型数据集,其他服务,如语音到文本或股票行情,依赖于流来表示与时间相关的消息序列
  7. 流控制:计算能力和网络容量在客户端和服务器之间通常是不平衡的。流控制允许更好的缓冲区管理,以及过度活跃的对等体提供对DOS的保护。
  8. 元数据交换:认证或跟踪等常见的跨领域问题依赖于不属于服务声明接口的数据交换。依赖于他们将这些特性演进到服务,暴露API来提供能力。
  9. 标准化状态码:客户端通常以有限的方式响应API调用返回的错误。应约束状态码名称空间,以使这些错误处理决策更加清晰。如果需要更丰富的特定领域的状态,则可以使用元数据交换机制来提供该状态。
  10. 互通性:报文协议(Wire Protocol)必须遵循普通互联网基础框架

gRPC 的一些特性

  1. gRPC基于服务的思想:定义一个服务,描述这个服务的方法以及入参出参,服务器端有这个服务的具体实现,客户端保有一个存根,提供与服务端相同的服务。

  2. gRPC默认采用protocol buffer作为IDL(Interface Description Lanage)接口描述语言,服务之间通信的数据序列化和反序列化也是基于protocol buffer的,因为protocol buffer的特殊性,所以gRPC框架是跨语言的通信框架(与编程语言无关性),也就是说用Java开发的基于gRPC的服务,可以用GoLang编程语言调用

  3. gRPC同时支持同步调用和异步调用,同步RPC调用时会一直阻塞直到服务端处理完成返回结果,异步RPC是客户端调用服务端时不等待服务段处理完成返回,而是服务端处理完成后主动回调客户端告诉客户端处理完成

  4. gRPC是基于http2协议实现的,http2协议提供了很多新的特性,并且在性能上也比http1提搞了许多,所以gRPC的性能是非常好的

  5. gRPC并没有直接实现负载均衡和服务发现的功能,但是已经提供了自己的设计思路。已经为命名解析和负载均衡提供了接口

  6. 基于http2协议的特性:gRPC允许定义如下四类服务方法

    1. 一元RPC:客户端发送一次请求,等待服务端响应结构,会话结束,就像一次普通的函数调用这样简单
    2. 服务端流式RPC:客户端发起一起请求,服务端会返回一个流,客户端会从流中读取一系列消息,直到没有结果为止
    3. 客户端流式RPC:客户端提供一个数据流并写入消息发给服务端,一旦客户端发送完毕,就等待服务器读取这些消息并返回应答
    4. 双向流式RPC:客户端和服务端都一个数据流,都可以通过各自的流进行读写数据,这两个流是相互独立的,客户端和服务端都可以按其希望的任意顺序独写

gRPC的使用场景

  • 低延迟,高度可扩展的分布式系统

  • 开发与云服务器通信的客户端

  • 设计一个准确,高效,且与语言无关的新协议时

  • 分层设计,以实现扩展,例如。身份验证,负载平衡,日志记录和监控等

  • 谷歌长期以来一直在gRPC中使用很多基础技术和概念。目前正在谷歌的几个云产品和谷歌面向外部的API中使用。Square,Netflix,CoreOS,Docker,CockroachDB,Cisco,Juniper Networks以及许多其他组织和个人也在使用它。

gRPC的数据封装和数据传输问题

这里我们主要介绍pb的工作方式,即怎样封装数据;

数据封装

gRPC 使用的是自己的封装方式 Protocol Buffer简称ProtoBuf,是Google开发的一种跨语言、跨平台、可扩展的用于序列化数据协议。

下面是一个protoBuf 的样例

// XXXX.proto
// rpc服务的类 service关键字, Test服务类名
service Test {
// rpc 关键字,rpc的接口
rpc HowRpcDefine (Request) returns (Response) ; // 定义一个RPC方法
}
// message 类,c++ class
message Request {
//类型 | 字段名字| 标号
int64 user_id = 1;
string name = 2;
}
message Response {
repeated int64 ids = 1; // repeated 表示数组
Value info = 2; // 可嵌套对象
map<int, Value> values = 3; // 可输出map映射
}
message Value {
bool is_man = 1;
int age = 2;
}

以上是一个使用样例,包含方法定义、入参、出参。可以看出有几个明确的特点:

  • 有明确的类型,支持的类型有多种
  • 每个field会有名字
  • 每个field有一个数字标号,一般按顺序排列(下文编解码会用到这个点)
  • 能表达数组、map映射等类型
  • 通过嵌套message可以表达复杂的对象
  • 方法、参数的定义落到一个.proto 文件中,依赖双方需要同时持有这个文件,并依此进行编解码
    protobuf作为一个以跨语言为目标的序列化方案,protobuf能做到多种语言以同一份proto文件作为约定,不用A语言写一份,B语言写一份,各个依赖的服务将proto文件原样拷贝一份即可。

但.proto文件并不是代码,不能执行,要想直接跨语言是不行的,必须得有对应语言的中间代码才行,中间代码要有以下能力:

  • 将message转成对象,例如C++里是class,golang里是struct,需要各自表达后,才能被理解
  • 需要有进行编解码的代码,能解码内容为自己语言的对象、能将对象编码为对应的数据

在完成数据封装之后,我们就准备好了将它传输出去,接下来就是数据传输了。

数据传输

grpc采用HTTP2.0,相对于HTTP1.0 在 更快的传输 和 更低的成本 两个目标上做了改进。有以下几个基本点:

  • HTTP2 未改变HTTP的语义(如GET/POST等),只是在传输上做了优化
  • 引入帧、流的概念,在TCP连接中,可以区分出多个request/response
  • 一个域名只会有一个TCP连接,借助帧、流可以实现多路复用,降低资源消耗
  • 引入二进制编码,降低header带来的空间占用
    HTTP1.1核心问题在于:在同一个TCP连接中,没办法区分response是属于哪个请求,一旦多个请求返回的文本内容混在一起,则没法区分数据归属于哪个请求,所以请求只能一个个串行排队发送。这直接
    导致了TCP资源的闲置。
    HTTP2为了解决这个问题,提出了 流 的概念,每一次请求对应一个流,有一个唯一ID,用来区分不同的请求。基于流的概念,进一步提出了 帧 ,一个请求的数据会被分成多个帧,方便进行数据分割传输,每个帧都唯一属于某一个流ID,将帧按照流ID进行分组,即可分离出不同的请求。这样同一个TCP连接中就可以同时并发多个请求,不同请求的帧数据可穿插在一起,根据流ID分组即可。HTTP2.0基于这种二进制协议的乱序模式 (Duplexing),直接解决了HTTP1.1的核心痛点,通过这种复用TCP连接的方式,不用再同时建多个连接,提升了TCP的利用效率。

总结
传输使用 http2 协议,是在tcp链接完成之后,再在应用层发送时的一个协议,通过流 ID 和 帧报文的两个概念 解决了传输拥塞的问题。我们将这种方式称之为 tcp链接复用

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

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

相关文章

Java获取Jar、War包路径,并生成可编辑修改的本地配置文件

前言 本地的可修改配置文件的编写理应是一个很常用的功能&#xff0c;但由于数据库的存在&#xff0c;它鲜少被提及&#xff0c;大多数我们直接存储到数据库中了。 以至于现今&#xff0c;除了没接触数据库的新手时常使用它以外&#xff0c;它没有太多的出场机会。 也因此&am…

浅谈C++重载、重写、重定义

C重载、重写、重定义 重载、重写、重定义对比一、重载&#xff08;overload&#xff09;二、重写 / 覆盖&#xff08;override&#xff09;三、重定义 / 隐藏&#xff08;redefining&#xff09; * 为什么在虚函数中不能使用 static 关键字&#xff1f;动态绑定&#xff08;Dyn…

3.6 Windows驱动开发:内核进程汇编与反汇编

在笔者上一篇文章《内核MDL读写进程内存》简单介绍了如何通过MDL映射的方式实现进程读写操作&#xff0c;本章将通过如上案例实现远程进程反汇编功能&#xff0c;此类功能也是ARK工具中最常见的功能之一&#xff0c;通常此类功能的实现分为两部分&#xff0c;内核部分只负责读写…

【刷题专栏—突破思维】LeetCode 138. 随机链表的复制

前言 随机链表的复制涉及到复制一个链表&#xff0c;该链表不仅包含普通的next指针&#xff0c;还包含random指针&#xff0c;该指针指向链表中的任意节点或空节点。 文章目录 原地修改链表 题目链接&#xff1a; LeetCode 138. 随机链表的复制 原地修改链表 题目介绍&#xf…

Vue3-shallowRef 和 shallowReactive函数(浅层次的响应式)

Vue3-shallowRef 和 shallowReactive函数&#xff08;浅层次的响应式&#xff09; shallowRef函数 功能&#xff1a;只给基本数据类型添加响应式。如果是对象&#xff0c;则不会支持响应式&#xff0c;层成也不会创建Proxy对象。ref和shallowRef在基本数据类型上是没有区别的…

IDEA 高分辨率卡顿优化

VM设置优化 -Dsun.java2d.uiScale.enabledfalse 增加该条设置&#xff0c;关闭高分切换 https://intellij-support.jetbrains.com/hc/en-us/articles/115001260010-Troubleshooting-IDE-scaling-DPI-issues-on-Windows​intellij-support.jetbrains.com/hc/en-us/articles/1…

【Spring】依赖注入方式,DI的方式

这里写目录标题 1. setter注入在一个类中注入引用类型在一个类中注入简单类型 2. 构造器注入在一个类中注入引用类型在一个类中注入简单类型 3. 依赖注入方式选择4. 依赖自动装配按类型注入按名称注入 5. 集合注入 1. setter注入 在一个类中注入引用类型 回顾一下之前setter注…

一个开源的汽修rbac后台管理系统项目,基于若依框架,实现了activiti工作流,附源码

文章目录 前言&源码项目参考图&#xff1a; e店邦O2O平台项目总结一、springboot1.1、springboot自动配置原理1.2、springboot优缺点1.3、springboot注解 二、rbac2.1、概括2.2、三个元素的理解 三、数据字典3.1、概括与作用3.2、怎么设计3.3、若依中使用字典 四、工作流—…

基于PI+重复控制的并网逆变系统谐波抑制策略模型

微❤关注“电气仔推送”获得资料&#xff08;专享优惠&#xff09; PI重复控制简介&#xff1a; 重复控制这一新型控制理论最早于出现日本学术界&#xff0c;其目的是为了用于解决质子加速器跟踪精度的问题。Yamamoto Y 等人提出了重复控制数学基础的内模原理&#xff0c;在控…

Filter和ThreadLocal结合存储用户id信息

ThreadLocal并不是一个Thread&#xff0c;而是Thread的局部变量。当使用ThreadLocal维护变量时&#xff0c;ThreadLocal为每个使用该变量的线程提供独立的变量副本&#xff0c;所以每一个线程都可以独立地改变自己的副本&#xff0c;而不会影响其它线程所对应的副本。ThreadLoc…

基于R语言平台Biomod2模型的物种分布建模与可视化分析

!](https://img-blog.csdnimg.cn/84e1cc8c7f9b4b6ab60903ffa17d82f0.jpeg#pic_center)

python+django+mysql个人博客项目部署(VMware部署)

目录 一、Vmware新建win7虚拟机 二、组件/软件安装 2.1 安装python3 2.2 更新pip 2.3 安装pycharm 2.4 安装django 2.5 win安装mysql 三、配置数据库 3.1 安装sqlite客户端 3.2 db.sqlite3导出为myblog.sql 3.3 Heidisql连接本地sql 四、部署项目 4.1 安装模块 4.2 尝试运行 …

Pytorch torch.normal()的用法

该函数原型如下&#xff1a; normal(mean, std, *, generatorNone, outNone) 该函数返回从单独的正态分布中提取的随机数的张量&#xff0c;该正态分布的均值是mean&#xff0c;标准差是std。 用法如下&#xff1a;我们从一个标准正态分布N&#xff5e;(0,1)&#xff0c;提取…

【Java】ArrayList和LinkedList使用不当,性能差距会如此之大!

文章目录 前言源码分析ArrayList基本属性初始化新增元素删除元素遍历元素 LinkedList实现类基本属性节点查询新增元素删除元素遍历元素 分析测试 前言 在面试的时候&#xff0c;经常会被问到几个问题&#xff1a; ArrayList和LinkedList的区别&#xff0c;相信大部分朋友都能回…

【Unity】单例模式及游戏声音管理类应用

【Unity】单例模式及游戏声音管理类应用 描述 在日常游戏项目开发中&#xff0c;单例模式是一种常用的设计模式&#xff0c;它允许在应用程序的生命周期中只创建一个对象实例&#xff0c;并提供对该实例的全局访问点。通过使用单例模式&#xff0c;可以提高代码的可维护性和可…

cesium雷达效果(脉冲圆)

cesium雷达效果(脉冲圆) 下面富有源码 实现思路 使用ellipse方法加载圆型,修改ellipse中‘material’方法重写glsl来实现当前效果 示例代码 index.html <!DOCTYPE html> <html lang="en"><head>

Redis(集合Set和有序集合SortedSet)

SET集合中的元素是不允许重复的&#xff0c;SET中的命令都是以S开头的。 使用SADD 在集合中添加元素&#xff0c;使用SMEMBERS查看元素。 当添加重复元素时&#xff0c;会返回0代表添加失败&#xff0c;查询还是就Redis一个元素。 使用SISMEMBER查询元素是否在集合中&#xff…

井盖位移监测,智能井盖智慧监测方式

在推动城市向智能化和高效化方向发展的过程中&#xff0c;科学技术发挥着至关重要的作用。智能井盖传感器作为科学技术进步的产物&#xff0c;正逐渐在城市管理过程之中崭露头角。这些看似不起眼的设备&#xff0c;虽然隐藏在井盖下方不被人们看到&#xff0c;但实实在在为人民…

Jquery 通过class名称属性,匹配元素

UI自动化过程中&#xff0c;常常需要判断某个元素是否满足条件&#xff0c;再走不通的脚本逻辑&#xff1b;、本文介绍如何通过jquery判断菜单是否展开&#xff0c;来决定是否执行菜单展开脚本&#xff1b;Jquery通过class名称属性&#xff0c;匹配元素 我们先分析&#xff0c;…

HTTP 到 HTTPS 再到 HSTS 的转变

近些年&#xff0c;随着域名劫持、信息泄漏等网络安全事件的频繁发生&#xff0c;网站安全也变得越来越重要&#xff0c;也促成了网络传输协议从 HTTP 到 HTTPS 再到 HSTS 的转变。 HTTP HTTP&#xff08;超文本传输协议&#xff09; 是一种用于分布式、协作式和超媒体信息系…