Verwendet Nginx intern Multithreading?
某草草
某草草 2017-05-16 17:21:17
0
1
636

Nginx unterteilt die Bearbeitung einer Anfrage in mehrere Phasen. Wird es in diesen Phasen zu E/A-Blockierungen kommen? Wenn es eine Blockierung gibt, führt Nginx andere Anfragen aus, aber wird es bei der Ausführung anderer Anfragen eine Prioritätsunterscheidung geben (werden Anfragen, die bereits zu einem späteren Zeitpunkt fortgeschritten sind, zuerst ausgeführt?)? Wird Nginx außerdem über einen Thread-Pool verfügen, um es in jeder Phase zu verarbeiten, oder wird es von Anfang bis Ende einen eigenen Thread haben?

某草草
某草草

Antworte allen(1)
伊谢尔伦

cat /proc/3776/status|grep Threads 可见Nginx工作进程只有1个线程,其中3776是Nginx工作进程的PID。另外Nginx从1.7.11加入了AIO线程池支持,能够使用AIO多线程读取和发送大文件,以免工人进程被阻塞(小文件用sendfile,大文件用AIO线程池),要启用线程池支持,configure时需要显式加入--with-threads选项。
https://www.nginx.com/blog/thread-pools-boost-performance-9x/
http://nginx.org/en/docs/ngx_core_module.html#thread_pool

转:
当listen_fd有新的accept()请求过来,操作系统会唤醒所有子进程,因为这些进程都epoll_wait()同一个listen_fd,操作系统又无从判断由谁来负责accept,索性干脆全部叫醒,但最终只会有一个进程成功accept,其他进程accept失败.所有子进程都是被"吓醒"的,所以称之为Thundering Herd(惊群).

监听套接字在启动时就完成初始化,worker进程通过这些套接字接受,读取请求和输出响应.Nginx并没有像PHP-FPM那样采用master进程来分发请求,这个工作由操作系统内核机制完成,所以可能会导致惊群现象,也就是当listen_fd有新的accept()请求过来,操作系统会唤醒所有子进程.

Nginx解决惊群的思路:避免惊群.
http://nginx.org/en/docs/ngx_core_module.html#accept_mutex
具体措施有使用全局互斥锁(accept_mutex on),每个工作进程在epoll_wait()之前先去申请锁,申请到则继续处理,获取不到则等待,并设置了一个负载均衡的算法(当某一个工作进程的任务量达到总设置量的7/8时,则不会再尝试去申请锁)来均衡各个进程的任务量.

Nginx解决惊群的新方法:使用内核提供的Socket ReusePort功能
NGINX 1.9.1 支持socket分片:
http://nglua.com/docs/sharding.html
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(进程)得到这个连接.这样做降低了延迟并提高了工作进程的性能,它也意味着工作进程在准备处理它们前被赋予了新的连接.

nginx默认以多进程的方式工作,一个master进程和多个worker进程,master进程主要用来管理worker进程.多个worker进程同等竞争来自客户端的请求,一个worker进程可以处理多个请求,但不能处理其它worker进程的请求.每个worker进程里面只有一个主线程,在epoll支持下,采用异步非阻塞的方式来处理请求,从而实现高并发.epoll支持监听多个事件(socket轮询),当事件没准备好时,放到epoll里面,事件准备好了,就去读写.与多线程相比,这种事件处理方式是有很大的优势的,不需要创建线程,每个请求占用的内存也很少,没有上下文切换,事件处理非常的轻量级.并发数再多也不会导致无谓的资源浪费(上下文切换),更多的并发数,只是会占用更多的内存而已.而httpd常用的工作方式是每个请求会独占一个工作线程,当并发数上到几千时,就同时有几千的线程在处理请求了,这对操作系统来说,是个不小的挑战.线程带来的内存占用非常大,线程的上下文切换带来的cpu开销很大,httpd的性能自然就上不去了.Tengine团队之前有对连接数进行过测试,在24G内存的机器上,Nginx处理的并发请求数达到过200万.(平均1G内存可以处理8万多请求)Nginx支持将某一个进程绑定在某一个核上(CPU亲缘性绑定),这样就不会因为进程的切换带来cache的失效,所以推荐设置cpu有几个核就设置几个worker进程.但注意,过多的worker进程,只会导致进程来竞争cpu资源了,从而带来不必要的上下文切换,所以worker进程不是越多越好.详细参见:
http://tengine.taobao.org/book/chapter_02.html

Beliebte Tutorials
Mehr>
Neueste Downloads
Mehr>
Web-Effekte
Quellcode der Website
Website-Materialien
Frontend-Vorlage
Über uns Haftungsausschluss Sitemap
Chinesische PHP-Website:Online-PHP-Schulung für das Gemeinwohl,Helfen Sie PHP-Lernenden, sich schnell weiterzuentwickeln!