摘要:在数据中心中,工作负载吞吐量常常受到代理服务器的附件带宽的限制,尽管后端服务器的聚合带宽要高得多。因此我们引入一个新的架构去解决这个问题,主要是通过结合可编程网络交换机和控制器在一起作为一个网络“Prism”,它可以透明地将个人客户事务重定向到不同的后端服务器。与传统的代理方法不同,通过Prism,事务有效负载数据可以在客户机和后端服务器之间直接交换,从而消除了代理瓶颈。因为控制器只处理事务元数据,所以它的事务率应该比传统代理高得多。而经过原型系统的实验评估证明了操作的正确性,改进的带宽利用率和低的包转发开销甚至在软件中也是如此。
1 介绍
数据中心的节点连接网络交换机,为多个服务器提供同时通信的能力。目前的趋势是将一个服务器对之间的通信与其他服务器对之间的通信隔离开来,通常提供全对分带宽,以提供更可预测的服务。然而,即使在具有全对分带宽的拓扑结构上,应用程序仍然可能遇到吞吐量有限的问题。当一个服务器在多个其他服务器之间代理流量时,其连接到内核的带宽限制了工作负载的总吞吐量。这种基于代理的通信是很常见的,其中包括了分布式存储、MapReduce和web工作负载,它们都需要有状态的应用程序级逻辑来操作代理上的应用程序事务。一开始是通过安装额外的和/或更快的网卡的方法,简单地增加代理服务器的fabric连接带宽来缓解这个问题。这就让硬件配置更加的复杂,即增加了布线成本,还减少服务灵活性,这些都是为了有限的回报并留下了后端带宽利用率低下的问题。
本文呈现的Prism架构,提供了一种更好的解决方案,因为代理的一个角色是通过TCP连接中继事务有效辐照数据,并且可以和它的应用程序级的处理相分离,当这种处理只涉及到事务的元数据时(请求和响应报头),Prism通过利用可编程网络交换机以线速率转换有效负载包,将事务有效负载数据中继到网络fabric。它最初是为即将到来的P4硬件交换机设计的,但是即使在软件交换机中实现,它也能获得良好的性能。Prism仍然是一个具有事务粒度操作的真正代理架构,即使应用程序重用TCP连接发出长事务流时也是如此。这个不仅具有挑战性,而且对于支持HTTP、memcached、iSCSI和NFS等传统和现代应用程序协议也很重要。在这个领域一些相关联的方法比如Maglev,Ananta, Duet, Rubik,仅仅是在建立到后端服务器的连接时才会进行负载均衡,但是无法对不同的后端服务器执行后续的事务。这将导致负载随时间的增长严重不平衡。至于Prism,经证明可以提高大于2Mb的数据传输的吞吐量,并证明了它的包转换损耗非常低,即使在软件交换机中实现,也可以转发高达几十Gb/s的流量。
这允许数据中心操作员最初通过末端交换机上游的软件交换机部署Prism,而不需要可编程的硬件交换机。
2 Prism的设计
Prism使用一个控制器应用程序,该应用程序使用软件定义的网络(SDN)接口来动态编程一组SDN网络交换机,以透明地将客户端发出的事务重定向到逻辑服务器IP地址,从而定向到不同的物理后端服务器。Prism可以为每个客户端事务迁移控制器和不同后端服务器之间的TCP连接,方法是通过可编程交换机重写TCP头。后端服务器再通过这些已经建立、迁移的连接进行通信。在任何时候,处理客户端连接(控制器或后端服务器)的端点负责通过ACK、重发等方式维护TCP语义。只有在保证没有未回复ACK的数据时,连接才会迁移。
2.1 建立连接
Prism的使用对客户端是透明的,客户端是未修改的,并执行正常的协议实现。客户端连接到最初"逻辑"服务器IP地址转发到Prism控制器。Prism控制器与客户端一起处理TCP连接的建立和拆除,并维护有效的元数据,以确定哪个后端服务器应该处理给定的客户端请求。它还解析请求报头,并对Prism交换机进行编程,以重写承载请求和响应有效载荷数据的TCP段的包报头。客户机以正常的方式开始事务序列,即打开与服务器的TCP连接。图1中的步骤1说明了客户机与Prism控制器执行所需的TCP三向握手,协商任何所需的TCP选项。图1中的实线箭头表示在客户端连接上发送的TCP包,虚线表示控制器、交换机和后端服务器之间的Prism控制消息。
2.2 请求解析
在图1的步骤2中,客户端通过发送请求开始事务,控制器接收并解析请求。当控制器确定它已接收到整个请求标头时,它将参考它维护的关于后端服务器的元数据,以选择一个来处理请求。它在步骤3中发送PUSH/ACK,如果请求是读,则将TCP接收窗口设置为0。这可以防止在控制器将请求提交给后端时客户机发出额外的请求。如果客户端在其请求头之后已经包含了一些请求有效载荷数据,则控制器仅应答请求头的接收,从而迫使客户端重新传输任何请求有效载荷数据,因此它将到达后端。
2.3 请求的握手
在步骤4中,控制器指示Prism开关改写从客户机发送的数据包的目的地IP地址的选择后端服务器,并重新发送的数据包的源IP地址从后端服务器端逻辑的IP地址。其结果是,在客户机和后端之间将直接交换任何下列(有效负载)包,而交换机结构将执行所需的重写(在硬件中,一旦P4交换机可用)。在对交换机进行配置之后,控制器与第5步中选择的后端服务器进行联系,并向它传递有关TCP连接状态和客户机请求的有效信息,以便服务器能够接管连接并为请求提供服务。这包括关于客户端请求的应用程序级信息,以及TCP端口、序列和ACK编号,以及为连接的两个方向协商的TCP选项。
2.4 后端请求的处理
在从控制器接收到手动控制消息后,后端服务器处理客户机请求。图1演示了一个客户端读取,其中后端服务器首先在步骤6中发送响应标头,然后在步骤7中发送负载数据。(对于一个客户写,顺序将是相反的;首先读取有效载荷数据,然后发送响应标头。)后端服务器需要发送和接收TCP数据包,这些数据包经过交换机的头重写后,被客户机接受为属于控制器和客户机之间已经建立的连接。因为后端服务器知道交换器执行的头重写,所以它必须只确保TCP源和目标端口以及序列和ACK编号以及控制器与客户端协商的任何TCP选项在传输段中是正确的。
当客户端请求是写请求时,后端必须仅打包该请求的有效负载数据(步骤8),而不能打包客户端发送的任何其他数据,例如下一个请求。对于客户端读取,后端将TCP接收窗口设置为零,以防止客户端发送任何进一步的数据,但是对于写操作,这是不可能的。另外,后端必须忽略。(而不是ACK)客户端发送的任何TCP FIN,以防止客户端在连接返回给控制器之前关闭连接。为了正确地跟踪连接和维护元数据,需要将连接交还给控制器。主数据交换完成后,服务器通知第9步中的控制器,并包含关于连接进程的足够信息(即,新的TCP序列和ACK编号,时间戳选项等),以便控制器可以接管连接。对于后端服务器,这就结束了服务请求。如果无法预见的事件导致后端服务器无法为客户端请求提供服务,则需要将此情况通知控制器(步骤9)。然后,控制器可以将TCP连接重置到客户端,以发出故障信号。此外,控制器可能希望为处理后端服务器崩溃的请求设置超时。
2.5 为下一个请求做准备
在第9步中,控制器从后端接收到请求完成通知后,它将从交换机中删除头部重写规则(第10步)。然后,它在步骤11中向客户端合成一个ACK,重新打开接收窗口(如果之前的读请求关闭了该窗口)。这允许客户端发出下一个请求。如果客户端发送了一个新的请求,操作将在第2步恢复。如果客户端通过发送FIN来关闭连接,控制器将继续执行FIN握手来关闭步骤12中的连接。控制器本身也可以通过发送FIN来启动连接拆卸。
3 构思论述
3.1 支持TLS
如果使用TLS保护应用程序协议,则客户端将在步骤1之后通过连接开始TLS握手。为了支持TLS,需要扩展控制器来完成握手。它还必须通过足够的TLS会话的状态信息在步骤5中,后端服务器的TLS实现后端服务器必须增强支持直接递送一个TLS会话到“握手完成”状态,和后端必须通过足够的信息发展的TLS会话在第9步控制器。
3.2 消除控制器通知
如果控制器知道给定客户端请求的有效负载数据的大小,例如,基于它维护的请求头或元数据,那么第9步中的一些通知延迟可能会减少。控制器可以通过使用计数器跟踪TCP序列和ACK编号来确定开关,从而监视各个TCP连接的进程。一旦交换了经过修改的数据量,交换机将通知控制器,或者交换机本身可以通过删除相应的重写规则将连接恢复到控制器。这两种方法中的任何一种都可能比后端显式通知更快。
3.3 重写规则的投机性缓存
在第9步之后,控制器可能希望将下一个客户机请求定向到相同的后端服务器,可以推测,它可能会推迟删除交换机规则,直到解析了下一个请求之后。在这种情况下,控制器可以跳过下一个请求的第5步,从而减少延迟。
3.4 数据包转换
Prism使用一个可编程的开关来转换包,因为它们是通过fabric传送的。它需要修改TCP和IP报头,因此P4交换机似乎提供了一种实现所需功能的简单方法,因为它们能够对任意的应用程序定义的报头执行操作。更容易获得的OpenFlow交换机不支持修改所有需要的TCP头字段。Prism的设计并不要求所有的包转换都是原子性的,甚至不要求在路径上的单一位置进行。包转换也可以直接在后端服务器上实现,而不是在网络交换机中实现,例如,在hypervisor层或后端服务器的来宾操作系统内的软件交换机或主机防火墙中,或者提供fabric附件的可编程NIC中,或者是它们的任何组合中。这里的关键结论是,一般的Prism设计可以用不同的贸易方式进行实例化。
3.5 Security Implications
一般来说,代理可以提高攻击弹性,充当防火墙来保护后端服务器。Prism体系结构可以进一步加强这一角色,因为它可以在控制器上使用简单而快速的用户空间TCP/IP堆栈,而常规代理通常在操作系统中使用完整的TCP/IP堆栈,这可能具有更大的攻击面。此外,Prism体系结构可以克服用户空间TCP栈的一个常见问题,即缺乏现代特性,如当前的拥塞控制算法和损失恢复机制,这也是因为它只处理连接设置。请注意,使用SYN cookie(一种缓解SYN泛滥攻击的常用技术)在用户空间堆栈中实现起来相当简单,因为它的实现甚至比处理SYN包的常规方法更简单。
3.6 设计的局限性
对于小消息事务性工作负载,即在这种情况下,将请求和响应转换为几个TCP包可能不是一个合适的解决方案。在这种情况下,与Prism接收窗口管理、规则添加和删除、控制器通知相关的开销无法充分摊销。这可能包括HTTP/2这样的协议,它允许块数据的主动交错管道传输,而Prism目前需要将这些块数据处理为单独的请求。支持这样的工作负载将需要对后端和Prism设计进行进一步修改,以便在执行多个并发事务时,控制器可以让连接保持在单个后端服务器上。
4 实现
图2展示了Prism控制器、交换机和后端软件的体系结构。我们使用netmap快速用户空间包I/O API在Linux上实现了Prism控制器。它还使用操作系统堆栈通过套接字API与后端进行控制通信。Prism后端使用TCP_REPAIR和TCP_INFO在用户空间中实现TCP连接的传递,不需要修改内核。对于应用程序逻辑,我们实现了一个简单的HTTP服务器,它服务于存储在主内存中的对象。
该原型没有使用P4,因为当时还没有可用的硬件交换机,而且参考软件交换机实现的性能非常差,仅支持59.8 Mb/s TCP吞吐量,平均延迟为204 ms。相反,我们将Prism实现为mSwitch的包处理模块,mSwitch是一个内核软件交换机,它可以在单个CPU内核上以超过10 mpp的速率转发包。虽然该原型以独立的方式将该软件交换机部署为网络结构的一部分,但Prism设计支持其他部署。例如,Prism包转换也可以直接在后端服务器上实现,例如,在运行后端服务器甚至其(来宾)操作系统的来宾虚拟机的管理程序内部的软件交换机中实现。Prism的设计并不要求所有的包转换都是原子性的,或者在路径上的单一位置进行(尽管原型是这样实现的)。Prism允许在客户机和后端服务器之间的路径上的不同点上进行不同的转换。例如,Prism控制器可以将后端服务器上的主机防火墙或可编程网络接口卡设置为零TCP接收窗口并清除FIN位。关键的结论是,第2节中描述的通用Prism设计可以用不同的方式进行实例化,并进行不同的权衡。