拉巴力的纸皮箱


  • 首页

  • 标签

  • 归档

  • 关于

  • 搜索

技术选型要注意什么?

发表于 2022-11-18

  • 充分了解才能用,基本了解,大局实现,

  • 充分测试,压测分析profile,

  • 非核心业务试行,

  • 业界选择,不是说别人牛,是因为别人拿业务来验证过

  • 待整理

我的重构(翻译)经历

发表于 2022-10-18

前言

  1. 这里的重构基本指的是:把用A语言写的服务,使用B语言重写
  2. 工作的大部分内容其实就是人肉代码翻译
  3. 当然,重构通常也伴随的架构的优化和调整
  4. 最后,为了保证工作的顺利进行和服务的稳定切换,也总结了一些经验
  5. 下面将简要讲述作者的三段重构经历,分别是将三种不同的语言重构成Java(本人公司的所在的业务的主要语言就是Java,个人没特殊语言癖好),作者其实对这三种语言都不熟悉,是怎么完成重构任务的呢?

一、PHP重构成Java(“一比一”迁移)

  • 负责该业务的模块
  • 启动环境太复杂,较复杂的逻辑通过在线工具运行验证
  • 和熟悉该业务的PHP同事合作
  • 切换服务接口使用灰度策略和配置开关
  • 覆盖好测试用例
  • 没本地环境,必要时在线运行验证

二、C++重构成Java(站在“巨人的肩膀”上重新出发)

  • 其他公司业务调整,业务并入,需复制一套业务功能基本相同的服务
  • 通过参考原业务的代码,发现其中架构存在的问题,进行优化;参考其中的实现,避免在新实现中出现考虑不周(站在“巨人的肩膀”上)
  • 和第一段重构经历不同的是,原服务只是作为参考,在业务功能上一摸一样,并不需要在内部实现上保持和原来完全一致,但是新服务需要融入现有的服务基础体系
  • 有意思的优化,原来因为业务逻辑的需要使用单体服务,新服务使用新的巧妙设计,是服务可以有多实例运行
  • 不需要本地环境,阅读参考即可

三、Lua重构成Java(对当前“一无所知”也没关系)

  • 本地把环境跑起来,通过调试验证逻辑
  • 新业务需要,需要参考部分逻辑,同时进行重构,反哺原业务团队
  • 需要本地环境,验证原本一无所知的逻辑

总结

  1. 编程语言的语言其实大同小异,花半天左右基本可以快速熟悉语法,在阅读代码的时候遇到不懂的地方,即时查阅即可;
  2. 对于一些复杂的逻辑,可以通过编写代码块,执行验证输出;可以在本地环境运行,也可以利用在线工具运行;
  3. 对于历史包袱较重的,要善于利用灰度策略;
  4. 阅读代码后,跟熟悉业务的同学请教确认,和同事们讨论有时也是很有必要的。

我的几张TCP原理学习手绘图

发表于 2022-09-08

网络寻址原理

负载均衡模式

TCP连接中的各种状态

发表于 2022-09-07

状态说明

  • CLOSED:无连接是活动的或正在进行
  • LISTEN:服务器在等待进入呼叫
  • SYN_RECV:一个连接请求已经到达,等待确认
  • SYN_SENT:应用已经开始,打开一个连接
  • ESTABLISHED:正常数据传输状态
  • FIN_WAIT1:应用说它已经完成
  • FIN_WAIT2:另一边已同意释放
  • ITMED_WAIT:等待所有分组死掉
  • CLOSING:两边同时尝试关闭
  • TIME_WAIT:另一边已初始化一个释放
  • LAST_ACK:等待所有分组死掉

flags 标志

  • S(SYN)
  • F(FIN)
  • P(PUSH)
  • R(RST)

常用命令

查看主机上的TCP连接状态

  • netstat –an
  • netstat –an |grep 'CLOSE_WAIT'
  • ss -t -n|grep 5000

统计当前各种状态的连接的数量的命令

  • netstat -n | awk '/^tcp/ {++S[$NF]} END {for(a in S) print a, S[a]}'

查看指定端口的连接

  • netstat -an | awk 'NR==2 || $4~/65016/'(client)
  • netstat -an | awk 'NR==2 || $5~/8080/'(server)

Linux netstat命令详解

  • http://www.cnblogs.com/ggjucheng/archive/2012/01/08/2316661.html

tcpdump

  • 想知道我们可以通过哪几个网卡抓包,可以使用-D参数 : tcpdump –D

  • 将抓包结果存放在文件中(可以用Wireshark打开查看) : tcpdump –w google.cap

  • 其中http协议的数据包都给过滤出来: tcpdump –r google.cap http

  • http://www.cnblogs.com/zhuimengle/p/5737848.html

Reference

  • TCP/IP TIME_WAIT状态原理

todo

  • tcp 三次握手和四次断连深入分析:连接状态和socket API的关系
    • close函数其实本身不会导致tcp协议栈立刻发送fin包,而只是将socket文件的引用计数减1,当socket文件的引用计数变为0的时候,操作系统会自动关闭tcp连接,此时才会发送fin包。
    • 这也是多进程编程需要特别注意的一点,父进程中一定要将socket文件描述符close,否则运行一段时间后就可能会出现操作系统提示too many open files

TIME_WAIT解析

发表于 2022-09-07

TIME_WAIT

  • 通信双方建立TCP连接后,主动关闭(FIN)连接的一方就会进入TIME_WAIT状态
    • 客户端主动关闭连接时,发送最后一个ack后,会进入TIME_WAIT状态,再停留2个MSL时间,进入CLOSED状态

TIME_WAIT状态存在的理由

  1. 可靠地实现TCP全双工连接的终止

    • TCP协议在关闭连接的四次握手过程中,最终的ACK是由主动关闭连接的一端(后面统称A端)发出的,如果这个ACK丢失,对方(后面统称B端)将重发出最终的FIN,因此A端必须维护状态信息(TIME_WAIT)允许它重发最终的ACK。如果A端不维持TIME_WAIT状态,而是处于CLOSED 状态,那么A端将响应RST分节,B端收到后将此分节解释成一个错误(在java中会抛出connection reset的SocketException)。
    • 因而,要实现TCP全双工连接的正常终止,必须处理终止过程中四个分节任何一个分节的丢失情况,主动关闭连接的A端必须维持TIME_WAIT状态 。
    • 对一个具体实现所给定的MSL值,处理的原则是:当TCP执行一个主动关闭,并发回最后一个ACK,该连接必须在TIMEWAIT状态停留的时间为2倍的MSL。这样可尽可能让TCP再次发送最后的ACK以防这个ACK丢失(另一端超时并重发最后的FIN)。
    • 总结:尽量避免主动关闭方ack丢失导致被关闭方异常(理论上从应用层看,被关闭方需要对这种异常进行处理,因为万一主动关闭方断电了呢)
  2. 允许老的重复分节在网络中消逝

    • TCP分节可能由于路由器异常而“迷途”,在迷途期间,TCP发送端可能因确认超时而重发这个分节,迷途的分节在路由器修复后也会被送到最终目的地,这个迟到的迷途分节到达时可能会引起问题。在关闭“前一个连接”之后,马上又重新建立起一个相同的IP和端口之间的“新连接”,“前一个连接”的迷途重复分组在“前一个连接”终止后到达,而被“新连接”收到了。为了避免这个情况,TCP协议不允许处于TIME_WAIT状态的连接启动一个新的可用连接,因为TIME_WAIT状态持续2MSL,基本可以保证当成功建立一个新TCP连接的时候,来自旧连接重复分组已经在网络中消逝。
    • IP包的最大生存时间记录在其TTL字段中,即MSL,超过将过期丢弃

MSL时间

  • MSL就是maximum segment lifetime(最大分节生命期),这是一个IP数据包能在互联网上生存的最长时间,超过这个时间IP数据包将在网络中消失 。MSL在RFC 1122上建议是2分钟,而源自berkeley的TCP实现传统上使用30秒。
    TCP报文段以IP数据报在网络内传输,而IP数据报则有限制其生存时间的TTL字段
  • TIME_WAIT状态维持时间是两个MSL时间长度,也就是在1-4分钟。Windows操作系统就是4分钟。
  • 为什么需要2MSL?
    • 第一个MSL是为了等自己发出去的最后一个ACK从网络中消失,同时让旧的数据包基本在网络中消失;
    • 第二MSL是为了等在对端收到ACK之前的一刹那可能重传的FIN报文从网络中消失(主要目的)
    • 问题:重传的FIN报文会重传多少次?
      • 重发次数由 tcp_orphan_retries 参数控制
    • 所以如果最后一个ack丢了,且对端又重试发FIN,那么还是无法避免FIN包没过期,所以2MSL只是尽可能,但这时旧的数据包基本消失了

总结

  • TIME_WAIT主动关闭方的状态
  • TIME_WAIT存在的原因
    1. 防止主动关闭方最后的ACK丢失,确保远程TCP接收到连接中断的请求
    2. 允许老的重复数据包在网络中过期

TIME_WAIT产生的场景

  • 进入TIME_WAIT状态的一般情况下是客户端。
  • 大多数服务器端一般执行被动关闭,服务器不会进入TIME_WAIT状态。
    但在服务器端关闭某个服务再重新启动时,服务器是会进入TIME_WAIT状态的。
    可以使用SO_REUSEADDR选项来复用端口。
举例:
1.客户端连接服务器的80服务,这时客户端会启用一个本地的端口访问服务器的80,访问完成后关闭此连接,立刻再次访问服务器的
80,这时客户端会启用另一个本地的端口,而不是刚才使用的那个本地端口。原因就是刚才的那个连接还处于TIME_WAIT状态。
2.客户端连接服务器的80服务,这时服务器关闭80端口,立即再次重启80端口的服务,这时可能不会成功启动,原因也是服务器的连
接还处于TIME_WAIT状态。

作为客户端和服务器

  1. 服务端提供服务时,一般监听一个端口就够了;
  2. 客户端则是使用一个本地的空闲端口(大于1024),与服务器的端口建立连接;
    • 如果使用短连接请求,那么客户端将会产生大量TIME_WAIT状态的端口(本地最多就能承受6万个TIME_WAIT状态的连接就无端口可用了,后续的短连接就会产生address already in use : connect的异常)
    • 因此,作为短连接请求的压测服务器,不能在短时间连续使用;
    • 一般来说一台机器可用Local Port 3万多个,如果是短连接的话,一个连接释放后默认需要60秒回收,30000/60 =500 这是大概的理论TPS值
  3. 一个提供高并发的服务器,同时依赖第三方服务(间接看来服务端也作为第三方服务的客户端),怎么应对 ?
    • 一般情况都是启用keepalive选项,避免短连接服务(一般依赖方也不会多达几千个,即调用的ip和端口不一样)
    • 启用SO_REUSEADDR选项
  4. 大多数服务器端一般执行被动关闭,服务器不会进入TIME_WAIT状态

如何复用TIME_WAIT端口

  1. 应用层发出请求前指定,如何Java HttpClient中设置reuseaddr
    1
    2
    3
    httpClient.setHttpRequestRetryHandler(new DefaultHttpRequestRetryHandler());
    httpClient.setReuseStrategy(new DefaultConnectionReuseStrategy());
    httpClient.setKeepAliveStrategy(new DefaultConnectionKeepAliveStrategy());
  2. 调整内核参数(net.ipv4.tcp_tw_reuse)

总结避免TIME_WAIT的方法

  1. 使用长连接(基本大部分业务场景都可以)
  2. 避免主动关闭
  3. 关闭的时候使用RST的方式 (比如程序中设置socket的SO_LINGER选项)(应用层貌似不是很方便实现)
  4. TIME_WAIT状态的TCP允许重用
  5. 增大可用端口范围,默认是 net.ipv4.ip_local_port_range = 32768 61000 (即对同一个服务器的ip+port可创建28233个连接)(只能缓解问题,不能根本解决问题)

Reference

  • TCP/IP TIME_WAIT状态原理
  • 发现大量的TIME_WAIT解决办法
  • [《TCP IP详解卷一》18.6.1]
  • 为什么 TCP 协议有 TIME_WAIT 状态
  • TCP四次挥手为何需要TIME_WAIT以及为何是2MSL?
  • TCP 才不傻:三次握手和四次挥手的异常处理
  • tcp短连接TIME_WAIT问题解决方法大全

你记得设置TCP_NODEPLAY吗?

发表于 2022-09-07
  • 有接触过TCP服务器实现的同学都会知道,需要注意TCP_NODELAY参数,为什么呢?

  • 若没有开启TCP_NODELAY,那么在发送小包的时候,可能会出现这样的现象:
    通过 TCP socket 分多次发送较少的数据时,比如小于 1460 或者 100 以内,对端可能会很长时间收不到数据,导致本端应用程序认为超时报错。

Nagle算法(Nagle‘s Algorithm)

  • TCP/IP协议中,无论发送多少数据,总是要在数据前面加上协议头,同时,对方接收到数据,也需要发送ACK表示确认。为了尽可能的利用网络带宽,TCP总是希望尽可能的发送足够大的数据。(一个连接会设置MSS参数,因此,TCP/IP希望每次都能够以MSS尺寸的数据块来发送数据)。

  • Nagle算法就是为了尽可能发送大块数据,避免网络中充斥着许多小数据块。

  • Nagle算法的基本定义是任意时刻,最多只能有一个未被确认的小段。 所谓“小段”,指的是小于MSS尺寸的数据块,所谓“未被确认”,是指一个数据块发送出去后,没有收到对方发送的ACK确认该数据已收到。

  • 举个例子,一开始client端调用socket的write操作将一个int型数据(称为A块)写入到网络中,由于此时连接是空闲的(也就是说还没有未被确认的小段),因此这个int型数据会被马上发送到server端,接着,client端又调用write操作写入一个int型数据(简称B块),这个时候,A块的ACK没有返回,所以可以认为已经存在了一个未被确认的小段,所以B块没有立即被发送,一直等待A块的ACK收到(大概40ms之后)(ACK延迟机制的超时时间),B块才被发送。

  • Nagle算法的改进在于:如果发送端欲多次发送包含少量字符的数据包(一般情况下,后面统一称长度小于MSS的数据包为小包,与此相对,称长度等于MSS的数据包为大包,为了某些对比说明,还有中包,即长度比小包长,但又不足一个MSS的包),则发送端会先将第一个小包发送出去,而将后面到达的少量字符数据都缓存起来而不立即发送,直到收到接收端对前一个数据包报文段的ACK确认、或当前字符属于紧急数据,或者积攒到了一定数量的数据(比如缓存的字符数据已经达到数据包报文段的最大长度)等多种情况才将其组成一个较大的数据包发送出去。
    TCP在三次握手建立连接过程中,会在SYN报文中使用MSS(Maximum Segment Size)选项功能,协商交互双方能够接收的最大段长MSS值。

ACK延迟机制(TCP Delayed Acknoledgement)

  • TCP/IP中不仅仅有Nagle算法(Nagle‘s Algorithm),还有一个ACK延迟机制(TCP Delayed Ack) 。当Server端收到数据之后,它并不会马上向client端发送ACK,而是会将ACK的发送延迟一段时间(假设为t),它希望在t时间内server端会向client端发送应答数据,这样ACK就能够和应答数据一起发送,就像是应答数据捎带着ACK过去。
  • 也就是如果一个 TCP 连接的一端启用了Nagle算法,而另一端启用了ACK延时机制,而发送的数据包又比较小,则可能会出现这样的情况:发送端在等待接收端对上一个packet的Ack才发送当前的packet,而接收端则正好延迟了此Ack的发送,那么这个正要被发送的packet就会同样被延迟。当然Delayed Ack是有个超时机制的,而默认的超时正好就是40ms。
  • 现代的 TCP/IP 协议栈实现,默认几乎都启用了这两个功能,那岂不每次都会触发这个延迟问题?事实不是那样的。仅当协议的交互是发送端连续发送两个packet,然后立刻read的时候才会出现问题。

总结:问题出现的三个条件

  1. 发送小包(仅当协议的交互是发送端连续发送两个 packet,然后立刻 read 的 时候才会出现问题。)
  2. 发送方启用了Nagle算法(发送方未接收到上一个包的ack,且待发送的是小包,则会等待)
  3. 接收方启用了ACK延时机制 且没及时准备好数据(希望响应ack可以和响应的数据一起发送,等待本端响应数据的准备)

解决办法

  • 开启TCP_NODELAY:禁用Nagle算法,禁止后当然就不会有它引起的一系列问题了。
  • 优化协议:连续 write 小数据包,然后 read 其实是一个不好的网络编程模式,这样的连续 write 其实应该在应用层合并成一次 write。

扩展

另一个问题的例子(HTTP服务)

  • 神秘的40毫秒延迟与TCP_NODELAY

  • 接口响应时间在client端开启keepalive后连续请求时由0ms变成40ms

  • 因为设计的一些不足,我没能做到把 短小的 HTTP Body 连同 HTTP Headers 一起发送出去,而是分开成两次调用实 现的,之后进入 epoll_wait 等待下一个 Request 被发送过来(相当于阻塞模 型里直接 read)。正好是 write-write-read 的模式

  • 那么 write-read-write-read 会不会出问题呢?维基百科上的解释是不会:

    • “The user-level solution is to avoid write-write-read sequences on sockets. write-read-write-read is fine. write-write-write is fine. But write-write-read is a killer. So, if you can, buffer up your little writes to TCP and send them all at once. Using the standard UNIX I/O package and flushing write before each read usually works.”
    • 我的理解是这样的:因为第一个 write 不会被缓冲,会立刻到达接收端,如果是 write-read-write-read 模式,此时接收端应该已经得到所有需要的数据以进行 下一步处理。接收端此时处理完后发送结果,同时也就可以把上一个packet 的 Ack 可以和数据一起发送回去,不需要 delay,从而不会导致任何问题。

Reference

  • TCP_NODELAY和Nagle算法

有了TCP的keepalive,应用层还需要实现保活逻辑吗?

发表于 2022-09-06

结论

  • 对于实时性高的业务,基本都需要在应用层自行实现保活逻辑,应用层的心跳协议是必不可少的

TCP keepalive 的 问题

  1. 检测周期长,开启后默认是2h(系统内核参数 tcp_keepalive_time),这就意味着服务端可能维持着一个死连接;
  2. TCP keepalive 是由操作系统负责探查,即便进程死锁,或阻塞等,操作系统也会收发 TCP keepalive 消息,无法及时感知客户端已经实际已经下线;

应用层实现心跳的基本做法

  1. 服务端和客户端都开启tcp keepalive
  2. 客户端定时发心跳包到服务端
  3. 服务端根据自定义的规则,在一定时间内收不到心跳包的时,断开客户端的连接。

应用层实现心跳保活逻辑的好处

  1. 可以在发送心跳包的同时顺带业务或指令数据,这样服务端获得客户端的详细状态,同时可以更好满足业务场景
  2. 可以灵活控制探查客户端的时间和策略,更快下线有异常的连接,减少服务端不必要的负担

Reference

  • 在以TCP为连接方式的服务器中,为什么在服务端设计当中需要考虑心跳?
  • 闲说HeartBeat心跳包和TCP协议的KeepAlive机制
  • TCP协议的KeepAlive机制与HeartBeat心跳包

关于HTTP相关协议的一些总结

发表于 2022-09-05

粗浅概括

  • HTTP - TCP
  • HTTPS - TCP + TLS
  • SPDY -> TCP + TLS + 多路复用、头部压缩等特性 –> 发展成 HTTP/2
    • SPDY是Speedy的音,是更快的意思
  • HTTP/2 - TCP + TLS(理论上可选) + 多路复用、头部压缩等特性
  • QUIC - UDP –> 发展成 HTTP/3
  • HTTP/3 - UDP

其他基础

  • RTT(Round-Trip Time): 往返时延。在计算机网络中它是一个重要的性能指标,表示从发送端发送数据开始,到发送端收到来自接收端的确认(接收端收到数据后便立即发送确认),总共经历的时延。

HTTP

  • 请求-响应模式(半双工)
  • 安全问题

“队头堵塞” (线头阻塞)(Head-of-line blocking)(HOLB)

  • HTTP 1.1 默认启用长TCP连接,但所有的请求-响应都是按序进行的(串行发送和接收)
  • HTTP 1.1 的管道机制:客户端可以同时发送多个请求,但服务端也需要按请求的顺序依次给出响应的;
  • 客户端在未收到之前所发出所有请求的响应之前,将会阻塞后面的请求(排队等待),这称为”队头堵塞”

管道机制(Pipelining)

  • 在管道机制下,服务端如何控制按顺序返回响应的?
    • HTTP是应用层协议,当然由各个应用程序按照规范自行实现了
    • 比如使用nginx,或jetty等,若服务端需要支持管道机制,都要底层逻辑自行实现,避免暴露给业务层
    • 那么因为要按顺序响应,那么当最前的请求的处理较慢时,同样会对服务端产生阻塞。
  • Pipelining需要客户端和服务端同时支持
  • 几乎所有的浏览器都是默认关闭或者不支持Pipelining的:对性能的提高有限、大文件会阻塞优先级更高的小文件等
  • 只有GET和HEAD要求可以进行管线化,而POST则有所限制

HTTPS

  • HTTPS(HTTP over TLS/SSL),TLS/SSL(会话层)

  • SSL(Secure Socket Layer)是安全套接层,TLS(Transport Layer Security)是传输层安全协议,建立在SSL3.0协议规范,是 SSL3.0 的后续版本。

  • TLS可以用在TCP上,也可以用在无连接的UDP报文上。协议规定了身份认证、算法协商、密钥交换等的实现。

  • SSL是TLS的前身,现在已不再更新

jks、pfx和cer 证书文件

  • jks是JAVA的keytools证书工具支持的证书私钥格式。
  • pfx是微软支持的私钥格式。
  • cer是证书的公钥。

权威证书颁发的公钥匙一般是预装的

  • SSL/TLS协议详解(中)——证书颁发机构

  • 当我们安装浏览器或操作系统时,将会附有一组证书颁发机构,例如DigiCert。当浏览器自带DigiCert时,这意味着浏览器具有DigiCert的公钥,网站可以向DigiCert索取证书和签名。因此,DigiCert将使用DigiCerts私钥在服务器证书上进行加密签名。当我们发起连接时,服务器将发送嵌入了其公钥的证书。由于浏览器具有DigiCert的公钥,因此可以在服务器证书上验证DigiCert的签名,同时也说明证书上写的服务器的公钥是可信的。

  • 根据RSA的加密原理,如果用CA的公钥解密成功,说明该证书的确是用CA的私钥加密的,可以认为被验证方是可信的。

HTTP/2

  • 全双工
  • 二进制格式传输、多路复用、header压缩、服务端推送、优先级和依赖关系、重置、流量控制

多路复用(Multiplexing)

  • 客户端发送多个请求和服务端给出多个响应的顺序不受限制, 避免”队头堵塞”
  • 每个数据流都有一个唯一的编号,从而让请求和响应对应起来
  • 客户端和服务器 可以发生信号取消某个数据流,并保持这个连接
  • 客户端还可以提升提升某个数据流优先级

加密

  • HTTP/2 沒规定一定要使用加密(例如 SSL),但目前大部分浏览器的 HTTP/2 都需要在 HTTPs上运行
  • gRPC 虽然使用 HTTP/2,但默认并没有需要配置加密证书

重用连接(针对浏览器)

  • 使用HTTP1.1协议,浏览器为了快速,针对同一域名设置了一定的并发数,稍微加快速度
  • 使用HTTP/2,浏览器针对同一个域名的资源,只建立一个tcp连接通道

头部压缩

  • 头部压缩也存在一些缺点 ,不管是Client还是Server,都要维护索引表,以确定每个索引值对应HTTP header的信息,通过占用更多内存换取数据量传输的减少(空间换时间)。

推送

  • Chrome将禁用HTTP/2服务器推送(Server Push)支持
    • 这功能逻辑本身就有问题,比如资源存放在单个业务服务器上,并行推送多个静态资源只会降低响应速度,性能不升反降。而对于前后端分离的业务来说,HTTP/2 本身就支持多路复用,server push 只能稍微降低浏览器解析 html 的时间,对现代浏览器来说性能提升可以忽略不计。

HTTP/3

  • HTTP/1.x 有连接无法复用、队头阻塞、协议开销大和安全因素等多个缺陷

  • HTTP/2 通过多路复用、二进制流、Header 压缩等等技术,极大地提高了性能,但是还是存在着问题的

  • QUIC 基于 UDP 实现,是 HTTP/3 中的底层支撑协议,该协议基于 UDP,又取了 TCP 中的精华,实现了即快又可靠的协议

  • HTTP3.0,也称作HTTP over QUIC。HTTP3.0的核心是QUIC(读音quick)协议,由Google在2015年提出的SPDY v3演化而来的新协议,传统的HTTP协议是基于传输层TCP的协议,而QUIC是基于传输层UDP上的协议,可以定义成:HTTP3.0基于UDP的安全可靠的HTTP2.0协议。

  • 在网络条件较差的情况下,HTTP/3在增强网页浏览体验方面的效果非常好

  • TCP从来就不适合处理有损无线环境中的数据传输

  • TCP中的行头阻塞

TCP的限制

  1. TCP可能会间歇性地挂起数据传输
    • TCP流的行头阻塞(HoL): 序列号较低的数据段丢包问题,导致阻塞
  2. TCP不支持流级复用
  3. TCP会产生冗余通信
    • TCP连接握手会有冗余的消息交换序列,即使是与已知主机建立的连接也是如此。

新特性

  • 选择UDP作为底层传输层协议。抛弃TCP的缺点(TCP传输确认、重传慢启动等),同时。此外QUIC是用户层协议,不需要每次协议升级时修改内核;
  • 流复用和流控:解决了行头阻塞问题。
  • 灵活的拥塞控制机制、更好的错误处理能力、更快的握手
  • 新的HTTP头压缩机制,称为QPACK,是对HTTP/2中使用的HPACK的增强(QUIC流是不按顺序传递的,在不同的流中可能包含不同的HTTP头)

采用HTTP/3的限制

  • 不仅涉及到应用层的变化,还涉及到底层传输层的变化
  • UDP会话会被防火墙的默认数据包过滤策略所影响
  • 中间层,如防火墙、代理、NAT设备等需要兼容
  • 需迫使中间层厂商标准化
  • HTTP/3在现有的UDP之上,以QUIC的形式在传输层处理,增加了HTTP/3在整个协议栈中的占用空间。这使得HTTP/3较为笨重,不适合某些IoT设备
  • NGINX和Apache等主流web服务器需要支持

Q&A

HTTP 与 TCP backlog关系

  1. 没直接关系
  2. HTTP是应用层协议,TCP backlog 是应用程序在操作系统层接收tcp连接的队列数
  3. 比如tomcat,作为一个HTTP应用服务,TCP backlog对应其acceptCount的配置

关于 HTTP keepalive

  • 要利用HTTP的keep-alive机制,需要服务器端和客户端同时支持

  • HTTP是应用层协议,具体的表现行为取决于HTTP服务器以及HTTP client的实现

  • wireshark抓包简单查看HTTP keep-alive原理

  • 继续深入理解HTTP keepalive

  1. keepalive 是否开启服务端控制还是客户端控制?
    • keepalive可以由双方共同控制,需要双方都开启才能生效,HTTP1.1客户端默认开启,客户端想关闭可以通过设置Connection: Close,服务端同样想关闭可以设置Connection: Close。双方哪方先收到Connection: Close 则由收到方关闭(前提是双方的实现都支持,比如telnet就不支持)
  2. keepalive的时间是由服务端控制还是客户端控制?
    • 时间主要还是由服务端控制,时间一到由服务端主动关闭,当然客户端如果有实现设置一定时间后,由客户端主动关闭也可以。一般的HTTPclient库都有提供相应的配置,设置关闭长期不使用的连接,如connectionManager.closeIdleConnections(readTimeout * 2, TimeUnit.MILLISECONDS);
    • HTTPs://my.oschina.net/greki/blog/83350
  3. keepalive时间一到,是由客户端主动关闭还是服务端主动关闭?
    • 哪方的时间短,由哪一方来关闭,除非双方的实现有更明确的协议
  4. 如果客户端不是HTTPclient,使用telnet连接服务端?
    • telnet客户端除了连接时进行三次握手,用来发送数据接收数据,基本无其他实现逻辑。即接收到服务器的响应之后,不会有相关HTTP协议的处理。

HTTP keepalive VS TCP keepalive

  • HTTPs://zhuanlan.zhihu.com/p/385597183; HTTPs://juejin.cn/post/6992845852192702477
  • HTTP 的 Keep-Alive,是由应用层(用户态) 实现的,称为 HTTP 长连接;
  • TCP 的 Keepalive,是由 TCP 层(内核态) 实现的,称为 TCP 保活机制;
  • HTTP协议的Keep-Alive意图在于短时间内连接复用,希望可以短时间内在同一个连接上进行多次请求/响应。
  • TCP的KeepAlive机制意图在于保活、心跳,检测连接错误。当一个TCP连接两端长时间没有数据传输时(通常默认配置是2小时),发送keepalive探针,探测链接是否存活。
  • tcp的keepalive是在ESTABLISH状态的时候,双方如何检测连接的可用行。而HTTP的keep-alive说的是如何避免进行重复的TCP三次握手和四次挥手的环节。
  • 总之,HTTP的Keep-Alive和TCP的KeepAlive不是一回事。

Chrome中HTTP下载续传原理

  • Chrome下载文件时暂停和继续是什么原理?

HTTP连接复用时,同一个连接上的多个请求和响应如何对应上?

  • “队头堵塞”(Head-of-line blocking):所有的请求-响应都是按序进行的(HTTP)
  • 多路复用(Multiplexing):每个数据流都有一个唯一的编号,从而让请求和响应对应起来(HTTP/2)

可以外网使用HTTP/3,再转发到内网的HTTP服务?

  • 上层nginx使用HTTP3,下层应用服务器(如spring boot jetty等)还是使用HTTP,其实理论上是可以的。nginx转发时要由接受到的udp包改成tcp发送。(内网丢包概率一般应该比外网丢包低很多),如果采用这种转发方式,这就意味着内网无法使用四层负载转发,因为底层协议不一样(udp和tcp)
  • 现在主流的代理服务Nginx/Apache都没有实现QUIC,一些比较小众的代理服务如Caddy就实现了

使用HTTPS还存在中间人攻击?

  • 结论:可以避免。只要不信任不安全的HTTPs网站,就不会被中间人攻击

  • 中间人攻击:HTTPs://urlify.cn/zQj6f2

  • 既然证书是公开的,如果要发起中间人攻击,我在官网上下载一份证书作为我的服务器证书,那客户端肯定会认同这个证书是合法的,如何避免这种证书冒用的情况?
    其实这就是非加密对称中公私钥的用处,虽然中间人可以得到证书,但私钥是无法获取的,一份公钥是不可能推算出其对应的私钥,中间人即使拿到证书也无法伪装成合法服务端,因为无法对客户端传入的加密数据进行解密。

  • 只要客户端是我们自己的终端,我们授权的情况下,便可以组建中间人网络,而抓包工具便是作为中间人的代理。

Q: 为什么需要证书?
A: 防止”中间人“攻击,同时可以为网站提供身份证明。

Q: 使用 HTTPS 会被抓包吗?
A: 会被抓包,HTTPS 只防止用户在不知情的情况下通信被监听,如果用户主动授信,是可以构建“中间人”网络,代理软件可以对传输内容进行解密。

扩展

cURL 发 HTTP/2请求

  1. Mac OS Curl HTTP/2 支持
    brew install curl --with-ngHTTP2
/usr/local/Cellar/curl/7.50.3/bin/curl --HTTP2 -kI  HTTPs://localhost:8443/user/1
HTTP/2 200
server: Jetty(9.3.10.v20160621)
date: Sun, 30 Oct 2016 02:08:46 GMT
content-type: application/json;charset=UTF-8
content-length: 23
  1. linux:HTTPs://www.sysgeek.cn/curl-with-HTTP2-support/

HTTP/3 握手优化

  • 1倍时延 = 一次单向传输时延 = 0.5 RTT
  • HTTPS 的 7 次握手以及 9 倍时延
  • HTTPS: 7 次握手以及 9 倍时延 (4.5 RTT); HTTP/3: 3 次握手以及 5 倍时延 (2.5 RTT)
    当客户端想要通过 HTTPS 请求访问服务端时,整个过程需要经过 7 次握手并消耗 9 倍的延迟。如果客户端和服务端因为物理距离上的限制,RTT 约为 40ms 时,第一次请求需要 ~180ms;不过如果我们想要访问美国的服务器,RTT 约为 200ms 时,这时 HTTPS 请求的耗时为 ~900ms,这就是一个比较高的耗时了。我们来总结一下 HTTPS 协议需要 9 倍时延才能完成通信的原因:

TCP 协议需要通过三次握手建立 TCP 连接保证通信的可靠性(1.5-RTT);
TLS 协议会在 TCP 协议之上通过四次握手建立 TLS 连接保证通信的安全性(2-RTT);
HTTP 协议会在 TCP 和 TLS 上通过一次往返发送请求并接收响应(1-RTT);
需要注意的是,本文对往返延时的计算都基于特定的场景以及特定的协议版本,网络协议的版本在不断更新和演进,过去忽略的问题最开始都会通过补丁的方式更新,但是最后仍然会需要从底层完成重写。

HTTP/3 就是一个这样的例子,它会使用基于 UDP 的 QUIC 协议进行握手,将 TCP 和 TLS 的握手过程结合起来,把 7 次握手减少到了 3 次握手,直接建立了可靠并且安全的传输通道,将原本 ~900ms 的耗时降低至 ~500ms,

Reference

  • HTTP协议篇(一):多路复用、数据流
  • HTTP管线化(HTTP pipelining)
  • HTTP/2 资料汇总
  • HTTP,HTTPs,spdy,HTTP2等协议的主要区别详解
  • 一文看完 HTTP3 的演化历程
  • 深入解读HTTP3的原理及应用
  • HTTPS 原理分析——带着疑问层层深入

Chrome下载文件时暂停和继续是什么原理?

发表于 2022-08-30
  • 这个问题很久前就研究过了,觉得挺有意思,这里总结记录一下
  • 所有的文字整理来源于: https://bbs.csdn.net/topics/392163074,感谢wjyiooo的耐心解答

Range

  • Range,是在 HTTP/1.1(http://www.w3.org/Protocols/rfc2616/rfc2616.html)里新增的一个 header field,也是现在众多号称多线程下载工具(如 FlashGet、迅雷等)实现多线程下载的核心所在。

chrome 版本58

  1. 抓包确认,chrome点击暂停的时候会发送一系列窗口变动应答,将窗口降到5,并且不再应答ACK包。 当点击恢复的时候只是重新发送ACK给服务器,同时将窗口重新设置为256。
  2. 以上可以确认它的“续传”只是利用TCP滑动窗口的特性,跟断不断网没关系,也不属于真正意义的断点续传功能(一般用range头部实现)。当然如果你中断网络超过了服务器的TCP连接超时时间那么就不能续传了,而且如果关闭浏览器即使网络非常正常也不能续传(也是因为TCP连接断了)。
  3. 在等待足够长时间让TCP连接关掉后,chrome就可以断点续传了,原理也是头部带range。

总结

  1. 本地有临时下载文件
  2. 短时间内点继续,利用的是TCP滑动窗口的特性(与服务器未断开)
  3. 长时间之后点继续,再次发请求,带range头,继续下载剩余部分(与服务器断开)

扩展

使用Range进行多线程下载

  • Http 请求头 Range:https://www.cnblogs.com/1995hxt/p/5692050.html
  1. curl -H “Range: bytes=0-1551” http://127.0.0.1:8180/bg-upper.png -v -o 0-1151.png
  2. curl -H “Range: bytes=1552-3103” http://127.0.0.1:8180/bg-upper.png -v -o 1552-end.png
  3. 合并 cat 0-1151.png 1552-end.png > filename.png

推送技术总结

发表于 2022-08-05

概述

  • 从客户端是手机APP的角度来理解推送(PUSH),展示的形式有两种:

    1. App 推送:消息内容通过手机通知栏(状态栏)展示
    2. 应用内消息:各种业务数据推送(通过定义模版或命令号等方式推送给APP内的业务使用)
  • 从Web端角度看理解推送,一般只有网页内消息(跟手机APP的应用内消息是一样的类型)

  • APP推送:

    1. 在线推送(应用级方案):APP进程控制推送消息,理论上只要APP要获得“手机通知栏”的权限(一般通过在APP内维持长连接来进行推送,但前提是APP已经启动和运行,并且能常驻)
    2. 离线推送(系统级方案):通过手机操作系统或手机厂商提供的通道进行推送。这种推送方式可以在APP未启动的情况下,推送APP的消息。
    3. APP进程运行时,应该优先走在线推送,自己的推送系统更快、更有保障。
  • 应用场景

    • APP推送:电商内APP(推送促销消息)
    • 应用内消息:直播类APP(推送送礼特效消息)
    • APP推送和应用内消息都需要:IM类APP(推送用户聊天信息)
  • 从推送的实现角度看,基本可以概括为两种:主动轮询(pull 拉)和长连接 (push 推)

实现方式

  • 以下实现方式没有进行严格分类,从原理上看存在相互联系
  1. HTTP轮询

    1. 短轮询(Polling)
    2. 长轮询(Long-polling)(Nacos和apollo配置中心也是用这种)
    • 从TCP的角度看HTTP长轮询:HTTP开启keepalive,服务端保持连接并不需要发额外数据包,有数据时可以立刻推送,跟TCP长连推送无异。展示服务端有点费连接的相关资源,数据包是HTTP相比较大而已。
  2. SSE (Server Sent Event 服务器发送事件)

    • sse 单通道,只能服务端向客户端发消息; webscoket 是双通道
    • 实现成本较低
    • http 协议,服务端响应的是text/event-stream类型的数据流信息
    • 场景:站内信、未读消息数、状态更新、股票行情、监控数量等场景
  3. WebSocket

  4. MQTT (通常结合TCP长连接一起使用)

  5. TCP长连接(自定义消息或protobuf等格式)

  6. 系统级方案

    • Android和IOS本身的消息推送(Android的C2DM和IOS的APNS,系统与服务器建立连接,APP向系统注册关注的消息,实现系统级消息推送)
    • 国内Android无法访问Google服务器,所以国内的手机厂商比如小米、OPPO、华为等,都实现来各自的系统级推送。
    • 避免维持长连接而导致的过多资源消耗,IM类要求即时的更应该接系统级推送
  7. 第三方推送平台

    • 集成各种手机平台,各种推送类型,甚至短信等推送
    • 简单来说:由专业的平台做专业的事(太麻烦了,我只是想推送了消息,帮我搞定吧。。。)

Reference

  • 7种 实现web实时消息推送的方案
  • SSE 服务器发送事件详解
<1…567…16>

153 日志
165 标签
RSS
© 2025 Kingson Wu
由 Hexo 强力驱动
|
主题 — NexT.Pisces v5.1.4