LibProNet是一个开源的C++网络通信引擎,它由一套网络库、一个消息框架和一些有用的网络编程套件构成。与其他著名的网络库诸如libevent/libuv/asio相比,LibProNet更加简洁清晰,容易使用。
LibProNet的工程地址为:https://github.com/libpronet/libpronet
我们今天测试的是LibProNet的网络库模块,目的是为了验证一下该模块的性能和能力参数。测试平台采用青云服务器和Ubuntu操作系统,测试工具采用LibProNet里的TestTcpServer和TestTcpClient程序。
我们关心的是400万TCP长连接的情况下,服务端程序的表现,比如CPU消耗、内存消耗等,客户端只是起配合的作用。因此服务端要求环境比较干净,不能有其他的程序干扰。我们使用两台测试机,一台运行服务端,一台运行客户端。由于是海量连接,每个TCP地址最多能发起60000多个连接,为了达到400万连接,我们需要在客户机上创建虚拟网卡。每块虚拟网卡发起60000个连接,大概需要创建70块虚拟网卡。
测试参数里,我们为每个套接字设置2048字节的发送缓冲区,2048字节的接收缓冲区,以及2048字节的接收池。考虑带些冗余,每个链路消耗的内存应该不会超过8K,400万链路即便不考虑虚拟内存交换,至多消耗32G物理内存,我们申请48G内存的主机应该是足够了。默认情况下,青云服务帐户有CPU核心数和内存配额的限制,大概是总共10个核心,总共40G内存,如果增加配额,需要提交身份认证。为了完成测试,上传证件,完成认证,之后CPU核心数和内存配额就足够测试使用了。
先申请两台如下配置的主机:
再申请一个交换机,并将两台主机与交换机相连:
外加一台路由器:
并将交换机连接到路由器:
接下来启动主机,通过Web页面的远程控制工具进入Linux系统,为了方便后续的测试,我们通过sudo su命令进入管理员模式。先看一下CPU配置:
此外,为了下载代码和编译工具,我们还需要申请一个公网IP,并将公网IP绑定到路由器上。这样,两台主机就可以通过路由器连接外网了。
系统就绪后,Server主机的IP地址为192.168.0.201,Client主机的IP地址为192.168.0.202。
为了支持海量连接,我们需要修改Linux系统配置,以便允许打开大量的文件句柄。我们保持在一个控制台终端里进行测试,执行以下命令:
sysctl -w fs.file-max=4100000
cat /proc/sys/fs/file-max
cat /proc/sys/fs/file-nr
sysctl -w fs.nr_open=4100000
cat /proc/sys/fs/nr_open
echo "* soft nofile 4100000" >> /etc/security/limits.conf
echo "* hard nofile 4100000" >> /etc/security/limits.conf
ulimit -n 4100000
ulimit -n
sysctl -w net.ipv4.ip_local_port_range="1024 65535"
cat /proc/sys/net/ipv4/ip_local_port_range
现在,如果命令行里没有提示错误,那么海量连接就允许了。注意不要重启机器,否则就要重新执行上述命令了,因为我们没有做永久设置。
另外,在Client主机里,我们需要创建70块虚拟网卡,命令如下:
ifconfig eth0:0 192.168.0.100 netmask 255.255.255.0 up
ifconfig eth0:1 192.168.0.101 netmask 255.255.255.0 up
ifconfig eth0:2 192.168.0.102 netmask 255.255.255.0 up
......
ifconfig eth0:69 192.168.0.169 netmask 255.255.255.0 up
ifconfig eth0:70 192.168.0.170 netmask 255.255.255.0 up
为了便于记忆,我们创建了71块虚拟网卡,第一行的eth0:0占个位,我们不使用它。
现在,运行测试的操作系统环境准备好了,剩下的工作就是下载和编译代码了。我们需要安装必要的开发工具,比如git/gcc/g++/automake/make等。
apt-get update
apt-get install autoconf automake gcc g++ make git-core screen nload
下载代码:
cd /
mkdir test
cd test
git clone https://github.com/libpronet/libpronet.git
编译代码:
cd libpronet/build/linux-gcc-r/x86_64
chmod 777 *.sh
./autogen.sh
make
准备运行目录:
cd ../../../pub/lib-r
chmod 777 *.sh
./_get-linux-x86_64.sh
cd ../../run_box
chmod 777 *.sh
./_get-linux-x86_64-r.sh
至此,运行目录就准备好了。为了便于在终端里切换上下文,我们让测试程序运行在screen环境里。对于服务端而言,只有一个服务进程,我们只需要创建一个screen会话就可以了,然后在这个会话环境里启动test_tcp_server程序;对于客户端而言,由于要创建70个测试进程,所以需要启动70个screen会话,在每个会话里运行一个test_tcp_client进程,各个进程分别绑定到192.168.0.101~192.168.0.170的IP地址。
服务端:
screen -S myserver #创建一个screen会话,名字叫myserver
./test_tcp_server #在myserver会话里运行服务端程序
Ctrl-A,D #按Ctrl-A组合键,再释放,再按D键,把screen切到后台,回到shell
客户端需要先用vi修改一下test_tcp_client.cfg文件,把服务器地址tcpc_server_ip的值改为192.168.0.201,把连接数tcpc_connection_count的值改为60000,其他保持默认。
screen -S myclient01
./test_tcp_client 0 0 192.168.0.101
Ctrl-A,D
screen -S myclient02
./test_tcp_client 0 0 192.168.0.102
Ctrl-A,D
......
screen -S myclient70
./test_tcp_client 0 0 192.168.0.170
Ctrl-A,D
注意控制一下并发节奏,一段时间后,连接就都建好了。
我们可以在服务端动态查看实际的在线连接数,先回到screen会话:
screen -r myserver
可以看到,一共40个线程,420万连接。我们切到shell看一下系统资源消耗:
Ctrl-A,D
ps统计数据:
vmstat统计数据:
top统计数据:
nload统计数据:
再到Web云控制台看一下统计信息:
为了直观显示,我们把四条占用数据都集合到一个图里了。可以看出,服务器的资源足够,远远没有用完呢!客户端的CPU消耗比较高些,是因为进程太多了,70个进程,每个进程10个工作线程,总体切换比较厉害。不过因为客户端只是这里的配角,我们不管它了。
通过资源消耗估计,服务端应该还可以支持更多的链路,不过我们就不继续测试它了。
上面的测试数据是在链路心跳包为200字节的情况下的数据,流量压力并不大。那我们加大一些数据压力会怎样呢。出于简单,我们修改一下服务端的心跳包大小,改为1000字节。这可以在服务端程序的控制台里,动态修改,命令如下:
screen -r myserver
htbtsize 1000
然后再看一下各项参数,vmstat:
top:
nload:
通过nload我们可以看到,目前的平均发送带宽达到了60.03MBit/s,但CPU和内存占用变化不大。
上述测试过程我们保持平稳运行了几个小时,通过分析测试数据,我们认为LibProNet的网络库还是很优异的,完全可以胜任海量系统的底层数据引擎。当然了,长期的生产环境测试才是最有意义的。