美文网首页
利用tcpcopy引流做模拟在线测试(转)

利用tcpcopy引流做模拟在线测试(转)

作者: 烨枫_邱 | 来源:发表于2019-05-16 18:34 被阅读0次

    一、工具介绍

    Tcpcopy是一个分布式在线压力测试工具,可以将线上流量拷贝到测试机器,实时的模拟线上环境,达到在程序不上线的情况下实时承担线上流量的效果,尽早发现bug,增加上线信心。

    与传统的压力测试工具(如:abench)相比,tcpcopy的最大优势在于其实时及真实性,除了少量的丢包,完全拷贝线上流量到测试机器,真实的模拟线上流量的变化规律。

    二、Tcpcopy的原理

    1.流程

    现在以nginx作为前端说明tcpcopy的原理:

    上图中左边是线上前端机,右边是测试前端机。线上前端机开启tcpcopy客户端(tcpcopy进程),测试前端机开启tcpcopy服务端(interception进程),且两台机器上都启动了nginx服务。

    Tcpcopy拷贝一次流量访问的步骤如下:

    ① 一个访问到达线上前端机;

    ② socket包在ip层被拷贝了一份传给tcpcopy进程;

    ③ tcpcopy修改包的目的及源地址,发给测试前端机;

    ④ 拷贝的包到达测试前端机;

    ⑤ 测试前端机的nginx处理访问,并返回结果;

    ⑥ 返回结果在ip层被截获、丢弃,由intercpetion拷贝返回结果的ip header返回;

    ⑦ ip header被发送给线上前端机的tcpcopy进程。

    2.代码分析

    1) 首先,在链路层或者IP层,在把包交到上一层之前,系统会检查有没进程创建了socket(AF_PACKET,SOCK_DGRAM,…) 或socket(AF_INET,SOCK_RAW,…)等类型的套接字(即原始套接字sock_raw),如果有,这个包就会被复制一份并发送到这个 socket的缓冲区。tcpcopy就是通过这种方式来复制访问流量的。上述的两种抓包方式,前者工作在数据链路层,后者工作在IP层。在 tcpcopy中不同版本所使用的抓包函数不同,在0.3版本中是:

    int sock = socket(AF_PACKET,SOCK_RAW,htons(ETH_P_IP));

    而在0.4版本中,用的是:

    int sock = socket(AF_INET,SOCK_RAW,IPPROTO_TCP);

    以上两个函数分别工作在链路层和IP层,前者会把进来和出去的包都抓取到,后者只 抓取到进来的包。

    2) Tcpcopy在发送拷贝的数据包的时候,使用了如下socket:

    sock = socket(AF_INET, SOCK_RAW,IPPROTO_RAW);

    并对这个socket设置了IP_HDRINCL:

    setsockopt(sock, IPPROTO_IP, IP_HDRINCL, &n, sizeof(n));

    因此网络层不会再增加ip header. 发送之前更改了包的目的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));

    3) 在测试前端机上加载了ip_queue模块,并设置iptables规则:

    iptables -I OUTPUT -p tcp –sport 80 -j QUEUE

    复制的访问流量到达测试前端机上的nginx,nginx处理并返回结果,这个结果包在IP层会被前面所设置的iptables规则匹配发往目标(target)QUEUE。而QUEUE是由ip_queue模块实现。下一步这个匹配包就会被内核经过netlink socket发往用户空间的程序(在这是tcpcopy的服务端interception进程)。

    netlink socket是内核与用户进程之间的一种通信机制,是网络应用程序与内核通信的最常用的接口,可以用来配置网络的各个方面(比如包的过滤)。

    interception用如下方式创建netlink socket:

    int sock = socket(AF_NETLINK,SOCK_RAW,NETLINK_FIREWALL);

    NETLINK_FIREWALL协议有三种消息类型:IPQM_MODE,IPQM_PACKET,IPQM_VERDICT.

    内核通过一个IPQM_PACKET消息将刚才截获的返回结果包发送到interception,interception给内核发送一个 IPQM_VERDICT消息告诉内核对这个包的裁决结果(DROP,ACCEPT,etc.)。tcpcopy通过这样的办法将测试前端机上nginx 返回的结果截获丢弃,并由interception返回一个ip header.相应代码实现如下:

    拷贝结果包的ip header,发送:

    interception向内核发送IPQM_VERDICT消息报告裁决结果:

    内核接收到这个包后将packet_id这个包drop或accept。在后文中可以看到从0.4版本开始的tcpcopy利用这个特点保留了一个允许访问的ip列表,因为默认情况下访问测试前端机上nginx服务所得到的结果会在ip层被drop掉,造成在80端口上无法访问nginx。有了这个允许ip列表,即使是刷了iptables规则、起了interception进程,在某些机器上也是可以正常访问测试前端机上的nginx服务的。

    三、操作方法

    下载地址:http://tcpcopy.googlecode.com/files/tcpcopy-0.3.3.tar.gz,下载tcpcopy源码包后解压,执行常规的./configure;make;make install三部曲即可。

    假如有两台机器:

    机器A:线上前端机,ip:61.135.xxx.1;

    机器B:测试前端机,ip:61.135.xxx.2;

    两台机器上都起了nginx服务,操作者在两台机器上都需有sudo权限。

    操作步骤:

    1. 在B依次执行,

    1) 加载ip_queue模块,modprobe ip_queue;

    2) 配置iptables规则,sudo iptables -t filter -I OUTPUT -p tcp –sport 80 -j QUEUE;

    3) 启动tcpcopy服务端,sudo ./interception & ;

    2. 在A上执行,

    启动tcpcopy客户端,sudo ./tcpcopy 61.135.xxx.1 80 61.135.xxx.2 80 &;

    如果在A上看到“I am booted”,则表示操作成功,tcpcopy已经开始工作,可以查看一下机器B上nginx的日志确认。

    四、高级用法

    1. 级联

    设有线上前端机一台命名A,测试前端机若干B,C,D,……利用tcpcopy可以将A上的访问流量拷贝到B,B拷贝到C,C拷贝到D,……这样就将一份流量放大了多倍,可以用来测试引擎的极限承受能力。

    2. 同一tcpcopy实例内多重复制

    从0.4版开始,tcpcopy支持在同一个客户端实例复制多份请求到同一个服务端,启动的方式如下(比如要复制2份,使用-n这个选项来控制要复制的份数),

    sudo ./tcpcopy 61.135.xxx.1 80 61.135.xxx.2 80;

    sudo ./tcpcopy 61.135.xxx.1 80 61.135.xxx.2 80 -n 1;

    sudo ./tcpcopy 61.135.xxx.1 80 61.135.xxx.2 80 -n 2;

    3. 服务端允许访问ip列表

    由于配置了iptables规则,使用tcp协议且源端口号为80的包都会被匹配放到目标QUEUE去,进而被drop掉,因此这个时候测试前端机上的nginx服务是不可访问的。从0.4版本开始,可以指定一个允许访问ip列表,在列表中的机器上是可以访问测试前端机上的nginx服务的。假如要添加61.135.xxx.3,61.135.xxx.4到允许ip列表,启动interception时使用如下方式:

    sudo ./interception 61.135.xxx.3:61.135.xxx.4;

    五、tcpcopy在一淘的应用

    一淘引擎在今年2月份时有一次重大的更新,在上线之前,利用tcpcopy把所有前端机的流量拷贝到新的demo前端机上,进行在线模拟实验。引流示例如下图:

    所有线上前端机都开启tcpcopy客户端,由于一直报”Message too long”(这是由于packets长度超过1500造成,每分钟差不多有50个)刷屏,所以将stderror重定向,

    sudo ./tcpcopy ipA 80 ipB 80 2>/dev/null &

    在测试前端机上开启tcpcopy服务端程序interception,并设置iptables规则。

    压了大约有一个星期,期间观察qps,load等各项指标是否正常。新引擎单个集群一天的平均qps大约是110,峰值大约240。实验结果显示的包丢失率大约是(1822213-1797242)/1822213=1.37%. 后来进一步将多个线上前端机的流量引到一个测试前端,测试新引擎的单集群极限服务能力,qps能达到1000以上, latency大约40ms,达到了上线要求。

    Tcpcopy客户端和服务端本身占用的资源较少,不影响在线服务。

    13991 root 20 0 160m 77m 888 R 7.7 0.3 71:26.24 tcpcopy

    7723 root 15 0 42592 38m 324 S 5.8 0.2 12:14.83 interception

    %cpu分别占7.7%和5.8%,物理内存占用分别是77m和38m.

    由于几乎完全模拟了线上环境,我们对于新引擎上线更有信心,最终上线圆满成功,实现平稳过渡。现在利用tcpcopy拷贝线上流量作模拟压测已成为我们日常开发上线流程中的一项内容。

    六、tcpcopy架构漫谈

    基于server的请求回放领域,一般分为离线回放和在线实时复制两大领域,一般研究者都是从离线回放的角度在苦苦研究,而在实时复制领域,研究非常少,至少从sigcomm评审人的评审意见来看,没有看到相关内容。

    请求实时复制,据我所知,一般可以分为两类:

    1)基于应用层的请求复制

    2)基于底层数据包的请求复制

    传统的做法一般从应用层面进行复制,比如基于服务器的请求复制,这种复制的好处就是实现起来相对简单,但也存在着若干缺点:

    1)请求复制从应用层出发,穿透整个协议栈,这样就容易挤占应用的资源,比如宝贵的连接资源

    2)测试跟实际应用耦合在一起,容易导致对在线系统的影响,比如有些基于服务器的复制,会导致用户请求的处理时间取决于最慢的请求处理时间(max(真正的请求处理时间,被复制的请求请求处理时间))

    3)很难支撑压力大的请求复制(据若干用户反映,这种类型的请求复制,曾经严重影响在线系统)

    4)很难控制网络延迟

    基于底层数据包的请求复制,可以做到无需穿透整个协议栈,路程最短的,可以从数据链路层抓请求包,从数据链路层发包,路程一般的,可以在IP层抓请求包,从IP层发出去,不管怎么走,只要不走TCP,对在线的影响就会小得多。

    因此从数据包的角度去做基于server的请求复制,方向是对的,而且潜力非常巨大,很可惜,tcpreplay的作者做了一点这方面的探索(flowreplay),就放弃了。这方面的研究至少我没有看到过(一般都去研究整个网络了,sigcomm评审人也没有提出类似的研究方案)。

    进入正题,tcpcopy是如何进行架构演化的呢?

    tcpcopy架构已历经三代,基本原理都一样,本质是利用在线数据包信息,模拟tcp客户端协议栈,欺骗测试服务器的上层应用服务。由于tcp交互是相互的,一般情况下需要知道测试服务器的响应数据包信息,才能利用在线请求数据包,构造出适合测试服务器的请求数据包,因此只要基于数据包的方式,无论怎么实现(除非是tcp协议改的面目全非),都需要返回响应包的相关信息。

    三种架构的差别就在于在什么地方截获响应包

    我们先看看tcpcopy最初的架构:

    从上图可以看出,tcpcopy是从数据链路层(pcap接口)抓请求数据包,发包是从IP层发出去,测试服务器的TCP协议栈没有类似ip queue或者nfqueue的干扰,响应包会直接返回给在线机器(通过设置路由),tcpcopy可以在数据链路层捕获到这些响应包,这些响应包会到达IP层,一般最终被丢弃掉(除非是客户端IP地址就是这台在线机器的IP地址,会通过IP层,但会被TCP reset掉)。

    这种架构一般只能工作在同一网段,而且对于外网应用,一般只能复制单台在线流量给测试服务器,无法对网易广告投放系统进行深度问题发现和潜能挖掘。

    第一种架构总结如下:

    好处:

    1)简单,粗暴

    2)适合冒烟测试

    3)测试结果比较真实

    不好的地方:

    1)相对而言,会更加影响在线,因为响应包信息全部回给在线机器了(当然这种还是比应用层面的请求复制,影响更小)

    2)同一网段限制

    3)对于外网应用,无法充分利用或者很难充分利用多台在线流量,从而无法为压力测试提供技术支持

    4)内网应用严重受限制,因请求的客户端IP地址不能是被复制的在线机器的IP地址

    第二种架构,也就是目前开源的架构,大致架构如下:

    从上面图中我们可以看出,tcpcopy默认从IP层抓包,从IP层发包,与第一种架构不同的是,我们在测试服务器进行响应包的截获,并通过intercept程序返回响应包的必要信息给tcpcopy。这种架构为分布式压力测试提供了可能性,相比第一种架构,大大推动了tcpcopy的进化。

    我们先从响应包的截获来分析,理论上,可以在测试服务器的IP层或者数据链路层进行截获响应包,我们具体分析如下:

    1)在数据链路层抓,正常情况下,其响应数据包会返回给真正发起请求的客户端,这会或多或少影响到客户端的TCP(频繁地reset)模块,而且在压力大的时候,会给交换机、路由器甚至整个网络,带来不必要的干扰。

    2)在测试服务器的IP抓响应包,正好有netlink技术来解决上面的问题,netlink是一种用户态进程与内核进行交互的技术,具体地我们可以利用内核模块ip queue(内核3.5以下版本)或者nfqueue(内核3.5或者以上版本)来达到捕获响应包的目的。

    我们采用了第二种方式,也即上图中的IP层来截获响应包,当响应包传递给intercept后,我们就能copy到响应包信息的必要信息(一般为TCP/IP头部信息),传递给tcpcopy,我们还可以通过verdict告诉内核,该如何处理这些响应包,如果没有设置白名单的话,就会在IP层丢弃掉这些响应包,这时候你是无法利用tcpudmp来抓到这些响应包的(tcpdump工作在数据链路层)。

    这种设计的好处就是可以支持复制多台在线流量到一台测试服务器中去,我们在intercept保留路由信息,知道响应包的相关信息该如何返回给哪一个tcpcopy实例。然而这种架构,intercept会不同程度地占用测试服务器的资源,而且ip queue或者nfqueue,并不一定能够高效工作,因而给测试,特别是高压测试和短连接压力测试,带来了很大麻烦。

    这种架构总结如下:

    好处:

    1)支持复制多台在线流量

    2)影响在线机器更小,因为一般只需要返回TCP/IP头部信息

    不好的地方:

    1)较第一种更为复杂

    2)性能极限往往在ip queue或者nfqueue

    3)intercept扩展性不好,受制于ip queue和nfqueue无法支持多进程进行响应包的捕获操作

    4)intercept影响测试服务器的最终测试结果,特别是压力大的时候

    5)无法对测试服务器进行完整测试(没有覆盖到数据链路层的出口)

    6)运维不方便

    第三种架构,如下图:

    上述架构,也即最新架构,是为了极限测试的目的而设计的,把intercept的工作从测试服务器(test server)中offload出来,放到另外一台独立的辅助服务器(assistant server,原则上一定要用同网段的一台闲置的服务器来充当辅助服务器)上面进行截获响应包,而且把原先从IP层捕获响应数据包的工作转移到从数据链路层抓响应包,这些改变大大降低了对测试机器的各种干扰(除了路由设置,其它已经没有影响了),而且大大扩大了捕获响应包的能力。当然这种测试也更加真实。

    具体如下:

    在运行上层服务的测试服务器test server上面设置路由信息,把待测试应用的需要被捕获的响应数据包信息路由到辅助服务器assistant server 上面,在assistant server上面,我们在数据链路层截获到响应包,从中抽取出有用的信息,再返回给相应的tcpcopy。

    为了高效使用,这种架构推荐使用pcap进行抓包,这样就可以在内核态进行过滤,否则只能在用户态进行包的过滤,而且在intercept端或者tcpcopy端设置filter(通过-F参数,类似tcpdump的filter),达到多个实例来共同完成抓包的工作,这样可扩展性就更强,适合于超级高并发的场合。

    这种架构需要的机器资源也更多,而且也变得更加难使用,需要了解tcp知识,route知识和pcap filter知识(类似于tcpdump过滤条件),因此推荐有条件的并且熟悉上述知识的人使用最新的架构。

    需要注意的是,在某些场景,pcap抓包丢包率会远高于raw socket抓包,因此最好利用pf_ring来辅助或者采用raw socket来抓包

    总结如下:

    好处:

    1)更加真实

    2)可扩展性更强

    3)适合高并发场合

    4)无ip queue或者nfqueue的各种限制

    5)对测试服务器几乎没有任何性能干扰的影响

    6)在运行服务的测试服务器,运维更加方便

    7)不会随运行服务的服务器崩溃而崩溃

    不好的地方:

    1)操作难度更大

    2)需要的机器数量更多

    3)需要的知识也更多

    4)assistant server(运行intercept的机器)原则上必须要和测试服务器(test server)在同一个网段

    上面三种架构均具有价值,目前开源出来的仅仅包括第二种架构和第三种架构,tcpcopy默认采用第二种架构,有条件的可以采用第三种架构。

    相关文章

      网友评论

          本文标题:利用tcpcopy引流做模拟在线测试(转)

          本文链接:https://www.haomeiwen.com/subject/mhrwaqtx.html