Nginx基础之完全私货分享

NGINX完全私货分享

在这里插入图片描述

1.1 你有梦想吗?

​ 几十年如一梦,回首过往,任何事物都是由微不足道开始。我们仰望金字塔的顶端,有多少人会注意到塔底的石砖。值得你去追求的梦想,不应该是空中楼阁,而是从地基开始一层一层,一步一步逐渐累积,逐渐完善的建筑。我爱各种风格的建筑,但不会喜欢一遇风雨就支离破碎的垃圾。

1.2 Nginx的前辈:Apache

​ 我假定你是有一定的基础,对于web的热爱使你主动的了解了一些基础知识。
​ 对于Apache,我们应当去了解他的底层模型,并承上启下讲述NGINX,为何优秀。

1.2.1 Apache 的 prefork模式:

​ 你可以称为预派生模式,该模式有一个主控制进程,主进程生成多个子进程,使用select模型,最大并发为1024,每个子进程有一个独立的线程响应用户请求,相对其他模式而言比较占用内存,但比较稳定,可以设置最大和最小进程数,是一种经典的模式,也是最稳定的模式。perfork模式适合访问量不是很大的场景。

优点:

  • 稳定

缺点:

  • 相对较慢
  • 占用资源
  • 1024个进程不适用与高并发场景

在这里插入图片描述

该模式最多可有1024个进程,在X64架构中最多有2048个

1.2.2 Apache 的 woker 模式:

​ 该模式是一种多进程和多线程混合的模式(即:一个进程可以生成多个线程来响应请求)。有一个主进程,主进程生成多个子进程,每个子进程又会生成多个线程来处理请求,当一个子进程的线程不够用时,又会再启动一个新的子进程,然后在进程里通过线程处理请求。相比于perfork模式,该模式可以承受更高的并发。

优点:

  • 相比perfork占用的内存较小
  • 可以同时处理更多请求

缺点:

  • 使用keepalived的长连接方式,导致线程会一直被占用,即使没有数据传输(空连接)也需要一直等待到超时才会释放。因此,在高并发的场景下仍然会导致无服务线程可用(当然,perfork肯定也有这种情况)

在这里插入图片描述

1.2.3 Apache 的 event 模式:

​ Apache中的“新模式” 2012年发布的Apache 2.4.X系列正式支持该模式。
​ 该模式属于事件驱动模型(epoll),他和work模式很像,同样是一个进程响应多个请求,但是最大的区别在于它通过一个监听线程解决了work模式的keepalived长连接导致线程被占用导致资源浪费的问题。
​ 在event的模式中,会有专门的一个线程来管理keepalive类型的线程,当有请求来时,通过监听线程分配给空闲的线程,当某个线程处理完用户请求后,该会话会保持并交于监听线程管理,自己去处理新的请求,并不负责保持会话。

优点:

  • 单个线程能够相应更多的请求
  • 占据更少内存(发现内存占用和线程的关系了吗)
  • 高并发下表现更加优秀
  • 有一个专门的监控线程来管理keepalived型的线程
  • 当有真实的请求过来的时候,监控线程将请求传递给服务线程,服务线程执行完毕后,控制其释放

缺点:

  • 没有线程安全控制(监控线程挂掉了)

在这里插入图片描述

1.3 NGINX 一款高性能的web服务端:

Ninx是由1994年毕业于俄罗斯国立莫斯科鲍曼科技大学的同学为俄罗斯rambler.ru公司开发的,开发工作最早从
2002年开始,第一次公开发布时间是2004年10月4日,版本号是0.1.0,官网地址 www.nginx.org
Nginx历经十几年的迭代更新(https://nginx.org/en/CHANGES), 目前功能已经非常完善且运行稳定,另外
Nginx的版本分为开发版、稳定版和过期版,nginx以功能丰富著称,它即可以作为http服务器,也可以作为反向代
理服务器或者邮件服务器,能够快速的响应静态网页的请求,支持FastCGI/SSL/Virtual Host/URL
Rwrite/Gzip/HTTP Basic Auth/http或者TCP的负载均衡(1.9版本以上且开启stream模块)等功能,并且支持第三方
的功能扩展。

天猫 淘宝 小米 163 京东新浪等一线互联网公司都在用Nginx或者进行二次开发

NGINX的工作模式简介

httpd MPM(Multi-Processing Module,多进程处理模块)模式:
prefork:进程模型,两级结构,主进程master负责生成子进程,每个子进程负责响应一个请求
worker:线程模型,三级结构,主进程master负责生成子进程,每个子进程负责生成多个线程,每个线程响应
一个请求
event:线程模型,三级结构,主进程master负责生成子进程,每个子进程生成多个线程,每个线程响应一个请
求,但是增加了一个监听线程,用于解决在设置了keep-alived场景下线程的空等待问题。

################################################

Nginx(Master+Worker)模式:
主进程
工作进程 #直接处理客户的请求

################################################

线程验证方式:
# cat /proc/PID/status
# pstree -p PID

1.3.1 究竟怎样才算是高性能?

​ 加载快速的网站和加载缓慢的网站

1.3.2 同样一个网站,影响用户加载速率的原因有哪些?

客户端方面:

  • 客户端硬件问题
  • 客户端网络速率
  • 客户端与服务端距离

服务端方面:

  • 服务端网络速率
  • 服务端硬件配置
  • 服务端架构设计
  • 服务端应用程序工作模式
  • 服务端并发数量
  • 服务端相应文件大小及数量
  • 服务端I/O压力

1.3.3 讲讲服务端I/O:

​ I/O在计算机中指Input/Output, IOPS (Input/Output Per Second)即每秒的输入输出量(或读写次数),是衡量磁盘性能的主要指标之一。IOPS是指单位时间内系统能处理的I/O请求数量,一般以每秒处理的I/O请求数量为单位,I/O请求通常为读或写数据操作请求。

​ 一次完整的I/O是用户空间的进程数据与内核空间的内核数据的报文的完整交换,但是由于内核空间与用户空间是严格隔离的,所以其数据交换过程中不能由用户空间的进程直接调用内核空间的内存数据,而是需要经历一次从内核空间中的内存数据copy到用户空间的进程内存当中,所以简单说I/O就是把数据从内核空间中的内存数据复制到用户空间中进程的内存当中。

用户空间想拿到数据,必须先经过内核调用读取磁盘内容至内核空间,再由内核空间将数据拷贝至用户空间,期间经历了两次拷贝。

1.3.4 系统也有多种I/O模型:

​ 这一节是重点,因为系统并非只有一种I/O模型,因此当说起I/O模型时,你最好知道有哪几种。

同步 synchronous:

调用者等待被调用者返回消息后才能继续执行,如果被调用者不提供消息则为同步,同步需要调用者主动询问事情是否处理完成。

你在用茶壶烧水,在水烧开的过程中你别的事都不能做,只是不停的确认水烧开了没有,好好想想,如果有成千上万的水壶呢?

异步 asynchronous :

被调用者通过通知等回调机制主动的通知调用者自己的运行状态

你在用比较好的水壶烧水,这个水壶可以实时告诉你水温,水开了就会发出响声提醒你,好好想想,如果有成千上万的水壶呢?

阻塞 blocking :

指I/O操作需要彻底完成后才返回到用户空间,在此之前,调用者被挂起,干不了别的事。

你在专心致志等水烧开,再水烧开前,你做不了别的事,好好想想,如果有成千上万的水壶呢?

非阻塞 unblocking :

指I/O操作被调用后可以立即返回给用户一个操作值,无需等到I/O操作完成,最终的调用结果返回之前,调用者不会被挂起,可以抽身去做别的事

你在等水烧开之前,可以做别的事,好好想想,如果有成千上万的水壶呢?

1.4 以系统I/O模型为基础的网络I/O模型 :

阻塞型、非阻塞型、多路复用型、信号驱动型、异步

1.4.1 同步阻塞型I/O模型(blocking IO) :

阻塞IO模型是最简单的IO模型,用户线程在内核进行IO操作时候会被阻塞(什么也做不了)

用户线程通过系统调用read发起IO读操作,由用户空间转到内核空间。在此之后一直等待,直到内核的数据包到达,再由内核将数据拷贝到用户空间,这个过程也是一直等待(这里有两个等待的过程)

Apache的perfork就是这个模型,有印象吧?

在这里插入图片描述

注意看最右边的两个等待阶段

1.4.2 同步非阻塞I/O模型(noblocking IO) :

程序向内核发送请求IO之后一直会等待的内核相应,如果内核处理请求的IO操作不能立即返回IO结果,程序进程将不在等待,而是继续处理其他请求,但是仍然会每隔一段时间就来查看内核I/O是否完成。

在这里插入图片描述

注意查看反复确认是否完成的过程

1.4.3 IO多路复用型(IO multiplexing):

​ IO多路复用就是我们说的select,poll,epoll(之后会讲到),有些地方也称这种IO方式为事件驱动IO (event driven IO)。select/epoll的好处就在于单个进程就可以同时处理多个网络连接的IO。它的基本原理就是select,poll,epoll这个几个函数功能会不断的轮询所负责的所有socket连接,当某个socket有数据到达了,就通知用户进程。 当用户进程调用了select,那么整个进程会被block,而同时,kernel会“监视”所有select负责的socket,当任何一个socket中的数据准备好了,select就会返回。这个时候用户进程再调用read操作,将数据从kernel拷贝到用户进程。

有点绕?

记得上面智能水壶的故事吧?当水烧开了(数据准备好了),水壶会发出声响提醒你

这是什么意思呢?

这是怎么回事呢?

​ 首先,这是一种思路,目的是节约时间,节约什么时间?节约的是诸多进程不断请求数据的这么个时间。这种思路是,将由一个线程监控多个网络请求(我们后面将称为fd文件描述符,linux系统把所有网络请求以一个fd来标识),这样就可以只需要一个或几个线程就可以完成数据状态询问的操作,当有数据准备就绪之后再分配对应的线程去读取数据,这么做就可以节省出大量的线程资源出来,这个就是IO复用模型的思路。

在这里插入图片描述

请了一个人专门查看水壶是否烧开了,发现烧开了的就通知其他人取开水

1.4.4 信号驱动式IO(signal-driven IO):

那问题又来了,总是有新的问题是吧? IO多路复用解决的是由一个线程来监控多个fd,但是select是用轮询的方式来监控多个fd的。

啥叫轮询? 无数个fd从头到尾一列列个表,从第一个循环到最后一个,一个个看状态

这种方法有人也觉得比较浪费时间,因为这样一直反复轮询下去,总会有蛮多是未准备好的。能不能不要总是这样轮询,能不能当数据准备好了就主动通知我呢?

能!

这就是信号驱动式IO

该模式中,不用轮询的方式去监控数据就绪的状态,而是调用sigaction时候建立一个SIGIO信号处理程序,当内核数据准备好之后再通过SIGIO程序告知数据已准备就绪,此时再发起recvfrom读取数据请求。在该模式下,工作线程在发出信号监控后即可返回,不会阻塞,所以,一个工作线程也可以同时监视多个fd。

当然,recvfrom方法将数据从内核空间拷贝到用户空间还是需要时间等待的。

在这里插入图片描述

signal-driven I/O 用户进程可以通过sigaction系统调用注册一个信号处理程序,然后主程序可以继续向下执行,当有IO操作准备就绪时,由内核通知触发一个SIGIO信号处理程序执行,然后将用户进程所需要的数据从内核空间拷贝到用户空间 此模型的优势在于等待数据报到达期间进程不被阻塞。用户主程序可以继续执行,只要等待来自信号处理函数的通知。

1.4.5 异步(非阻塞)IO(asynchronous IO):

最后压轴的方法也来自一个想法:能不能仅发送一个请求高速内核我要读取什么数据,然后什么都不用管了,让内核自己去完成剩下的所有事情。让数据从内核拷贝到用户空间的这个时间也可以做别的事。

当然也有~

在异步IO中,进程只需要向内核发送一个read请求,内核收到请求后就会建立一个信号联系,当数据准备好之后,会主动将数据复制到用户空间,复制完后,内核会发起一个通知告诉进程。

该模式就成为异步IO模型。

在这里插入图片描述

程序进程向内核发送IO调用后,不用等待内核响应,可以继续接受其他请求,内核调用的IO如果不能立即返回,内核会继续处理其他事物,直到IO完成后将结果通知给内核,内核在将IO完成的结果返回给进程,期间进程可以接受新的请求,内核也可以处理新的事物,因此相互不影响,可以实现较大的同时并实现较高的IO
复用,因此异步非阻塞使用最多的一种通信方式。

1.4.6 五种IO对比

在这里插入图片描述

这五种 I/O 模型中,越往后,阻塞越少,注意红色的blocked,理论上效率也是最优前四种属于同步 I/O,因为其中真正的 I/O 操作(recvfrom)将阻塞进程/线程,只有异步 I/O 模型才与 POSIX 定义的异步 I/O 相匹配。

1.5 事件驱动模型:

#1、select:
POSIX所规定,目前几乎在所有的平台上支持,其良好跨平台支持也是它的一个优点,本质上是通过设置或者检查
存放fd标志位的数据结构来进行下一步处理
缺点
单个进程能够监视的文件描述符的数量存在最大限制,在Linux上一般为1024,可以通过修改宏定义
FD_SETSIZE,再重新编译内核实现,但是这样也会造成效率的降低
单个进程可监视的fd数量被限制,默认是1024,修改此值需要重新编译内核
对socket是线性扫描,即采用轮询的方法,效率较低
select 采取了内存拷贝方法来实现内核将 FD 消息通知给用户空间,这样一个用来存放大量fd的数据结构,这
样会使得用户空间和内核空间在传递该结构时复制开销大

#2、poll:
本质上和select没有区别,它将用户传入的数组拷贝到内核空间,然后查询每个fd对应的设备状态
其没有最大连接数的限制,原因是它是基于链表来存储的
大量的fd的数组被整体复制于用户态和内核地址空间之间,而不管这样的复制是不是有意义
poll特点是“水平触发”,如果报告了fd后,没有被处理,那么下次poll时会再次报告该fd
select是边缘触发即只通知一次

3、epoll:
在Linux 2.6内核中提出的select和poll的增强版本
支持水平触发LT和边缘触发ET,最大的特点在于边缘触发,它只告诉进程哪些fd刚刚变为就需态,并且只会通知
一次
使用“事件”的就绪通知方式,通过epoll_ctl注册fd,一旦该fd就绪,内核就会采用类似callback的回调机制
来激活该fd,epoll_wait便可以收到通知
优点:
没有最大并发连接的限制:能打开的FD的上限远大于1024(1G的内存能监听约10万个端口),具体查
看/proc/sys/fs/file-max,此值和系统内存大小相关
效率提升:非轮询的方式,不会随着FD数目的增加而效率下降;只有活跃可用的FD才会调用callback函数,即
epoll最大的优点就在于它只管理“活跃”的连接,而跟连接总数无关
内存拷贝,利用mmap(Memory Mapping)加速与内核空间的消息传递;即epoll使用mmap减少复制开销

4、rtsig:
不是一个常用事件驱动,最大队列1024,不是很常用

5、kqueue:
用于支持BSD系列平台的高校事件驱动模型,主要用在FreeBSD 4.1及以上版本、OpenBSD 2.0级以上版本,
NetBSD级以上版本及Mac OS X 平台上,该模型也是poll库的变种,因此和epoll没有本质上的区别,都是通
过避免轮训操作提供效率。

6、/dev/poll:
用于支持unix衍生平台的高效事件驱动模型,主要在Solaris 平台、HP/UX,该模型是sun公司在开发
Solaris系列平台的时候提出的用于完成事件驱动机制的方案,它使用了虚拟的/dev/poll设备,开发人员将要
见识的文件描述符加入这个设备,然后通过ioctl()调用来获取事件通知,因此运行在以上系列平台的时候请使
用/dev/poll事件驱动机制。

7、eventport:
该方案也是sun公司在开发Solaris的时候提出的事件驱动库,只是Solaris 10以上的版本,该驱动库看防止
内核崩溃等情况的发生。
8、Iocp:
Windows系统上的实现方式,对应第5种(异步I/O)模型。

1.5.1 常见的模型对比

在这里插入图片描述

说一下两个术语:

水平触发:只通知一次

边缘触发:通知多次

在这里插入图片描述

1.5.2 MMAP内存拷贝介绍(Memory Mapping):

mmap()系统调用使得进程之间通过映射同一个普通文件实现共享内存。普通文件被映射到进程地址空间后,进程可以向访问普通内存一样对文件进行访问。

简单来说就是多了一个快捷方式,在不同进程访问同一个文件时不需要一个个从内核空间中将文件拷贝到用户空间,而是通过这个快捷方式直接访问。

1.5.3 MMAP图示:

先看看传统方式:

在这里插入图片描述

MMAP方式:

0201031003220340.png

  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值