常见的十个网络问题(一)

有一次看陶辉老师直播,提出的大厂最常问的十个网络问题,这里自己做一个总结。

一、请详细介绍一下TCP三次握手机制,以及为什么要进行TCP三次握手

TCP三次握手流程:
这里将主动发起连接的一方称为A,另一方称为B
1、 A发送SYN包,也就是TCP头部的flags中的SYN标志位置1,向B同步自己的初始sequence number:P,A进入SYN_SENT状态。
2、B收到A的SYN包之后,将SYN包插入到syn_backlog队列中。并回复A一个SYN包,同时也对A的SYN包进行ACK,也就是将TCP头部中的SYN、ACK标志位都置1,向A同步自己的sequence number:Q,ACK的number为P+1。B进入SYN_RCVD状态。
3、A收到B的SYN包之后,对B的SYN包进行ACK,ACK number为Q+1,然后进入ESTABLISHED状态,B接收到这个ACK之后,将syn_backlog队列中的半连接取出插入到accept队列中。此时连接建立成功,B也进入ESTABLISHED状态。

上面三步是正常情况下建立三次握手的流程,然而网络环境复杂多变,或者设置了防火墙,也不一定能建立成功的,发送的包可能丢失,这个时候就需要重传机制。其中第一步,A向B发送SYN包,如果迟迟不能收到B的ACK,那么A将重试发送SYN,在linux上提供了一个内核参数用于控制重试次数:tcp_syn_retries,例如设置为3,通过抓包,如果一直没建立成功的情况下,A总共会发送4个SYN包,每个SYN包之间的时间间隔是1、2、4、8…这样按照指数型的方式递增,也就是说如果配置为3的话,A一共要等待15s左右才能放弃建立连接。在此期间,A将一直处于SYN_SENT状态。在第二步中B向A发送SYN+ACK,linux提供了一个内核参数tcp_synack_retries用于控制B重试发送SYN+ACK的次数,也就是第三步中A向B发送的ACK B迟迟没有收到的话,B将一直重试发送SYN+ACK.B将一直处于SYN_RCVD状态。

在上面建立连接的过程中涉及到了两个队列,一个是syn 队列,它定义了B处于SYN_RCVD状态的最大个数,可以通过内核参数tcp_max_syn_backlog控制,在应对SYN攻击的时候可以调大这个值。或者我们在优化服务器并发能力的时候也需要调整这个值。另一个是accept 队列。建立好连接后,应用程序是从accept队列中取出一个连接进行处理,系统级的accept队列长队由参数net.core.somaxconn控制,而对于一个监听的端口来讲,就是监听的backlog参数,在nginx的listen指令中有一个参数就是backlog,用于调整端口级别的accept队列长度。

再展开讲,tcp还有tcp_syncookies选项用于处理SYN队列满了的情况下通过cookie来实现快速建立连接的功能,还有可以开启tcp fast open选项用来减少再次建立连接的时候三次握手的时间消耗。这都为我们在进行三次握手的调优提供了思路。

为什么要进行三次握手:

TCP号称是可靠的传输协议,那么它靠什么实现可靠传输呢?就是通过sequence number和ACK机制,就是说发出去的包需要收到回复,否则会进行重传,这样来实现可靠。而三次握手就是用于协商A、B双方的初始sequence number,然后在后面的传输过程中会根据数据长度逐渐递增。A、B双方对各自接收到的对方的包进行ACK,从而实现整个传输过程的可靠。此外还有协商最大报文长度MSS、协商滑动窗口等信息。在tcp的options部分可以看到。

二、能否简单介绍下HTTP协议中缓存的处理流程

http协议的缓存是非常繁杂的,主要分为私有缓存和共享缓存,也可以说是浏览器缓存和服务器缓存。通常一个复杂的系统在终端和提供服务的服务端中间有层层的代理,包括正向代理、反向代理等。其中每一层都有可能进行缓存,通常称之为共享缓存,也就是可以供每个相同的请求使用的缓存。而私有缓存是放在终端的,只能供终端设备如浏览器使用。

缓存的存在能大大提升我们的访问体验,对于服务提供商也能大大节省带宽消耗。特别是私有缓存也就是浏览器上的缓存,直接就是0传输,即便是304也仅仅只有一个头部传输的消耗。通常情况下我们是私有缓存和共享缓存结合起来共同使用的。

而缓存是把双刃剑,对缓存使用不当的话有可能造成更新不及时甚至出现一些严重的错误。所以就要求缓存的操作者对缓存的使用要心理有数,什么时候该缓存,缓存多长时间,是私有缓存还是共享缓存,什么时候不要缓存等等。

http协议提供了一些头部用于控制缓存的使用,例如cache-control、expires、age等,这些头部有些用于请求头、有些用于响应头,有些可以同时出现在请求头部和响应头部中,从而提供了对缓存的精细的操作。

通常一些http服务的中间件都提供了对缓存的操作,例如nginx,nginx的ngx_http_proxy_module提供了对http协议的共享缓存操作。而其他例如fastcgi、uwsgi等协议的缓存也同时提供了,这些模块中有非常丰富的指令用于控制缓存。只能说nginx,真香。。。

用于控制缓存的头部的使用详情请参考我另一篇博客:http缓存详解

三、在地址栏键入URL之后,网络世界发生了什么?

这是一个无比宏大和开放的问题。除了解释基本的处理流程,可以从各个环节展开讲,我想聊个几个小时应该问题不大。。。

这里罗列一下需要出现的知识点:

http协议头部

DNS

NAT

路由选路协议

负载均衡

缓存

。。。

留下评论