84669 orang belajar
152542 orang belajar
20005 orang belajar
5487 orang belajar
7821 orang belajar
359900 orang belajar
3350 orang belajar
180660 orang belajar
48569 orang belajar
18603 orang belajar
40936 orang belajar
1549 orang belajar
1183 orang belajar
32909 orang belajar
IO流程是怎样的?nginx、apache是基于哪种IO,为什么?
学习是最好的投资!
可以用 sudo strace -p PID 查看编号的PID的进程的系统调用.nginx master: rt_sigsuspendnginx worker: epoll_waitphp-fpm master: epoll_wait (events.mechanism = epoll)php-fpm worker: accept poll可见Nginx工作进程进行了epoll_wait系统调用,epoll是Linux内核提供的异步网络IO编程接口.
http://liuxun.org/blog/nginx-gong-zuo-jin-cheng-mo-xing/Nginx并没有像PHP-FPM那样采用master进程来分发连接,这个工作由操作系统内核机制完成,所以可能会导致惊群现象,也就是当listen_fd有新的accept()请求过来,操作系统会唤醒所有子进程.Nginx通过全局互斥锁来避免惊群(accept_mutex on),每个工作进程在epoll_wait()之前先去申请锁,申请到则继续处理,获取不到则等待,并设置了一个负载均衡的算法(当某一个工作进程的任务量达到总设置量的7/8时,则不会再尝试去申请锁)来均衡各个进程的任务量.http://nginx.org/en/docs/ngx_core_module.html#accept_mutex
Nginx解决惊群的新方法:使用内核提供的Socket ReusePort功能NGINX 1.9.1 支持socket分片:http://nglua.com/docs/sharding.htmlhttp://nginx.com/blog/socket-sharding-nginx-release-1-9-1/NGINX1.9.1支持socket的SO_REUSEPORT选项,这个选项在许多操作系统的新版本有效,包括DragonFly BSD和Linux(3.9+内核).这个选项允许多个socket监听同一个IP地址和端口的组合.内核负载均衡这些进来的sockets连接,将这些socket有效的分片.当SO_REUSEPORT选项没开启时,连接进来时监听socket默认会通知某个进程.如果accept_mutex off这个指令,此时会唤醒所有的工作进程,它们将为了得到它产生竞争,这就是所谓的惊群现象.如果使用epoll且不用锁(accept_mutex off),当监听端口有读操作时,是会产生惊群现象的.启用SO_REUSEPORT选项后,每个进程将有个独立的监听socket.内核决定哪个是有效的socket(进程)得到这个连接.这样做降低了延迟并提高了工作进程的性能,它也意味着工作进程在准备处理它们前被赋予了新的连接.开启SO_REUSEPORT支持,只需将新的参数reuseport加到listen指令的后面:listen 80 reuseport;包含这个reuseport参数后将禁用这个监听socket的accept_mutex,因为锁变得多余了.基准测试:NGINX 1.9.1启用reuseport完美解决惊群后,每秒处理的请求数提升了2到3倍,同时降低了延迟和stdev指标.附:淘宝的Tengine据说很早就加入了socket分片功能.
上面说的是网络IO的异步,下面说磁盘IO的异步.
在高性能的服务器编程中,I/O模型理所当然的是重中之重,需要谨慎选型.对于网络套接字,我们可以采用epoll的方式来轮询,尽管epoll也有一些缺陷,但总体来说还是很高效的,尤其来大量套接字的场景下.但对于Regular File来说,是不能够用的.采用poll/epoll,即O_NOBLOCK方式对于传统文件句柄是无效的.也就是说我们的open,read,mkdir之类的Regular File操作必定会导致阻塞.在多线程,多进程模型中,可以选择以同步阻塞的方式来进行IO操作,任务调度由操作系统来保证公平性.
NGINX从1.7.11试验性引入线程池,特定场景性能提升9倍.https://www.nginx.com/blog/thread-pools-boost-performance-9x/测试服务器有2个Intel Xeon E5645处理器(共计:12核,24超线程)和10-Gbps的网络接口.磁盘子系统是由4块西部数据WD1003FBYX磁盘组成的RAID10阵列.操作系统是Ubuntu Server 14.04.1 LTS.
thread_pool default threads=32 max_queue=65536;aio threads=default;这里定义了一个名为default,包含32个线程,任务队列最多支持65536个请求的线程池.如果任务队列过载,NGINX将输出如下错误日志并拒绝请求:thread pool "NAME" queue overflow: N tasks waiting
有了这个线程池,NGINX有可能没有任何性能损失地卸载任何长期阻塞的操作.许多流行的库仍然没有提供异步非阻塞接口,此前,这使得它们无法与NGINX兼容.我们可以花大量的时间和资源,去开发我们自己的无阻塞原型库,但这么做始终都是值得的吗?现在,有了线程池,我们可以相对容易地使用这些库,而不会影响这些模块的性能.FreeBSD已经有足够好的异步接口来读取文件,这时候不需要使用线程池.Linux缺乏这样的机制,所以对于一些不适合缓存在虚拟内存的文件(大文件),可以卸载读操作到AIO线程池,避免阻塞工作进程.我们如果可以改进卸载读操作到线程池,将会非常有意义.我们只需要知道所需的文件数据是否在内存中,只有不在内存中时,读操作才应该卸载到一个单独的线程中.
Linux内核提供的异步文件操作接口AIO,需要DirectIO,无法利用内存的Page Cache,这种奇怪的实现可能是Oracle/IBM专门为数据库应用设计的,MySQL就用到了AIO.AIO+DirectIO绕过了虚拟文件系统VFS高速缓存固然让大型数据库系统如Oracle,MySQL(InnoDB)非常高兴,因为Oracle,MySQL都有自己的缓存系统,所以不需要操作系统的Page Cache缓存,DirectIO能避免数据就被缓存两次而浪费内存.也就是说,如果你想让自己的程序通过AIO实现异步文件IO,那么你最好建立自己的内存缓存系统,而不是依赖内核.
最后,Linux上Apache 2.4系列默认的event MPM,是一个多进程,每个工作进程包含多个线程的epoll事件驱动的MPM.Apache 2.2系列的prefork MPM是纯粹的多进程架构,没有引入多线程,也没有使用内核的epoll特性,估计主要是为了方便移植.IBM AIX上面的IBM HTTP Server貌似就是基于Apache改造的.
可以用 sudo strace -p PID 查看编号的PID的进程的系统调用.
nginx master: rt_sigsuspend
nginx worker: epoll_wait
php-fpm master: epoll_wait (events.mechanism = epoll)
php-fpm worker: accept poll
可见Nginx工作进程进行了epoll_wait系统调用,epoll是Linux内核提供的异步网络IO编程接口.
http://liuxun.org/blog/nginx-gong-zuo-jin-cheng-mo-xing/
Nginx并没有像PHP-FPM那样采用master进程来分发连接,这个工作由操作系统内核机制完成,
所以可能会导致惊群现象,也就是当listen_fd有新的accept()请求过来,操作系统会唤醒所有子进程.
Nginx通过全局互斥锁来避免惊群(accept_mutex on),每个工作进程在epoll_wait()之前先去申请锁,申请到则继续处理,获取不到则等待,
并设置了一个负载均衡的算法(当某一个工作进程的任务量达到总设置量的7/8时,则不会再尝试去申请锁)来均衡各个进程的任务量.
http://nginx.org/en/docs/ngx_core_module.html#accept_mutex
Nginx解决惊群的新方法:使用内核提供的Socket ReusePort功能
NGINX 1.9.1 支持socket分片:
http://nglua.com/docs/sharding.html
http://nginx.com/blog/socket-sharding-nginx-release-1-9-1/
NGINX1.9.1支持socket的SO_REUSEPORT选项,这个选项在许多操作系统的新版本有效,包括DragonFly BSD和Linux(3.9+内核).
这个选项允许多个socket监听同一个IP地址和端口的组合.内核负载均衡这些进来的sockets连接,将这些socket有效的分片.
当SO_REUSEPORT选项没开启时,连接进来时监听socket默认会通知某个进程.
如果accept_mutex off这个指令,此时会唤醒所有的工作进程,它们将为了得到它产生竞争,这就是所谓的惊群现象.
如果使用epoll且不用锁(accept_mutex off),当监听端口有读操作时,是会产生惊群现象的.
启用SO_REUSEPORT选项后,每个进程将有个独立的监听socket.内核决定哪个是有效的socket(进程)得到这个连接.
这样做降低了延迟并提高了工作进程的性能,它也意味着工作进程在准备处理它们前被赋予了新的连接.
开启SO_REUSEPORT支持,只需将新的参数reuseport加到listen指令的后面:
listen 80 reuseport;
包含这个reuseport参数后将禁用这个监听socket的accept_mutex,因为锁变得多余了.
基准测试:NGINX 1.9.1启用reuseport完美解决惊群后,每秒处理的请求数提升了2到3倍,同时降低了延迟和stdev指标.
附:淘宝的Tengine据说很早就加入了socket分片功能.
上面说的是网络IO的异步,下面说磁盘IO的异步.
在高性能的服务器编程中,I/O模型理所当然的是重中之重,需要谨慎选型.
对于网络套接字,我们可以采用epoll的方式来轮询,尽管epoll也有一些缺陷,但总体来说还是很高效的,尤其来大量套接字的场景下.
但对于Regular File来说,是不能够用的.采用poll/epoll,即O_NOBLOCK方式对于传统文件句柄是无效的.
也就是说我们的open,read,mkdir之类的Regular File操作必定会导致阻塞.
在多线程,多进程模型中,可以选择以同步阻塞的方式来进行IO操作,任务调度由操作系统来保证公平性.
NGINX从1.7.11试验性引入线程池,特定场景性能提升9倍.
https://www.nginx.com/blog/thread-pools-boost-performance-9x/
测试服务器有2个Intel Xeon E5645处理器(共计:12核,24超线程)和10-Gbps的网络接口.
磁盘子系统是由4块西部数据WD1003FBYX磁盘组成的RAID10阵列.
操作系统是Ubuntu Server 14.04.1 LTS.
thread_pool default threads=32 max_queue=65536;
aio threads=default;
这里定义了一个名为default,包含32个线程,任务队列最多支持65536个请求的线程池.
如果任务队列过载,NGINX将输出如下错误日志并拒绝请求:
thread pool "NAME" queue overflow: N tasks waiting
有了这个线程池,NGINX有可能没有任何性能损失地卸载任何长期阻塞的操作.
许多流行的库仍然没有提供异步非阻塞接口,此前,这使得它们无法与NGINX兼容.
我们可以花大量的时间和资源,去开发我们自己的无阻塞原型库,但这么做始终都是值得的吗?
现在,有了线程池,我们可以相对容易地使用这些库,而不会影响这些模块的性能.
FreeBSD已经有足够好的异步接口来读取文件,这时候不需要使用线程池.
Linux缺乏这样的机制,所以对于一些不适合缓存在虚拟内存的文件(大文件),可以卸载读操作到AIO线程池,避免阻塞工作进程.
我们如果可以改进卸载读操作到线程池,将会非常有意义.
我们只需要知道所需的文件数据是否在内存中,只有不在内存中时,读操作才应该卸载到一个单独的线程中.
Linux内核提供的异步文件操作接口AIO,需要DirectIO,无法利用内存的Page Cache,
这种奇怪的实现可能是Oracle/IBM专门为数据库应用设计的,MySQL就用到了AIO.
AIO+DirectIO绕过了虚拟文件系统VFS高速缓存固然让大型数据库系统如Oracle,MySQL(InnoDB)非常高兴,
因为Oracle,MySQL都有自己的缓存系统,所以不需要操作系统的Page Cache缓存,DirectIO能避免数据就被缓存两次而浪费内存.
也就是说,如果你想让自己的程序通过AIO实现异步文件IO,那么你最好建立自己的内存缓存系统,而不是依赖内核.
最后,Linux上Apache 2.4系列默认的event MPM,是一个多进程,每个工作进程包含多个线程的epoll事件驱动的MPM.
Apache 2.2系列的prefork MPM是纯粹的多进程架构,没有引入多线程,也没有使用内核的epoll特性,估计主要是为了方便移植.
IBM AIX上面的IBM HTTP Server貌似就是基于Apache改造的.