mac os下有办法是用epoll吗?我要编译一个linux下写的源码,发现系统里没有epoll,有办法安装吗?
你这个程序是 linux-only 的还是 POSIX 兼容的?
如果是兼容的你看看他缺那个函数库装上就行了。我记得 mac 有 posix 兼容支持功能库装上就行了,当然这个兼容不全,有些东西还要自己另外装。
不过 epoll 我没印象是什么……好像是 Linux 内核的?
如果是 Linux 内核的东西,那这个程序就是 Linux-Only 的程序,你只能做源代码移植了。
BSD 的内核有 Linux 兼容接口层可以用,MAC 的我没印象有。
epoll 一共有三个函数,分别是 epoll_create() , epoll_ctl(),
epoll_wait() 。
下面介绍三个函数的原理
epoll_create()
该函数建立一个epoll句柄
epoll_ctl()
该函数是功能是将被监听的文件描述符添加到epoll句柄,或者从epoll句柄中删除,或者更改文件描述符的监听状态
epoll_wait()
该函数返回就绪的文件描述和就绪数目的大小
select 缺点
epoll 效率提升
当然以上优点是在特定环境下:
高并发,且任意时间只有少量的文件是活跃的,如果并发量低,文件活跃地多,select就不一定比 epoll 慢。
正确使用select和epoll需要理解在什么情况下,文件描述符会表示为就绪态。
SUSv3中说:如果对I/O函数的调用不会被阻塞,而不论该函数是否能够实际传输数据,此时文件描述符(未指定 O_NONBLOCK 标志)被认为是就绪的。
select 和 epoll 只会告诉我们 I/O 操作是否会阻塞, 而不是告诉我们到底能否成功传输数据。
默认情况下,epoll提供的是水平触发通知,表示epoll会告诉我们何时能在文件描述符上以非阻塞的方式执行 I/O 操作。 这和 select所提供的通知类型相同
epoll的边缘触发通知,表示自从上一次调用epoll_wait() 依赖,文件上是否已经有 I/O活动了,如果有多个I/O 事件发生的话,epoll将它们合并成一次单独的通知, 通过epoll_wait() 返回。 注意: 这里不同于信号驱动 I/O, 信号驱动 I/O中会产生多个信号。
想象下面一种情景
使用epoll监视一个套接字上的输入 ( EPOLLIN ), 接下来会发生如下事件。
边缘触发通知通常和非阻塞文件描述符结合使用
做服务器,你需要知道服务器都需要什么技术。首先,搭建服务器一般都是在Linux平台,所以你需要了解Linux知识,包括Linux操作命令。
另外,服务器经常需要脚本,你需要知道shell脚本的知识。
然后,就是网络通信,服务器和客户端需要进行通信,你需要知道tcp/ip协议,网络编程,http和https协议,还有单播,组播,广播。
还有,服务器一般还需要数据库做支撑,所以数据库还需要了解。
当然,最基础的编程语言肯定是需要熟练掌握的,最好能懂算法,这样搭建服务器才高效。
最后,还有一些特殊的技术,比如多客户端同时连接服务器问题,epoll,select技术,进程间通信技术,多线程技术,文件操作等。
当然,以上所有技术了解最好,有些是必须熟练使用的。但是有些不用熟练使用,因为服务器,也不会让你全干,分到每个人手上的活只是一部分。
在Linux Socket服务器短编程时,为了处理大量客户的连接请求,需要使用非阻塞I/O和复用,select、poll
和epoll是Linux API提供的I/O复用方式,自从Linux 26中加入了epoll之后,在高性能服务器领域得到广泛的
应用,现在比较出名的nginx就是使用epoll来实现I/O复用支持高并发,目前在高并 发的场景下,nginx越来越
收到欢迎。
select:
下面是select的函数接口:
[cpp] view plain copy
int select (int n, fd_set readfds, fd_set writefds, fd_set exceptfds, struct timeval timeout);
select 函数监视的文件描述符分3类,分别是writefds、readfds、和exceptfds。调用后select函数会阻塞,直
到有描述副就绪(有数据 可读、可写、或者有except),或者超时(timeout指定等待时间,如果立即返回设为
null即可),函数返回。当select函数返回后,可以 通过遍历fdset,来找到就绪的描述符。
select目前几乎在所有的平台上支持,其良好跨平台支持也是它的一个优点。select的一 个缺点在于单个进程
能够监视的文件描述符的数量存在最大限制,在Linux上一般为1024,可以通过修改宏定义甚至重新编译内核的
方式提升这一限制,但 是这样也会造成效率的降低。
poll:
[cpp] view plain copy
int poll (struct pollfd fds, unsigned int nfds, int timeout);
不同与select使用三个位图来表示三个fdset的方式,poll使用一个 pollfd的指针实现。
[cpp] view plain copy
struct pollfd {
int fd; / file descriptor /
short events; / requested events to watch /
short revents; / returned events witnessed /
};
pollfd结构包含了要监视的event和发生的event,不再使用select“参数-值”传递的方式。同时,pollfd并没有
最大数量限制(但是数量过大后性能也是会下降)。 和select函数一样,poll返回后,需要轮询pollfd来获取
就绪的描述符。
从上面看,select和poll都需要在返回后,通过遍历文件描述符来获取已经就绪的socket。事实上,同时连接的
大量客户端在一时刻可能只有很少的处于就绪状态,因此随着监视的描述符数量的增长,其效率也会线性下降。
epoll:
epoll的接口如下:
[cpp] view plain copy
int epoll_create(int size);
int epoll_ctl(int epfd, int op, int fd, struct epoll_event event);
typedef union epoll_data {
void ptr;
int fd;
__uint32_t u32;
__uint64_t u64;
} epoll_data_t;
struct epoll_event {
__uint32_t events; / Epoll events /
epoll_data_t data; / User data variable /
};
int epoll_wait(int epfd, struct epoll_event events, int maxevents, int timeout);
主要是epoll_create,epoll_ctl和epoll_wait三个函数。epoll_create函数创建epoll文件描述符,参数size并
'不是限制了epoll所能监听的描述符最大个数,只是对内核初始分配内部数据结构的一个建议。返回是epoll描
述符。-1表示创建失败。epoll_ctl 控制对指定描述符fd执行op操作,event是与fd关联的监听事件。op操作
有三种:添加EPOLL_CTL_ADD,删除EPOLL_CTL_DEL,修改EPOLL_CTL_MOD。分别添加、删除和
修改对fd的监听事件。epoll_wait 等待epfd上的io事件,最多返回maxevents个事件。
在 select/poll中,进程只有在调用一定的方法后,内核才对所有监视的文件描述符进行扫描,而epoll事先通
过epoll_ctl()来注册一 个文件描述符,一旦基于某个文件描述符就绪时,内核会采用类似callback的回调机制,
迅速激活这个文件描述符,当进程调用epoll_wait() 时便得到通知。
epoll的优点主要是一下几个方面:
1 监视的描述符数量不受限制,它所支持的FD上限是最大可以打开文件的数目,这个数字一般远大于2048,
举个例子,在1GB内存的机器上大约是10万左 右,具体数目可以cat /proc/sys/fs/file-max察看,一般来说这个
数目和系统内存关系很大。select的最大缺点就是进程打开的fd是有数量限制的。这对 于连接数量比较大的
服务器来说根本不能满足。虽然也可以选择多进程的解决方案( Apache就是这样实现的),不过虽然linux上面
创建进程的代价比较小,但仍旧是不可忽视的,加上进程间数据同步远比不上线程间同步的高效,所以也 不是
一种完美的方案。
2 IO的效率不会随着监视fd的数量的增长而下降。epoll不同于select和poll轮询的方式,而是通过每个fd定义的
回调函数来实现的。只有就绪的fd才会执行回调函数。
3支持电平触发和边沿触发(只告诉进程哪些文件描述符刚刚变为就绪状态,它只说一遍,如果我们没有采取
行动,那么它将不会再次告知,这种方式称为边缘触发)两种方式,理论上边缘触发的性能要更高一些,但是
代码实现相当复杂。
4mmap加速内核与用户空间的信息传递。epoll是通过内核于用户空间mmap同一块内存,避免了无畏的内存拷贝。
1、nginx相对于apache的优点:
轻量级,同样起web 服务,比apache占用更少的内存及资源
抗并发,nginx 处理请求是异步非阻塞的,而apache 则是阻塞型的,在高并发下nginx 能保持低资源低消耗高性能
高度模块化的设计,编写模块相对简单
社区活跃,各种高性能模块出品迅速啊
apache 相对于nginx 的优点:
rewrite ,比nginx 的rewrite 强大
动态页面
模块超多,基本想到的都可以找到
少bug ,nginx 的bug 相对较多
超稳定
存在就是理由,一般来说,需要性能的web 服务,用nginx 。如果不需要性能只求稳定,那就apache 吧。
后者的各种功能模块实现得比前者,例如ssl 的模块就比前者好,可配置项多。这里要注意一点,epoll(freebsd 上是 kqueue )网络
IO 模型是nginx 处理性能高的根本理由,但并不是所有的情况下都是epoll 大获全胜的,如果本身提供静态服务的就只有寥寥几个文
件,apache 的select 模型或许比epoll 更高性能。当然,这只是根据网络IO 模型的原理作的一个假设,真正的应用还是需要实测了再说
的。
2、作为 Web 服务器:相比 Apache,Nginx 使用更少的资源,支持更多的并发连接,体现更高的效率,这点
使 Nginx 尤其受到虚拟主机提供商的欢迎。在高连接并发的情况下,Nginx是Apache服务器不错的替代品: Nginx在美国是做虚拟主机生
意的老板们经常选择的软件平台之一 能够支持高达 50,000 个并发连接数的响应, 感谢Nginx为我们选择了 epoll and kqueue 作为开发模型
Nginx
作为负载均衡服务器: Nginx 既可以在内部直接支持 Rails 和 PHP 程序对外进行服务, 也可以支持作为 HTTP代理 服务器对外进行
服务 Nginx采用C进行编写, 不论是系统资源开销还是CPU使用效率都比 Perlbal 要好很多
作为邮件代理服务器: Nginx 同时也是一个非常优秀的邮件代理服务器(最早开发这个产品的目的之一也是作为邮件代理服务器), Lastfm 描述了成功并且美妙的使用经验
Nginx 是
一个安装非常的简单 , 配置文件非常简洁(还能够支持perl语法), Bugs 非常少的服务器: Nginx 启动特别容易, 并且几乎可以做到
724不间断运行,即使运行数个月也不需要重新启动 你还能够不间断服务的情况下进行软件版本的升级
3、Nginx 配置简洁, Apache 复杂
Nginx 静态处理性能比 Apache 高 3倍以上
Apache 对 PHP 支持比较简单,Nginx 需要配合其他后端用
Apache 的组件比 Nginx 多
现在 Nginx 才是 Web 服务器的首选
4、最核心的区别在于apache是同步多进程模型,一个连接对应一个进程;nginx是异步的,多个连接(万级别)可以对应一个进程
5、nginx处理静态文件好,耗费内存少但无疑apache仍然是目前的主流,有很多丰富的特性所以还需要搭配着来当然如果能确定nginx就适合需求,那么使用nginx会是更经济的方式
apache有先天不支持多核心处理负载鸡肋的缺点,建议使用nginx做前端,後端用apache。大型网站建议用nginx自代的集群功能
6、
从个人过往的使用情况来看,nginx的负载能力比apache高很多。最新的服务器也改用nginx了。而且nginx改完配置能-t测试一下配置有没
有问题,apache重启的时候发现配置出错了,会很崩溃,改的时候都会非常小心翼翼现在看有好多集群站,前端nginx抗并发,后端apache集群,
配合的也不错。
7、nginx处理动态请求是鸡肋,一般动态请求要apache去做,nginx只适合静态和反向。
8、从我个人的经验来看,nginx是很不错的前端服务器,负载性能很好,在老奔上开nginx,用webbench模拟10000个静态文件请求毫不吃力。apache对php等语言的支持很好,此外apache有强大的支持网路,发展时间相对nginx更久,
9、
Nginx优于apache的主要两点:1Nginx本身就是一个反向代理服务器 2Nginx支持7层负载均衡;其他的当然,Nginx可能会比
apache支持更高的并发,但是根据NetCraft的统计,2011年4月的统计数据,Apache依然占有6271%,而Nginx是
735%,因此总得来说,Aapche依然是大部分公司的首先,因为其成熟的技术和开发社区已经也是非常不错的性能。
10、你对web server的需求决定你的选择。大
部分情况下nginx都优于APACHE,比如说静态文件处理、PHP-CGI的支持、反向代理功能、前端Cache、维持连接等等。在
Apache+PHP(prefork)模式下,如果PHP处理慢或者前端压力很大的情况下,很容易出现Apache进程数飙升,从而拒绝服务的现象。
11、可以看一下nginx lua模块:https://githubcom/chaoslawapache比nginx多的模块,可直接用lua实现apache是最流行的,why?大多数人懒得更新到nginx或者学新事物
12、对于nginx,我喜欢它配置文件写的很简洁,正则配置让很多事情变得简单运行效率高,占用资源少,代理功能强大,很适合做前端响应服务器
13、Apache在处理动态有优势,Nginx并发性比较好,CPU内存占用低,如果rewrite频繁,那还是Apache吧
我问了在约APP的专家,修改上述限制的最简单的办法就是使用ulimit命令:
[speng@as4 ~]$ ulimit -n
上述命令中,在中指定要设置的单一进程允许打开的最大文件数。如果系统回显类似于“Operation notpermitted”之类的话,说明上述限制修改失败,实际上是因为在中指定的数值超过了Linux系统对该用户打开文件数的软限制或硬限制。因此,就需要修改Linux系统对用户的关于打开文件数的软限制和硬限制。
第一步,修改/etc/security/limitsconf文件,在文件中添加如下行:
speng soft nofile 10240
speng hard nofile 10240
其中speng指定了要修改哪个用户的打开文件数限制,可用’'号表示修改所有用户的限制;soft或hard指定要修改软限制还是硬限制;10240则指定了想要修改的新的限制值,即最大打开文件数(请注意软限制值要小于或等于硬限制)。修改完后保存文件。
第二步,修改/etc/pamd/login文件,在文件中添加如下行:
session required /lib/security/pam_limitsso
这是告诉Linux在用户完成系统登录后,应该调用pam_limitsso模块来设置系统对该用户可使用的各种资源数量的最大限制(包括用户可打开的最大文件数限制),而pam_limitsso模块就会从/etc/security/limitsconf文件中读取配置来设置这些限制值。修改完后保存此文件。
第三步,查看Linux系统级的最大打开文件数限制,使用如下命令:
[speng@as4 ~]$ cat /proc/sys/fs/file-max
12158
这表明这台Linux系统最多允许同时打开(即包含所有用户打开文件数总和)12158个文件,是Linux系统级硬限制,所有用户级的打开文件数限制都不应超过这个数值。通常这个系统级硬限制是Linux系统在启动时根据系统硬件资源状况计算出来的最佳的最大同时打开文件数限制,如果没有特殊需要,不应该修改此限制,除非想为用户级打开文件数限制设置超过此限制的值。修改此硬限制的方法是修改/etc/rclocal脚本,在脚本中添加如下行:
echo 22158 > /proc/sys/fs/file-max
这是让Linux在启动完成后强行将系统级打开文件数硬限制设置为22158。修改完后保存此文件。
完成上述步骤后重启系统,一般情况下就可以将Linux系统对指定用户的单一进程允许同时打开的最大文件数限制设为指定的数值。如果重启后用 ulimit-n命令查看用户可打开文件数限制仍然低于上述步骤中设置的最大值,这可能是因为在用户登录脚本/etc/profile中使用ulimit -n命令已经将用户可同时打开的文件数做了限制。由于通过ulimit-n修改系统对用户可同时打开文件的最大数限制时,新修改的值只能小于或等于上次 ulimit-n设置的值,因此想用此命令增大这个限制值是不可能的。所以,如果有上述问题存在,就只能去打开/etc/profile脚本文件,在文件中查找是否使用了ulimit-n限制了用户可同时打开的最大文件数量,如果找到,则删除这行命令,或者将其设置的值改为合适的值,然后保存文件,用户退出并重新登录系统即可。
通过上述步骤,就为支持高并发TCP连接处理的通讯处理程序解除关于打开文件数量方面的系统限制。
2、修改网络内核对TCP连接的有关限制(参考对比下篇文章“优化内核参数”)
在Linux上编写支持高并发TCP连接的客户端通讯处理程序时,有时会发现尽管已经解除了系统对用户同时打开文件数的限制,但仍会出现并发TCP连接数增加到一定数量时,再也无法成功建立新的TCP连接的现象。出现这种现在的原因有多种。
第一种原因可能是因为Linux网络内核对本地端口号范围有限制。此时,进一步分析为什么无法建立TCP连接,会发现问题出在connect()调用返回失败,查看系统错误提示消息是“Can’t assign requestedaddress”。同时,如果在此时用tcpdump工具监视网络,会发现根本没有TCP连接时客户端发SYN包的网络流量。这些情况说明问题在于本地Linux系统内核中有限制。其实,问题的根本原因在于Linux内核的TCP/IP协议实现模块对系统中所有的客户端TCP连接对应的本地端口号的范围进行了限制(例如,内核限制本地端口号的范围为1024~32768之间)。当系统中某一时刻同时存在太多的TCP客户端连接时,由于每个TCP客户端连接都要占用一个唯一的本地端口号(此端口号在系统的本地端口号范围限制中),如果现有的TCP客户端连接已将所有的本地端口号占满,则此时就无法为新的TCP客户端连接分配一个本地端口号了,因此系统会在这种情况下在connect()调用中返回失败,并将错误提示消息设为“Can’t assignrequested address”。有关这些控制逻辑可以查看Linux内核源代码,以linux26内核为例,可以查看tcp_ipv4c文件中如下函数:
static int tcp_v4_hash_connect(struct sock sk)
请注意上述函数中对变量sysctl_local_port_range的访问控制。变量sysctl_local_port_range的初始化则是在tcpc文件中的如下函数中设置:
void __init tcp_init(void)
内核编译时默认设置的本地端口号范围可能太小,因此需要修改此本地端口范围限制。
第一步,修改/etc/sysctlconf文件,在文件中添加如下行:
netipv4ip_local_port_range = 1024 65000
这表明将系统对本地端口范围限制设置为1024~65000之间。请注意,本地端口范围的最小值必须大于或等于1024;而端口范围的最大值则应小于或等于65535。修改完后保存此文件。
第二步,执行sysctl命令:
[speng@as4 ~]$ sysctl -p
如果系统没有错误提示,就表明新的本地端口范围设置成功。如果按上述端口范围进行设置,则理论上单独一个进程最多可以同时建立60000多个TCP客户端连接。
第二种无法建立TCP连接的原因可能是因为Linux网络内核的IP_TABLE防火墙对最大跟踪的TCP连接数有限制。此时程序会表现为在 connect()调用中阻塞,如同死机,如果用tcpdump工具监视网络,也会发现根本没有TCP连接时客户端发SYN包的网络流量。由于 IP_TABLE防火墙在内核中会对每个TCP连接的状态进行跟踪,跟踪信息将会放在位于内核内存中的conntrackdatabase中,这个数据库的大小有限,当系统中存在过多的TCP连接时,数据库容量不足,IP_TABLE无法为新的TCP连接建立跟踪信息,于是表现为在connect()调用中阻塞。此时就必须修改内核对最大跟踪的TCP连接数的限制,方法同修改内核对本地端口号范围的限制是类似的:
第一步,修改/etc/sysctlconf文件,在文件中添加如下行:
netipv4ip_conntrack_max = 10240
这表明将系统对最大跟踪的TCP连接数限制设置为10240。请注意,此限制值要尽量小,以节省对内核内存的占用。
第二步,执行sysctl命令:
[speng@as4 ~]$ sysctl -p
如果系统没有错误提示,就表明系统对新的最大跟踪的TCP连接数限制修改成功。如果按上述参数进行设置,则理论上单独一个进程最多可以同时建立10000多个TCP客户端连接。
3、使用支持高并发网络I/O的编程技术
在Linux上编写高并发TCP连接应用程序时,必须使用合适的网络I/O技术和I/O事件分派机制。
可用的I/O技术有同步I/O,非阻塞式同步I/O(也称反应式I/O),以及异步I/O。在高TCP并发的情形下,如果使用同步I/O,这会严重阻塞程序的运转,除非为每个TCP连接的I/O创建一个线程。但是,过多的线程又会因系统对线程的调度造成巨大开销。因此,在高TCP并发的情形下使用同步 I/O是不可取的,这时可以考虑使用非阻塞式同步I/O或异步I/O。非阻塞式同步I/O的技术包括使用select(),poll(),epoll等机制。异步I/O的技术就是使用AIO。
从I/O事件分派机制来看,使用select()是不合适的,因为它所支持的并发连接数有限(通常在1024个以内)。如果考虑性能,poll()也是不合适的,尽管它可以支持的较高的TCP并发数,但是由于其采用“轮询”机制,当并发数较高时,其运行效率相当低,并可能存在I/O事件分派不均,导致部分TCP连接上的I/O出现“饥饿”现象。而如果使用epoll或AIO,则没有上述问题(早期Linux内核的AIO技术实现是通过在内核中为每个 I/O请求创建一个线程来实现的,这种实现机制在高并发TCP连接的情形下使用其实也有严重的性能问题。但在最新的Linux内核中,AIO的实现已经得到改进)。
综上所述,在开发支持高并发TCP连接的Linux应用程序时,应尽量使用epoll或AIO技术来实现并发的TCP连接上的I/O控制,这将为提升程序对高并发TCP连接的支持提供有效的I/O保证。
内核参数sysctlconf的优化
/etc/sysctlconf 是用来控制linux网络的配置文件,对于依赖网络的程序(如web服务器和cache服务器)非常重要,RHEL默认提供的最好调整。
推荐配置(把原/etc/sysctlconf内容清掉,把下面内容复制进去):
netipv4ip_local_port_range = 1024 65536
netcorermem_max=16777216
netcorewmem_max=16777216
netipv4tcp_rmem=4096 87380 16777216
netipv4tcp_wmem=4096 65536 16777216
netipv4tcp_fin_timeout = 10
netipv4tcp_tw_recycle = 1
netipv4tcp_timestamps = 0
netipv4tcp_window_scaling = 0
netipv4tcp_sack = 0
netcorenetdev_max_backlog = 30000
netipv4tcp_no_metrics_save=1
netcoresomaxconn = 262144
netipv4tcp_syncookies = 0
netipv4tcp_max_orphans = 262144
netipv4tcp_max_syn_backlog = 262144
netipv4tcp_synack_retries = 2
netipv4tcp_syn_retries = 2
这个配置参考于cache服务器varnish的推荐配置和SunOne 服务器系统优化的推荐配置。
varnish调优推荐配置的地址为:http://varnishprojectslinprono/wiki/Performance
不过varnish推荐的配置是有问题的,实际运行表明“netipv4tcp_fin_timeout = 3”的配置会导致页面经常打不开;并且当网友使用的是IE6浏览器时,访问网站一段时间后,所有网页都会打不开,重启浏览器后正常。可能是国外的网速快吧,我们国情决定需要调整“netipv4tcp_fin_timeout = 10”,在10s的情况下,一切正常(实际运行结论)。
修改完毕后,执行:
/sbin/sysctl -p /etc/sysctlconf
/sbin/sysctl -w netipv4routeflush=1
命令生效。为了保险起见,也可以reboot系统。
调整文件数:
linux系统优化完网络必须调高系统允许打开的文件数才能支持大的并发,默认1024是远远不够的。
执行命令:
Shell代码
echo ulimit -HSn 65536 >> /etc/rclocal
echo ulimit -HSn 65536 >>/root/bash_profile
ulimit -HSn 65536
网站模板库 » mac os下有办法是用epoll吗?我要编译一个linux下写的源码,发现系统里没有epoll,有办法安装吗?
0条评论