libevent监控文件描述符个数上有限制吗
2个回答
展开全部
一.C10K的问题
C10K的问题在上个世纪90年代就被提出来了。大概的意思是当用户数超过1万时,很多设计不良好的网络服务程序性能都将急剧下降、甚至瘫痪。并且,这个问题并不能通过升级硬件设备解决,是操作系统固有的问题,也就是说,如果你的服务器最高能支撑1000个并发,尽管你升级了计算能力高一倍的 cpu,内存再翻一番,硬盘转速在快一倍,也无法支撑2000个并发。
经典的网络编程模型有4个:
1. Serve one client with each thread/process, and use blocking I/O。即对每个客户都使用不同的线程或进程进行服务,在每个线程或进程中使用阻塞I/O。这是小程序和java常用的策略,对于交互式的应用也是常见的选择,这种策略很能难满足高性能程序的需求,好处是实现极其简单,容易实现复杂的交互逻辑。我们常用的Apache、ftpd等都是这种工作。
2. Serve many clients with single thread, and use nonblocking I/O and readiness notification。即对所有的客户使用单一一个线程或进程进行服务,在这个线程或进程里,采用异步IO的策略。这是经典模型,优点在于实现较简单,方便移植,也能提供足够的性能;缺点在于无法充分利用多CPU的资源。
3. Serve many clients with each thread, and use nonblocking I/O and readiness notification 对经典模型2的简单改进,仍然采用异步IO的策略,但对所有的客户使用多个线程或进程进行服务。缺点是容易在多线程并发上出bug,甚至某些OS不支持多线程进行readiness notification
4. Serve many clients with each thread, and use asynchronous I/O 在有AI/O支持的OS上,能提供相当高的性能。不过AI/O编程模型和经典模型差别相当大,基本上很难写出一个框架同时支持AI/O和经典模型。这个模型主要是用于window平台上。
在linux上开发高性能的网络应用,只能选着第2、3种方式。考虑到复杂性,我们往往只采用第2种。下面就讨论一下第二种模型。
我们知道,实现异步IO一般是采用select 或poll来实现。Select 定义如下:
int select(int n, fd_set *rd_fds, fd_set *wr_fds, fd_set *ex_fds, struct timeval *timeout);
Poll 的接口如下:
int poll(struct pollfd *ufds, unsigned int nfds, int timeout);
然而 Select 和Poll 在连接数增加时,性能急剧下降。这有两方面的原因:首先操作系统面对每次的select/poll 操作,都需要重新建立一个当前线程的关心事件列表,并把线程挂在这个复杂的等待队列上,这是相当耗时的。其次,应用软件在select/poll 返回后也需要对传入的句柄列表做一次扫描来判断哪些句柄是可用的,这也是很耗时的。这两件事都是和并发数相关,而I/O 事件的密度也和并发数相关,导致CPU 占用率和并发数近似成O(n2)的关系。
因为以上的原因,Unix 上开发了性能更高的epoll, kqueue, /dev/poll 这3个程序接口来解决上述问题。其中epoll 是linux 的方案,kqueue 是freebsd 的方案,/dev/poll 是最古老的Solaris 的方案,使用难度依次递增。
简单的说,这些api 做了两件事:
1. 避免了每次调用select/poll 时kernel 分析参数建立事件等待结构的开销,kernel 维护一个长期的事件关注列表,应用程序通过句柄修改这个列表和捕获I/O 事件。
2. 避免了select/poll 返回后,应用程序扫描整个句柄表的开销,Kernel 直接返回具体的事件列表给应用程序。
二. libevent库
由于epoll, kqueue, /dev/poll每个接口都有自己的特点,程序移植非常困难,于是需要对这些接口进行封装,以让它们易于使用和移植,其中libevent库就是其中之一。
按照libevent的官方网站,libevent库提供了以下功能:当一个文件描述符的特定事件(如可读,可写或出错)发生了,或一个定时事件发生了,libevent就会自动执行用户指定的回调函数,来处理事件。目前,libevent已支持以下接口/dev/poll, kqueue(2), event ports, select(2), poll(2) 和 epoll(4)。Libevent的内部事件机制完全是基于所使用的接口的。因此libevent非常容易移植,也使它的扩展性非常容易。目前,libevent已在以下操作系统中编译通过:Linux,BSD,Mac OS X,Solaris和Windows。
使用libevent库进行开发非常简单,也很容易在各种unix平台上移植。一个简单的使用libevent库的程序如下:
三.libevent库的应用
Go2代理是一个大流量的代理应用,月流量近TB。其中图片、flash、zip文件占总流量的绝大部分。为了减少流量成本,需要将部分进行分流。开始时,使用了传统的php代理来分流,但Go2并发访问极大,多进程架构的php无法承受,在虚拟主机vps上启动数秒后就立即瘫痪。后改用 python的twisted网络架构,采用了twisted的异步tcp通讯功能。运行一段时间后,发现twisted的异步dns稳定性不太好,经常发生系统级的崩溃。最后,经过分析比较,决定采用libevent库来做Go2 的分流代理应用。
Libevent库支持异步socket,支持异步dns,并本身还带了个简单的http 服务器。Go2 的分流代理应用就是使用了libevent库的以上三个功能。
1、简单的http 服务器:实现的分类代理的用户端的输入,输出管理。
2、异步socket,实现了高并发性的用户接入,和高并发性的目的服务器访问。
3、异步dns,解决了dns查询时的并发性和高效性。
C10K的问题在上个世纪90年代就被提出来了。大概的意思是当用户数超过1万时,很多设计不良好的网络服务程序性能都将急剧下降、甚至瘫痪。并且,这个问题并不能通过升级硬件设备解决,是操作系统固有的问题,也就是说,如果你的服务器最高能支撑1000个并发,尽管你升级了计算能力高一倍的 cpu,内存再翻一番,硬盘转速在快一倍,也无法支撑2000个并发。
经典的网络编程模型有4个:
1. Serve one client with each thread/process, and use blocking I/O。即对每个客户都使用不同的线程或进程进行服务,在每个线程或进程中使用阻塞I/O。这是小程序和java常用的策略,对于交互式的应用也是常见的选择,这种策略很能难满足高性能程序的需求,好处是实现极其简单,容易实现复杂的交互逻辑。我们常用的Apache、ftpd等都是这种工作。
2. Serve many clients with single thread, and use nonblocking I/O and readiness notification。即对所有的客户使用单一一个线程或进程进行服务,在这个线程或进程里,采用异步IO的策略。这是经典模型,优点在于实现较简单,方便移植,也能提供足够的性能;缺点在于无法充分利用多CPU的资源。
3. Serve many clients with each thread, and use nonblocking I/O and readiness notification 对经典模型2的简单改进,仍然采用异步IO的策略,但对所有的客户使用多个线程或进程进行服务。缺点是容易在多线程并发上出bug,甚至某些OS不支持多线程进行readiness notification
4. Serve many clients with each thread, and use asynchronous I/O 在有AI/O支持的OS上,能提供相当高的性能。不过AI/O编程模型和经典模型差别相当大,基本上很难写出一个框架同时支持AI/O和经典模型。这个模型主要是用于window平台上。
在linux上开发高性能的网络应用,只能选着第2、3种方式。考虑到复杂性,我们往往只采用第2种。下面就讨论一下第二种模型。
我们知道,实现异步IO一般是采用select 或poll来实现。Select 定义如下:
int select(int n, fd_set *rd_fds, fd_set *wr_fds, fd_set *ex_fds, struct timeval *timeout);
Poll 的接口如下:
int poll(struct pollfd *ufds, unsigned int nfds, int timeout);
然而 Select 和Poll 在连接数增加时,性能急剧下降。这有两方面的原因:首先操作系统面对每次的select/poll 操作,都需要重新建立一个当前线程的关心事件列表,并把线程挂在这个复杂的等待队列上,这是相当耗时的。其次,应用软件在select/poll 返回后也需要对传入的句柄列表做一次扫描来判断哪些句柄是可用的,这也是很耗时的。这两件事都是和并发数相关,而I/O 事件的密度也和并发数相关,导致CPU 占用率和并发数近似成O(n2)的关系。
因为以上的原因,Unix 上开发了性能更高的epoll, kqueue, /dev/poll 这3个程序接口来解决上述问题。其中epoll 是linux 的方案,kqueue 是freebsd 的方案,/dev/poll 是最古老的Solaris 的方案,使用难度依次递增。
简单的说,这些api 做了两件事:
1. 避免了每次调用select/poll 时kernel 分析参数建立事件等待结构的开销,kernel 维护一个长期的事件关注列表,应用程序通过句柄修改这个列表和捕获I/O 事件。
2. 避免了select/poll 返回后,应用程序扫描整个句柄表的开销,Kernel 直接返回具体的事件列表给应用程序。
二. libevent库
由于epoll, kqueue, /dev/poll每个接口都有自己的特点,程序移植非常困难,于是需要对这些接口进行封装,以让它们易于使用和移植,其中libevent库就是其中之一。
按照libevent的官方网站,libevent库提供了以下功能:当一个文件描述符的特定事件(如可读,可写或出错)发生了,或一个定时事件发生了,libevent就会自动执行用户指定的回调函数,来处理事件。目前,libevent已支持以下接口/dev/poll, kqueue(2), event ports, select(2), poll(2) 和 epoll(4)。Libevent的内部事件机制完全是基于所使用的接口的。因此libevent非常容易移植,也使它的扩展性非常容易。目前,libevent已在以下操作系统中编译通过:Linux,BSD,Mac OS X,Solaris和Windows。
使用libevent库进行开发非常简单,也很容易在各种unix平台上移植。一个简单的使用libevent库的程序如下:
三.libevent库的应用
Go2代理是一个大流量的代理应用,月流量近TB。其中图片、flash、zip文件占总流量的绝大部分。为了减少流量成本,需要将部分进行分流。开始时,使用了传统的php代理来分流,但Go2并发访问极大,多进程架构的php无法承受,在虚拟主机vps上启动数秒后就立即瘫痪。后改用 python的twisted网络架构,采用了twisted的异步tcp通讯功能。运行一段时间后,发现twisted的异步dns稳定性不太好,经常发生系统级的崩溃。最后,经过分析比较,决定采用libevent库来做Go2 的分流代理应用。
Libevent库支持异步socket,支持异步dns,并本身还带了个简单的http 服务器。Go2 的分流代理应用就是使用了libevent库的以上三个功能。
1、简单的http 服务器:实现的分类代理的用户端的输入,输出管理。
2、异步socket,实现了高并发性的用户接入,和高并发性的目的服务器访问。
3、异步dns,解决了dns查询时的并发性和高效性。
2016-07-02
展开全部
epoll跟select都能提供多路I/O复用的解决方案。在现在的Linux内核里有都能够支持,其中epoll是Linux所特有,而select则应该是POSIX所规定,一般操作系统均有实现。网上现在关于这两者不同的介绍已经到处都是了。我这里也不能多说出什么东西,只是记录下我看了实现代码之后的一些总结。两者的使用场景一般是通过一个入口能够同时监控多路I/O。一般使用的接口,epool就是intepoll_wait(intepfd,structepoll_event*events,intmaxevents,inttimeout);select为:intselect(intnfds,fd_set*readfds,fd_set*writefds,fd_set*exceptfds,structtimeval*timeout);通过上述两个函数能够将调用线程阻塞,线程变为可执行条件有两种情况:无任何事件发生,超时时间已过在所控制的I/O有事件到来epoll_wait函数中看不到相关的监控信息,因为是通过epoll_ctl已经加入,而select之间在函数调用中由(fd_set*readfds,fd_set*writefds,fd_set*exceptfds)传入。epoll_wait饭互结果通过events返回,而select的传入参数也是传出参数。两者传出参数均表示发生事件的对应I/O标识。两种方式的区别主要体现在以下几个方面:select所能控制的I/O数有限,这主要是因为fd_set数据结构是一个有大小的,相当与一个定长所数组。select每次都需要重新设置所要监控的fd_set(因为调用之后会改变其内容),这增加了程序开销。select的性能要比epoll差,具体原因会在后续内容中详细说明。嗯,说道这个为什么select要差,那就要从这个selectAPI说起了。这个传进去一个数组,内部实现也不知道那个有哪个没有,所以要遍历一遍。假设说我只监控一个文件描述符,但是他是1000。那么select需要遍历前999个之后再来poll这个1000的文件描述符,而epoll则不需要,因为在之前epoll_ctl的调用过程中,已经维护了一个队列,所以直接等待事件到来就可以了。Linux中select此段相关代码为:/*遍历所有传入的fd_set*/for(i=0;i
已赞过
已踩过<
评论
收起
你对这个回答的评价是?
推荐律师服务:
若未解决您的问题,请您详细描述您的问题,通过百度律临进行免费专业咨询
您可能需要的服务
百度律临官方认证律师咨询
平均3分钟响应
|
问题解决率99%
|
24小时在线
立即免费咨询律师
14778人正在获得一对一解答
广州萤火虫6分钟前提交了问题
长沙森林舞者2分钟前提交了问题
大连海浪之心6分钟前提交了问题