C10K问题和Libevent库介绍

http://blog.chinaunix.net/uid-20761674-id-75056.htmlphp

一.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上开发高性能的网络应用,只能选着第二、3种方式。考虑到复杂性,咱们每每只采用第2种。下面就讨论一下第二种模型。

html

咱们知道,实现异步IO通常是采用select 或poll来实现。Select 定义以下:java

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库的程序以下:
python

   


三.libevent库的应用

Go2代理是一个大流量的代理应用,月流量近TB。其中图片、flash、zip文件占总流量的绝大部分。为了减小流量成本,须要将部分进行分流。开始时,使用了传统的php代理来分流,但Go2并发访问极大,多进程架构的php没法承受,在虚拟主机vps上启动数秒后就当即瘫痪。后改用 python的twisted网络架构,采用了twisted的异步tcp通信功能。运行一段时间后,发现twisted的异步dns稳定性不太好,常常发生系统级的崩溃。最后,通过分析比较,决定采用libevent库来作Go2 的分流代理应用。

Libevent库支持异步socket,支持异步dns,并自己还带了个简单的http 服务器。Go2 的分流代理应用就是使用了libevent库的以上三个功能。
一、简单的http 服务器:实现的分类代理的用户端的输入,输出管理。
二、异步socket,实现了高并发性的用户接入,和高并发性的目的服务器访问。
三、异步dns,解决了dns查询时的并发性和高效性。

下面简单介绍一下Go2 的分流代理程序的主要流程。源代码请参考http://bbs.mycbc.cn/upload/bbs/viewthread.php?tid=601&extra=page%3D1

A.      主程序流程

linux



一、使用event_init()初始化libevent环境;
二、使用evhttp_new()生成http服务实例,并使用evhttp_bind_socket聆听指定的端口;
三、使用evhttp_set_cb设置http服务实例的url回调函数。
四、进入libevent的事件循环。每当有用户请求url,libevent将自动调用url所对应的回调函数。

B.      用户请求处理流程:

编程



一、Libevent监控到用户url访问请求,libevent调用自定义的回调函数。

二、对用户最终访问的url进行base64解码操做,获取到用户访问的目的URL。

三、检查目的URL是否合法,非法,则结束。

四、URL合法,检查是否有本地缓存,有,直接从本地缓存获取数据,返回,并结束。

五、没有本地缓存,则经过libevent的异步dns查询api 对目的域名进行解释,并设置解释完成后的回调函数。Api原型:evdns_resolve_ipv4(host, 0, http_dns_cb, req),其中host是域名, http_dns_cb是解释完成后的回调函数。

六、在回调函数http_dns_cb中,完成如下操做:

a) 使用libevent异步socket链接到指定的服务器,并经过监控socket是否可写来判断链接是否成功。经过设置监听socket写事件来完成这个功能:event_set (&req->proxyev, socket, EV_WRITE, my_connect_cb, req ),其中参数EV_WRITE告诉libevent,只监控socket的可写事件;my_connect_cb是事件发生后的回调函数。

b) 在my_connect_cb函数中,经过监控socket的可读事件,来获取服务器返回的数据:event_set(&req->proxyev, socket, EV_READ, my_read_cb, req ),其中参数EV_READ是告诉libevent只监控socket的可读事件;my_read_cb是当可读事件发生后的回调函数。

c) my_read_cb回调函数则是核心的数据处理函数。负责从服务器中获取数据,并将数据返回给用户。

七、将图片缓存到本地,结束。

Go2 的分流代理在实际应用中,每分钟能处理3000个请求,月流量近TB,而应用则是跑在一台低端的vps上。

参考文档:
一、C10K问题---epoll简介,搜狗实验室, http://www.sogou.com/labs/report/1-1.pdf
二、The C10K problem(英文),http://www.kegel.com/c10k.html
三、libevent 官方网站,http://www.monkey.org/~provos/libevent/
小程序

http://www.cnblogs.com/fll/archive/2008/05/17/1201540.htmlapi

相关文章
相关标签/搜索