来,让我们做一个数据流的"分光镜"吧
来,让我们做一个数据流的"分光镜"吧
自由的眼 发表于11个月前
来,让我们做一个数据流的"分光镜"吧
  • 发表于 11个月前
  • 阅读 42
  • 收藏 0
  • 点赞 0
  • 评论 0

前一段时间,写过一篇帖子,http://eip.teamshub.com/t/3245814
里面最后提到了一种数据"分光镜"的技术。
今天我就来说说这个东东到底是什么,以及怎么运用。
当年习惯性的在QQ上搜索技术群,尤其是服务器技术的群,其中吹水的很多,加了看了几天就退了。被朋友推荐加入了一个tcpcopy的群(这个群那时候需要推荐才能加入),刚加入这个群的时候,6天没一个人说话。正准备放弃的时候,看到了群主的github连接,于是上去看了一眼。
似乎是一个类似抓包的开源工具,我感兴趣的是那几千个star为什么会给一个这样的工具。
于是和群主聊天,开始研究它的技术实现,最终发现,这确实是一个不得了的东西。
有幸和群主一起约出来吃饭,更加深入了解了这个东西的用途,这个东西很多大公司都在使用,确实起到了很好的测试效果。我开始在我的项目中使用,起到了非常好的效果。
数据分光镜是什么呢?
它解决的是"开发 - 测试 -运维"一条线上的信任关系。
开发不断的出新的迭代,传统的测试,往往通过测试工具,覆盖一定的场景,但是不可能完美覆盖所有的场景,导致了运维没次上线系统更新都是心惊胆战,生怕出什么篓子,从此往复循环,大家都活的很累。
而实际线上的数据流动多种多样,几乎可以覆盖各种情况,远远超过了传统测试能覆盖的测试结果。
那么,我们有没有一种方式,将在线的巨大流量,在不知不觉中导入到我的迭代的新系统中去呢?从而完成线上测试?
答案是可以的,我们需要将在线的数据流量,神不知鬼不觉的复制出来一份(类似光学的分光,你可以把数据变成一种光),传递给我的更新服务器,从而做到压力测试。
那么你可能会有一个疑问,我复制过去的流量,那么返回数据流量如何处理?其实很简单,在Linux下,使用IP Route规则做一个"黑洞",把哪些不必要的数据"吸"入黑洞就可以了。这样,在线数据什么都不会受到影响,同时,导出的流量,足足可以验证你的新上线的服务器是否稳定。当然,你也可以用此调试BUG,比如一个能引起服务器崩溃的BUG,在生产环境下不可停机的基础上,我们导入流量到测试服务器上,在测试服务器上做BUG的验证,极大的减轻了测试和运维的压力,同时也可以给程序员增加上线的信心。
来让我们看一张图,看看tcpcopy是怎么做的。


这是来源在一个网易平台的网络广告推荐算法的更新测试实例。(作者是网易的)
由于推荐算法会不断的更新,如果产生了推送广告不是用户想要的,就会造成很大的负面影响,
那么,使用tcpcopy,实际就可以将在线流量导入到每次的测试服务器上运行,即可得到相应的测试结果。
tcpcopy实际上不止可用在http,所有的tcp基础数据包也支持。比如一些硬件的数据流,视频流等等。当初我和作者开始开发适合于tcp任意数据包的数据流格式,并获得了成功。
它的实现是利用底层的数据抓包,直接从物理层链路抓数据,并修改包中关于IP指向的部分(将原有指向当前服务器的地址信息修改成测试主机的IP信息,并修改路由信息将数据跳到测试主机上去。前提是测试主机必须和生产环境在一个网段上)
那么,生产环境的数据流,就会被自动分成两份,一份流向当前正常的生产环境。另一份流向测试服务器。
那么,在测试服务器上,我们也需要做一些工作,设置回流的路由"中断",毕竟,我们不希望测试的服务器返回数据干扰生产环境,所以,我们必须做一个"黑洞",把测试服务器返回的数据全部吸收掉。
怎么做这个黑洞呢?我们需要设置一条路由规则,让返回的数据走到一个其它的IP上面去,在这个IP上把数据丢弃即可。同时,返回上层tcp发送"成功"。欺骗测试服务器网络一切正常,实际上返回的数据因为不存在的IP在底层被丢弃掉了。只是测试服务器不知道而已。
例如,具体事例,可以参考这里(http://www.cnblogs.com/tommyli/p/4239570.html)
之所以再说一遍,是因为这篇文章的顺序有问题,如果按照它的顺序,会造成一部分数据回流到正式环境,所以,步骤很重要,在这里强调一下,别被坑了。
第一步先制造数据黑洞,保证测试主机数据不能流回生产环境。
route add -net 192.168.100.0 netmask 255.255.255.0 gw 10.53.132.52
数据黑洞就造成了。
intercept -i eth1 -F tcp and src port 8090 -d当然,如果你的测试服务器被拿下干别的事情,最好恢复一下路由,否则会对别人不知情的使用者造成数据发送的困扰,切记。
那么,黑洞设置完了,我们看看怎么设置在线服务器。
先需要在在线服务器上安装tcpcopy,建议使用源代码编译安装方式,因为代码会根据环境进行一些优化的配置。
然后运行
tcpcopy -x 8090-10.53.132.55:8090 -s 10.53.132.52 -c 192.168.100.x -n 5
这里的一些参数,我需要说明一下
直接上源码来的快些,实际上,它可以支持不止是指定端口转发那么简单,还可以根据规则决定生产环境的那些数据被转发,那些不转发,真正起到"分光"的作用,那就是后话了。
    printf("tcpcopy " VERSION "\n");
#if (!TC_PCAP_SND)
    printf("-x use to specify the IPs and ports of the source and target\n"
           "               servers. Suppose 'sourceIP' and 'sourcePort' are the IP and port \n"
           "               number of the source server you want to copy from, 'targetIP' and \n");
    printf("               'targetPort' are the IP and port number of the target server you want\n"
           "               to send requests to, the format of could be as follows:\n"
           "               'sourceIP:sourcePort-targetIP:targetPort,...'. Most of the time,\n");
    printf("               sourceIP could be omitted and thus could also be:\n"
           "               'sourcePort-targetIP:targetPort,...'. As seen, the IP address and the\n"
           "               port number are segmented by ':' (colon), the sourcePort and the\n");
    printf("               targetIP are segmented by '-', and two 'transfer's are segmented by\n"
           "               ',' (comma). For example, './tcpcopy -x 80-192.168.0.2:18080' would\n"
           "               copy requests from port '80' on current server to the target port\n"
           "               '18080' of the target IP '192.168.0.2'.\n");
#else
    printf("-x use to specify the IPs, ports and MAC addresses of\n"
           "               the source and target. The format of could be as follow:\n");
    printf("               'sourceIP:sourcePort@sourceMac-targetIP:targetPort@targetMac,...'.\n"
           "               Most of the time, sourceIP could be omitted and thus could\n"
           "               also be: sourcePort@sourceMac-targetIP:targetPort@targetMac,...'.\n");
    printf("               Note that sourceMac is the MAC address of the interface where \n"
           "               packets are going out and targetMac is the next hop's MAC address.\n");
#endif
    printf("-H   change the localhost IP address to the given IP address\n");
    printf("-c  change the client IP to one of IP addresses when sending to the\n"
           "               target server. For example,\n"
           "               './tcpcopy -x 8080-192.168.0.2:8080 -c 62.135.200.x' would copy\n"
           "               requests from port '8080' of current online server to the target port\n"
           "               '8080' of target server '192.168.0.2' and modify the client IP to be\n"
           "               one of net 62.135.200.0/24.\n");
#if (TC_OFFLINE)
    printf("-i      set the pcap file used for tcpcopy to (only valid for the\n"
           "               offline version of tcpcopy when it is configured to run at\n"
           "               enable-offline mode).\n");
    printf("-a       accelerated times for offline replay\n");
    printf("-I       set the threshold interval for offline replay acceleration\n"
           "               in millisecond.\n");
#endif
#if (TC_PCAP)
    printf("-i   The name of the interface to listen on. This is usually a driver\n"
           "               name followed by a unit number, for example eth0 for the first\n"
           "               Ethernet interface.\n");
    printf("-F    user filter (same as pcap filter)\n");
    printf("-B       buffer size for pcap capture in megabytes(default 16M)\n");
    printf("-S   capture bytes per packet\n");
#endif
#if (TC_PCAP_SND)
    printf("-o   The name of the interface to send. This is usually a driver\n"
           "               name followed by a unit number, for example eth0 for the first\n"
           "               Ethernet interface.\n");
#endif
    printf("-n       use to set the replication times when you want to get a \n"
           "               copied data stream that is several times as large as the online data.\n"
           "               The maximum value allowed is 1023. As multiple copying is based on \n"
           "               port number modification, the ports may conflict with each other,\n");
    printf("               in particular in intranet applications where there are few source IPs\n"
           "               and most connections are short. Thus, tcpcopy would perform better \n"
           "               when less copies are specified. For example, \n"
           "               './tcpcopy -x 80-192.168.0.2:8080 -n 3' would copy data flows from \n");
    printf("               port 80 on the current server, generate data stream that is three\n"
           "               times as large as the source data, and send these requests to the\n"
           "               target port 8080 on '192.168.0.2'.\n");
    printf("-f       use this parameter to control the port number modification process\n"
           "               and reduce port conflications when multiple tcpcopy instances are\n"
           "               running. The value of should be different for different tcpcopy\n"
           "               instances. The maximum value allowed is 1023.\n");
    printf("-m       set the maximum memory allowed to use for tcpcopy in megabytes, \n"
           "               to prevent tcpcopy occupying too much memory and influencing the\n"
           "               online system. When the memory exceeds this limit, tcpcopy would quit\n"
           "               automatically. The parameter is effective only when the kernel \n");
#if (TC_MILLION_SUPPORT)
    printf("               version is 2.6.32 or above. The default value is 4096.\n");
#else
    printf("               version is 2.6.32 or above. The default value is 1024.\n");
#endif
    printf("-M       MTU value sent to backend (default 1500)\n");
    printf("-D       MSS value sent back(default 1460)\n");
    printf("-R       set default rtt value\n");
    printf("-U       set user session pool size in kilobytes(default 1).\n"
           "               The maximum value allowed is 63.\n");
    printf("-C       parallel connections between tcpcopy and intercept.\n"
           "               The maximum value allowed is 11(default 2 connections).\n");
    printf("-s   intercept server list\n"
           "               Format:\n"
           "               ip_addr1:port1, ip_addr2:port2, ...\n");
    printf("-t       set the session timeout limit. If tcpcopy does not receive response\n"
           "               from the target server within the timeout limit, the session would \n"
           "               be dropped by tcpcopy. When the response from the target server is\n"
           "               slow or the application protocol is context based, the value should \n"
           "               be set larger. The default value is 120 seconds.\n");
    printf("-k       set the session keepalive timeout limit.\n");
    printf("-l      save the log information in \n"
           "-r       set the percentage of sessions transfered (integer range:1~100)\n"
           "-p       set the target server listening port. The default value is 36524.\n");

共有 人打赏支持
粉丝 0
博文 9
码字总数 16565
作品 1
×
自由的眼
如果觉得我的文章对您有用,请随意打赏。您的支持将鼓励我继续创作!
* 金额(元)
¥1 ¥5 ¥10 ¥20 其他金额
打赏人
留言
* 支付类型
微信扫码支付
打赏金额:
已支付成功
打赏金额: