文档章节

来,让我们做一个数据流的"分光镜"吧

 自由的眼
发布于 2016/12/13 10:38
字数 2553
阅读 56
收藏 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
西城
技术主管
私信 提问
物理界科学无法解释现象:因果可以倒置,当下可以改变曾经

  物理学中有趣的实验是双缝干涉实验,它证明了光具有波粒二象性;更有趣的实验是单粒子双缝干涉实验,它表明:物体在产生与探测的奇怪过渡间,可能并不是明确存在的,甚至不是真正的粒子,...

科学解说家
01/02
0
0
HTTP 400 错误 - 请求无效 (Bad request)

介绍 您的Web服务器认为客户端发送的数据流 (例如您的浏览器或我们的 CheckUpDown 机器人 ) 是 ' 畸形的',即没有完全遵守 HTTP 协议。 因此您的 Web 服务器无法理解和处理该请求。 该错误几...

五大三粗
2015/11/12
0
0
Rxjs实践-各种排序算法排序过程的可视化展示

这几天学习下《算法》的排序章节,具体见对排序的总结,想着做点东西,能将各种排序算法的排序过程使用Rxjs通过可视化的方式展示出来,正好练系一下Rxjs的使用 本文不会太多介绍Rxjs的基本概念...

xiyuyizhi
2017/10/27
0
0
Head First C 第十章 进程间通信 创建管道

Head First C 第十章 进程间通信 创建管道 我们已经可以通过重定向的方式,将子进程的输出重定向到文件,但我们想从进程中直接读取数据,如何使实现。 用管道连接进程 我们曾经用一个命令来连...

AlexTuan
2016/04/10
58
0
精读《dob - 框架使用》

本系列分三部曲:《框架实现》 《框架使用》 与 《跳出框架看哲学》,这三篇是我对数据流阶段性的总结,正好补充之前过时的文章。 本篇是 《框架使用》。 1 引言 现在我们团队也在重新思考数...

黄子毅
2017/12/31
0
0

没有更多内容

加载失败,请刷新页面

加载更多

EOS官方钱包keosd

EOS官方钱包的名称是keosd,它负责管理你的私钥,并且帮你进行交易的签名。 不过不幸的是,keosd钱包对普通用户并不友好,它是一个命令行程序,目前还没有像以太坊的mist那样的图形化界面,而...

汇智网教程
今天
25
0
ArrayList的实现原理以及实现线程安全

一、ArrayList概述 ArrayList是基于数组实现的,是一个动态的数字,可以自动扩容。 ArrayList不是线程安全的,效率比较高,只能用于单线程的环境中,在多线程环境中可以使用Collections.syn...

一看就喷亏的小猿
今天
34
0
Netty 备录 (一)

入职新公司不久,修修补补1个月的bug,来了点实战性的技术---基于netty即时通信 还好之前对socket有所使用及了解,入手netty应该不是很难吧,好吧,的确有点难,刚看这玩意的时候,可能都不知道哪里...

_大侠__
昨天
40
0
Django简单介绍和用户访问流程

Python下有许多款不同的 Web 框架。Django是重量级选手中最有代表性的一位。许多成功的网站和APP都基于Django。 Django是一个开放源代码的Web应用框架,由Python写成。 Django遵守BSD版权,初...

枫叶云
昨天
52
0
Spring Cloud Stream消费失败后的处理策略(四):重新入队(RabbitMQ)

应用场景 之前我们已经通过《Spring Cloud Stream消费失败后的处理策略(一):自动重试》一文介绍了Spring Cloud Stream默认的消息重试功能。本文将介绍RabbitMQ的binder提供的另外一种重试...

程序猿DD
昨天
25
0

没有更多内容

加载失败,请刷新页面

加载更多

返回顶部
顶部