收藏 分享(赏)

TCP迁移技术报告.PDF

上传人:精品资料 文档编号:7175711 上传时间:2019-05-08 格式:PDF 页数:65 大小:733.28KB
下载 相关 举报
TCP迁移技术报告.PDF_第1页
第1页 / 共65页
TCP迁移技术报告.PDF_第2页
第2页 / 共65页
TCP迁移技术报告.PDF_第3页
第3页 / 共65页
TCP迁移技术报告.PDF_第4页
第4页 / 共65页
TCP迁移技术报告.PDF_第5页
第5页 / 共65页
点击查看更多>>
资源描述

1、 第 I 页 TCP 迁移技术报告 汪 黎 第 II 页 目录 图目录 V 表目录 .VI 摘要 . VII ABSTRACT.VIII 第一章 绪论 .1 1.1 研究背景 1 1.2 研究现状 2 1.2.1 当前流行的集群调度技术 .2 1.2.2 正在开展的研究项目 .5 1.3 报告的组织 6 第二章 Linux 的网络实现 7 2.1 网络设备接口层 7 2.2 网络接口核心层 8 2.3 网络协议层 9 2.4 网络接口 Socket 层 . 11 2.5 本章小结 13 第三章 基于 Netfilter 的 TCP 迁移方法 14 3.1 Netfilter 框架简介 14 3

2、.1.1 Netfilter 框架的结构和功能 .14 3.1.2 Netfilter 的应用实例: Linux 防火墙 .16 3.2 基于 Netfilter 的 TCP 迁移方法 .17 3.2.1 技术思想概述 .17 3.2.2 连接的建立过程 .17 3.2.3 连接的通信过程 .20 3.2.4 连接的取消过程 .20 3.3 测试 21 3.4 本章小结 22 第 III 页 第四章 基于连接修改和传递技术的 TCP 迁移方法 23 4.1 技术思想概述 23 4.2 连接传递技术 24 4.3 本章小结 25 第五章 基于重构连接现场的 TCP 迁移方法 26 5.1 技术实

3、现背景 26 5.1.1 网络相关系统调用的内部实现 .26 5.1.2 TCP 连接的建立过程 .30 5.1.3 网络缓冲区的基本操作 .32 5.2 技术实现概述 36 5.3 技术实现难点 37 5.3.1 Handoff 协议 .37 5.3.2 连接现场重构 .37 5.3.3 HTTP 请求报文零拷贝传递 .38 5.4 本章小结 39 第六章 对持久连接( P-HTTP)的支持 .40 6.1 概述 40 6.1.1 提出背景 .40 6.1.2 持久连接协议( P-HTTP)概述 .40 6.1.3 持久连接带来的问题 .41 6.1.4 国际上的解决办法 .41 6.2 技

4、术思想概述 42 6.3 实现算法 42 6.3.1 一次迁移过程 .42 6.3.2 多次迁移过程 .43 6.4 BE 调度技术 .44 6.5 本章小结 45 第七章 大规模基于请求内容分发的系统 TCPHA.46 7.1 系统体系结构 46 7.2 系统工作过程 46 第 IV 页 7.3 系统实现的关键技术 47 7.3.1 服务器体系结构 .47 7.3.2 ARP 问题及其解决方案: ARP 过滤 50 7.3.3 动态 IP 隧道技术 .51 7.4 性能测试与比较 52 7.5 本章小结 52 第八章 总结与展望 .53 参考文献 .54 第 V 页 图目录 图 1. 1 服

5、务器集群的结构 .1 图 3. 1 Netfilter HOOK 位置 15 图 3. 2 三方之间的 TCP 连接 19 图 3. 3 CommView 显示的测试结果 .21 图 3. 4 浏览器显示的测试结果 22 图 4. 1 Linux 网络相关数据结构实现 24 图 5. 1 基本 TCP 客户 -服务器程序编程模型 .27 图 5. 2 socket 系统调用实现 28 图 5. 3 TCP 连接建立过程 -服务器方 .30 图 5. 4 TCP 连接建立过程 -客户方 .31 图 5. 5 sk_buff 与网络报文之间的关系 33 图 5. 6 sk_buff_head 与

6、sk_buff 的关系 34 图 5. 7 LINUX 2.4 的 sk_buff 与网络报文之间的关系 .35 图 5. 8 基于连接现场重建的 TCP 迁移方法 .37 图 5. 9 Handoff 请求报文格式 .37 图 5. 10 Handoff 响应报文格式 .37 图 6. 1 支持 P-HTTP 的集群调度技术 41 图 7. 1 TCPHA 系统体系结构 .46 图 7. 2 TCPHA 系统报文交换时序图 .47 图 7. 3 TCPHA 调度器处理请求的简单步骤 .48 图 7. 4 多进程结构 48 图 7. 5 多线程结构 49 图 7. 6 单进程事件驱动结构 49

7、 图 7. 7 多线程事件驱动结构 50 第 VI 页 表目录 表 7. 1 TCPHA 与 Squid,KTCPVS 性能比较 .52 第 VII 页 摘要 本文首先介绍了国际上流行的集群调度技术,指出了实现 TCP 迁移技术的较大意义。然后,本文分析了 Linux 网络源代码的框架,逻辑上的各层间的功能和接口;分析了网络服务器的编程模型及相关系统调用的操作系统实现; 分析了 TCP 连接的建立过程; 接下来,本文提出了三种实现 TCP 迁移的方法,这三种方法是:基于 Netfilter 的 TCP 迁移方法;基于连接修改和传递的 TCP 迁移方法;基于重建连接现场的 TCP 迁移方法;还提

8、出了解决持久连接问题的方法:多重迁移算法( multi-handoff) 。最后,本文介绍了基于连接现场重建 TCP 迁移方法的服务器集群调度系统的实现。 关键词:操作系统, Linux, 服务器集群系统 , TCP 迁移 第 VIII 页 ABSTRACT At first,the popular server cluster scheduling technologies is introduced,the significance of implementing TCP Handoff is pointed out.We analysis the framework of Linux n

9、etwork source codes and the function and interface between each layer in logic.and on the analysis of the programming model of network servers and implementing of interrelated system calls and the course of TCP connection establishing,we present three technologies of implementing TCP Handoff,which a

10、re TCP Handoff based Netfilter;TCP Handoff based connection modifying and connection transfering;TCP Handoff based connection locale reconstructing。 We also present a algorithm to support P-HTTP effectively,which is named multi-handoff algorithm.At last,a server cluster scheduling system is introduc

11、ed,which is based the key technology:TCP Handoff based connection locale reconstructing. Key words: Operating System, Linux, Server Cluster System, TCP Handoff 第 1 页 第一章 绪论 1.1 研究背景 随着 Internet 在世界各地的飞速普及和发展,网络服务器的负载越来越重。解决网络服务的可伸缩性和可靠性已是非常紧迫的问题。通过高性能网络或局域网互联的服务器集群 (Server Cluster)已成为实现高可伸缩、高可用网络服务的

12、有效结构。服务器集群的结构如图 1.1 所示,它通常由一台前端调度器(简写为 FE,下同)和若干台后端服务器(简写为BE,下同)组成,彼此之间通过高性能网络互联。整个集群共享一个虚拟 IP 地址,集群中只有 FE 对客户方可见,集群对客户方看来就像是一台高性能的服务器。所有的客户请求首先到达 FE,由 FE 将请求根据一定的负载平衡算法分发给 BE。采用集群技术的系统有以下优点: 图 1. 1 服务器集群的结构 z 性能 网络服务的工作负载通常是大量相互独立的任务,通过一组服务器分而治之,可以获得很高的整体性能。 z 性能 /价格比 组成集群的 PC 服务器或 RISC 服务器和标准网络设备因

13、为大规模生产,价格低,具有很高的性能价格比。若整体性能随着结点数的增长而接近线性增加, (这极大地依赖于集群调度系统)该系统的性能 /价格比接近于 PC 服务器。所以,这种松耦合结构比紧耦合的多处理器系统具有更好的性能 /价格比。 z 可伸缩性 集群中的结点数目可以增长到成千上万个,其伸缩性远超过单台超级计算机。 z 高可用性 在硬件和软件上都有冗余,通过检测软硬件的故障,将故障屏蔽,由存活结点提供服务,可实现高可用性。 但是,用集群系统来提供可伸缩网络服务是有难度的,表现在: z 透明性( Transparency) 第 2 页 如何高效地使得由多个计算机组成的松藕合的集群系统构成一个虚拟服

14、务器;客户端应用程序与集群系统交互时,就像与一 台高性能、高可用的服务器交互一样,客户端无须作任何修改。部分服务器的切 入和切出不会中断服务,这对用户也是透明的。 z 性能( Performance) 性能要接近线性加速,这需要设计很好的软硬件的体系结构,消除系统可能存在的瓶颈。将负载较均衡地调度到单个服务器上。 z 高可用性( Availability) 需要设计和实现很好的系统资源和故障的监测和处理系统。 当发现一个模块失效时,要将模块上提供的服务迁移到其他模块 上。在理想状况下,这种迁移是即时的、自动的。 z 可管理性( Manageability) 要使集群系统变得易管理,就像管理一个

15、单一系统一样。在理想状况下,软硬件模块的插入能做到即插即用( Plug connect(socket_descriptor,地址 ,端口 ); send(socket_descriptor,” hello world” ); recv(socket_descriptor,buffer,1024,0); 第一个系统调用指定了协议族为 Inet 协议族 (由参数 AF_INET 指定) , 即 TCP/IP 协议,同时是利用面向连接的服务(由参数 SOCK_STREAM 指定) ,这样就对应到 TCP 协议,以后的操作就是利用 Socket 的标准函数进行的。 从上面我们可以看到两个问题,首先 S

16、ocket 层需要根据用户指定的协议族 (上面是AF_INET) 从 32 种协议族中选择一种协议族来完成用户的要求,当协议族确定以后,还要把特定的服务映射到协议族下的具体协议,例 如当用户指定的是面向连接的服务时, Inet协议族会映射到 TCP 协议。 从多个协议中选择用户指定的协议,并把具体 的处理交给选中的协议,这与网络接口第 12 页 核心层向上和向下衔接的问题本质上是一样的,所以解决的方法也是一样的,同样还是通过数组。在 Linux/net/socket.c 定义了这个数组 static struct net_proto_family*net_familiesNPROTO 。 其中

17、 net_families2是 TCP/IP 协议, net_families3是 X.25 协议,具体哪一项对应什么协议,在 include/linux/socket.h 有定义。但是每一项的数据结构 net_proto_family的 ops域是空的, 也就是具体协议族处理函数的地址是不知道的。协议的处理函数和 ops 域建立联系是通过 sock_register()(Linux/net/socket.c)这个函数建立的,例如 TCP/IP 协议是这样建立关系的: int _init inet_init(void) (net/ipv4/af_inet.c) (void) sock_regi

18、ster( 只要给出 AF_INET(在宏里定义是 2),就可以找到 net_failies2 里面的处理函数了。 协议的映射完成了,现在要进行服务的映射了 。根据系统分层设计的思想,上层不需要知道下层的什么协议能对应特定的服务,这种映射由协议族自己完成。在 TCP/IP 协议族里, 这种映射是通过 struct list_head inetswSOCK_MAX( net/ipv4/af_inet.c)这个数组进行的,在谈论这个数组之前先看另外一个数组 inetsw_array(net/ipv4/af_inet.c),该数组是静态定义的,从其定义中可以看到: SOCK_STREAM 映射到了

19、TCP 协议, SOCK_DGRAM 映射到了 UDP 协议, SOCK_RAW 映射到了 IP 协议。现在只要把 inetsw_array 里的三项添加到数组 inetswSOCK_MAX就可以了,添加是通过函数 inet_register_protosw()实现的。在inet_init()(net/ipv4/af_inet.c) 里完成了这些工作。 还有一个需要映射的就是 socket,诸如 accept,send,connect,release,bind 等的操作函数是怎么映射的呢?是通过上面的 inetsw_array 数组中的项的 ops 和 prot 域来映射的。例如,对应 TCP

20、 协议的项的 prot 域为 tcp_prot, tcp_prot 中的 connect 函数指针域赋值为tcp_v4_connect。因此,用户调用 connect()函数,其实就是调用了 tcp_v4_connect()函数。 现在讲述网络接口 Socket 层和用户层的衔接。 系统调用 socket(),bind(),connect(),accept(),send(),release()等是在 Linux/net/socket.c 里面实现的 ,系统调用对应的实现函数是相应的函数名加上 sys_的前缀。 现在看看当用户调用 socket()这个函数进行的工作: socket(AF_INE

21、T,SOCK_STREAM,0)调用了 sys_socket(),sys_socket()接着调用 socket_creat(),socket_creat()就会根据用户提供的协议族参数在 net_families里寻找合适的协议族,如果协议族没有被安装就要请求安装该协议族的模块,然后就调用该协议族的 create()函数的处理句柄。根据参数 AF_INET,inet_creat()就被调用了, inet_creat()根据服务类型在数组 inetswSOCK_MAX中选择合适的第 13 页 协议,并把协议的操作集赋给 socket,根据 SOCK_STREAM, TCP 协议被选中: ine

22、t_creat() answer=inetsw 用户要求服务服务 ; sock-ops = answer-ops; sk-prot = answer-prot 对于其它的系统调用实现函数,将在后面的章节中讲述。 2.5 本章小结 本章简要介绍了 Linux 内核源代码中网络部分的总体框架。 Linux 的网络代码实现非常好地遵循分层设计原则,根据代码功能的逻辑结构,网络代码大致可分为四层: z 网络设备接口层 z 网络接口核心层 z 网络协议层 z 网络接口 Socket 层 Linux 网络代码的良好的组织和编程风格,非常便于阅读,也非常利于在其上做开发。 第 14 页 第三章 基于 Net

23、filter 的 TCP 迁移方法 在 Linux 内核 2.4 中,引入了一个最新的编程框架: Netfilter。它提供了非常好的接口用于抓取、截获、分析网络上的数据包。基于 Netfilter 的 Linux 防火墙,有着非常优秀的性能。 本章首先介绍 Netfilter 编程框架,然后提出基于 Netfilter 框架的 TCP 迁移方法,并给出测试结果。 3.1 Netfilter 框架简介 3.1.1 Netfilter 框架的结构和功能 Netfiler 框架是随着 Linux 防火墙技术的发展而诞生的。 Linux 的防火墙技术经历了若干代的沿革,最早使用的 ipfwadm 是

24、 Alan Cox 在 Linux 发展的初期,从 FreeBSD 的内核代码中移植过来的。后来经历了 ipchains,再经由 Paul Russell 在 Linux kernel 2.3 系列的开发过程中发展了 Netfilter 这个架构。而用户空间的防火墙管理工具,也相应的发展为 iptables。它提供了对 2.0.x 内核中的 ipfwadm 以及 2.2.x 内核中的 ipchains 的兼容。Netfilter/iptables 这个组合目前相当的令人满意。在经历了 Linux kernel 2.4 和 2.5 的发展以后,的确可以说, Netfilter/iptables

25、经受住了大量用户广泛使用的考验。 Netfilter 在 Linux 内核中的 IPv4、 IPv6 和 DECnet 等网络协议栈中都有相应的实现。在编译 Linux 内核时, Netfilter 作为一个在编译过程中可选的部件。 在 IPv4 协议栈中,为了实现对 Netfilter 架构的支持,在 IP 数据包在 IPv4 协议栈中的游历路线之中,仔 细选择了五个钩挂( HOOK)点。在这五个钩挂点上,各引入了一行对 NF_HOOK() 宏函数的一个相应的调用。这五个钩挂点被分别命名为 PREROUTING, LOCAL-IN, FORWARD, LOCAL-OUT 和 POSTROUT

26、ING。它们的含义如下: NF_IP_PRE_ROUTING:在接收到的报文作路由之前; NF_IP_FORWARD:在接收到的报文转向另一个 NIC(转发)之前; NF_IP_POST_ROUTING:在报文发送之前; NF_IP_LOCAL_IN:在接收到的报文作路由,确定是本机接收的报文之后; NF_IP_LOCAL_OUT:在本地报文作发送路由之前。 如图 3.1 所示: 第 15 页 图 3. 1 Netfilter HOOK 位置 NF_HOOK() 这个宏函数,定义在 linux-2.4.19/include/linux/netfilter.h 里面 ,它的实现代码如下: #if

27、def CONFIG_NETFILTER #define NF_HOOK(pf, hook, skb, indev, outdev, okfn) nf_hook_slow(pf), (hook), (skb), (indev), (outdev), (okfn) #else #define NF_HOOK(pf, hook, skb, indev, outdev, okfn) (okfn)(skb) #endif /*CONFIG_NETFILTER*/ 从该宏函数的实现可知,当 #ifdef CONFIG_NETFILTER 这个条件编译被满足的时候,就转去调用 nf_hook_slow()

28、 函数;如果 CONFIG_NETFILTER 没有被定义,则调用NF_HOOK 宏中的参数 okfn, 这实际上是一个函数指针, 指出从 Netfilter 模块转回到 IPv4 协议栈,继续往下处理时要执行的函数。如果 CONFIG_NETFILTER 被定义,执行nf_hook_slow() 函数的最后,实际上也会调用 okfn。这样就给了用户在编译内核的时候一个选项,可以通过定义 CONFIG_NETFILTER 与否来决定是否把 Netfilter 支持代码编译进内核。现在来看一下 NF_HOOK 宏即 nf_hook_slow()的调用时机。 其中一个调用的地方是 ip_rcv()

29、函数,它是 IP 层接收报文的总入口,函数的代码如下: ip_rcv() return NF_HOOK(PF_INET, NF_IP_PRE_ROUTING, skb, dev, NULL, ip_rcv_finish); ip_rcv()只是对接收到的 IP 报文进行了一下校验和检查,没有对其进行路由,然后就调用了 nf_hook_slow() 函数。 nf_hook_slow()函数的主要功能就是根据 pf 和 hook 参数(这里分别为 PF_INET,NF_IP_PRE_ROUTING) ,索引数组 nf_hooks。 nf_hooks 是一个二维数组,定义如下: struct lis

30、t_head nf_hooksNPROTONF_MAX_HOOKS。可见数组中每个元素为一个链表头元素,即每个数组元素可以延伸出一个链表。链表中每个元素为一个nf_hook_ops 结构。 nf_hook_slow()函数在索引得到对应的链表后,它会遍历这个链表,对第 16 页 链表中的每个元素,执行其 hook 函数。并根据 hook 函数的返回值,决定对 IP 数据包进行的下一步处理。 Hook 函数可以有五种返回值,它们对应的意义如下: NF_ACCEPT:继续正常的报文处理; NF_DROP:将报文丢弃; NF_STOLEN:由 hook 函数处理了该报文,不再继续传送; NF_QUE

31、UE:将报文入队,通常交由用户程序处理; NF_REPEAT:再次调用该 hook 函数。 如果 hook 函数返回的值是 NF_ACCEPT,则 nf_hook_slow()函数调用它参数中的 okfn函数,这里为 ip_rcv_finish 函数,继续协议栈对报文的处理。其它返回值对应的处理如上所述。可见,用户可以通过在链表中加入自己的处理函数( hook 函数) ,使得协议栈在处理报文的典型阶段,调用用户自己的处理函数,并由用户决定协议栈是否对该报文进行继续处理。 向 nf_hooks 数组登记处理函数是通过 nf_register_hook()实现的。用户通过填充一个nf_hook_o

32、ps 结构,指出该函数的调用点(五个钩挂点之一)和对应的处理函数。然后以该结构的指针为参数,调用 nf_register_hook()函数即可实现向系统注册自己的处理函数。 3.1.2 Netfilter 的应用实例:Linux 防火墙 现在来看 Linux 的防火墙的结构。 Linux 的防火墙由 iptables 和 Netfilter 两大部分组成。Netfilter 提供在网络协议栈处理流程的典型点上注册处理函数的功能。 Iptables 则存储处理规则。 Iptables 是通过 table(表)来组织防火墙规则的,一个 table 就是一组类似的防火墙规则的集合。 iptables

33、 里面默认定义了三个 table: filter, mangle 和 nat,绝大部分报文处理功能都可以通过在这些内建( built-in)的表格中填入 rule(规则)完成。 filter,该模块的功能是过滤报文,不作任何修改,或者接受,或者拒绝。它在NF_IP_LOCAL_IN、 NF_IP_FORWARD 和 NF_IP_LOCAL_OUT 三处注册了 hook 函数,也就是说,所有报文都将经过 filter 模块的处理。 nat,网络地址转换( Network Address Translation) ,该模块以 Connection Tracking 模块为基础,仅对每个连接的第一个

34、报文进行匹配和处理,然后交由 Connection Tracking 模块将处理结果应用到该连接之后的所有报文。 nat 在 NF_IP_PRE_ROUTING 、NF_IP_POST_ROUTING 注册了 hook 函数,如果需要,还可以在 NF_IP_LOCAL_IN 和NF_IP_LOCAL_OUT 两处注册 hook 函数,提供对本地报文(出 /入)的地址转换。 nat 仅对报文头的地址信息进行修改,而不修改报文内容,按所修改的部分, nat 可分为源 NAT( SNAT)和目的 NAT( DNAT)两类,前者修改第一个报文的源地址部分,而后者则修改第 17 页 第一个报文的目的地址

35、部分。 SNAT 可用来实现 IP 伪装,而 DNAT 则是透明代理的实现基础。 mangle,属于可以进行报文内容修改的 IP Tables,可供修改的报文内容包括 MARK、TOS、 TTL 等, mangle 表的操作函数嵌入在 Netfilter 的 NF_IP_PRE_ROUTING 和NF_IP_LOCAL_OUT 两处。 内核编程人员还可以通过注入模块,调用 Netfilter 的接口函数创建新的 iptables。 3.2 基于 Netfilter 的 TCP 迁移方法 3.2.1 技术思想概述 该技术的主要思想是通过 Netfilter 框架的支持,模拟成客户,在 BE 上“

36、重现”连接的建立过程,即在 FE 上复制并缓存客户方在连接建立过程中发送来的报文。在决定迁移的 BE 后,通过 IP 隧道,将这些报文封装后发送给 BE, BE 根据 IP 隧道协议解开封装后,报文被 TCP 迁移系统的内核模块所截获,模块从中依次提取出各个报文,然后伪装成客户与 BE 的协议栈进行三次握手过程,使连接从 FE 迁移到 BE 上。其中根据客户方发出的ACK 报文,可以推测出 FE 的序列号,这样可以通过两种方法使 BE 的序列号与 FE 一致: ( 1) 由 BE 上的内核模块每次截获该连接上的报文,修改序列号,使其在客户方和 BE 看来保持一致,然后再传送给 BE 的协议栈正

37、常处理。这种方法的优点是与具体操作系统实现无关,对操作系统协议栈透明,对上层应用透明,甚至不需要代码在内核运行,只要操作系统提供截取数据包的相应功能即可。这一优点也使得该技术也可在基于 Windows的操作系统中采用。 ( 2) 由 BE 上的内核模块直接修改内存中的 TCP 协议实现的相关数据结构的序列号 域。这种方法的优点是“一劳永逸” ,但与具体操作系统实现相关。 利用 Netfilter 框架支持,在集群 FE 和 BE 上,分别挂接 IP 报文遍历的 IP_LOCAL_IN链和 IP_LOCAL_OUT 链两处,用于截取 /改写 TCP 报文。挂接 IP_LOCAL_IN 链,将截获

38、所有发送给本机的 IP 报文。而挂接 IP_LOCAL_OUT 链,将截获所有本机将要发出的 IP报文。在 FE 上,模块的功能主要是记录连接,迁移信息,分析 HTTP 请求内容,转发报文给 BE。在 BE 上,则主要是改写序列号,丢弃某些响应报文,以达到“欺骗” BE 的目的。通过这些方法,来实现 TCP Handoff。 可见,该方法由于完全在模块注册的回调 HOOK 函数中实现,因而对操作系统协议栈是透明的,无需修改操作系统协议栈,因而也就无需重新编译内核。 3.2.2 连接的建立过程 假设有三台主机 A, B, C。 A 是客户, B 是集群的前端机, C 是集群后端服务器中迁移的目的

39、结点。实现 TCP Handoff 的模块名为 KTH( Kernel TCP Handoff) ,KTH 分别安第 18 页 装在 B, C 上。 系统的工作过程如下: Step 1:客户端 A 向集群发起请求,典型的请求以一个 SYN( CSEQ 表示客户端报文的初始序列号)报文为开始,标记一个 TCP 连接开始并请求回应一个三次握手协议过程。该请求到达前端调度器 B。 Step 2:前端调度器 B 上的 KTH 系统将截获客户端的 SYN 请求报文,解析后,将其复制一份,缓存下来,另外记下该连接的发送方地址和端口,用于计算 hash 值,将该连接记录到 Hash 表中,连接的状态记录为

40、SYN_REVD。再将该报文上传给协议栈正常处理。 Step 3:前端调度器 B 回应一个 ACK( CSEQ 1,表示对应于初始序列的应答序列)到客户端口。同时,发起一个 SYN( VSEQ 表示新的报文序列号) 。该 ACK+SYN 报文同样在发送前由 KTH 截获, KTH 只是简单地将该连接的状态改为 SYNACK_SENT,然后让该报文正常发送出去。 Step 4: ACK+SYN 报文回送到客户端 A, A 接收响应。 Step 5: A 在收到集群的正确应答报文后,认为连接已经建立(实际上, A 仅仅是和前端调度器 B 建立了连接) 。对集群调度器 B 的的 SYN( VSEQ)

41、进行应答,发送 ACK( VSEQ+1) 。至此完成了三次握手的全部过程,并且开始进行数据通信,向 B 发出数据请求报文(这里假设为 HTTP 请求报文) DATA( CSEQ 1) 。 Step 6: ACK( VSEQ+1)报文到达 B 后,由 B 上的 KTH 系统复制一份缓存起来,并将该连接的状态改为 ESTABLISHED,然后交给协议栈正常处理。这里,记录连接状态的目的主要是为了实现精确的同步和报文的正确处理, 例如, 在接到客户方重传报文的情况下,不进行不必要的报文复制。另外每次状态转换均重新启动对应新状态的定时器。如果定时器超时,表明连接超时,则 B 从 Hash 表中删除该连

42、接对应的表项。 Step 7:当客户方的 HTTP 请求到达时,同样由 B 上的 KTH 截获, KTH 分析该 HTTP请求,并根据请求内容进行规则匹配,从而调度到后端的一台服务器 C,在 Hash 表中登记该服务器地址,然后将先前复制的 SYN 报文, ACK 报文,连同该 HTTP 请求报文,封装为一个报文,通过 IP 隧道发送给选出的后端服务器 C,同时, “安静地”撤消该连接,所谓“安静地”撤消,是指并不遵循 TCP 协议,发出一个 FIN 报文,向连接的对方发出信息表示己方撤消连接,而只是直接撤消连接的一切相关数据结构,这类似于一条 TCP 连接因连接的对方不可达(例如中途将网线拔

43、了) ,超时而撤消连接的情况。同时修改 Hash 表中该连接的状态为 HANDOFFED。 B 以后只负责将 A 发来的报文在 IP 层封装后通过 IP 隧道转发给 C。 Step 8: B 刚才转发的报文首先被后端服务器 C 上的 KTH 系统截获, KTH 先直接将该IP 隧道报文交给 IP 隧道设备解开封装。 Step 9: IP 隧道设备解开封装后,将原始 IP 报文重新放入协议栈中,又重新被 KTH 系统截获。 KTH 系统解析该报文,从中提取出客户方 A 原始的 SYN( CSEQ)报文,记下报文的初始序列号 CSEQ,然后直接交给协议栈。同时,将该连接记录到 C 的连接 Hash

44、 表中,连接的状态记录为 SYN_REVD。 Step 10: C 产生 SYN+ACK 报文,注意,这里后端服务器 C 产生的初始序列号与前端调度器 B 产生的是肯定不同的,该报文同样由 KTH 系统截获,记下该序列号为 RSEQ,第 19 页 然后将该 SYN+ACK 报文“悄悄地”丢弃,即不再通过协议栈向下传输发送,但是又让协议栈认为该报文已正常处理完毕。 Netfilter 通过 HOOK 函数返回 NF_STOLEN 支持该操作。同时修改连接的状态为 SYNACK_SENT。 Step 11:接着, KTH 从先前的 IP 报文中又提取出客户方 A 的 ACK( VSEQ+1)报文,

45、计算偏差 OFFSET=RSEQ-VSEQ,根据 TCP 协议,该偏差是固定的。利用这个偏差,我们就可以修正序列号,从而将连接在客户方 A 与后端服务器 C 之间建立起来。 Step 12:修改该 ACK( VSEQ+1)报文的 TCP 报文头中的 ack_seq 域的值,将其加上OFFSET,这样,实际上该报文变为了( RSEQ+1)报文,重新计算校验和(实际上,这里有个小技巧,只需设一个标志位,可以使 Linux 操作系统协议栈跳过校验和检查,从而不用重新计算校验和。 但对要发送出去的报文, 在修改序列号后, 就必须重新计算校验和了) ,修改该连接状态为 ESTABLISHED,将报文交给

46、协议栈。以后 C 上的 KTH 截获到的所有该连接上收到的报文,修改序列号的方法均为将其加上 OFFSET,下文不再赘述。这样,C 就以为是它发出去的 SYN+ACK 报文的响应报文到了,这样,三次握手完成,后端服务器 C 与客户 A 也建立了“相同的”连接。这样,实际上该 TCP 连接在客户方和调度器之间,客户方和后端服务器之间,均处于半连接状态,如图 3.2 所示: 图 3. 2 三方之间的 TCP 连接 Step 13 : KTH 从先前的 IP 报文中最后提取出 HTTP 请求( seq:CSEQ+1,ack_seq:VSEQ+1)报文, KTH 将 ack_seq 域的值加上 OFF

47、SET,即将该报文变为( seq:CSEQ+1,ack_seq:RSEQ+1)报文,重新计算校验和,交给协议栈。 Step 14:后端服务器 C 响应该 HTTP 请求,响应报文( seq:RSEQ+n,ack_seq:CSEQ+2)同样在发送前由 KTH 系统截获。 Step 15: KTH 将报文的 seq 域减去 OFFSET,变为( seq:VSEQ+n,ack_seq:CSEQ+2) ,重新计算校验和,交给协议栈 ,发送给客户方 A。以后 C 上的 KTH 截获到的所有该连接上发送的报文,修改序列号的方法均为将其减去 OFFSET,下文不再赘述。 A 以为是前端调度器 B 发来的响应

48、,从而客户方也正确地得到了响应。 至此,实际上已完成连接的迁移工作,而该过程对客户 A 是透明的, A 认为连接的另一个端点是 B,而实际上已变成了 C。而对 C 看来,连接的另一个端点是 A,因而 HTTP响应不通过 B 而直接发送给 A。 第 20 页 3.2.3 连接的通信过程 迁移的连接上的后续报文由 A 发送给 B, B 上的 KTH 模块截获报文后, 查找 Hash 表,得到迁移的目的后端服务器 C 的地址。 KTH 模块将报文使用 IP 隧道协议封装后,转发给C。 C 上的 KTH 模块截获报文后,修改报文的序列号,然后交给协议栈正常处理。 C 发出的响应报文同样在发送前由 KT

49、H 模块截获,修改报文的序列号,重新计算校验和,然后交给协议栈正常处理。 3.2.4 连接的取消过程 首先考虑客户方主动关闭连接的情况: Step 1:客户方 A 发起一个 FIN,到达前端调度器 B。 Step 2:前端调度器 B 记录该连接为 CLOSE_WAIT 状态,将该报文封装后通过 IP 隧道转发给后端服务器 C。 Step 3:后端服务器 C 上的 KTH 接到转发的 FIN,同样记录该连接为 CLOSE_WAIT 状态,将报文交给协议栈。 Step 4:后端服务器 C 上的 KTH 接到将要发送的 ACK,修改序列号,计算校验和,将报文交给协议栈发送。 Step 5:后端服务器 C 上的 KTH 接到将要发送的 FIN,修改序列号 , 计算校验和,将报文交给协议栈发送。 Step 6:客户方 A 收到 FIN后,撤消连接,发送响应 ACK 到达前端调度器 B, KTH 将该报文通过 IP 隧道发送给后端服务器 C。 Step 7:后端服务器 C 上的 KTH 接到 ACK,修改序列号,交给协议栈, C 将撤消连接。一段时间后, B, C 由于 CL

展开阅读全文
相关资源
猜你喜欢
相关搜索

当前位置:首页 > 企业管理 > 管理学资料

本站链接:文库   一言   我酷   合作


客服QQ:2549714901微博号:道客多多官方知乎号:道客多多

经营许可证编号: 粤ICP备2021046453号世界地图

道客多多©版权所有2020-2025营业执照举报