nginx 多进程 + io多路复用 实现高并发

一、nginx 高并发原理

简单介绍:nginx 采用的是多进程(单线程) + io多路复用(epoll)模型 实现高并发

二、nginx 多进程

  • 启动nginx
    o_4071177893-5bc03aa71d0f3_articlex.png
解析初始化配置文件后会 创建(fork)一个master进程 之后 这个进程会退出 
master 进程会 变为孤儿进程 由init进程托管。(可以通过python 或php 启动后创建子进程,然后杀死父进程得见子进程会由init进程托管)
如下图可以看到nginx master 进程由init(ppid 为1 )进程管理。

o_1559542370(1).png

  • master进程和worker进程
    o_20170303170640322.png
1、master 
首先nginx 创建一个master 进程,通过socket() 创建一个sock文件描述符用来监听(sockfd)
绑定端口(bind) 开启监听(listen)。
nginx 一般监听80(http) 或 443 (https)端口
(fork 多个子进程后,master 会监听worker进程,和等待信号)2、worker
然后 创建(fork)多个 worker子进程(复制master 进程的数据),
此时所有的worker进程 继承了sockfd(socket文件描述符),
当有连接进来之后 worker进程就可以accpet()创建已连接描述符,
然后通过已连接描述符与客户端通讯
  • 惊群现象
由于worker进程 继承了master进程的sockfd,当连接进来是,所有的子进程都将收到通知并“争着”与
它建立连接,这就叫惊群现象。大量的进程被激活又挂起,最后只有一个进程accpet() 到这个连接,这会消耗系统资源
(等待通知,进程被内核全部唤醒,只有一个进程accept成功,其他进程又休眠。这种浪费现象叫惊群)
  • nginx 对惊群现象的处理
原因:多个进程监听同一个端口引发的。
解决:如果可以同一时刻只能有一个进程监听端口,这样就不会发生“惊群”了,此时新连接事件只能唤醒正在监听的唯一进程。如何保持一个时刻只能有一个worker进程监听端口呢?nginx设置了一个accept_mutex锁,在使用accept_mutex锁是,只有进程成功调用了ngx_trylock_accept_mutex方法获取锁后才可以监听端口(linux 内核2.6 之后 不会出现惊群现象,只会有一个进程被唤醒)
  • 代码简单理解
    o_1559551783(1).png

三、worker进程

  • worker进程做了什么事
从上图中,我们可以看到worker进程做了
1、accept() 与客户端建立连接
2、recv()接收客户端发过来的数据
3、send() 向客户端发送数据
4、close() 关闭客户端连接
  • 如果不使用io多路复用 会是什么样的
首先 等待客户端有连接进来
accpet()  与客户端建立连接后
recv()  一直等待客户的发送过来数据(此时处于io阻塞状态)如果此时又有客户端过来建立连接,那么只能等待,需要一直等待close() 之后才可以建立连接也就是说这个worker进程会因为recv() 而处于阻塞状态,而不能处理与其他客户端建立连接,
这段时间不能做任何事,这是对性能了浪费。(进程 和线程的切换也是需要消耗 时间的。)
  • 能不能利用io堵塞的时间 accept,recv
nginx 采用了io多路复用技术实现了 

四、io多路复用

  • 什么是io复用
IO复用解决的就是并发行的问题,比如多个用户并发访问一个WEB网站,对于服务端后台而言就会产生多个请求,处理多个请求对于中间件就会产生多个IO流对于系统的读写。那么对于IO流请求操作系统内核有并行处理和串行处理的概念,串行处理的方式是一个个处理,前面的发生阻塞,就没办法完成后面的请求。这个时候我们必须考虑并行的方式完成整个IO流的请求来实现最大的并发和吞吐,这时候就是用到IO复用技术。IO复用就是让一个Socket来作为复用完成整个IO流的请求。
当然实现整个IO流的请求多线程的方式就是其中一种。
(一个socket作为复用来完成整个io流的请求连接建立(accept),而处理请求(recv,send,close)则采用多线程)
  • io复用之多线程处理
# -*- coding:utf-8 -*-
import socket
from threading import Threaddef comm(conn):data = conn.recv(1024)conn.send(data)conn.close()obj = socket.socket(socket.AF_INET,socket.SOCK_STREAM)   # sockfd (socket 文件描述符,这个描述符是用来监听的--监听socket)
obj.bind(('127.0.0.1',8082))                             # 绑定地址
obj.listen(5)                                            # 开启监听while True:conn,addr  = obj.accept()             // 每建立一个 连接 就交由线程处理t = Thread(target=comm,args=(conn,))  // 创建线程对象t.start()                             // 启动// 这样就可以处理多个io请求,不会因为一个没处理完而导致的堵塞
  • io 多路复用
多个描述符(监听描述符,已连接描述符) 的io 操作都能在一个线程内并发交替顺序完成,这就叫io多路复用,
这里的复用指的是复用同一个线程
  • io 多路复用的三种机制 select poll epoll
    • select
        #include <sys/select.h>int select(int nfds, fd_set *readfds, fd_set *writefds, fd_set *exceptfds, struct timeval *timeout);//参数nfds是需要监听的最大的文件描述符值+1//rdset,wrset,exset分别对应需要检测的可读文件描述符的集合,//可写文件描述符的集合集异常文件描述符的集合//参数timoout为结构timeval,用来设置select()的等待时间
        1、用户将自己所关心的文件描述符添加进描述符集中,并且明确关心的是读,写,还是异常事件2、select 通过轮询的方式不断扫码所有被关心的文件描述符,具体时间由参数timeout决定的3、执行成功则返回文件描述符已改变的个数4、具体哪一个或哪几个文件描述符就绪,则需要文件描述符集传出,它既是输入型参数,又是输出型参数5、fd_set 是用位图存储文件描述符的,因为文件描述符是唯一且递增的整数
        特点:1、可关心的文件描述符数量是有上限的,取决于fd_set(文件描述符集)的大小2、每次的调用select 前,都要把文件描述符重新添加进fd_set(文件描述符集)中,因为fd_set也是输出型参数在函数返回后,fd_set中只有就绪的文件描述符3、通常我们要关心的文件描述符不止一个,所有首先用数组保存文件描述符,每次调用select前再通过遍历数逐个添加进去
    
        缺点:1、每次调用select都需要手动设置fd_Set2、每次调用select 需要遍历fd_set 集合,而且要将fd_set 集合从用户态拷贝到内核态,如何fd很多时,开销会很大3、select 支持的文件描述符数量太少 32- 1024 64 -2048
    • poll
        #include <sys/poll.h>int poll(struct pollfd *fds, nfds_t nfds, int timeout);// 第一个参数是指向一个结构数组的第一个元素的指针// 第二个参数是要监听的文件描述符的个数// 第三个参数意义与select相同        //pollfd结构struct pollfd{int fd; short events;  short revents;};//events 是我们要关心的事件,revents是调用后操作系统设置的参数,//也就是表明该文件描述符是否就绪
        首先创建一个pollfd结构体变量数组fd_list,然后将我们然后将我们关心的fd(文件描述符)放置在数组中的结构变量中,并添加我们所关系的事件,调用poll函数,函数返回后我们再通过遍历的方式去查看数组中那些文件描述符上的事件就绪了。
        特点(相对于select)1、每次调用poll之前不需要手动设置文件描述符集2、poll将用户关系的实际和发生的实际进程分离3、支持的文件描述符数量理论上是无上限的,其实也有,因为一个进程能打开的文件数量是有上限的 ulimit -n 查看进程可打开的最大文件数
        1、poll 返回后,也需要轮询pollfd 来获取就绪的描述符2、同时连接的大量客户端,可能只有很少的处于就绪状态,因此随着监事的描述符数量的增长,其效率也会线性下降
    • select poll 的共同点
        都做了很多 无效的 轮询检测描述符是否就绪的操作
    • epoll
      • 代码
          #include <sys/epoll.h>int epoll_create(int size);     // 在内核里,一切皆文件。所以,epoll向内核注册了一个文件系统,//epoll_create的作用是创建一个epoll模型,该模型在底层建立了->//**红黑树,就绪队列,回调机制**//size可以被忽略,不做解释int epoll_ctl(int epfd, int op, int fd, struct epoll_events *event);//epfd:epoll_create()的返回值(epoll的句柄,本质上也是一个文件描述符)//op:表示动作,用三个宏来表示//    EPOLL_CTL_ADD:注册新的fd到epfd中//    EPOLL_CTL_MOD:修改已经注册的fd的监听事件//    EPOLL_CTL_DEL:从epfd中删除一个事件//fd:需要监听的文件描述符//event:具体需要在该文件描述符上监听的事件int epoll_wait(int epfd, struct epoll_event *events, int maxevents, int timeout);//函数调用成功,返回文件描述符就绪的个数,也就是就绪队列中文件描述符的个数,//返回0表示超时,小于0表示出错//epoll_event结构体struct epoll_event{uint32_t events;  /* Epoll events */epoll_data_t data;/* User data variable */}__EPOLL_PACKED;//events可以是一堆宏的集合,这里介绍几个常用的//  EPOLLIN:表示对应的文件描述符可以读(包括对端socket正常关闭)//  EPOLLOUT:表示对应的文件描述符可以写//  EPOLLET:将EPOLL设为边缘触发(Edge Triggered)模式,//          默认情况下epoll为水平触发(Level Triggered)模式typedef union epoll_data{void *ptr;int fd;uint32_t u32;uint64_t u64;}epoll_data_t;//联合体里通常只需要填充fd就OK了,其他参数暂时可以不予理会
      • 工作原理
          1、创建一个epoll 对象,向epoll 对象中添加文件描述符以及我们所关心的在在该文件描述符上发生的事件2、通过epoll_ctl 向我们需要关心的文件描述符中注册事件(读,写,异常等),操作系统将该事件和对象的文件描述符作为一个节点插入到底层建立的红黑树中3、添加到文件描述符上的实际都会与网卡建立回调机制,也就是实际发生时会自主调用一个回调方法,将事件所在的文件描述符插入到就绪队列中4、引用程序调用epoll_wait 就可以直接从就绪队列中将所有就绪的文件描述符拿到,可以说时间复杂度O(1)
      • 水平触发工作方式(LT)
          处理socket时,即使一次没将数据读完,下次调用epoll_wait时该文件描述符也会就绪,可以继续读取数据
      • 边沿触发工作方式(ET)
          处理socket时没有一次将数据读完,那么下次再调用epoll_wait该文件描述符将不再显示就绪,除非有新数据写入在该工作方式,当一个文件描述符就绪是,我们要一次性的将数据读完
      • 隐患问题
          当我们调用read读取缓冲去数据时,如果已经读取完了,对端没有关系蟹段,read就会堵塞,影响后续逻辑解决方式就是讲文件描述符,设置成非堵塞的,当没有数据的时候,read也不会被堵塞,可以处理后续逻辑(读取其他的fd或者继续wait)ET 的性能要好与LT,因为epoll_wait返回的次数比较少,ninx中默认采用ET模式使用epoll
      • 特点
          1、采用了回调机制,与轮询区别看待2、底层采用红黑树结构管理已经注册的文件描述符3、采用就绪队列保存已经就绪的文件描述符
      • 优点
          1、文件描述符数目无上限:通过epoll_ctl 注册一个文件描述符后,底层采用红黑树结构管理所有需要监控的文件描述符2、基于实际的就绪通知方式:每当有文件描述符就绪时,该响应事件会调用回调方法将该文件描述符插入到就绪队列中,不需要内核每次去轮询式的查看每个被关心的文件描述符3、维护就绪队列:当文件描述符就绪的时候,就会被放到内核中的一个就绪队列中,调用epoll_wait可以直接从就绪队列中获取就绪的文件描述符,时间复杂度是O(1)

四、总结

nginx 通过 多进程 + io多路复用(epoll) 实现了高并发采用多个worker 进程实现对 多cpu 的利用通过eopll 对 多个文件描述符 事件回调机制和就绪描述符的处理 实现单线程io复用从而实现高并发 

转载于:https://www.cnblogs.com/xiaobaiskill/p/10969180.html

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/275026.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

ux设计工具_UX设计中的工具和实用主义

ux设计工具There’s a zillion tools for User Experience and User Interface Design. Don’t take my word for it: a simple Google search for “what are the best tools for wireframing” (to take just one aspect of UX) leads you to endless pages of “The 20 best…

幕后常驻嘉宾配音小姐姐的2021年度总结

大家好&#xff0c;我是若川。这是公众号幕后常驻嘉宾配音小姐姐&#xff0c;看完了上一个阿源小姐姐的年度总结《一张图看程序媛阿源的2021个人年度流水账》&#xff0c;写的年度总结投稿。点击以下音频可以查看收听往期更多音频。以下是正文~Hi&#xff0c;大家好呀~我是若川…

结果规格化_结果

结果规格化If you’ve seen an Instagram story involving a question and people tilting their heads, you probably were looking at the “Who Is More” Instagram filter. In this article, I will share the creative process and decision making behind this filter.如…

2021 年 JavaScript 大事记

大家好&#xff0c;我是 ConardLi&#xff0c;不知不觉中&#xff0c;2021 年已经接近尾声了&#xff0c;不知道在 2021 这一年&#xff0c;你收获了什么&#xff1f;又失去了什么呢&#xff1f;又到了开始做年终总结的时候了&#xff0c;今天&#xff0c;我来给 JavaScript 做…

动画 制作_您希望制作的10个醒目的徽标动画

动画 制作重点 (Top highlight)标志设计 (Logo Design) Have you ever watched paint dry? No? I didn’t think so. How about watched a turtle crossing the road? Probably not. Maybe spent an hour standing in line at the post office? Well that’s pretty likely…

使用 CSS 用户选择控制选择

IE10 平台预览 4 包括一个新的 CSS 属性的支持-ms-user-select&#xff0c;这使得 Web 开发者控制完全可以选择什么的文本&#xff0c;在其网站上更容易。如果你是看我一整天都在我的工作站&#xff0c;您会注意到我读计算机上时&#xff0c;我选择的文本。我不是只有一个人读起…

一个在校的普通前端小姐姐的2021

大家好&#xff0c;我是若川。这是我的源码共读群里一个大三的前端小姐姐&#xff08;小曹同学&#xff09;的年度总结。她写了5篇源码笔记。同时做了很多项目&#xff0c;获得了很多奖。而且策划和建立了学校工作室的前端训练营&#xff0c;40人报名参加。总之就是现在的大学生…

按钮 交互_SwiftUI中的微交互—菜单按钮动画

按钮 交互Microinteractions have become increasingly important in a world with a dizzying number of digital platforms and an ocean of content. While microinteractions used to be considered an interesting resource in the early days of digital design, in toda…

选择控件— UI组件系列

重点 (Top highlight)The word “toggle” is a reference to a switch with a short handle that alternates between two states each time it is activated. You encounter it every time you “switch” on the lights.单词“ toggle”是指带有短手柄的开关&#xff0c;该开…

SEE Conf: Umi 4 设计思路文字稿

大家好&#xff0c;我是若川。持续组织了5个月源码共读活动&#xff0c;感兴趣的可以点此加我微信 ruochuan12 参与&#xff0c;每周大家一起学习200行左右的源码&#xff0c;共同进步。同时极力推荐订阅我写的《学习源码整体架构系列》 包含20余篇源码文章。复制此链接 https:…

用户体验改善案例_改善用户体验研究的5种习惯

用户体验改善案例There’s plenty of misunderstanding around user research, whether it’s the concept of validation or one-off anecdotes being thrown around as concrete evidence for a product decision.用户研究存在很多误解&#xff0c;无论是验证的概念还是一次性…

巴克莱对冲_“巴克莱的财政预算案”:使金钱管理对心理健康有效—用户体验案例研究

巴克莱对冲Disclaimer: all official Barclays assets used for this project are purely for educational/project purposes only and do not reflect the intentions of Barclays or any of its affiliates.免责声明&#xff1a;用于此项目的所有官方巴克莱资产纯粹是出于教育…

6 个对所有 Web 开发者都有用的 GitHub 仓库

作者&#xff1a;Mehdi Aoussiad原文&#xff1a;https://javascript.plainenglish.io/6-useful-github-repositories-for-all-web-developers-44f26912fd66大家好&#xff0c;我是若川。持续组织了5个月源码共读活动&#xff0c;感兴趣的可以点此加我微信 ruochuan12 参与&…

openfiler的iSCSI配置(二)

为什么80%的码农都做不了架构师&#xff1f;>>> 一.openfiler iSCSI配置 1.启动iSCSI target server服务。在Services列表下。 2.设置访问列表。在System---Network Access Configuration下设置。 3.创建卷设备 二.ISCSI客户端配置 1.安装open-iscsi # apt-get ins…

送你一份用Electron开发桌面应用的避坑指南【送3本书,含犀牛书】

大家好&#xff0c;我是若川。持续组织了5个月源码共读活动&#xff0c;感兴趣的可以点此加我微信 ruochuan12 参与&#xff0c;新年第一次送3本书。抽奖规则见文末。如今&#xff0c;Electron 领域发生了重大的变革&#xff0c;Electron 版本更新换代极快&#xff0c;难以计数…

nginx修改upstream不重启的方法(ngx_http_dyups_module模块)

为什么80%的码农都做不了架构师&#xff1f;>>> nginx很强大&#xff0c;第三方模块也不少,淘宝在nginx上很活跃&#xff0c;特别是章亦春&#xff0c;他参与的模块至少10&#xff0c; 好了今天主角不是他&#xff0c;是一款动态配置upstream的模块&#xff0c;这个…

c# 设计原则需要学习吗_向最好的学习:产品设计原则

c# 设计原则需要学习吗重点 (Top highlight)In my job as Design Team Lead at SimpleSite, I’ve recently been part of creating a set of Product Design Principles. In this process, I spent a lot of time studying the theory, learning about best practices, and ge…

Node.js 2021年开发者报告解读

大家好&#xff0c;我是若川。持续组织了5个月源码共读活动&#xff0c;感兴趣的可以点此加我微信 ruochuan12 参与&#xff0c;每周大家一起学习200行左右的源码&#xff0c;共同进步。同时极力推荐订阅我写的《学习源码整体架构系列》 包含20余篇源码文章。很多人觉得Node.js…

搭建nginx反向代理用做内网域名转发

为什么80%的码农都做不了架构师&#xff1f;>>> 情景 由于公司内网有多台服务器的http服务要映射到公司外网静态IP&#xff0c;如果用路由的端口映射来做&#xff0c;就只能一台内网服务器的80端口映射到外网80端口&#xff0c;其他服务器的80端口只能映射到外网的…

外国经典儿童读物合集pdf_帮助父母在线购买儿童读物–用户体验案例研究

外国经典儿童读物合集pdfTŤ As our first group project at GA, we needed to quickly learn how to use several online tools that helped our team of 4 collaborate and communicate while socially distant. Despite the rather extreme circumstances our team was stil…