C10K问题

C10K问题:

网络服务在处理数以万计的客户端连接时,往往出现效率底下甚至完全瘫痪,这被成为C10K问题。

(C10K = connection 10 kilo 问题)。k 表示 kilo,即 1000 比如:kilometer(千米), kilogram(千克)。

非阻塞I/O,最关键的部分是 readiness notification(when ready, then notify!) 和找出哪一个 socket 上面发生了 I/O 事件。

一般我们首先会想到用 select 来实现。

int select(int n, fd_set *rd_fds; fd_set *wr_fds, fd_set *ex_fds, struct timeval * timeout);

其中用到了 fd_set 结构,而 fd_set 不能大于 FD_SETSIZE,默认是 1024,很容易导致数组越界。

针对 fd_set 的问题,*nix 提供了 poll 函数作为 select 的一个替代品:

int poll(struct pollfd *ufds, unsigned int nfds, int timeout)

第一个参数 ufds 是用户提供的一个 pollfd 数组,大小由用户自行决定,因此避免了 FD_SETSIZE 带来的麻烦。

然而 select 和 poll 在连接数增加时,性能急剧下降。这有两方面的原因:

《1》首先操作系统面对每次的 select/poll 操作,都需要重新建立一个当前线程的关心事件链表,并把线程挂在这个复杂的等待队列上,这是相当耗时的。

《2》其次,应用软件在 select/poll 返回后也需要对传入的句柄链表做一次循环扫描来 dispatch,这也是很耗时的。这两件事都是和并发数相关,而 I/O 事件的密度也和并发数相关,导致 CPU 占用率和并发数近似成O(n2) 的关系。

基于以上原因,*nix 的 hacker 们开发了 epoll, kqueue, /dev/poll 这3套利器。epoll 是 Linux 的方案,kqueue 是 freebsd 的方案,/dev/poll 是 solaris 的方案。

简单的说,这些 api 做了两件事:

《1》避免了每次调用 select/poll 时 kernel 分析参素建立事件等结构的开销,kernel 维护一个长期的时间关注列表,应用程序通过句柄修改这个链表和捕获I/P事件

《2》避免了select/poll 返回后,应用程序扫描整个句柄表的开销,kernel 直接返回具体的链表给应用程序。

在接触具体 api 之前,先了解一下边缘触发 (edge trigger) 和条件触发 (level trigger) 的概念。边缘触发是指每当状态变化时发生一个 io 事件,假定经过长时间的沉默后,现在来了 100 个字节,这是无论边缘触发和条件触发都会产生一个 read ready notification 通知应用程序可读。应用程序在读完来的 50 个字节,然后重新调用 api 等待 io 事件。这时条件触发的 api 会因为还有 50 个字节可读从而立即返回用户一个 read ready notification。而边缘触发的 api 会因为可读这个状态没有发生变化而陷入长期等待。

因此在使用边缘触发的 api 时,要注意每次都要读到 socket 返回 EWOULDBLOCK 为止,否则这个 socket 就算废了。而使用条件触发的 api 时,如果应用程序不需要写就不要关注 socket 可写的事件,否则会无限次的立即返回一个 write ready nitification。大家常用的 select 就是属于条件触发这一类,以前本人翻过长期关注 socket 写事件从而 CPU 100% 的毛病。

epoll 相关调用:

int epoll_create(int size);
int epoll_ctl(int epfd, int op, int fd, struct epoll_event *event);
int epoll_wait(int epfd, struct epoll_event *events, int maxevents, int timeout);

epoll_create 创建 kernel 中的关注事件表,相当于创建 fd_set。

epoll_ctl 修改这个表,相当与 FD_SET 等操作。

epoll_wait 完全是 select/poll 的升级版,支持的事件完全一致。并且 epoll 同时支持边缘触发和条件触发,一般来讲边缘触发的性能要好一些。

简单的例子:

strut epoll_event ev, *events;  

int kdpfd = epoll_create(100); // 创建 kernel 中的关注事件表,返回一个 kernel 事件表的句柄  

ev.events = EPOLLIN | EPOLLET; // 边缘触发
ev.data.fd = listener;  

epoll_ctl(kdpfd, EPOLL_CTL_ADD, listener, &ev); // 将事件 ev 加入到 kernel 关注的事件表中  

for(;;){  

   nfds = epoll_wait(kdpfd, events, maxevents, -1); // 等待被通知   

   for(n = 0; n < nfds; n++){
      if(events[n].data.fd == listener){  

         client = accept(listener, (struct sockaddr*)&local, &addrlen);   

         if(client < 0){  

            peror("accept");  

            continue;  

         }  

         setnonblocking(client);  

         ev.events = EPOLLIN | EPOLLET;  

         ev.data.fd = client;  

         if(epoll_ctl(kdpfd, EPOLL_CTL_ADD, client, &ev) < 0){  

            fprintf(stderr, "epoll set insertion error: fd = %d, client);  

            return -1;
        }
     }else
         do_use_fd(events[n].data.fd);
   }
}  
时间: 2024-12-28 04:41:58

C10K问题的相关文章

网络编程——C10K简述

C10K问题 网络服务在处理数以万计的客户端连接时,往往出现效率底下甚至完全瘫痪,这被成为C10K问题. (C10K = connection 10 kilo 问题).k 表示 kilo,即 1000 比如:kilometer(千米), kilogram(千克). 非阻塞I/O,最关键的部分是readiness notification(when ready, then notify!)和找出哪一个socket上面发生了I/O事件. 一般我们首先会想到用select来实现. int select

网络编程——The C10K Problem(C10K = connection 10 kilo 问题)。k 表示 kilo,即 1000

The C10K problem翻译 (C10K = connection 10 kilo 问题).k 表示 kilo,即 1000 比如:kilometer(千米), kilogram(千克). 如今的web服务器需要同时处理一万个以上的客户端了,难道不是吗?毕竟如今的网络是个big place了. 现在的计算机也很强大了,你只需要花大概$1200就可以买一个1000MHz的处理器,2G的内存, 1000Mbit/sec的网卡的机器.让我们来看看--20000个客户,每个为50KHz,100K

C10K problem

什么是C10K问题 1W个客户端连接上一个server,客户不定时的发送请求. I/O策略 软件架构 1.单线程解决多重I/O调用 不要使用阻塞/同步的调用,如果非要这么做,那就采用多进程或者多线程来并发处理. 使用非阻塞的调用和就绪通知策略,当下一个I/O可用时通知调用者.适用于套接字I/O,而不是磁盘I/O. 使用异步的调用和通知策略,当下一个I/O可用时通知调用者,适用于磁盘I/O和套接字I/O. 2.如何控制服务每个客户端的代码 每一个client对应一个服务端进程,每一个进程保存cli

The C10K problem

The C10K problem编写连接数巨大的高负载服务器程序时,经典的多线程模式和select模式都不再适用.应当抛弃它们,采用epoll/kqueue/dev_poll来捕获I/O事件.最后简要介绍了AIO.网络服务在处理数以万计的客户端连接时,往往出现效率低下甚至完全瘫痪,这被称为 C10K问题.随着互联网的迅速发展,越来越多的网络服务开始面临C10K问题,作为大型 网站的开发人员有必要对C10K问题有一定的了解.本文的主要参考文献是 http://www.kegel.com/c10k.

关于C10K、异步回调、协程、同步阻塞

最近到处在争论这些话题,发现很多人对一些基础的常识并不了解,在此发表一文做一下解释.此文未必能解答所有问题,各位能有一个大致的了解就好. C10K的由来 大家都知道互联网的基础就是网络通信,早期的互联网可以说是一个小群体的集合.互联网还不够普及,用户也不多.一台服务器同时在线100个用户估计 在当时已经算是大型应用了.所以并不存在什么C10K的难题.互联网的爆发期应该是在www网站,浏览器,雅虎出现后.最早的互联网称之为Web1.0, 互联网大部分的使用场景是下载一个Html页面,用户在浏览器中

C10K问题2

http://blog.csdn.net/zhoudaxia/article/details/12920993 是时候让 Web 服务器同时处理一万客户端了,你不觉得吗?毕竟,现在的 Web 是一个大地盘了. 并且,计算机也是一样的大. 你可以花 $1200 左右购买一台 1000MHz,2Gb RAM 和一块 1000Mbit/s 以太网卡的机器.我们来看看——在 20000 客户端(是 50KHz,100Kb 和 50Kb/s/客户端)时,它不采取任何更多的马力而是采用 4Kb 的硬盘和为2

轻松应对C10k问题

http://blog.csdn.net/u011011917/article/details/17203539 传统的.教科书里的I/O复用等待函数select/poll在处理数以万计的客户端连接时,往往出现效率低下甚至完全瘫痪,,这被称为C10K 问题. 本文尝试着以一个最简单的单线程epoll程序为基础,轻松应对收发数据不频繁的过万客户端并发连接.并以此回顾C10K问题,介绍应对C10K问题的本质方法,线程模式的选择,介绍服务器编程流行的Reactor模式.  顺带介绍怎么应对socket

C10K问题和Libevent库介绍

http://blog.chinaunix.net/uid-20761674-id-75056.html 一.C10K的问题 C10K的问题在上个世纪90年代就被提出来了.大概的意思是当用户数超过1万时,很多设计不良好的网络服务程序性能都将急剧下降.甚至瘫痪.并且,这个问题并不能通过升级硬件设备解决,是操作系统固有的问题,也就是说,如果你的服务器最高能支撑1000个并发,尽管你升级了计算能力高一倍的 cpu,内存再翻一番,硬盘转速在快一倍,也无法支撑2000个并发. 经典的网络编程模型有4个:

从C10K问题来看常见的中小型服务器I/O模型

问题描述: 关于C10问题的经典描述可以查看这个网页 http://www.kegel.com/c10k.html 具体来说就是服务器如何处理10k个客户端的并发连接,即 concurrent 10,000 connection .如果在很早以前互联网还不普及的时候,一个服务器很少会同时出现有10k的连接,但是现在互联网高速发展,这种规模的连接可能随处可见,所以如何来解决C10k的问题对于服务提供者来说是一个最先需要解决的问题.有人可以说现在硬件成本很低,连接增多可能会消耗很大的内存那么我扩充内