免费注册 查看新帖 |

Chinaunix

  平台 论坛 博客 文库
最近访问板块 发新帖
楼主: wyezl

epoll模型的使用及其描述符耗尽问题的探讨 [复制链接]

论坛徽章:
0
发表于 2006-09-25 10:24 |显示全部楼层
继续这个问题。 有过实际网络编程经验的兄弟看一下。
这个server在访问量不是非常大的情况下,有时候cpu利用率能达到99%,但过几分钟又自己下去了。
而且99%的时候服务不受任何影响,速度还是很快。
load average: 0.20    最高能达到1。

在99%的时候,重新启动http server,立刻能降下去。 但一会还有可能上去。很奇怪。


请帮忙分析下是什么原因。

论坛徽章:
1
2015年辞旧岁徽章
日期:2015-03-03 16:54:15
发表于 2006-09-25 22:13 |显示全部楼层

貌似内存被吃光了

这阵子一直在编写代理服务器
发现了一个有趣的现象:
当服务器很快,客户端很慢的时候
大量数据积压在代理服务器的tcp缓冲区里
代理服务器内存占用急剧上升,内存快用完的时候,发生SWAP然后CPU占用也上去了
最糟糕的时候是内存占用增长过快,代理服务程序被内核直接杀掉
在默认TCP内核参数下,代理1000个并发连接(2000个套接字)最高消耗掉800M内存
在top界面看不到服务程序内存内存消耗增加,但系统可用内存几分钟内就没有了
断开连接内存就恢复了

若是客户端或服务器拔网线或是拔电,就只好等KEEPALIVE起作用了,
此期间内存占用一直居高不下

论坛徽章:
0
发表于 2006-09-26 10:02 |显示全部楼层
原帖由 safedead 于 2006-9-25 22:13 发表
这阵子一直在编写代理服务器
发现了一个有趣的现象:
当服务器很快,客户端很慢的时候
大量数据积压在代理服务器的tcp缓冲区里
代理服务器内存占用急剧上升,内存快用完的时候,发生SWAP然后CPU占用也上去了
...


网络编程在实际应用中经常出现一些奇怪的现象。
远远没有书上讲的几个调用那么干净简单。
我那个程序没有动态分配内存。 所以内存基本上空闲。
就是cpu用了n多。

正常情况输出。
strace  -c   -p16940
Process 16940 attached - interrupt to quit

Process 16940 detached
% time     seconds  usecs/call     calls    errors syscall
------ ----------- ----------- --------- --------- ----------------
81.33    4.041201         313     12929           accept
13.48    0.669718          52     12929           epoll_ctl
  3.39    0.168595           7     25858           fcntl64
  1.79    0.089180           7     12929           time
------ ----------- ----------- --------- --------- ----------------
100.00    4.968694                 64645           total



vmstat
procs -----------memory---------- ---swap-- -----io---- --system-- ----cpu----
r  b   swpd   free   buff  cache   si   so    bi    bo   in    cs us sy id wa
0  0   4988 873736  48832  53464    0    0     1     5    0     9  2  4 94  0



accept在严重的时候占用99。95%。 估计是因为没有使用非阻塞导致的吧。

[ 本帖最后由 wyezl 于 2006-9-26 10:03 编辑 ]

论坛徽章:
0
发表于 2006-09-26 10:38 |显示全部楼层
晕,顶这么多贴?? 小的描述符关闭后可以复用的, 只需要在程序设计时自己注意一下.  一般设计时会设定一个最大上限比如允许 1024 个并发连接. 那么你可以将套接字描述符控制在 1100 以下.(假设主程序还有若干文件描述符打开)

比如在 accept 之后调用系统调用 dup(), 它会复制一个描述符出来, 如果你确定有较小的可以尝试5次调用dup()直到返回较小的为止.

fd2 = dup(fd);
close(fd);

..................

[ 本帖最后由 hightman 于 2006-9-26 10:39 编辑 ]

论坛徽章:
0
发表于 2006-09-26 10:46 |显示全部楼层
原帖由 hightman 于 2006-9-26 10:38 发表
晕,顶这么多贴?? 小的描述符关闭后可以复用的, 只需要在程序设计时自己注意一下.  一般设计时会设定一个最大上限比如允许 1024 个并发连接. 那么你可以将套接字描述符控制在 1100 以下.(假设主程序还有若干文件描 ...


我更晕。你那治标不治本。
现在问题已经转移到cpu利用率上来了。跟fd无关了。
偶尔cpu利用率过高的问题。

论坛徽章:
1
2015年辞旧岁徽章
日期:2015-03-03 16:54:15
发表于 2006-09-26 20:20 |显示全部楼层
accept占用高我还从没遇到过
我用的是阻塞socket
每秒新建连接数不超过2000
并发控制在8000之内

你的accept速度是不是太快了, 我记得你的每秒新建连接超过1万了
我发生CPU高涨全是软中断和TCP缓存不够引起的
跟网卡有关(PCI-X 64bit 66MHz效率太低了)

2.6内核的异步IO机制还有内核级线程使得高并发容易实现多了,
但是按下葫芦又起瓢, 其它以前看不到的问题现在都出现了

论坛徽章:
0
发表于 2006-09-28 10:46 |显示全部楼层
原帖由 safedead 于 2006-9-26 20:20 发表
accept占用高我还从没遇到过
我用的是阻塞socket
每秒新建连接数不超过2000
并发控制在8000之内

你的accept速度是不是太快了, 我记得你的每秒新建连接超过1万了
我发生CPU高涨全是软中断和TCP缓存不够引起 ...


问题是,不上线测试问题就是出不来。
用工具测试情况都很理想。

估计跟client的网络状态有关。


站内短信给我留个msn吧,有空跟你请教网络编程。

[ 本帖最后由 wyezl 于 2006-9-28 10:49 编辑 ]

论坛徽章:
0
发表于 2006-09-29 17:39 |显示全部楼层
原帖由 solegoose 于 2006-9-1 10:13 发表
我认为原因是没有对每个FD进行超时的管理.
假设下列情况,一用户发起连接,服务器accept成功,返回了FD,但是在用户发起请求前,如果网络有问题,此FD当然无法返回POLLIN,当然就不会有POLLOUT等等了,这样FD就无法关闭. ...

为什么你们总是想着关闭FD呢?
我是这样做的

void *thread(void *data)
{
        struct epoll_event events[20];


        for ( ; ; ) {
                printf("begin epoll wait, threadid = %d\n", pthread_self());
                int nfds=epoll_wait(epfd,events,20, -1);

                for(int i=0;i<nfds;++i)
                {
                        //printf("begin epoll wait, fd  = %d, events = %lu\n", events.data.fd, events.events);
                        if(events.data.fd == g_listenfd )
                        {
                                num ++;
                                struct sockaddr_in clientaddr;
                                socklen_t clilen;

                                int connfd = accept(g_listenfd,(struct sockaddr *)&clientaddr, &clilen);
                                if(connfd<0){
                                        printf("error in g_listenfd\n");
                                        break;
                                }
                                //printf("ip = %s\n", inet_ntoa(clientaddr.sin_addr));
                                int intMsg;
                                intMsg = allowip.select_ip(clientaddr.sin_addr.s_addr);
                                //printf("intMsg = %d\n", intMsg);
                                if(intMsg == 1 || num == 1)
                                {
                                        setnonblocking(connfd);

                                        //printf("new connection fd = %d\n", connfd);

                                        struct epoll_event ev;
                                        ev.data.fd=connfd;
                                        ev.events=EPOLLHUP|EPOLLERR|EPOLLIN|EPOLLET|EPOLLPRI;
                                        epoll_ctl(epfd, EPOLL_CTL_ADD, connfd ,&ev);
                                }
                        }

                        else if(events.events&EPOLLIN)
                        {

                                char buffer[102400] = {0};
                                if ( (events.data.fd) < 0) continue;
                                int connfd = events.data.fd;       

                                int a = recv(connfd, buffer, sizeof(buffer), 0);

                                if (a > 0)
                                {
                                               //业务处理               
                                }
                                else
                                {
                                        if (a == 0 || errno == ECONNRESET)
                                        {

                                                struct epoll_event ev;
                                                ev.data.fd=connfd;
                                                if (epoll_ctl(epfd, EPOLL_CTL_DEL, connfd ,&ev) == 0)
                                                {
                                                        //ev.events=EPOLLHUP|EPOLLERR|EPOLLOUT|EPOLLET|EPOLLPRI;
                                                        //printf("epoll_ctl after del return = %d\n", epoll_ctl(epfd, EPOLL_CTL_MOD, connfd ,&ev));
                                                }

                                                if (myclose(connfd) == 0)
                                                        printf("close success\n");
                                                else
                                                        printf("close error\n");
                                        }

                                }
                        }

                        else if(events.events&EPOLLOUT)
                        {   
                                if ( (events.data.fd) < 0) continue;
                                int connfd = events.data.fd;

                                //send(connfd, buffer, strlen(buffer), 0);

                                struct epoll_event ev;
                                ev.data.fd=connfd;
                                ev.events=EPOLLHUP|EPOLLERR|EPOLLIN|EPOLLET|EPOLLPRI;
                                epoll_ctl(epfd, EPOLL_CTL_MOD, connfd ,&ev);

                        }
                        else if(events.events&EPOLLERR)
                        {
                                printf("error on fd = %d\n", events.data.fd);
                        }
                        else if(events.events&EPOLLHUP)
                        {
                                printf("hup on fd = %d\n", events.data.fd);
                        }
                        else if (events.events & EPOLLPRI)
                        {
                                printf(" epollpri %d\n", events.data.fd);
                        }
                        else if (events.events & EPOLLET)
                                printf("epollet %d\n", events.data.fd);
                }
        }
}

[ 本帖最后由 GodArmy 于 2006-9-29 17:40 编辑 ]

论坛徽章:
0
发表于 2006-09-29 18:41 |显示全部楼层
原帖由 GodArmy 于 2006-9-29 17:39 发表

为什么你们总是想着关闭FD呢?
我是这样做的

void *thread(void *data)
{
        struct epoll_event events[20];


        for ( ; ; ) {
                printf("begin epoll wait, threadid = %d\n", pthread_sel ...


我觉得这个程序能用但效率比较低。
能把程序中的高明之处指出来吗?


现在描述符到是小事了。
accept成了大事,有时候莫名其妙把cpu吃到99%。
比较奇怪,我还单独一个线程接受的呢。

论坛徽章:
0
发表于 2006-11-02 19:25 |显示全部楼层

不知道LZ是否试验了libevent

libevent封装了epoll的操作
默认是用的EPOLLLT
虽然没有用EPOLLET,但满足千个左右的client应该是没有问题的吧

我也在用libevent封装自己的程序
使用过程中发现了一些问题
一起探讨吧
您需要登录后才可以回帖 登录 | 注册

本版积分规则 发表回复

  

北京盛拓优讯信息技术有限公司. 版权所有 京ICP备16024965号-6 北京市公安局海淀分局网监中心备案编号:11010802020122 niuxiaotong@pcpop.com 17352615567
未成年举报专区
中国互联网协会会员  联系我们:huangweiwei@itpub.net
感谢所有关心和支持过ChinaUnix的朋友们 转载本站内容请注明原作者名及出处

清除 Cookies - ChinaUnix - Archiver - WAP - TOP