http2.0/http3.0(quic)/grpc

目录

http1.x

http2.0

相较于http1.0的改进点

http3.0

QUIC如何解决队头阻塞问题的?

QUIC如何做流量控制的?

QUIC如何做拥塞控制的?

QUIC更快的建立连接?

RPC和http有什么区别

protobuf压缩


http1.x

  1. 冗余的header:每个请求都会带上冗余重复的Header,导致传输的体积很大
  2. http是无状态的协议,每个请求没有做特殊的标识:无法通过一个TCP链接并发的发送多个请求,只能等上一个请求的rsp返回了,才能发送下一个请求。(只能串行的发送)
    1. 因为http1.x是基于”文本“的协议,请求的内容打包在header/body中,内容通过CRLF来分割,同一个TCP链接中,无法区分req/rsp是属于哪个请求
    2. 于是http1.x提出了pipeline:允许请求方一口气的发送多个请求,但是有一个严重的弊端,需要对应的rsp按照req的顺序严格排列(因为每个请求没有唯一的标识,所以不按照顺序排列就无法区分rsp是属于哪个req)。==> 若前面的req迟迟不来,后面的请求都会要等待
      • Chrome浏览器,一个域名,只能有6个TCP链接在同时工作

http2.0

相较于http1.0的改进点

  1. header压缩
    1. 静态字典:常见的头部名称,如,get/post/cookie等
    2. 动态字典:比如一个req过来,会将字段保存在动态字典中,再一个req,若发现相同的字段,无需传递,只需要使用动态字典中的标识
  2. 流/帧 + 多路复用
    1. http2.0提出了流的概念,每个请求对应一个流,每个流都有唯一的ID,用来区分不同的req/rsp
    2. 基于流的概念,又提出了帧:一个请求的数据被分成多个帧,方便进行数据传输。每个帧都属于某一个流ID
    3. 多路复用:在一个TCP链接上,可以同时发起无数个请求,并且响应可以同时返回
  3. 请求划分优先级
    1. 多路复用带来的一个问题是,在共享连接的基础上会存在一些关键请求被阻塞,SPDY 允许给每个请求设置优先级,这样重要的请求就会优先得到响应
  4. 服务端推送
    1. 在HTTP1.x中,访问一个页面,浏览器首先获取HTML资源,然后在解析页面时增量地获取其他资源,服务器必须等待浏览器发出请求后才下发页面内资源。而服务器实际上是知道页面内资源有哪些的,如果服务器能够在浏览器显式请求资源之前就将资源推送到浏览器,页面加载速度将会大大提示,这也是本篇的主旨。
    2. 简单来讲,就是当用户的浏览器和服务器在建立链接后,服务器主动将一些资源推送给浏览器并缓存起来,这样当浏览器接下来请求这些资源时就直接从缓存中读取,不会在从服务器上拉了,提升了速率

http2.0存在的问题:http2.0只是通过多路复用技术解决了http层面上的队首阻塞,但是tcp层面的毫无办法TCP 的队头阻塞并没有彻底解决。TCP 为了保证可靠传输,有一个“超时重传”机制,丢失的包必须等待重传确认

TCP队头阻塞
        我们都知道,TCP是一种可靠传输,这个可靠就是体现在它能够“按序到达”,然后再被上层接收,这里的按序到达指的是最终顺序是按序排列的,也就是说每当有一个或几个Packet丢失的时候,会等待它到达后合并,然后再向上交付。

       因此,很容易可以理解,当一个流的第一个数据包丢失了,那么即使后面的数据包都到达了,后面的这些数据包也不能被处理,而是要等第一个数据包到了之后才能被上层接收处理,那么这个时候不止是第一个数据包需要额外等待一个或多个RTT,后面的第二个Packet、第三个Packet......都需要同样多等待那么多时间才能处理,但实际上他们是按时到达了的,这也就是所谓的TCP队头阻塞

http3.0

http3.0彻底弃用了TCP协议,改用可靠的UDP协议(QUIC

TCP协议存在的缺点:其实也不能怪 TCP 协议,它本来设计目的就是为了保证数据的有序性

        1. TCP建立连接的延迟

        2. TCP存在队头阻塞问题:

                1. 发送窗口的队头阻塞:TCP 发送出去的数据,都是需要按序确认的,只有在数据都被按顺序确认完后,发送窗口才会往前滑动。

                

                案例:客户端发送了第 5~9 字节的数据,但是第 5 字节的 ACK 确认报文在网络中丢失了,那么即使客户端收到第 6~9 字节的 ACK 确认报文,发送窗口也不会往前移动。这就是发送窗口的头部阻塞问题

                2. 接收窗口的队头阻塞:接收窗口什么时候才能滑动?当接收窗口收到有序数据时,接收窗口才能往前滑动,然后那些已经接收并且被确认的「有序」数据就可以被应用层读取。(但是,当接收窗口收到的数据不是有序的)

                案例:比如收到第 33~40 字节的数据,由于第 32 字节数据没有收到, 接收窗口无法向前滑动,那么即使先收到第 33~40 字节的数据,这些数据也无法被应用层读取的。只有当发送方重传了第 32 字节数据并且被接收方收到后,接收窗口才会往前滑动,然后应用层才能从内核读取第 32~40 字节的数据

QUIC如何解决队头阻塞问题的?

1. 在一条 QUIC 连接上可以并发发送多个 HTTP 请求 (Stream)。

2. 但是,QUIC 给每一个 Stream 都分配了一个独立的滑动窗口,这样使得一个连接上的多个 Stream 之间没有依赖关系,都是相互独立的,各自控制的滑动窗口

     

QUIC如何做流量控制的?

TCP 流量控制是通过让「接收方」告诉「发送方」,它(接收方)的接收窗口有多大,从而让「发送方」根据「接收方」的实际接收能力控制发送的数据量 。在前面说到,

        1. TCP 的发送窗口在收到对已发送数据的顺序确认 ACK后,发送窗口才能往前滑动,否则停止滑动。

        2. TCP 的接收窗口在收到有序的数据后,接收窗口才能往前滑动,否则停止滑动;

        QUIC 是基于 UDP 传输的,而 UDP 没有流量控制,因此 QUIC 实现了自己的流量控制机制。不过,QUIC 的滑动窗口滑动的条件跟 TCP 有所差别的。QUIC实现了2中级别的流量控制:stream、connection。

1. stream级别的流量控制

        回想一下 TCP,当发送方发送 seq1、seq2、seq3 报文,由于 seq2 报文丢失了,接收方收到 seq1 后会 ack1,然后接收方收到 seq3 后还是回 ack1(因为没有收到 seq2),这时发送窗口无法往前滑动。

        是,QUIC 就不一样了,即使中途有报文丢失,发送窗口依然可以往前滑动,具体怎么做到的呢?我们来看看。        

① 最开始,接收方的接收窗口初始状态如下:

        

② 接着,接收方收到了发送方发送过来的数据,有的数据被上层读取了,有的数据丢包了,此时的接收窗口状况如下:

         

        可以看到,即使中间有数据包丢失了,也不会影响后面数据的接收。接收窗口的左边界取决于接收到的最大偏移字节数,此时的接收窗口 = 最大窗口数 - 接收到的最大偏移数,这里就跟 TCP 不一样了。

        那接收窗口触发的滑动条件是什么呢?看下图:

                

        当图中的绿色部分数据超过最大接收窗口的一半后,最大接收窗口向右移动,同时给对端发送「窗口更新帧」。当发送方收到接收方的窗口更新帧后,发送窗口也会往前滑动,即使中途有丢包,依然也会滑动,这样就防止像 TCP 那样在出现丢包的时候,导致发送窗口无法移动,从而避免了无法继续发送数据

        在前面我们说过,每个 Stream 都有各自的滑动窗口,不同 Stream 互相独立,队头的 Stream A 被阻塞后,不妨碍 StreamB、C的读取。而对于 TCP 而言,其不知道将不同的 Stream 交给上层哪一个请求,因此同一个Connection内,Stream A 被阻塞后,StreamB、C 必须等待。

        总结:QUIC 协议中同一个 Stream 内,滑动窗口的移动仅取决于接收到的最大字节偏移(尽管期间可能有部分数据未被接收),而对于 TCP 而言,窗口滑动必须保证此前的 packet 都有序的接收到了,其中一个 packet 丢失就会导致窗口等待。 

2. connection级别的流量控制

        而对于 Connection 级别的流量窗口,其接收窗口大小就是各个 Stream 接收窗口大小之和。

Connection 流量控制

上图所示的例子,所有 Streams 的最大窗口数为 120,其中:

        Stream 1 的最大接收偏移为 100,可用窗口 = 120 - 100 = 20

        Stream 2 的最大接收偏移为 90,可用窗口 = 120 - 90 = 30

        Stream 3 的最大接收偏移为 110,可用窗口 = 120 - 110 = 10

那么,整个 Connection 的可用窗口 = 20 + 30 + 10 = 60

QUIC如何做拥塞控制的?

        QUIC 协议当前默认使用了 TCP 的 Cubic 拥塞控制算法(我们熟知的慢开始、拥塞避免、快重传、快恢复策略),同时也支持 CubicBytes、Reno、RenoBytes、BBR、PCC 等拥塞控制算法,相当于将 TCP 的拥塞控制算法照搬过来了,QUIC 是如何改进 TCP 的拥塞控制算法的呢?

        QUIC 是处于应用层的,应用程序层面就能实现不同的拥塞控制算法,不需要操作系统,不需要内核支持。这是一个飞跃,因为传统的 TCP 拥塞控制,必须要端到端的网络协议栈支持,才能实现控制效果。而内核和操作系统的部署成本非常高,升级周期很长,所以 TCP 拥塞控制算法迭代速度是很慢的。

        而 QUIC 可以随浏览器更新,QUIC 的拥塞控制算法就可以有较快的迭代速度

        TCP 更改拥塞控制算法是对系统中所有应用都生效,无法根据不同应用设定不同的拥塞控制策略。但是因为 QUIC 处于应用层,所以就可以针对不同的应用设置不同的拥塞控制算法,这样灵活性就很高了。

QUIC更快的建立连接

        对于 HTTP/1 和 HTTP/2 协议,TCP 和 TLS 是分层的,分别属于内核实现的传输层、openssl 库实现的表示层,因此它们难以合并在一起,需要分批次来握手,先 TCP 握手(1RTT),再 TLS 握手(2RTT),所以需要 3RTT 的延迟才能传输数据,就算 Session 会话服用,也需要至少 2 个 RTT。

        HTTP/3 在传输数据前虽然需要 QUIC 协议握手,这个握手过程只需要 1 RTT,握手的目的是为确认双方的「连接 ID」,连接迁移就是基于连接 ID 实现的。

        但是 HTTP/3 的 QUIC 协议并不是与 TLS 分层,而是QUIC 内部包含了 TLS,它在自己的帧会携带 TLS 里的“记录”,再加上 QUIC 使用的是 TLS1.3,因此仅需 1 个 RTT 就可以「同时」完成建立连接与密钥协商,甚至在第二次连接的时候,应用数据包可以和 QUIC 握手信息(连接信息 + TLS 信息)一起发送,达到 0-RTT 的效果

        如下图右边部分,HTTP/3 当会话恢复时,有效负载数据与第一个数据包一起发送,可以做到 0-RTT:

        

RPC和http有什么区别

  1. RPC是方法,http是传输协议。其实两者不是一个类型,没有什么可比性
  2. 传输协议
    1. RPC:tcp协议、http协议
    2. http:http协议
  3. 传输效率
    1. RPC ①如果使用自定义的TCP协议,可以让请求头的信息更少 ②使用http2.0协议,传输效率也很高
    2. http:请求头中包含很多无用的信息,比如refer,keepalivetime,last-modify等信息。在流量大的时候,每次请求多几个字节,影响效率
  4. 性能
    1. RPC:可以基于thrift或pb来实现二进制传输
    2. http:也可以使用pb,但是目前主流的浏览器大部分是使用json文本传输

protobuf压缩

optional uint64 id = 1;

序列号 + 类型 = 序列号<<3 | 类型

id保存的值:采用base128压缩

GRPC原理

  • 1
    点赞
  • 6
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值