TCP并发是指一个服务器同时“hold住”的连接数量,确切的说就是指服务器端看到的“ESTABLISHED”状态的TCP连接数量。通过 netstat -n|grep ^tcp|awk '{print $NF}'|sort -nr|uniq -c
可以查看当前服务器TCP状态统计报告,下图是我的执行结果(我正在通过SSH连接这台机器所以有一个“ESTABLISHED”状态的TCP连接)
测试TCP并发就是指 让这个值达到的顶峰 ,要实现这个必须满足两点:
短时间内构造百万级连接
服务器端同时hold住百万级连接
需要注意的是上面的“测试”不包括“连接之后的交互”仅仅是指“hold住连接”。
很多服务器都是TCP结构的比如Mysql、Tomcat、Nginx,这些工具也有相应的压力测试工具,比较著名的包括:Jmeter、Tsung。这些工具的实现基本上是一致的
同时启动多个任务
每个任务打开一个socket连接到服务器
这种测试方法受限于三个资源
可以启动的任务数量(线程数或者进程数)
可以打开的socket数量(文件描述符)
受限于本机可用端口最大值——65535
第一个限制我们可以通过“协程”之类的技术手段解决;第二个限制在内存满足的情况下可以通过调整系统参数解决(参考我的《你真知道“Too many open files”?》);第三个限制几乎是致命的——传统上只能通过多台服务器一块协同。 即便解决了上述三个问题也很难在“短时间”内造成巨大的压力,大量的socket会吃光内存,多台服务器协同必然是一个分布式问题(想想就掉头发)。
TCP连接给人的感觉是一个“通道”,这其实这是一个“错觉”。所有的网络基本上都是基于“存储转发”的经过。三次握手之后的TCP连接到达“ESTABLISHED”状态,服务器会为它保留资源——即使客户端已经不再理睬这个连接。那么我们是不是可以不经过TCP/IP协议栈直接通过raw socket构造三次握手呢?只要我们大批量的构造三次握手就可以对服务器构成巨大的压力了。
我们重点关注Client->Server的两个箭头。第一个数据包是SYN数据包,seq=随机数;第二个数据包是ACK数据包,ACK=收到数据包的seq+1,seq=收到数据包的ack。 其实TCP数据包之间是没有直接关系的,我们收到一个数据包就可以直接算出回复数据包的ack、seq 上面的思路基本上可以证明我们的方法在理论上是可行的,在实践上我们还需要克服一些问题
怎么获取Server到Client的SYN+ACK(三次握手中的第二个箭头);毕竟我们不是直接使用Socket打开TCP连接(这样做就不需要自己构造TCP三次握手了)
Server在收到Client请求后会尝试对Client进行ARP地址,如果发现无法解析就认为是一个非法的数据包直接发送RST数据包关闭TCP连接
第一个问题我们通过libpcap“旁路”kernel,直接获取原始数据包。下图是libpcap的原理
libpcap底层使用的是BPF(Berkeley Packet Filter)驱动,这是kernel中专门用来“调试”的驱动程序最早是为Unix开发现在已经成为各种操作系统的标配(只要支持tcpdump那么底层一定是有实现这个驱动模型的)。它独立于kernel中的其他协议栈直接和读取数据链路层的数据包。 通过libpcap我们可以获取所有的数据包(即便操作系统不处理)然后构造自己的数据包通过raw socket直接把写入到数据链路层。 整个“收包”->“处理”->“回包”完全不需要kernel参与 。
第二个问题其实在前面的文章中我已经给出了答案——构造并且回复ARP数据包(《深入理解ARP攻击 》)。简单来说就是 通过libpcap获取arp request,通过raw socket回复arp response。
我努力去掉所有不相关的东西只保留了最精简的部分,不到300行的代码。代码分为两大部分“发起TCP SYN数据包”和“回复SYN+ACK数据包、ARP request数据包”。具体内容可以看这里 这次我特意放上了cmake文件,执行以下cmake就可以编译了。 https://github.com/fireflyc/million-tcp-client
受限于端口上限,一台服务器只能模拟65535个TCP连接。但是我提供的演示程序是可以指定IP地址的,这个IP地址只需要和目标IP在同一个网络内就可以了。比如我的测试环境:
测试机器有自己的IP地址172.16.46.128,但是这个IP地址并没有用途,只是为了方便我SSH连接。服务器的IP地址是172.16.46.133,我启动三个tcp-client分别绑定200、201、202。
每个TCP-Client进程都可以模拟65535个TCP连接。(这个其实还有改进的余地)
纠正一下《你真知道“Too many open files”? 》这篇文章的一个纰漏,一台服务器可以达到的TCP连接的极限不是受限于内存而是——1048576。 soft nofile的上限是2^20=1048576,所以一台服务器理论上可以达到的最大TCP并发数是——1048576。
最近一直在折腾data plane的一些事情所以写了一些关于这方面内容。SDN其实是一个“难者不会,会者不难”的东西,仅仅“沉迷于”玩玩opendaylight、ONOS的意淫,甚至都不了解open flow、没有研究过OVS那真不能算SDN。深入到“底层”后会发现打开了一个新世界的大门。“传统厂商”的一些技术会呈现在面前(兵器库),传统交换机、路由器、DPI设备看起来很高大上的东西其实也就是“原来如此”。归根结底“网络开发”的技术要求没有变,不是说因为有了SDN就意味着工作更轻松了、更加高层了可以完全无视底层实现了。SDN(或者说云计算)对开发者的要求是—— 要用兵器库中的工具去制造更高级的兵器 。(恩,OpenStack、ODL、ONOS乃至OVS都只能算兵器而已)
欢迎关注公众账号了解更多信息“写程序的康德——思考、批判、理性”