Nginx深入详解之多进程网络模型,用共享锁解决惊群问题

编程之家收集整理的这篇文章主要介绍了Nginx深入详解之多进程网络模型,用共享锁解决惊群问题编程之家小编觉得挺不错的,现在分享给大家,也给大家做个参考。

搜索热词

遇到问题】

    手头原来有一个单进程的linux epoll服务器程序,近来希望将它改写成多进程版本,主要原因有:

  1. 在服务高峰期间 并发的 网络请求非常海量,目前的单进程版本的程序有点吃不消:单进程时只有一个循环先后处理epoll_wait()到的事件,使得某些不幸排队靠后的socket fd的网络事件处理不及时(担心有些socket客户端等不耐烦而超时断开);
  2. 希望充分利用到服务器的多颗cpu

 

    但随着改写工作的深入,便第一次碰到了“惊群”问题,一开始我的程序设想如下:

  1. 主进程先监听端口, listen_fd = socket(...);
  2. 创建epoll,epoll_fd = epoll_create(...);
  3. 然后开始fork(),每个子进程进入大循环,去等待new  accept,epoll_wait(...),处理事件等。

 

    接着就遇到了“惊群”现象:当listen_fd有新的accept()请求过来,操作系统会唤醒所有子进程(因为这些进程都epoll_wait()同一个listen_fd,操作系统又无从判断由谁来负责accept,索性干脆全部叫醒……),但最终只会有一个进程成功accept,其他进程accept失败。外国IT友人认为所有子进程都是被“吓醒”的,所以称之为Thundering Herd(惊群)。

    打个比方,街边有一家麦当劳餐厅,里面有4个服务小窗口,每个窗口各有一名服务员。当大门口进来一位新客人,“欢迎光临!”餐厅大门的感应式门铃自动响了(相当于操作系统底层捕抓到了一个网络事件),于是4个服务员都抬起头(相当于操作系统唤醒了所有服务进程)希望将客人招呼过去自己所在的服务窗口。但结果可想而知,客人最终只会走向其中某一个窗口,而其他3个窗口的服务员只能“失望叹息”(这一声无奈的叹息就相当于accept()返回EAGAIN错误),然后埋头继续忙自己的事去。

    这样子“惊群”现象必然造成资源浪费,那有木有好的解决办法呢?

 

 

【寻找办法】

    看了网上N多帖子和网页,阅读多款优秀开源程序的源代码,再结合自己的实验测试,总结如下:

  1.  实际情况中,在发生惊群时,并非全部子进程都会被唤醒,而是一部分子进程被唤醒。但被唤醒的进程仍然只有1个成功accept,其他皆失败。
  2. 所有基于linux epoll机制的服务器程序在多进程时都受惊群问题的困扰,包括 lighttpd 和 Nginx 等程序,各家程序的处理办法也不一样。
  3. lighttpd的解决思路:无视惊群。采用Watcher/Workers模式,具体措施有优化fork()与epoll_create()的位置(让每个子进程自己去epoll_create()和epoll_wait()),捕获accept()抛出来的错误并忽视等。这样子一来,当有新accept时仍将有多个lighttpd子进程被唤醒。
  4. Nginx解决思路:避免惊群。具体措施有使用全局互斥锁,每个子进程在epoll_wait()之前先去申请锁,申请到则继续处理,获取不到则等待,并设置了一个负载均衡的算法(当某一个子进程的任务量达到总设置量的7/8时,则不会再尝试去申请锁)来均衡各个进程的任务量。
  5. 一款国内的优秀商业MTA服务器程序(不便透露名称):采用Leader/Followers线程模式,各个线程地位平等,轮流做Leader来响应请求。
  6. 对比lighttpd和Nginx两套方案,前者实现方便,逻辑简单,但那部分无谓的进程唤醒带来的资源浪费的代价如何仍待商榷(有网友测试认为这部分开销不大 http://www.iteye.com/topic/382107)。后者逻辑较复杂,引入互斥锁和负载均衡算分也带来了更多的程序开销。所以这两款程序在解决问题的同时,都有其他一部分计算开销,只是哪一个开销更大,未有数据对比。
  7. 坊间也流传Linux 2.6.x之后的内核,就已经解决了accept的惊群问题,论文地址 http://static.usenix.org/event/usenix2000/freenix/full_papers/molloy/molloy.pdf 。
  8. 但其实不然,这篇论文里提到的改进并未能彻底解决实际生产环境中的惊群问题,因为大多数多进程服务器程序都是在fork()之后,再对epoll_wait(listen_fd,...)的事件,这样子当listen_fd有新的accept请求时,进程们还是会被唤醒。论文的改进主要是在内核级别让accept()成为原子操作,避免被多个进程都调用了。

 

【采用方案】

    多方考量,最后选择参考lighttpd的Watcher/Workers模型,实现了我需要的那款多进程epoll程序,核心流程如下:

  1. 主进程先监听端口, listen_fd = socket(...); ,setsockopt(listen_fd, SOL_SOCKET, SO_REUSEADDR,...),setnonblocking(listen_fd),listen(listen_fd,...)。
  2. 开始fork(),到达子进程数上限(建议根据服务器实际的cpu核数来配置)后,主进程变成一个Watcher,只做子进程维护和信号处理等全局性工作。
  3. 每一个子进程(Worker)中,都创建属于自己的epoll,epoll_fd = epoll_create(...);,接着将listen_fd加入epoll_fd中,然后进入大循环,epoll_wait()等待并处理事件。千万注意,epoll_create()这一步一定要在fork()之后
  4. 大胆设想(未实现):每个Worker进程采用多线程方式来提高大循环的socket fd处理速度,必要时考虑加入互斥锁来做同步,但也担心这样子得不偿失(进程+线程频繁切换带来的额外操作系统开销),这一步尚未实现和测试,但看到Nginx源码中貌似有此逻辑。

【小结】

    纵观现如今的Linux服务器程序开发(无论是游戏服务器/WebServer服务器/balabala各类应用服务器),epoll可谓大行其道,当红炸子鸡一枚。它也确实是一个好东西,单进程时的事件处理能力就已经大大强于poll/select,难怪Nginx/Lighttpd等生力军程序都那么喜欢它。

    但毕竟只有一个进程的话,晾着服务器的多个cpu实在是罪过,为追求更高的机器利用率更短的请求响应处理时间,还是折腾着搞出了多进程epoll。

总结

以上是编程之家为你收集整理的Nginx深入详解之多进程网络模型,用共享锁解决惊群问题全部内容,希望文章能够帮你解决Nginx深入详解之多进程网络模型,用共享锁解决惊群问题所遇到的程序开发问题。

如果觉得编程之家网站内容还不错,欢迎将编程之家网站推荐给程序员好友。

本图文内容来源于网友网络收集整理提供,作为学习参考使用,版权属于原作者。
如您喜欢寻找一群志同道合、互帮互助的学习伙伴,可以点击下方链接加入:
编程之家官方1群:1065694478(已满)
编程之家官方2群:163560250(已满)
编程之家官方3群:312128206(已满)
编程之家官方4群:230427597

相关文章

猜你在找的Nginx相关文章

摘要: 什么是负载均衡?通俗一点讲,就是在高并发、大数据环境下给服务器减压的技术。负载均衡是任何一个有一定规模的互联网企业都会考虑的问题,负载方式很多,有依靠硬件实现的,也有依靠软件实现负载的。今天来聊聊使用软件来负载的方式。什么是负载均衡?通俗一点讲,就是在高并发、大数据
说明:此脚本简单只适合centos系统,仅作参考#!/bin/bash#判断系统类型是否为centosSERVER_NAME='CentOS'OS_SERVER_NAME=$(hostnamectl|awk'NR==7{print$3}')echo"$OS_SERVER_NAME"["$SERVER_NAME"!="$OS_SERVER_NAME"]&&
nginx静态文件二级目录 location 可以看出根目录下还得建立一个根目录相同的文件夹
前言:本文章适合有Linux基础者阅读,需掌握源码方式安装nginx(文中作者直接省略了nginx的源码安装过程)1.当前系统环境系统主机名IP地址Centos7.4xmh10.0.0.2002.nginx版本当前版本:nginx-1.12.2新版本:nginx-1.14.2本文章使用源码包方式安装nginxnginx存放:/applicat
安装Nginx#apt-getinstallnginx#yuminstallnginx查看安装路径#whereisnginx配置nginxlocation~.*\.(gif|jpg|jpeg|png)${expires24h;root/data/www/images/;#指定图片存放路径access_log/data/www/imagesginx/logs
80端口:server{listen80;#listen[::]:80;server_name域名;indexindex.htmlindex.htmindex.phpdefault.htmldefault.htmdefault.php;root/home/wwwroot/aaa;includenone.conf;#error_page
Nginx工作模式简介nginx有两种工作模式:master-worker模式和单进程模式。在master-worker模式下,有一个master进程和至少一个的worker进程,单进程模式顾名思义只有一个进程。这两种模式有各自的特点和适用场景。Nginx两种工作模式1、master-worker模式master-worker模式下nginx启
命令列表先把所有的命令给出来了。yum-yinstallgcc-c++yum-yinstallwgetyuminstall-ypcrepcre-develyuminstall-yzlibzlib-develyuminstall-yopensslopenssl-develwget-chttps:/ginx.org/downloadginx-1.14.1.tar.gztar-zxvfnginx-1.14.1.tar.gz