nginx、swoole高并发原理初探
阅前热身
为了更加形象的说明同步异步、阻塞非阻塞,我们以小明去买奶茶为例。
同步与异步
同步与异步的重点在消息通知的方式上,也就是调用结果通知的方式。
同步:当一个同步调用发出去后,调用者要一直等待调用结果的通知,直到得到调用结果。
异步:当一个异步调用发出去后,调用者不能立即得到调用结果的返回。
异步调用,要想获得结果,一般有两种方式:
1、主动轮询异步调用的结果;
2、被调用方通过callback来通知调用方调用结果。
举个栗子:
同步买奶茶:小明点单交钱,然后等着拿奶茶;
异步买奶茶:小明点单交钱,店员给小明一个小票,等小明奶茶做好了,再来取。
异步买奶茶,小明要想知道奶茶是否做好了,有两种方式:
1、小明主动去问店员,一会就去问一下:“奶茶做好了吗?”...直到奶茶做好。
2、等奶茶做好了,店员喊一声:“小明,奶茶好了!”,然后小明去取奶茶。
阻塞与非阻塞
阻塞与非阻塞的重点在于进/线程等待消息时候的行为,也就是在等待消息的时候,当前进/线程是挂起状态,还是非挂起状态。
1、阻塞调用发出去后,在消息返回之前,当前进/线程会被挂起,直到有消息返回,当前进/线程才会被激活。
2、非阻塞调用发出去后,不会阻塞当前进/线程,而会立即返回。
举个栗子:
1、阻塞买奶茶:小明点单交钱,干等着拿奶茶,什么事都不做;
2、非阻塞买奶茶:小明点单交钱,等着拿奶茶,等的过程中,时不时刷刷微博、朋友圈...
Submit
同步与异步,重点在于消息通知的方式;
阻塞与非阻塞,重点在于等消息时候的行为。
所以,就有了下面4种组合方式
同步阻塞:小明在柜台干等着拿奶茶;
同步非阻塞:小明在柜台边刷微博边等着拿奶茶;
异步阻塞:小明拿着小票啥都不干,一直等着店员通知他拿奶茶;
异步非阻塞:小明拿着小票,刷着微博,等着店员通知他拿奶茶。
2Nginx如何处理高并发
Apache面对高并发,为什么很无力?
Apache处理一个请求是同步阻塞的模式。如图:
每到达一个请求,Apache都会去fork一个子进程去处理这个请求,直到这个请求处理完毕。
面对低并发,这种模式没什么缺点,但是,面对高并发,就是这种模式的软肋了。
1个客户端占用1个进程,那么,进程数量有多少,并发处理能力就有多少,但操作系统可以创建的进程数量是有限的。
并且,多进程就会有进程间的切换问题,而进程间的切换调度势必会造成CPU的额外消耗。当进程数量达到成千上万的时候,进程间的切换就占了CPU大部分的时间片,而真正进程的执行反而占了CPU的一小部分,这就得不偿失了。
下面,举例说明这2种场景是多进程模式的软肋:
1、及时消息通知程序比如及时聊天程序,一台服务器可能要维持数十万的连接(典型的C10K问题),那么就要启动数十万的进程来维持。这显然不可能。
2、调用外部Http接口时假设Apache启动100个进程来处理请求,每个请求消耗100ms,那么这100个进程能提供1000qps。
但是,在我们调用外部Http接口时,比如QQ登录、微博登录,耗时较长,假设一个请求消耗10s,也就是1个进程1s处理0.1个请求,那么100个进程只能达到10qps,这样的处理能力就未免太差了。
注:什么是C10K问题?网络服务在处理数以万计的客户端连接时,往往出现效率低下甚至完全瘫痪,这被称为C10K问题。(concurrent 10000 connection)
综上,我们可以看出,Apache是同步阻塞的多进程模式,面对高并发等一些场景,是很苍白的。
Nginx何以问鼎高并发
传统的服务器模型就是这样,因为其同步阻塞的多进程模型,无法面对高并发。
那么,有没有一种方式,可以让我们在一个进程处理所有的并发I/O呢?
答案是有的,这就是I/O复用技术。
①、I/O复用是神马?
所谓的I/O复用,就是多个I/O可以复用一个进程。
上面说的同步阻塞的多进程模型不适合处理高并发,那么,我们再来考虑非阻塞的方式。
采用非阻塞的模式,当一个连接过来时,我们不阻塞住,这样一个进程可以同时处理多个连接了。
比如一个进程接受了10000个连接,这个进程每次从头到尾的问一遍这10000个连接:“有I/O事件没?有的话就交给我处理,没有的话我一会再来问一遍。”
然后进程就一直从头到尾问这10000个连接,如果这1000个连接都没有I/O事件,就会造成CPU的空转,并且效率也很低,不好不好。
于是伟大的程序猿们日思夜想的去解决这个问题...终于!
我们能不能引入一个代理,这个代理可以同时观察许多I/O流事件呢?
当没有I/O事件的时候,这个进程处于阻塞状态;当有I/O事件的时候,这个代理就去通知进程醒来?
于是,早期的程序猿们发明了两个代理---select、poll。
select、poll代理的原理是这样的:
当连接有I/O流事件产生的时候,就会去唤醒进程去处理。
但是进程并不知道是哪个连接产生的I/O流事件,于是进程就挨个去问:“请问是你有事要处理吗?”......问了99999遍,哦,原来是第100000个进程有事要处理。那么,前面这99999次就白问了,白白浪费宝贵的CPU时间片了!痛哉,惜哉...
注:select与poll原理是一样的,只不过select只能观察1024个连接,poll可以观察无限个连接。
上面看了,select、poll因为不知道哪个连接有I/O流事件要处理,性能也挺不好的。
那么,如果发明一个代理,每次能够知道哪个连接有了I/O流事件,不就可以避免无意义的空转了吗?
于是,超级无敌、闪闪发光的epoll被伟大的程序员发明出来了。
epoll代理的原理是这样的:
当连接有I/O流事件产生的时候,epoll就会去告诉进程哪个连接有I/O流事件产生,然后进程就去处理这个进程。
如此,多高效!
②、基于epoll的Nginx
有了epoll,理论上1个进程就可以无限数量的连接,而且无需轮询,真正解决了c10k的问题。
Nginx是基于epoll的,异步非阻塞的服务器程序。自然,Nginx能够轻松处理百万级的并发连接,也就无可厚非了。
3swoole如何处理高并发以及异步I/O的实现
swoole介绍
swoole是PHP的一个扩展。
简单理解:swoole=异步I/O+网络通信
PHPer可以基于swoole去实现过去PHP无法实现的功能。
具体请参考swoole官网。
swoole如何处理高并发
Reactor模型介绍
IO复用异步非阻塞程序使用经典的Reactor模型,Reactor顾名思义就是反应堆的意思,它本身不处理任何数据收发。只是可以监视一个socket(也可以是管道、eventfd、信号)句柄的事件变化。
注:什么是句柄?句柄英文为handler,可以形象的比喻为锅柄、勺柄。也就是资源的唯一标识符、资源的ID。通过这个ID可以操作资源。
Reactor只是一个事件发生器,实际对socket句柄的操作,如connect/accept、send/recv、close是在callback中完成的。
swoole的架构
swoole采用 多线程Reactor+多进程Worker
swoole的架构图如下:
swoole的处理连接流程图如下:
当请求到达时,swoole是这样处理的:
因为reactor基于epoll,所以每个reactor可以处理无数个连接请求。 如此,swoole就轻松的处理了高并发。
swoole如何实现异步I/O
基于上面的Swoole结构图,我们看到swoole的worker进程有2种类型:
一种是 普通的worker进程,一种是 task worker进程。
worker进程是用来处理普通的耗时不是太长的请求;task worker进程用来处理耗时较长的请求,比如数据库的I/O操作。
我们以异步Mysql举例:
如此,通过worker、task worker结合的方式,我们就实现了异步I/O。
文章来源:https://mp.weixin.qq.com/s/WMi7LZj0bqXa72V9fRhwCA
nginx、swoole高并发原理初探的更多相关文章
- MySQL InnoDB 实现高并发原理
MySQL 原理篇 MySQL 索引机制 MySQL 体系结构及存储引擎 MySQL 语句执行过程详解 MySQL 执行计划详解 MySQL InnoDB 缓冲池 MySQL InnoDB 事务 My ...
- Nginx突破高并发的性能优化 - 运维笔记
在日常的运维工作中,经常会用到nginx服务,也时常会碰到nginx因高并发导致的性能瓶颈问题.今天这里简单梳理下nginx性能优化的配置(仅仅依据本人的实战经验而述,如有不妥,敬请指出~) 一.这里 ...
- [转]Nginx实现高并发的原理
Nginx 首先要明白,Nginx 采用的是多进程(单线程) & 多路IO复用模型.使用了 I/O 多路复用技术的 Nginx,就成了”并发事件驱动“的服务器. 异步非阻塞(AIO)的详解ht ...
- Nginx多进程高并发、低时延、高可靠机制在缓存(redis、memcache)twemproxy代理中的应用
1. 开发背景 现有开源缓存代理中间件有twemproxy.codis等,其中twemproxy为单进程单线程模型,只支持memcache单机版和redis单机版,都不支持集群版功能. 由于twemp ...
- Nginx多进程高并发、低时延、高可靠机制在缓存代理中的应用
1. 开发背景 现有开源缓存代理中间件有twemproxy.codis等,其中twemproxy为单进程单线程模型,只支持memcache单机版和redis单机版,都不支持集群版功能. 由于twemp ...
- Nginx多进程高并发、低时延、高可靠机制缓存代理中的应用
1. 开发背景 现有开源缓存代理中间件有twemproxy.codis等,其中twemproxy为单进程单线程模型,只支持memcache单机版和redis单机版,都不支持集群版功能. 由于twemp ...
- nginx多线程高并发
直接上图 Master-Worker模式 1.Nginx 在启动后,会有一个 master 进程和多个相互独立的 worker 进程. 2.接收来自外界的信号,向各worker进程发送信号,每个进程都 ...
- Nginx Ingress 高并发实践
概述 Nginx Ingress Controller 基于 Nginx 实现了 Kubernetes Ingress API,Nginx 是公认的高性能网关,但如果不对其进行一些参数调优,就不能充分 ...
- nginx处理高并发请求强于apache
ginx 不同于 Apache2 的一点就是,Nginx 采用单线程,非阻塞,异步 IO 的工作模型. Apache2 对于每一个请求,都会创建一个新进程或线程,会浪费很多内存和 CPU 时间,而 N ...
随机推荐
- Python之路(第三十二篇) 网络编程:udp套接字、简单文件传输
一.UDP套接字 服务端 # udp是无链接的,先启动哪一端都不会报错 # udp没有链接,与tcp相比没有链接循环,只有通讯循环 server = socket.socket(socket.AF_I ...
- 最小化webpack项目
先把代码贴出来,以后慢慢加说明 参考资料:入门 Webpack,看这篇就够了 / webpack 搭建自动打开,刷新浏览器 一.功能代码1.index.html <!DOCTYPE html&g ...
- d3.js画折线图
下载d3.zip,并解压到网页文件所在的文件夹 windows下,在命令行进入网页文件夹,输入 python -m http.server 在浏览器中输入127.0.0.1:8000/xxx.html ...
- 【Mybatis】MyBatis之动态SQL(六)
MyBatis 的强大特性之一便是它的动态 SQL,本章介绍动态 SQL 查看本章,请先阅读[Mybatis]MyBatis对表执行CRUD操作(三). 本例表结构 CREATE TABLE `emp ...
- Lambda根据属性名字选择或筛选
using System; using System.Linq.Expressions; internal class LambdaHelper { /// <summary> /// 指 ...
- 异常:Caused by: java.sql.SQLException: Field 'cust_id' doesn't have a default value
异常: 由Java.q.L.SqLExpExt引起:字段“CuSTyID”没有默认值 Caused by: java.sql.SQLException: Field 'cust_id' doesn't ...
- JSP页面使用include指令出现 Duplicate local variable basePath
现有三个页面 " include.jsp " " a.jsp " " b.jsp " 页面代码如下 首先是a.jsp <%@ page ...
- 学以致用三十一-----IPAddressField has been removed
python 和 django版本 在进行makemigrations的时候报错 设置的字段 class Servers(models.Model): '''服务器信息''' hostname = m ...
- Python if __name__ == '__main__':
python属于脚本语言,只能逐行运行, if __name__ == '__main__':这句相当于main(),即首先执行这条语句.
- C# 服务开发
1. 执行权限 对于一般服务项目,需要使用管理员权限打开Visual Studio.右击项目 -> 属性 -> 安全性,如下图: 勾选红框中部分,项目中会增加文件 app.mainfest ...