既然TCP要对包进行重传,就需要维护一个Sequence Number,看哪些包到了,哪些没到,哪些需要重传,传输的速度应该控制到多少,这就是TCP的滑动窗口协议。
整个TCP的发送,一开始会协商一个Sequence Number,从这个Sequence Number开始,每个包都有编号。滑动窗口将接收方的网络包分成四个部分:
已经接收,已经ACK,已经交给应用层的包;
已经接收,已经ACK,未发送给应用层;
已经接收,尚未发送ACK;
未接收,尚有空闲的缓存区域。
对于TCP层来讲,每一个包都有ACK。ACK需要从SLB回复到手机端,将上面的那个过程反向来一遍,当然路径不一定一致,可见ACK也不是那么轻松的事情。
如果发送方超过一定的时间没有收到ACK,就会重新发送。只有TCP层ACK过的包,才会发给应用层,并且只会发送一份,对于下单的场景,应用层是HTTP层。
你可能会问了,TCP老是重复发送,会不会导致一个单下了两遍?是否要求服务端实现幂?从TCP的机制来看,是不会的。只有收不到ACK的包才会重复发,发到接收端,在窗口里面只保存一份,所以在同一个TCP连接中,不用担心重传导致二次下单。
但是TCP连接会因为某种原因断了,例如手机信号不好,这个时候手机把所有的动作重新做一遍,建立一个新的TCP连接,在HTTP层调用两次RESTful API。这个时候可能会导致两遍下单的情况,因而RESTful API需要实现幂等。
当ACK过的包发给应用层之后,TCP层的缓存就空了出来,这会导致上面图中的大三角,也即接收方能够容纳的总缓存,整体顺时针滑动。小的三角形,也即接收方告知发送方的窗口总大小,也即还没有完全确认收到的缓存大小,如果把这些填满了,就不能再发了,因为没确认收到,所以一个都不能扔。
8.从数据中心进网关,公网NAT成私网
包从手机端经历千难万险,终于到了SLB的公网IP所在的公网网口。由于匹配上了MAC地址和IP地址,因而将网络包收了进来。
在虚拟网关节点的外网网口上,会有一个NAT规则,将公网IP地址转换为VPC里面的私网IP地址,这个私网IP地址就是SLB的HAProxy所在的虚拟机的私网IP地址。
当然为了承载比较大的吞吐量,虚拟网关节点会有多个,物理网络会将流量分发到不同的虚拟网关节点。同样HAProxy也会是一个大的集群,虚拟网关会选择某个负载均衡节点,将某个请求分发给它,负载均衡之后是Controller层,也是部署在虚拟机里面的。
当网络包里面的目标IP变成私有IP地址地址之后,虚拟路由会查找路由规则,将网络包从下方的私网网口发出来。这个时候包的格式为:
源MAC:网关MAC;
目标MAC:HAProxy虚拟机的MAC;
源IP:UE的公网IP;
目标IP:HAProxy虚拟机的私网IP。
9.进入隧道打标签,RPC远程调用下单
在虚拟路由节点上,也会有OVS,将网络包封装在VXLAN隧道里面,VXLAN ID就是给你的租户创建VPC的时候分配的。包的格式为:
外层源MAC:网关物理机MAC;
外层目标MAC:物理机A的MAC;
外层源IP:网关物理机IP;
外层目标IP:物理机A的IP;
内层源MAC:网关MAC;
内层目标MAC:HAProxy虚拟机的MAC;
内层源IP:UE的公网IP;
内层目标IP:HAProxy虚拟机的私网IP。
在物理机A上,OVS会将包从VXLAN隧道里面解出来,发给HAProxy所在的虚拟机。HAProxy所在的虚拟机发现MAC地址匹配,目标IP地址匹配,就根据TCP端口,将包发给HAProxy进程,因为HAProxy是在监听这个TCP端口的。因而HAProxy就是这个TCP连接的服务端,客户端是手机。对于TCP的连接状态,滑动窗口等,都是在HAProxy上维护的。
在这里HAProxy是一个四层负载均衡,也即他只解析到TCP层,里面的HTTP协议他不关心,就将请求转发给后端的多个Controller层的一个。
HAProxy发出去的网络包就认为HAProxy是客户端了,看不到手机端了。网络包格式如下:
源MAC:HAProxy所在虚拟机的MAC;
目标MAC:Controller层所在虚拟机的MAC;
源IP:HAProxy所在虚拟机的私网IP;
目标IP:Controller层所在虚拟机的私网IP。
当然这个包发出去之后,还是会被物理机上的OVS放入VXLAN隧道里面,网络包格式为:
外层源MAC:物理机A的MAC;
外层目标MAC:物理机B的MAC;
外层源IP:物理机A的IP;
外层目标IP:物理机B的IP;
内层源MAC:HAProxy所在虚拟机的MAC;
内层目标MAC:Controller层所在虚拟机的MAC;
内层源IP:HAProxy所在虚拟机的私网IP;
内层目标IP:Controller层所在虚拟机的私网IP。