Tcpcopy传统架构在产品中实践遇到一些问题,要理解和解决问题深入了解Tcpcopy两种的架构的原理是必须的。当了解的越多就发现它不仅仅是一个工具,而需要掌握不仅仅是简单的几个使用命令。
Tcpcopy传统架构与新架构最大的区别:传统架构的intercept进程与测试服务器在同一台机器上,新架构的intercept进程从测试服务器上offload出来,单独部署在辅助服务器上。下面分别对两种结构的原理详细介绍。
传统架构
Tcpcopy
传统架构下,在线机器上面抓取请求数据包,默认采用raw socket input 接口。raw socket(原始套接字)可以接收本机网卡上的数据帧或者数据包,可监听网络的流量和分析。可以通过3种方式创建这类socket ,这里只详细讲tcpcopy使用的函数。Raw_socket的原理和其它使用方式,可参考 http://blog.sina.com.cn/s/blog_9599e95101010w2g.html
抓包函数:int sock = socket(AF_INET,SOCK_RAW,IPPROTO_TCP)。 第一个参数表示协议簇, AF_INET 代表TCP/IP协议。第二个参数表示SOCKET类型。第三个参数表协议类型。该套接字可以接收协议类型为tcp(也可以设置其它协议类型)发往本机的IP数据包,不能收到非发往本机IP的数据包(IP软过滤会丢弃这些不是发往本机的数据包)。Tcpcopy利用Raw Socket只抓进来的包,而不能收到从本机发送出去的数据包这一特点,实现抓包的功能。系统在IP层会检查有没有进程创建这种类型的raw socket,如果有,这个包就会被复制一份并发送到这个socket的缓冲区,Tcpcopy就是通过这种方式来复制访问流量的。
在发包前,调用函数sock = socket(AF_INET, SOCK_RAW,IPPROTO_RAW),并且设置setsockopt(sock, IPPROTO_IP, IP_HDRINCL, &n, sizeof(n)),这样IP数据包头部就可以由用户自己编写(在不设置这个选项的情况下,IP协议会自动填充IP数据包的首部),Tcpcopy利用此函数将数据包的目的IP和端口改为测试机的IP和端口,如下:tcp_header->dest = remote_port;
ip_header->daddr = remote_ip;最后调用sendto函数发送包到测试前端机:
send_len = sendto(sock,(char *)ip_header,tot_len,0,(struct sockaddr *)&toaddr,sizeof(toaddr));
Intercept
测试机上Intercept进程主要完成的是对复制请求的响应包进行处理。复制的请求到达测试机经应用程序处理后的响应包如果不经处理,将会返回给线上客户端。Tcpcopy传统架构的使用需要Iptable这一工具辅助实现对响应包的处理。
modprobe ip_queue
iptables -I OUTPUT -p tcp –sport 2080 -j QUEUE
以上iptable命令,表示OUTPUT链从2080端口发出的包在IP层会被匹配发往目标QUEUE,而QUEUE是由ip_queue模块实现(http://bbs.chinaunix.net/thread-1941806-1-1.shtml).因此在使用iptable命令前,内核需要使用modprobbe命令加载ip_queue模块。有了以上两个步骤, 所有匹配到iptable命令的报文将会调用IP Queue模块的相关函数。
Tcpcopy服务器端的Intercept进程用如下方式创建Netlink socket:
int sock = socket(AF_NETLINK,SOCK_RAW,NETLINK_FIREWALL);
Netlink详细介绍http://linux.chinaunix.net/techdoc/beginner/2008/11/12/1044982.shtml。
NETLINK_FIREWALL协议有三种消息类型:IPQM_MODE,IPQM_PACKET,IPQM_VERDICT.其中内核通过IPQM_PACKET消息将刚才截获的返回结果包发送到Inercept。Intercept给内核发送一个IPQM_VERDICT消息告诉内核对这个包的裁决结果(DROP,ACCEPT)。Tcpcopy通过这样的办法将测试机上应用返回的结果截获丢弃,并由Intercept返回一个Ip header。 Tcpcopy利用这个特点保留了一个允许访问的ip列表,因为默认情况下访问测试前端机上应用服务所得到的结果会在IP层被drop掉,造成在2080端口上无法访问应用服务。有了这个白名单,即使是设置了iptables规则,在白名单内的机器上也是可以正常访问测试前端机上的应用服务的。
新架构
Tcpcopy
新架构的Tcpcopy进程的实现与旧架构相比差别不大,在线机器上面抓请求数据包默认采用raw socket input 接口,增加了采用pcap 接口抓包的功能。Libpcap是Packet Capture Libray的英文缩写,即数据包捕获函数库。该库提供的C函数接口用于捕捉经过指定网络接口的数据包,该接口应该是被设为混杂模式。常用的抓包软件Tcpdump就是在Libpcap的基础上开发而成的。Libpcap提供的接口函数实现和封装了与数据包截获有关的过程,工作原理不赘述,详细可参考http://www.cnblogs.com/coder2012/archive/2013/04/13/3012390.html。根据使用手册上的描述,新架构一般推荐使用Pcap抓包,安装命令如下:
./configure --enable-advanced --enable-pcap
make
make install
新架构和传统架构一样,默认使用Raw socket output 接口发包,采用Raw Socket命令发包命令如下: ./tcpcopy -x 80-测试机IP:测试机应用端口 -s 服务服务器IP -i eth0 。其中-i参数指定pcap从哪个网卡抓取请求包。
此外,新架构还支持通过pcap_inject(编译时候增加--enable-dlinject)来发包。使用pcap_inject发包有两点好处:1.可以避开在线机器在IP层的防火墙设置,因为tcpcopy进程复制过来的包源IP还是线上客户端的IP,在线机器上可能会被直接扔掉,在不能改变防火墙设置的情况下,采用pacp_inject直接从数据链路层发包,可以避开IP层复杂的防火墙设置;2.在压力比较大的场合推荐使用pcap_inject 来发包,根据测试结果来看合理利用pcap_inject 来发包可提高30%的性能(详见使用手册),但是pcap_inject发包需要知道数据包从在线机器发出下一跳的网卡地址,这需要使用tcpdump工具抓包获取.
Pcap发包命令:sudo ./tcpcopy -x 在线端口号@在线机器的出口网卡地址-测试机器的IP地址:测试机器的端口@下一跳网卡地址 -s 运行intercept的机器IP地址 -o 出口网卡设备 -i 抓包网卡设备。
测试服务器
新架构测试机部署上,需要更改其路由设置,目的是将测试应用程序的响应包路由到辅助测试服务器。以外网应用为例如下:
删除测试服务器的外网IP的默认路由
route del default gw 原外网网关IP
添加辅助测试服务器IP作为测试服务器的默认路由
route add default gw 辅助服务器的外网IP
这里的意思就是说,在测试服务器返回给客户端的响应走默认网关-辅助服务器的外网IP,但这台机器其实并没有开启路由模式,所以这些响应包到了辅助测试机后,会在ip层被drop掉,这样internet进程就可以在辅助测试服务器的数据链路层抓到这些响应包
辅助服务器
辅助服务器主要是用于捕获测试服务器转发过来的响应包,辅助服务器要确保没有开启路由模式cat /proc/sys/net/ipv4/ip_forward,为0表示没有开启。辅助服务器上采用的也是pcap抓取响应包,安装命令如下:
./configure --enable-advanced --enable-pcap
make
make install
辅助服务器intercept进程通过pcap抓取测试机应用程序的响应包,将头部抽取后发送给线上的tcpcopy进程,完成一次请求的复制。
小结:
Tcpcopy两种架构都是通过巧妙地应用一些网络工具和包实现其复制转发的功能,传统架构rawsocket+iptable+netlink,新架构pacp+route,通过对其深入的了解也拓展了许多网络知识,在之后遇到一些问题也可以比较清楚明白的去解释和分析。
对比两种架构的原理和实践中遇到的问题可以得出,传统架构更容易实施,但是由于它借助于linux的IP_QUEUE模块,其性能完全依赖于系统,在压力较大时性能表现较差;而新架构将测试机和辅助服务器分离开来,性能有所提升,但是在部署实施受硬件条件制约,比如测试机和辅助测试服务器需在一个网段等,同时需要用到的网络知识更多。在使用时,结合条件选择合适的架构。
相关文章:
最新内容请见作者的GitHub页:http://qaseven.github.io/