构建百万级连接的服务器之理论基础与实现Word下载.docx
《构建百万级连接的服务器之理论基础与实现Word下载.docx》由会员分享,可在线阅读,更多相关《构建百万级连接的服务器之理论基础与实现Word下载.docx(9页珍藏版)》请在冰豆网上搜索。
filter.ip_conntrack_max=1020000
需要重启系统服务生效:
#Linux
$sudosysctl-p/etc/sysctl.conf
#BSD
$sudo/etc/rc.d/sysctlreload
进程限制
执行:
ulimit-n
输出:
1024
说明当前Linux系统的每一个进程只能最多打开1024个文件.为了支持C1000K,你同样需要修改这个限制.
临时修改
ulimit-n1020000
不过,如果你不是root,可能不能修改超过1024,会报错:
-bash:
ulimit:
openfiles:
cannotmodifylimit:
Operationnotpermitted
永久修改
编辑/etc/security/limits.conf文件,加入如下行:
#/etc/security/limits.conf
workhardnofile1020000
worksoftnofile1020000
第一列的work表示work用户,你可以填*,或者root.然后保存退出,重新登录服务器.
注意:
Linux内核源码中有一个常量(NR_OPENin/usr/include/linux/fs.h),限制了最大打开文件数,如RHEL5是1048576(2^20),所以,要想支持C1000K,你可能还需要重新编译内核.
2.操作系统维持百万连接需要多少内存?
解决了操作系统的参数限制,接下来就要看看内存的占用情况.首先,是操作系统本身维护这些连接的内存占用.对于Linux操作系统,socket(fd)是一个整数,所以,猜想操作系统管理一百万个连接所占用的内存应该是4M/8M,再包括一些管理信息,应该会是100M左右.不过,还有socket发送和接收缓冲区所占用的内存没有分析.为此,我写了最原始的C网络程序来验证:
服务器
#include&
lt;
stdio.h&
gt;
stdlib.h&
string.h&
unistd.h&
errno.h&
arpa/inet.h&
netinet/tcp.h&
sys/select.h&
#defineMAX_PORTS10
intmain(intargc,char**argv){
structsockaddr_inaddr;
constchar*ip="
0.0.0.0"
;
intopt=1;
intbufsize;
socklen_toptlen;
intconnections=0;
intbase_port=7000;
if(argc&
2){
base_port=atoi(argv[1]);
}
intserver_socks[MAX_PORTS];
for(inti=0;
i&
MAX_PORTS;
i++){
intport=base_port+i;
bzero(&
amp;
addr,sizeof(addr));
addr.sin_family=AF_INET;
addr.sin_port=htons((short)port);
inet_pton(AF_INET,ip,&
addr.sin_addr);
intserv_sock;
if((serv_sock=socket(AF_INET,SOCK_STREAM,0))==-1){
gotosock_err;
if(setsockopt(serv_sock,SOL_SOCKET,SO_REUSEADDR,&
opt,sizeof(opt))==-1){
if(bind(serv_sock,(structsockaddr*)&
addr,sizeof(addr))==-1){
if(listen(serv_sock,1024)==-1){
server_socks[i]=serv_sock;
printf("
serverlistenonport:
%d\n"
port);
//optlen=sizeof(bufsize);
//getsockopt(serv_sock,SOL_SOCKET,SO_RCVBUF,&
bufsize,&
optlen);
//printf("
defaultsend/recvbufsize:
bufsize);
while
(1){
fd_setreadset;
FD_ZERO(&
readset);
intmaxfd=0;
FD_SET(server_socks[i],&
if(server_socks[i]&
maxfd){
maxfd=server_socks[i];
intret=select(maxfd+1,&
readset,NULL,NULL,NULL);
if(ret&
0){
if(errno==EINTR){
continue;
}else{
selecterror!
%s\n"
strerror(errno));
exit(0);
if(!
FD_ISSET(server_socks[i],&
readset)){
socklen_taddrlen=sizeof(addr);
intsock=accept(server_socks[i],(structsockaddr*)&
addr,&
addrlen);
if(sock==-1){
connections++;
connections:
%d,fd:
connections,sock);
return0;
sock_err:
error:
}
注意,服务器监听了10个端口,这是为了测试方便.因为只有一台客户端测试机,最多只能跟同一个IP端口创建30000多个连接,所以服务器监听了10个端口,这样一台测试机就可以和服务器之间创建30万个连接了.
客户端
=2){
Usage:
%sipport\n"
argv[0]);
constchar*ip=argv[1];
intbase_port=atoi(argv[2]);
chartmp_data[10];
intindex=0;
if(++index&
=10){
index=0;
intport=base_port+index;
connectto%s:
%d\n"
ip,port);
intsock;
if((sock=socket(AF_INET,SOCK_STREAM,0))==-1){
if(connect(sock,(structsockaddr*)&
if(connections%10000==9999){
pressEntertocontinue:
"
);
getchar();
usleep(1*1000);
/*
bufsize=5000;
setsockopt(serv_sock,SOL_SOCKET,SO_SNDBUF,&
bufsize,sizeof(bufsize));
setsockopt(serv_sock,SOL_SOCKET,SO_RCVBUF,&
*/
我测试10万个连接,这些连接是空闲的,什么数据也不发送也不接收.这时,进程只占用了不到1MB的内存.但是,通过程序退出前后的free命令对比,发现操作系统用了200M(大致)内存来维护这10万个连接!
如果是百万连接的话,操作系统本身就要占用2GB的内存!
也即2KB每连接.
可以修改
/proc/sys/net/ipv4/tcp_wmem
/proc/sys/net/ipv4/tcp_rmem
来控制TCP连接的发送和接收缓冲的大小(多谢@egmkang).
3.应用程序维持百万连接需要多少内存?
通过上面的测试代码,可以发现,应用程序维持百万个空闲的连接,只会占用操作系统的内存,通过ps命令查看可知,应用程序本身几乎不占用内存.
4.百万连接的吞吐量是否超过了网络限制?
假设百万连接中有20%是活跃的,每个连接每秒传输1KB的数据,那么需要的网络带宽是0.2Mx1KB/sx8=1.6Gbps,要求服务器至少是万兆网卡(10Gbps).
总结
Linux系统需要修改内核参数和系统配置,才能支持C1000K.C1000K的应用要求服务器至少需要2GB内存,如果应用本身还需要内存,这个要求应该是至少10GB内存.同时,网卡应该至少是万兆网卡.
当然,这仅仅是理论分析,实际的应用需要更多的内存和CPU资源来处理业务数据.
参考:
*http:
//www.cyberciti.biz/faq/linux-increase-the-maximum-number-of-open-files/
*
Relatedposts:
要记得清除sockaddr_in
构建C1000K的服务器
(2)–实现百万连接的comet服务器
数据传输中的停止等待机制的实现
Libevent2HTTP客户端示例
有趣的main函数参数
实现百万连接的comet服务器
这是关于C1000K序列文章的第二篇,在前一篇文章构建C1000K的服务器
(1)–基础中,介绍了支持C1000K的Linux系统的内核参数调整和系统设置.在本篇文章中,将对一个真正的应用服务器做C1000K测试.Comet服务器是一类逻辑相对简单,需要高并发连接的服务器.Comet在网站系统中的应用非常广泛,可以见这篇日志的介绍:
协议处理要开发一个支持百万并发连接的Comet服务器,我选择C/C++语言,当然还有其它的选择如Erlang,Java等.对于一个只支持long-pollingComet服务器,首先要具备解析HTTP协议的能力,我选择libevent来处理HTTP协议.通道和订阅者管理服务器在启动的时候,就预先分配了100万个通道对象的空间,但订阅者对象是按需分配的,通过内存池方式.100万个通道对象和程序的其它数据占用了24MB的内存.Benchmark启动icomet服务器:
./icomet
服务器监听了100个端口,是为了测试方便,原因见前一篇文章的分析:
构建C1000K的服务器
(1)–基础.然后启动benchmark客户端:
./tools/benchmark127.0.0.18100
benchmark程序每创建十万个连接,就会暂停,按回车后继续.通过top/ps查看icomet进程的内存占用.最终,得出如下数据.连接数进程VIRT进程RES039m24m100000302m288m200000579m565m5000001441m1427m10000002734m2720m