网络
HTTP请求过程
HTTP2相对于HTTP1.x有什么优势和特点?
二进制分帧
帧:HTTP/2 数据通信的最小单位消息:指 HTTP/2 中逻辑上的 HTTP 消息。例如请求和响应等,消息 由一个或多个帧组成。 流:存在于连接中的一个虚拟通道。流可以承载双向消息,每个流都有一个唯一的整数ID HTTP/2 采用二进制格式传输数据,而非 HTTP 1.x 的文本格式,二进制协议解析起来更高效。
服务器推送
服务端可以在发送页面HTML时主动推送其它资源,而不用等到浏览器解析到相应位置,发起请求再响应。例如服务端可以主动把JS和CSS文件推送给客户端,而不需要客户端解析HTML时再发送这些请求。 服务端可以主动推送,客户端也有权利选择是否接收。如果服务端推送的资源已经被浏览器缓存过,浏览器可以通过发送RST_STREAM帧来拒收。主动推送也遵守同源策略,服务器不会随便推送第三方资源给客户端。
头部压缩
HTTP/1.x会在请求和响应中中重复地携带不常改变的、冗长的头部数据,给网络带来额外的负担。 HTTP/2在客户端和服务器端使用“首部表”来跟踪和存储之前发送的键值对,对于相同的数据, 不再通过每次请求和响应发送 首部表在HTTP/2的连接存续期内始终存在,由客户端和服务器共同渐进地更新; 每个新的首部键-值对要么被追加到当前表的末尾,要么替换表中之前的值。 你可以理解为只发送差异数据,而不是全部发送,从而减少头部的信息量
多路复用
HTTP 1.x 中,如果想并发多个请求,必须使用多个TCP链接,且浏览器为了控制资源,还会对单个域名有6-8个的TCP链接请求限制。
HTTP2中: 同域名下所有通信都在单个连接上完成。单个连接可以承载任意数量的双向数据流。数据流以消息的形式发送,而消息又由一个或多个帧组成,多个帧之间可以乱序发送,因为根据帧首部的流标识可以重新组装
当你用浏览器打开一个链接的时候,计算机做了哪些工作步骤。
- 解析域名
- 发起TCP的三次握手
- 建立TCP请求后发起HTTP请求
- 服务器响应请求
- 浏览器得到HTML代码,进行解析和处理JSON数据,并请求HTML代码中的静态资源(JS、 CSS、图片等)
- 浏览器对页面进行渲染
HTTP优化方案
TCP复用:TCP连接复用是将多个客户端的HTTP请求复用到一个服务器端TCP连接上,而HTTP复用则是 一个客户端的多个HTTP请求通过一个TCP连接进行处理。前者是负载均衡设备的独特功能;而后者是 HTTP 1.1协议所支持的新功能
内容缓存:将经常用到的内容进行缓存起来,那么客户端就可以直接在内存中获取相应的数据了。
压缩:将文本数据进行压缩,减少带宽 SSL加速(SSL Acceleration):使用SSL协议对HTTP协议进行加密,在通道内加密并加速
TCP缓冲:通过采用TCP缓冲技术,可以提高服务器端响应时间和处理效率,减少由于通信链路问题给 服务器造成的连接负担。
Session和cookie的区别
Cookie保存在客户端,未设置存储时间的Cookie,关闭浏览器会话Cookie就会被删除;设 置了存储时间的Cookie保存在用户设备的磁盘中知道过期,同时Cookie在客户端所以可以伪造,不是 十分安全,敏感数据不易保存。Session保存在服务器端,存储在IIS的进程开辟的内存中,而Session过 多会消耗服务器资源,所以尽量少使用Session。
Session是服务器用来跟踪用户的一种手段,每个Session都有一个唯一标识:session ID。 当服务端生成一个Session时就会向客户端发送一个Cookie保存到客户端,这个Cookie保存的是 Session的SessionId这样才能保证客户端发起请求后,用户能够与服务器端成千上万的Session进行匹 配,同时也保证了不同页面之间传值的正确性.
存储数据类型不同:Session能够存储任意的JAVA对象,Cookie只能存储String类型的对 象。
长于10K的数据,不要用到Cookies。
同样是重定向307,303,302,301的区别
301重定向和302跳转是在网站开发中常用的状态码,用于指示浏览器或搜索引擎如何处理页面跳转。让我们来看看它们之间的区别:
- 301重定向:
- 永久重定向:当服务器返回301状态码时,它告诉浏览器或搜索引擎,被请求的网址已经永久地移动到了新的地址。
- 搜索引擎效果:搜索引擎会索引新地址,并将旧网址的PageRank(PR)值传递给新网址。
- 使用场景:301重定向通常用于域名跳转,以及在网站内容发生永久性变化时。
- 302跳转:
- 临时跳转:服务器返回302状态码时,表示被请求的资源仍然存在,但只是临时地从旧地址跳转到了新地址。
- 搜索引擎效果:搜索引擎会保留旧网址,同时抓取新的内容。
- 使用场景:302跳转适用于临时性的跳转,例如在用户登录时将其重定向到登录页面。
302是http1.0的协议状态码,在http1.1版本的时候为了细化302状态码又出来了两个303和307。 303明确表示客户端应当采用get方法获取资源,他会把POST请求变为GET请求进行重定向。 307会遵 照浏览器标准,不会从post变为get。
HTTP的keep-alive是干什么的?
在早期的HTTP/1.0中,每次http请求都要创建一个连接,而创建连接的过程需要消耗资源和时间,为了减少资源消耗,缩短响应时间,就需要重用连接。在后来的HTTP/1.0中以及HTTP/1.1中,引入了重用连接的机制,就是在http请求头中加入Connection: keep-alive来告诉对方这个请求响应完成后不要关闭,下一次咱们还用这个请求继续交流。协议规定HTTP/1.0如果想要保持长连接,需要在请求头中加上 Connection: keep-alive。
keep-alive的优点:
- 较少的CPU和内存的使用(由于同时打开的连接的减少了)
- 允许请求和应答的HTTP管线化 降低拥塞控制 (TCP连接减少了)
- 减少了后续请求的延迟(无需再进行握手)
- 报告错误无需关闭TCP连接
为什么TCP连接需要三次握手,两次不可以么,为什么?
为了防止已失效的连接请求报文突然又传送到了服务端,因而产生错误。客户端发出的连接请求报文并未丢失,而是在某个网络节点长时间滞留了,以致延误到链接释放以后的某个时间才到达 Server。如果不需要第三次握手,就可能出现服务端新建无用的连接,浪费性能
三次握手过程中有哪些不安全性
SYN洪泛攻击
伪装的IP向服务器发送一个SYN请求建立连接,然后服务器向该IP回复SYN和ACK,但是找不到该 IP对应的主机,当超时时服务器收不到ACK会重复发送。当大量的攻击者请求建立连接时,服务器就会 存在大量未完成三次握手的连接,服务器主机backlog被耗尽而不能响应其它连接。即SYN泛洪攻击 (属于DOS的一种,发送大量的半连接请求,耗费CPU和内存资源,引起网络堵塞甚至系统瘫痪)
当你在服务器上看到大量的半连接状态时,特别是源IP地址是随机的,基本上可以断定这是一次 SYN攻击.在Linux下可以如下命令检测是否被Syn攻击
防范措施:
1、降低SYN timeout时间,使得主机尽快释放半连接的占用
2、采用SYN cookie设置,如果短时间内连续收到某个IP的重复SYN请求,则认为受到了该IP的攻 击,丢弃来自该IP的后续请求报文
3、在网关处设置过滤,拒绝将一个源IP地址不属于其来源子网的包进行更远的路由
DDOS
DOS攻击利用合理的服务请求占用过多的服务资源,使正常用户的请求无法得到相应。 常见的DOS攻击有计算机网络带宽攻击和连通性攻击。 带宽攻击指以极大的通信量冲击网络,使得所有可用网络资源都被消耗殆尽,最后导致合法的用户请求无法通过。 连通性攻击指用大量的连接请求冲击计算机,使得所有可用的操作系统资源都被消耗殆尽,最终计算机无法再处理合法用户的请求。
TCP四次挥手
为什么要有TIME_WAIT状态?
TIME_WAIT状态存在有两个原因。
一、可靠终止TCP连接。如果最后一个ACK报文因为网络原因被丢弃,此时server因为没有收到ACK而 超时重传FIN报文,处于TIME_WAIT状态的client可以继续对FIN报文做回复,向server发送ACK报文。
二、保证让迟来的TCP报文段有足够的时间被识别和丢弃。连接结束了,网络中的延迟报文也应该被丢弃掉,以免影响立刻建立的新连接。
为什么会发生 TCP 粘包、拆包?
要发送的数据大于TCP发送缓冲区剩余空间大小,将会发生拆包。 待发送数据大于 MSS(最大报文长度),TCP 在传输前将进行拆包。要发送的数据小于TCP发送缓冲区的大小,TCP将多次写入缓冲区的数据一次发送出去,将会发生粘包。 接收数据端的应用层没有及时读取接收缓冲区中的数据,将发生粘包。
粘包、拆包解决办法
由于 TCP 本身是面向字节流的,无法理解上层的业务数据,所以在底层是无法保证数据包不被拆分和重 组的,这个问题只能通过上层的应用协议栈设计来解决,根据业界的主流协议的解决方案,归纳如下:
- 消息定长:发送端将每个数据包封装为固定长度(不够的可以通过补 0 填充),这样接收端每次 接收缓冲区中读取固定长度的数据就自然而然的把每个数据包拆分开来。
- 设置消息边界:服务端从网络流中按消息边界分离出消息内容。在包尾增加回车换行符进行分割, 例如 FTP 协议。
- 将消息分为消息头和消息体:消息头中包含表示消息总长度(或者消息体长度)的字段。 更复杂的应用层协议比如 Netty 中实现的一些协议都对粘包、拆包做了很好的处理。
生产Nginx现大量TIME-WAIT,导致连接耗尽,该如何处理?
1)导致 nginx端出现大量 TIME_WAIT 的情况有两种:
- keepalive_requests设置比较小,高并发下超过此值后nginx会强制关闭和客户端保持的keepalive长连 接;(主动关闭连接后导致nginx出现 TIME_WAIT )
- keepalive设置的比较小(空闲数太小),导致高并发下nginx会频繁出现连接数震荡(超过该值会关闭 连接),不停的关闭、开启和后端server保持的keepalive长连接;
2)导致后端server端出现大量 TIME_WAIT 的情况:
nginx没有打开和后端的长连接,即:没有设置 proxy_http_version 1.1; 和 proxy_set_header Connection “”; 从而导致后端server每次关闭连接,高并发下就会出现server端出现大量 TIME_WAIT
为什么关闭连接需要四次挥手
关闭连接时,被动断开方在收到对方的FIN结束请求报文时,很可能业务数据没有发送完成,并不能立即 关闭连接,被动方只能先回复一个ACK响应报文,告诉主动断开方:“你发的FIN报文我收到了,只有等 到我所有的业务报文都发送完了,我才能真正的结束,在结束之前,我会发你FIN+ACK报文的,你先等 着”。所以,被动断开方的确认报文,需要拆开成为两步,故总体就需要四步挥手。
为什么连接建立的时候是三次握手,可以改成两次握手吗?
在假想的TCP建立的连接时二次握手过程中,Client发送Server发送一个SYN请求帧,Server收到后发送 了确认应答SYN+ACK帧。按照两次握手的协定,Server认为连接已经成功地建立了,可以开始发送数据 帧。这个过程中,如果确认应答SYN+ACK帧在传输中被丢失,Client没有收到,Client将不知道Server 是否已准备好,也不知道Server的SN序列号,Client认为连接还未建立成功,将忽略Server发来的任何数据分组,会一直等待Server的SYN+ACK确认应答帧。而Server在发出的数据帧后,一直没有收到对应 的ACK确认后就会产生超时,重复发送同样的数据帧。这样就形成了死锁。
为什么主动断开方在TIME-WAIT状态必须等待2MSL的时间?
原因之一:主动断开方等待2MSL的时间,是为了确保两端都能最终关闭。假设网络是不可靠的,被动断开方发送FIN+ACK报文后,其主动方的ACK响应报文有可能丢失,这时候的被动断开方处于LAST-ACK状态的,由于收不到ACK确认被动方一直不能正常的进入CLOSED状态。在这种场景下,被动断开方会超 时重传FIN+ACK断开响应报文,如果主动断开方在2MSL时间内,收到这个重传的FIN+ACK报文,会重传 一次ACK报文,后再一次重新启动2MSL计时等待,这样,就能确保被动断开方能收到ACK报文,从而能 确保被动方顺利进入到CLOSED状态。只有这样,双方都能够确保关闭。反过来说,如果主动断开方在 发送完ACK响应报文后,不是进入TIME_WAIT状态去等待2MSL时间,而是立即释放连接,则将无法收到 被动方重传的FIN+ACK报文,所以不会再发送一次ACK确认报文,此时处于LAST-ACK状态的被动断开 方,无法正常进入到CLOSED状态。
原因之二:防止“旧连接的已失效的数据报文”出现在新连接中。主动断开方在发送完最后一个ACK报文 后,再经过2MSL,才能最终关闭和释放端口,这就意味着,相同端口的新TCP新连接,需要在2MSL的 时间之后,才能够正常的建立。2MSL这段时间内,旧连接所产生的所有数据报文,都已经从网络中消失 了,从而,确保了下一个新的连接中不会出现这种旧连接请求报文。
如果已经建立了连接,但是Client端突然出现故障了怎么办?
TCP还设有一个保活计时器,Client端如果出现故障,Server端不能一直等下去,这样会浪费系统资源。 每收到一次Client客户端的数据帧后,Server端都的保活计时器会复位。计时器的超时时间通常是设置 为2小时,若2小时还没有收到Client端的任何数据帧,Server端就会发送一个探测报文段,以后每隔75 秒钟发送一次。若一连发送10个探测报文仍然没反应,Server端就认为Client端出了故障,接着就关闭 连接。如果觉得保活计时器的两个多小时的间隔太长,可以自行调整TCP连接的保活参数。