网络
综述
一次通信的过程
从一次下单的过程看整个通信的过程:
1、在浏览器中输入网址,这是一个URL,浏览器通过DNS协议或者HTTPDNS找到了目标IP地址
2、应用层的处理:将请求的格式、内容、类型等信息写入HTTP请求中
3、传输层的两种协议的处理:TCP/UDP,区别就是一种是可靠的,一种是不可靠的,无论哪一种都会向数据包中加入相关的首部信息,其中最重要的是目标端口号和源端口号
4、网络层的IP协议会将数据再次包装,加入源IP地址和目标IP地址
5、在数据包传输的过程中,路由协议解决了传输路径的问题
6、在每一跳的过程中,会不断的寻找路由器和网关,在数据链路层会加入源MAC地址和目标MAC地址,完成每一跳的数据传输
服务器收到请求之后,就是上述过程的反过程。
数据链路
数据链路层依靠帧末尾的一个校验位来检测是否在发送过程中出现了错误,发送时主要靠随机接入协议,也就是发送数据时总是先发送,若发现信道拥堵则等待(以太网)
STP协议
集线器和交换机的区别:交换机可以记住网口对应的MAC地址,这就是转发表,也叫MAC地址表,它存在一个过期时间。
想要给一台机器发送信息,必须通过ARP协议先知道它的MAC地址:
ARP协议的基本过程:查看本地ARP缓存表、广播ARP请求、获取APR应答、填充本地ARP缓存表(IP-MAC地址的映射,存在过期时间)
广播ARP请求时,最初交换机不知道任何拓扑信息,交换机收到了该广播后,会继续将信息广播到其他所有的网口,直到某个网段存在该IP地址的机器,到这里一个ARP请求就完成了,在这个过程中,所有交换机都能学到转发表的信息(网口-MAC地址的对应关系),等下一次有相同的通信时,就不会再广播了。
但上述的广播机制存在一个环路问题,如下面这种网络结构来说:
如果机器1想发送信息给机器2,交换机收到ARP请求广播后会将其继续广播给交换机B,B会觉得两个网口都存在机器2,就会反复刷新转发表,最终形成环路问题,信道一直拥堵。
STP(Spanning Tree Protocol)协议让整个网络结构形成了一个最小生成树,这样通信时就会根据树状结构来进行通信,不会造成环路问题。
几个STP协议中的概念:
- Root Bridge:根交换机,某棵树的根节点
- Designated Bridges:指定交换机,是树的树枝节点,不是叶子节点,叶子节点一般是主机。其他交换机通过这个交换机到达根交换机,也就相当于拜他做了大哥
- Bridge Protocol Data Units (BPDU) ,网桥协议数据单元:决定交换机之间谁的地位更高,更高的在树中的位置越高
- Priority Vector,优先级向量:描述实力的一组ID:[Root Bridge ID, Root Path Cost, Bridge ID, and Port ID] ,判断谁实力更高时,先看Root Bridge ID,谁的根服务器ID大,谁就更强;再看Root Path Cost,谁距离根服务器越近,谁就越强(走这条路也就代价越小);最后看Bridge ID,就是自己的ID,这个一般由管理员分配,性能越好的交换机ID越小,在树生成的过程中地位更高。
最初的时候,各节点拥有不同的ID,通过互相发送BPDU来确定各自的地位,总能决出最后每个节点的地位:
- 根交换机遇到根交换机:输的会率领所有子节点归顺到一棵树中
- 指定交换机遇到指定交换机:
- 两者若属于同一颗树,会计算到根服务器的距离,再次决出上下关系。如1和2原来就以3为掌门,那么1和2相遇后会比较到3的距离,若1到3的距离>1到2的距离+2到3的距离,此后1会直接转发消息给2;
- 两者不属于同一颗树,则会各自拿掌门比较,输的就会率众归顺
- 根交换机遇到指定交换机:
- 两者若属于同一棵树,则代表出现了环,此时会计算距离。如1是掌门,5是1的子节点,6是5的子节点,若1和6相遇,则代表6通过其他子节点进入了树,存在环,此时会计算距离,若1到6的距离<1到5的距离+5到6的距离,会让6直接作为1的子节点,否则还是保持原状。
- 两者若属于不同的树,则指定交换机会拿自己掌门比较,然后决出胜利者
通过这样的策略最终总能生成一棵树,以后通信时就按照树的路线前进,一些交换机的网口被阻塞,不会出现环路的问题。
STP的不足:1、收敛时间较长;2、主机频繁上下线会触发大量BPDU
RSTP(快速生成树协议)和MSTP(多生成树协议)是对它的改进协议。
VLAN虚拟局域网
在局域网中存在数据安全问题,数据传输时,无关的主机也可能接收到数据,一般有两种解决方案:
1、设置多个交换机,无关的机器分属到不同的子网中,但这样成本太高
2、使用虚拟局域网,一个交换机连接多个VLAN
在VLAN中帧格式中会加入VLAN ID的信息,代表帧数据是属于哪个VLAN的,支持VLAN的交换机收到该数据帧后,会寻找归属该VLAN的数据网口,这样交换机只会将数据发送到该网口,其他网口的计算机就不会收到该数据。每个网口都可以自由设置对应的VLAN信息。交换机与交换机之间的网口叫Trunk口,它可以转发属于任何VLAN的口:
网络层
ICMP协议
ICMP协议主要有两种报文:查询报文、差错报文
ping就是查询报文,如果想知道网络包从源地址到目标地址需要经历哪些设备,还需要使用tcpdump进行分析。
很多中间设备是禁止ping的,此时ping不通不代表网络不通,此时还需要使用telnet等协议来测试网络。
Traceroute就是差错报文,它会发送不同TTL的UDP数据包,直到能走到目标地址。例如它会选择一个不可能的值作为端口号,TTL设置为1,这样第一个路由器就会返回一个端口不可达的错误报文。然后再设置为2,以此类推。它还可以故意设置不分片,让路由器返回不分片的错误提示,构造不同大小的数据包来推算路径的MTU。
配置路由
当路由器有多张网卡时,会根据路由表来选择包的出口,路由表包含多条路由规则,每一条路由规则都包含:目标网络、出口设备、下一跳网关,使用route命令或者ip route命令都可以查询路由规则。
设置路由规则:
ip route add 10.176.48.0/20 via 10.173.32.1 dev eth0
代表要去10.176.48.0/20这个目标网络,要从eth0端口出去,下一个路由器是10.173.32.1
可以配置多个路由表,将数据分发到不同的路由表:
ip rule add from 192.168.1.0/24 table 10
ip rule add from 192.168.2.0/24 table 20
表示从192.168.1.10/24这个网段来的,使用table 10中的路由表,而从192.168.2.0/24网段来的,使用table20的路由表。
一条路由规则也可以走多条路径,例如:
ip route add default scope global nexthop via 100.100.100.1 weight 1 nexthop via 200.200.200.1 weight 2
代表下一跳有两个地方,分别是100.100.100.1和200.200.200.1,权重分别为1比2,可以根据带宽对不同的端口设置不同的权重。
可以根据不同的来源走不同的网口:
$ ip route list table main
60.190.27.189/30 dev eth3 proto kernel scope link src 60.190.27.190
183.134.188.1 dev eth2 proto kernel scope link src 183.134.189.34
192.168.1.0/24 dev eth1 proto kernel scope link src 192.168.1.1
127.0.0.0/8 dev lo scope link
default via 183.134.188.1 dev eth2
来自60.190.27.190的请求走eth3,下一跳是60.190.27.189/30;规则从上到下匹配,若所有规则都匹配不上,则走183.134.188.1。
还可以针对特殊来源设置单独的路由策略,如添加一个路由表叫chao:
echo 200 chao >> /etc/iproute2/rt_tables
设置从192.168.1.101来的包都查看个chao这个新的路由表 :
ip rule add from 192.168.1.101 table chao
在路由表中添加规则:
# ip route add default via 60.190.27.189 dev eth3 table chao
# ip route flush cache
RIP和OSPF
RIP是距离向量算法,每个路由器都保存一个路由表,包含多行,每行的信息是到一个目标路由器,要多少距离。每个路由器将自己和相邻服务器的距离信息广播出去,其他路由器接受到之后就能得到到达所有路由器的距离。
缺点:坏消息传的慢,当某个路由器不可达时,消息要流转很久才能感知到;每次发送距离信息时,都要发送自己的全部路由表,当网络规模大时代价也大
OSPF是链路状态路由算法,所有路由器持有相同的信息,都能在本地构建一个完整的图,用Dijkstra算法计算两点之间的最短路径。节点之间更新信息时只需要发送更新的或改变的网络拓扑,更新信息小,坏消息传播迅速。
发现多个最短的路径,可以在多个路径中进行负载均衡,这就是等价路由。
传输层
UDP
UDP继承了IP包的特性,不保证不丢失,不保证按顺序到达。它和TCP相比,它处理速度快、时延低,但不提供可靠交付、不是面向字节流的(TCP是面向字节流的)、没有拥塞控制、是无状态的(TCP是有状态的,它会记录发送进度)
UDP应用场景:
- 网页或者APP的访问,如QUIC(全称Quick UDP Internet Connections,快速UDP互联网连接),它基于UDP,实现快速连接建立、减少重传时延,自适应拥塞控制
- 流媒体:直播
- 实时游戏
- 物联网、移动流量上网
TCP连接建立和断开
1、为什么TCP建立连接时要三次握手?而不是2次或者4次?
要保证双方的网络连接都正常,第一次握手是请求连接;第二次握手是服务器端要告知客户端请求连接的结果,并保证数据能正常发送到服务器,此时客户端能保证它的消息能发出,且能有响应;第三次握手是客户端响应服务器端的应答,此时服务器才能保证它的消息能发出,且能有响应
握手除了确定双方的网络连接都正常外,还要确定TCP包的序号,两者都要告诉对方发起的包的起始序列号,这是为了保证发送顺序。
2、三次握手中的异常场景
- 如果A发起连接的请求一直没有响应,就会一直重复发送建立连接的请求。如果B不愿意建立连接,就会忽略A的请求,A会重试一段时间后选择放弃,连接建立失败
- B收到了A的建立连接请求,然后返回应答,若A一直没有反应,则应答会发送多次
- A收到了B的确认应答,然后返回B一个应答,这个应答也许会丢,但是大部分情况下,A和B建立了连接之后,A会马上发送数据的,假如A发给B的应答丢了,当A后续发送的数据到达的时候,B可以认为这个连接已经建立。
- 建立连接后A一直不发送数据,若开启了keepalive机制,即使没有真实的数据包,也有探活包;服务端B针对长时间不发包的客户端,可以主动关闭
3、四次挥手的异常场景
首先A发送FIN断开连接,B返回响应值,此时A不会再发送数据,但B可能还有数据未处理完,B还是可以发送数据的,这个时候A可以选择不再接收数据了,也可以选择最后再接收一段数据,等待B也主动关闭。
等B处理完了之后,会发送FIN断开连接,A响应,整个连接就关闭了
几种异常场景:
- A发送FIN,B若一直没有回应,A会一直发送
- 等B响应后,A进入FIN_WAIT_2的状态,若B此时网络异常,则A就一直无法处理该状态,linux可以设置这个超时时间
- B发送FIN,A响应之后,若这个响应B一直未收到,则会重复发送FIN,如果A收到FIN后直接关闭连接,则A就无法收到重复发送的FIN,B就一直得不到响应,因而TCP协议要求A最后等待一段时间TIME_WAIT,这个时间要足够长,确保B收到ACK。
- TIME_WAIT还有一个作用是,可能B曾经发过的包还在路上,A若直接关闭连接,则这些包都收不到了,确保等待B发送的所有包都收到了。TIME_WAIT一般取2MSL,MSL是Maximum Segment Lifetime,报文最大生存时间,它是任何报文在网络上存在的最长时间,超过这个时间报文将被丢弃
- 若最后B超过了2MSL的时间,依然没有收到它发的FIN的ACK,此时A已经关闭连接了,B还在发送FIN,A若收到会返回一个RST(强制断开连接)
4、TCP状态机
略
TCP的其他特性
1、滑动窗口控制
TCP里,接收端会给发送端报一个窗口的大小,叫Advertised window(窗口探测字段),发送端的数据结构:
接收端也会维护一个数据结构,它内部只区分了三种数据:
- 接受已确认的数据(已经接受了但还没被应用层读取)
- 等待接受未确认的数据
- 未接受的数据
其中等待接受未确认的数据长度就是Advertised window,最大缓存的值=接受已确认的数据+等待接受未确认的数据
2、重试
重试有两层保证:
- 当某段数据的ACK没有收到时,经过一个重发超时时间,发送方就会将其重发,这个时间一般是要大于往返时间RTT,否则会引起不必要的重传。重传时间需要采样RTT进行估计,而且会不断变化,若还收不到则超时间隔加倍,以指数时间变化
- 依靠超时时间重发,等到超时重发经过的时间较长,比较短的方式是快速重传。当接收方收到一个序号大于下一个所期望的报文段时,就会检测到数据流中的一个间隔,于是它就会发送冗余的ACK,而当客户端收到三个冗余的ACK后,就会直接重传丢失的报文段
还有一种方式是SACK(Selective Acknowledgment),这种方式需要在TCP头里加一个SACK的东西,可以将缓存的地图发送给发送方,发送方就能立即感知到丢失的是哪个段
3、流量控制
发送端和接收端的发送和接受能力不匹配会影响效率,接收端主机告知发送端自己可以接受的数据大小,这个数据限度就是窗口大小。
当发送端发送过快时,它的缓冲区内就会充满了发送未确认的数据,从而无法发送新数据;当接受端接受过慢时,它的缓冲区内就会充满了接受已确认的数据(已经接受了但还没被应用层读取)
4、拥塞控制
发送的过程中,将拥塞窗口的大小和接收端主机通知的窗口大小比较,取其中的较小值作为发送窗口的大小,即:
LastByteSent - LastByteAcked <= min {cwnd, rwnd} ,其中拥塞窗口cwnd,滑动窗口rwnd。
滑动窗口rwnd是怕发送方把接收方缓存塞满,而拥塞窗口cwnd,是怕把网络塞满。
拥塞控制算法的主要问题:
- 丢包并不代表着通道满了,一旦出现丢包就降半不合理
- 理想模型中网络只有拥堵之后才会丢包,但此时降低速度已经来不及了
所以有了TCP BBR拥塞算法。它企图找到一个平衡点,就是通过不断地加快发送速度,将管道填满,但是不要填满中间设备的缓存,因为这样时延会增加,在这个平衡点可以很好的达到高带宽和低时延的平衡
Socket编程
略,等待新笔记
应用层
HTTP
HTTP是基于TCP的,每次连接都要经历三次握手,为了在一个连接中多请求几次,HTTP可以采用持久连接
HTTP/1.1版本是默认持久连接的:
Connection:Keep-Alive
HTTP请求报文组成:请求行+各种首部+实体
对于高并发的系统,在真正的业务逻辑之前,都需要有一个接入层,将静态资源的请求拦截:
在nginx这一层,对于静态资源,有Vanish缓存层。当缓存过期的时候,才会访问真正的Tomcat应用集群。 这也就是Cache-Control的作用。
HTTP响应报文组成:状态行+各种首部+实体
HTTP2.0
HTTP 2.0会对HTTP的头进行一定的压缩,将原来每次都要携带的大量key value在两端建立一个索引表,对相同的头只发送索引表中的索引
HTTP2.0还会将一个TCP连接中,切分成多个流,每个流都有自己的ID。流还能被切分为更小的消息,对它们采用二进制格式编码,比如Header帧(用于传输Header内容)、Data帧(用来传输实体信息),通过流和帧,HTTP2.0可以将多个请求分到不同的流中,然后再将请求内容拆成帧,进行二进制传输,这些帧可以打散乱序发送,然后根据每个帧首部的流标识符进行重新组装,根据优先级决定先处理哪个流的数据。
比如要发送三个独立的请求:一个获取css,一个获取js,一个获取图片jpg,HTTP2.0可以在一个连接中,将每个请求包装成流,然后每个流再分为帧乱序发送,但处理几个请求是按顺序的:
HTTP2.0不用借助pipeline机制用多条TCP连接来实现并行请求与响应,减少了TCP连接数对服务器性能的影响。
QUIC
HTTP 2.0存在一个问题:TCP协议在处理包是严格按照顺序的,前面stream 2的帧没有收到,会不断重传,后面stream 1的帧也会因此阻塞。
QUIC是基于UDP的应用层协议:
- 它是面向连接的,但并非是TCP的四元组标识,而是用一个随机的UUID,避免了网络变化时需要TCP重连的问题
- 它有自定义的重传机制,是在应用层实现的,它也有offset和应答的概念
- 它使一个连接上的stream之间没有依赖,假如stream2丢了一个UDP包,后面跟着stream3的一个UDP包,虽然stream2的那个包需要重传,但是stream3的包无需等待,就可以发给用户
- 它也有窗口机制,它的ACK是基于offset的,每个offset收到后就可用应答,然后就不会重发,中间的空档会等待到来或重发
HTTPS
只要是对称加密,就有密钥如何传递的问题,需要非对称加密算法来协助,但非对称加密算法效率不高。
非对称加密的公钥会放在证书中,证书需要一个权威机构颁发认证,这就是CA( Certificate Authority)。
HTTPS的过程:
1、客户端发送Client Hello消息,包含协议版本、加密算法、压缩算法等信息,还有一个随机数
2、服务器返回Server Hello消息, 包含协议版本、加密算法、压缩算法等信息,还有一个随机数
3、服务器发送证书给客户端
4、客户端验证证书的可信,拿CA的证书里面的公钥去解密服务器的证书,如果能成功,说明是可信的。为了保证CA证书中的公钥可信,还需要向上追溯CA的CA,直到可信为止
5、证书验证完毕后,客户端计算产生随机数字Pre-master,发送Client Key Exchange,并用证书中的公钥加密
6、客户端和服务器都有了三个随机数:自己的、对端的,以及刚生成的Pre-Master随机数。通过这三个随机数,可以在客户端和服务器产生相同的对称密钥
7、后续通信采用该对称密钥加密传输
上面的过程只包含了HTTPS的单向认证,也即客户端验证服务端的证书,是大部分的场景,也可以在更加严格安全要求的情况下,启用双向认证,双方互相验证证书
DNS
DNS服务器的作用是把域名转化为IP地址。
DNS服务器的流量很大,它是高可用、高并发和分布式的,DNS服务器是树状结构的。
DNS解析时,首先电脑会向本地域名服务器(本地DNS,一般是网络服务商ISP)询问,若它缓存了则返回,若没有它会继续向根域名服务器询问,根域名服务器是最高层次的服务器,它不直接用于域名解析,而是吧请求转发到对应的顶级域名服务器(专门解析.com的或者.net的),顶级域名服务器最后会询问权威DNS服务器,它是域名解析结果的原出处,最后会由他返回解析结果:
DNS除了解析域名,还可以做负载均衡,一个域名可能对应多个IP地址,它会优先返回一个距离比较近的IP地址。
解析域名时可以设置,第一次解析返回第一个IP,第二次解析返回第二个IP,这就实现了不同客户端访问不同服务器的方法,这就是一个简单的负载均衡。
当某个服务器挂了,DNS服务器会将这个IP地址删除,可以实现一定的高可用。
全局负载均衡器(GSLB,Global Server Load Balance)可以根据用户地理位置,返回距离较近的IP地址。
HttpDNS
传统DNS的问题:
1、缓存问题:域名对应的结果会缓存起来,每次请求时都会返回缓存数据,有些运营商会把一些静态页面缓存起来,当页面更新时返回的还是旧的结果,缓存也会让全局负载均衡失败,即使有更近的服务器地址,还是会返回缓存中的地址。
2、域名转发问题:有些DNS服务器会转发到其他运营商的DNS服务器,返回了一个其他运营商的网址,结果是每次访问都要跨运营商,速度很慢
3、解析慢:一次解析过程要递归遍历多个DNS服务器
HttpDNS是自己搭建的基于HTTP协议的DNS服务器集群,分布在多个地点和多个运营商。当客户端需要DNS解析的时候,直接通过HTTP协议进行请求这个服务器集群,得到就近的地址。
CDN
CDN分发网络,它的架构是一层一层的,访问网站时优先访问边缘节点,若缓存未命中则访问区域节点,最终只能回源网站访问。它的思想是能不访问真正的网址就不访问,提升网站访问速度。
从下到上,边缘节点的缓存最少,命中概率也最小;中心节点缓存最多,命中概率最大:
进行DNS解析时,要将域名www.web.com 解析为IP地址,权威DNS服务器会设置一个CHAME别名,指向另外一个域名如www.web.cdn.com ,本地DNS服务器继续解析这个域名,此时访问的就是web.cdn.com的权威DNS服务器了,它会再设置一个CHAME别名,指向另外一个域名,也即CDN网络的全局负载均衡器。
全局负载均衡器会为其分配一台缓存服务器的地址,它就是CDN分发网络的边缘节点。
CDN缓存的内容主要是静态资源,它们不怎么变化,比较适合缓存。
CDN还提供了以下特性:
- 主动推送缓存:从区域节点更新边缘节点的缓存
- 预处理服务:内容返回前进行预处理,如超清、标清、流畅等
- 防盗链:防止被别人盗走缓存
DHCP协议
DHCP发现包是没有源IP地址的,只有MAC地址。DHCP服务器通过MAC地址的唯一性发现这是一台新机器,DHCP提供包依然使用广播地址作为目标地址。当DHCP服务器有多个时,新机器有可能收到多个DHCP提供包,此时它会按照最先到达的那个来应用吗,然后设备发送DHCP请求包确认接收该IP地址,同时告知其他DHCP服务器放弃其他选择,此时由于还没有得到DHCP服务器的确认,还是以0.0.0.0为源IP地址,广播地址来发送。最后DHCP服务器广播返回一个DHCP提供包,宣布IP地址注册成功。
DHCP服务器不仅能自动分配IP地址,还能帮助设备自动安装操作系统,常用于多台空机器的安装配置。安装操作系统的过程在BIOS启动之后,这个过程被称为预启动执行环境(Pre-boot Execution Environment),简称PXE。要完成这个操作首先DHCP服务器要配置PXE服务器的地址和启动文件的位置,PXE的工作过程:
1、BIOS启动后,会将PXE客户端调入内存,它会连接DHCP服务器获取IP地址,并告知没有操作系统
2、DHCP服务器返回给它一个IP地址和PXE服务器的地址、启动文件的位置
3、机器连接到PXE服务器获取到启动文件并在本机器执行,继续向PXE服务器请求系统的其他信息,然后安装并启动操作系统
修订内容
3层交换机:(所谓的x层设备,就是在处理网络数据时解除几个首部然后再处理里面的数据,比如二层设备就是拿掉MAC头,三层设备就是拿掉MAC头和IP头)
CIDR:自由的划分网络号和主机号,如10.100.122.2/24 代表前24位是网络号。子网掩码 和 IP地址按位与,可以得到网络号
IP地址和MAC地址:有了MAC为什么还要有IP?因为MAC本身没有定位功能(它虽然也有一定规律,比如厂商号),不可能根据MAC地址获取网络号,它只能在一个子网内部靠ARP协议拥有一定定位功能。
ARP协议的应用场景:只有目标IP地址和源IP地址是同一个网段的,才会用ARP去获取它的MAC地址,没有MAC地址包是发不出去的;若是跨网段的,应该将包发给网关,然后由网关处理(网关肯定和本机是一个网段的,网关需要提前配置,一般是一个网段中的第一个,如192.168.1.0/24这个网段,网关往往会是192.168.1.1/24)
ARP协议的使用:
IP层需要查看目标地址和自己是否是在同一个局域网。如果是,就发送ARP协议来请求这个目标地址对应的MAC地址,然后将源MAC和目标MAC放入MAC头,发送出去即可;如果不在同一个局域网,就需要发送到网关,还要需要发送ARP协议,来获取网关的MAC地址,然后将源MAC和网关MAC放入MAC头,发送出去。
网关收到包发现MAC符合,取出目标IP地址,根据路由协议找到下一跳的路由器,获取下一跳路由器的MAC地址,将包发给下一跳路由器。
这样路由器一跳一跳终于到达目标的局域网。这个时候,最后一跳的路由器能够发现,目标地址就在自己的某一个出口的局域网上。于是,在这个局域网上发送ARP,获得这个目标地址的MAC地址,将包发出去。
改变IP地址(私有转公有)的网关被称为NAT网关;不改变IP地址的就是转发网关;而MAC地址只要过网关,就必定会改变,因为已经换了局域网。