Apache 几个经典的Web****服务端
①Apache prefork 模型
● 预派生模式,有一个主控制进程,然后生成多个子进程,使用select模型,最大并发 1024
● 每个子进程有一个独立的线程响应用户请求
● 相对比较占用内存,但是比较稳定,可以设置最大和最小进程数
● 是最古老的一种模式, 也是最稳定的模式,适用于访问量不是很大的场景
▲ 优点:稳定
■ 缺点:每个用户请求需要对应开启一个进程 , 占用资源较多,并发性差 , 不适用于高并发场景
②Apache worker 模型
● 一种多进程和多线程混合的模型
● 有一个控制进程,启动多个子进程
● 每个子进程里面包含固定的线程
● 使用线程程来处理请求
● 当线程不够使用的时候会再启动一个新的子进程, 然后在进程里面再启动线程处理请求,
● 由于其使用了线程处理请求,因此可以承受更高的并发
▲ **优点:**相比prefork 占用的内存较少,可以同时处理更多的请求
■ 缺点:使用keepalive 的长连接方式,某个线程会一直被占据,即使没有传输数据,也需要一直等待到超时才会被释放。如果过多的线程,被这样占据,也会导致在高并发场景下的无服务线程可用(该问题在prefork模式下,同样会发生)
③Apache event模型
● Apache中最新的模式, 2012 年发布的 apache 2.4.X 系列正式支持 event 模型 , 属于事件驱动模型
● 每个进程响应多个请求,在现在版本里的已经是稳定可用的模式
● 它和worker 模式很像,最大的区别在于,它解决了 keepalive 场景下长期被占用的线程的资源浪费问题 (某些线程因为被keepalive ,空挂在哪里等待,中间几乎没有请求过来,甚至等到超时)
● MPM中,会有一个专门的线程来管理这些 keepalive 类型的线程
当有真实请求过来的时候,将请求传递给服务线程,执行完毕后,又允许它释放。这样增强了高并发场 景下的请求处理能力
▲ 优点:单线程响应多请求,占据更少的内存,高并发下表现更优秀,会有一个专门的线程来管理keep-alive类型的线程,当有真实请求过来的时候,将请求传递给服务线程,执行完毕后,又允许它释放
■ **缺点:**没有线程安全控制
服务端I/O流程
I/O 在计算机中指 Input/Output , IOPS (Input/Output Per Second) 即每秒的输入输出量 ( 或读写次数 ) , 是衡量磁盘性能的主要指标之一。IOPS 是指单位时间内系统能处理的 I/O 请求数量,一般以每秒处理的 I/O请求数量为单位, I/O 请求通常为读或写数据操作请求。
一次完整的 I/O 是用户空间的进程数据与内核空间的内核数据的报文的完整交换,但是由于内核空间与用 户空间是严格隔离的,所以其数据交换过程中不能由用户空间的进程直接调用内核空间的内存数据,而 是需要经历一次从内核空间中的内存数据copy 到用户空间的进程内存当中,所以简单说 I/O 就是把数据从内核空间中的内存数据复制到用户空间中进程的内存当中。
服务器的I/O:
● 磁盘I/O
● 网络I/O : 一切皆文件 , 本质为对 socket 文件的读写
磁盘 I/O
磁盘 I/O 是进程向内核发起系统调用,请求磁盘上的某个资源比如是 html 文件或者图片,然后内核通过相 应的驱动程序将目标文件加载到内核的内存空间,加载完成之后把数据从内核内存再复制给进程内存,如果是比较大的数据也需要等待时间
网络 I/O
网络通信就是网络协议栈到用户空间进程的 IO 就是网络 IO
网络 I/O 处理过程
获取请求数据,客户端与服务器建立连接发出请求,服务器接受请求( 1-3 )
构建响应,当服务器接收完请求,并在用户空间处理客户端的请求,直到构建响应完成( 4 )
返回数据,服务器将已构建好的响应再通过内核空间的网络 I/O 发还给客户端( 5-7 )
不论磁盘和网络 I/O
每次 I/O ,都要经由两个阶段:
第一步:将数据从文件先加载至内核内存空间(缓冲区),等待数据准备完成,时间较长
第二步:将数据从内核缓冲区复制到用户空间的进程的内存中,时间较短
I/O****模型
模型相关概念
同步 / 异步:关注的是消息通信机制,即调用者在等待一件事情的处理结果时,被调用者是否提供完成状 态的通知。
同步: synchronous ,被调用者并不提供事件的处理结果相关的通知消息,需要调用者主动询问事情是否处理完成
异步: asynchronous ,被调用者通过状态、通知或回调机制主动通知调用者被调用者的运行状态
阻塞/ 非阻塞**:**关注调用者在等待结果返回之前所处的状态
阻塞: blocking ,指 IO 操作需要彻底完成后才返回到用户空间,调用结果返回之前,调用者被挂
起,干不了别的事情。
非阻塞: nonblocking ,指 IO 操作被调用后立即返回给用户一个状态值,而无需等到 IO 操作彻底完成,在最终的调用结果返回之前,调用者不会被挂起,可以去做别的事情。
网络I/O模型
阻塞型、非阻塞型、复用型、信号驱动型、异步
①阻塞型I/O****模型(blocking IO)
● 阻塞 IO 模型是最简单的 I/O 模型,用户线程在内核进行 IO 操作时被阻塞
● 用户线程通过系统调用read 发起 I/O 读操作,由用户空间转到内核空间。内核等到数据包到达后,然 后将接收的数据拷贝到用户空间,完成read 操作
● 用户需要等待read 将数据读取到 buffer 后,才继续处理接收的数据。整个 I/O 请求的过程中,用户线程是被阻塞的,这导致用户在发起IO 请求时,不能做任何事情,对 CPU 的资源利用率不够
**优点:**程序简单,在阻塞等待数据期间进程 / 线程挂起,基本不会占用 CPU 资源
**缺点:**每个连接需要独立的进程 / 线程单独处理,当并发请求量大时为了维护程序,内存、线程切换开销较apache 的 preforck 使用的是这种模式。
**同步阻塞:**程序向内核发送 I/O 请求后一直等待内核响应,如果内核处理请求的 IO 操作不能立即返回 , 则进程将一直等待并不再接受新的请求,并由进程轮询查看I/O 是否完成,完成后进程将 I/O 结果返回给Client,在 IO 没有返回期间进程不能接受其他客户的请求,而且是有进程自己去查看 I/O 是否完成,这种方式简单,但是比较慢,用的比较少
②非阻塞型I/O模型(nonblocking IO)
用户线程发起 IO 请求时立即返回。但并未读取到任何数据,用户线程需要不断地发起 IO 请求,直到数据 到达后,才真正读取到数据,继续执行。即 " 轮询 " 机制存在两个问题:如果有大量文件描述符都要等, 那么就得一个一个的read 。这会带来大量的 Context Switch ( read 是系统调用,每调用一次就得在用户态和核心态切换一次)。轮询的时间不好把握。这里是要猜多久之后数据才能到。等待时间设的太长,程序响应延迟就过大; 设的太短,就会造成过于频繁的重试,干耗 CPU 而已,是比较浪费 CPU 的方式,一 般很少直接使用这种模型,而是在其他IO 模型中使用非阻塞 IO 这一特性。
非阻塞:程序向内核发送请 I/O 求后一直等待内核响应,如果内核处理请求的 IO 操作不能立即返回 IO 结果,进程将不再等待,而且继续处理其他请求,但是仍然需要进程隔一段时间就要查看内核I/O 是否完成。
查看上图可知,在设置连接为非阻塞时,当应用进程系统调用 recvfrom 没有数据返回时,内核会立即返回一个 EWOULDBLOCK 错误,而不会一直阻塞到数据准备好。如上图在第四次调用时有一个数据报准备好了,所以这时数据会被复制到 应用进程缓冲区 ,于是 recvfrom 成功返回数据
当一个应用进程这样循环调用 recvfrom 时,称之为轮询 polling 。这么做往往会耗费大量 CPU 时间,实际使用很少
③多路复用I/O型(I/O multiplexing)
上面的模型中 , 每一个文件描述符对应的 IO 是由一个线程监控和处理
多路复用 IO 指一个线程可以同时(实际是交替实现,即并发完成)监控和处理多个文件描述符对应各自的IO ,即复用同一个线程
一个线程之所以能实现同时处理多个 IO, 是因为这个线程调用了内核中的 SELECT,POLL 或 EPOLL 等系统调用,从而实现多路复用IO
I/O multiplexing 主要包括 :select , poll , epoll 三种系统调用, select/poll/epoll 的好处就在于单个process就可以同时处理多个网络连接的 IO 。
它的基本原理就是 select/poll/epoll 这个 function 会不断的轮询所负责的所有 socket ,当某个 socket 有数据到达了,就通知用户进程。
当用户进程调用了 select ,那么整个进程会被 block ,而同时, kernel 会 " 监视 " 所有 select 负责的 socket ,当任何一个socket 中的数据准备好了, select 就会返回。这个时候用户进程再调用 read 操作,将数据从kernel拷贝到用户进程。
Apache prefork 是此模式的 select , worker 是 poll 模式。
IO 多路复用( IO Multiplexing) :是一种机制,程序注册一组 socket 文件描述符给操作系统,表示 " 我要监视这些fd 是否有 IO 事件发生,有了就告诉程序处理 "IO 多路复用一般和 NIO 一起使用的。 NIO 和 IO 多路复用是相对独立的。NIO 仅仅是指 IO API 总是能立刻返回,不会被 Blocking; 而 IO 多路复用仅仅是操作系统提供的一种便利的通知机制。操作系统并不会强制这俩必须得一起用,可以只用IO 多路复用 + BIO ,这时还是当前线程被卡住。IO 多路复用和 NIO 是要配合一起使用才有
实际意义
IO 多路复用是指内核一旦发现进程指定的一个或者多个 IO 条件准备读取,就通知该进程多个连接共用一个等待机制,本模型会阻塞进程,但是进程是阻塞在select 或者 poll 这两个系统调用上,而不是阻塞在真正的IO 操作上用户首先将需要进行 IO 操作添加到 select 中,同时等待 select 系统调用返回。当数据到达时,IO 被激活, select 函数返回。用户线程正式发起 read 请求,读取数据并继续执行从流程上来看,使用select函数进行 IO 请求和同步阻塞模型没有太大的区别,甚至还多了添加监视 IO ,以及调用 select 函数的额外操作,效率更差。并且阻塞了两次,但是第一次阻塞在select 上时, select 可以监控多个 IO 上是否已有IO 操作准备就绪,即可达到在同一个线程内同时处理多个 IO 请求的目的。而不像阻塞 IO 那种,一次只能监控一个IO 虽然上述方式允许单线程内处理多个 IO 请求,但是每个 IO 请求的过程还是阻塞的(在 select 函数上阻塞),平均时间甚至比同步阻塞IO 模型还要长。如果用户线程只是注册自己需要的 IO 请求,然 后去做自己的事情,等到数据到来时再进行处理,则可以提高CPU 的利用率 IO 多路复用是最常使用的 IO 模型,但是其异步程度还不够" 彻底 " ,因它使用了会阻塞线程的 select 系统调用。因此 IO 多路复用只能称 为异步阻塞IO 模型,而非真正的异步 IO
优缺点
优点:可以基于一个阻塞对象,同时在多个描述符上等待就绪,而不是使用多个线程 ( 每个文件描述符一个线程) ,这样可以大大节省系统资源
缺点:当连接数较少时效率相比多线程 + 阻塞 I/O 模型效率较低,可能延迟更大,因为单个连接处理需要 2 次系统调用,占用时间会有增加
IO 多路复用适用如下场合:
当客户端处理多个描述符时(一般是交互式输入和网络套接口),必须使用 I/O 复用
当一个客户端同时处理多个套接字时,此情况可能的但很少出现
当一个服务器既要处理监听套接字,又要处理已连接套接字,一般也要用到 I/O 复用
当一个服务器即要处理 TCP ,又要处理 UDP ,一般要使用 I/O 复用
当一个服务器要处理多个服务或多个协议,一般要使用 I/O 复用
④信号驱动式I/O模型(signal-driven IO)
信号驱动 I/O 的意思就是进程现在不用傻等着,也不用去轮询。而是让内核在数据就绪时,发送信号通知进程。
调用的步骤是,通过系统调用 sigaction ,并注册一个信号处理的回调函数,该调用会立即返回,然后主程序可以继续向下执行,当有I/O 操作准备就绪 , 即内核数据就绪时,内核会为该进程产生一个 SIGIO 信号,并回调注册的信号回调函数,这样就可以在信号回调函数中系统调用 recvfrom 获取数据 , 将用户进程所需要的数据从内核空间拷贝到用户空间
此模型的优势在于等待数据报到达期间进程不被阻塞。用户主程序可以继续执行,只要等待来自信号处理函数的通知。
在信号驱动式 I/O 模型中,应用程序使用套接口进行信号驱动 I/O ,并安装一个信号处理函数,进程继续运行并不阻塞
在信号驱动式 I/O 模型中,应用程序使用套接口进行信号驱动 I/O ,并安装一个信号处理函数,进程继续运行并不阻塞
当数据准备好时,进程会收到一个 SIGIO 信号,可以在信号处理函数中调用 I/O 操作函数处理数据。
**优点:**线程并没有在等待数据时被阻塞,内核直接返回调用接收信号,不影响进程继续处理其他请求因此可以提高资源的利用率
**缺点:**信号 I/O 在大量 IO 操作时可能会因为信号队列溢出导致没法通知
异步阻塞:程序进程向内核发送 IO调用后,不用等待内核响应,可以继续接受其他请求,内核收到进程 请求后 进行的 IO 如果不 能立即返回,就由内核等待结果,直到IO 完成后内核再通知进程。
⑤异步I/O模型(asynchronous IO)
异步 I/O 与 信号驱动 I/O 最大区别在于,信号驱动是内核通知用户进程何时开始一个 I/O 操作,而异步 I/O 是由内核通知用户进程I/O 操作何时完成,两者有本质区别 , 相当于不用去饭店场吃饭,直接点个外卖,把 等待上菜的时间也给省了
相对于同步I/O ,异步 I/O 不是顺序执行。用户进程进行 aio_read 系统调用之后,无论内核数据是否准备 好,都会直接返回给用户进程,然后用户态进程可以去做别的事情。等到socket 数据准备好了,内核直接复制数据给进程,然后从内核向进程发送通知。IO 两个阶段,进程都是非阻塞的。
信号驱动 IO 当内核通知触发信号处理程序时,信号处理程序还需要阻塞在从内核空间缓冲区拷贝数据到用户空间缓冲区这个阶段,而异步IO 直接是在第二个阶段完成后,内核直接通知用户线程可以进行后续操作了
优点:异步 I/O 能够充分利用 DMA 特性,让 I/O 操作与计算重叠
缺点:要实现真正的异步 I/O ,操作系统需要做大量的工作。目前 Windows 下通过 IOCP 实现了真正的异步 I/O ,在 Linux 系统下, Linux 2.6 才引入,目前 AIO 并不完善,因此在 Linux 下实现高并发网络编程时以 IO 复用模型模式 + 多线程任务的架构基本可以满足需求
Linux 提供了 AIO 库函数实现异步,但是用的很少。目前有很多开源的异步 IO 库,例如 libevent 、 libev 、libuv。
异步非阻塞:程序进程向内核发送 IO 调用后,不用等待内核响应,可以继续接受其他请求,内核调用的IO如果不能立即返回,内核会继续处理其他事物,直到 IO 完成后将结果通知给内核,内核在将 IO 完成的结果返回给进程,期间进程可以接受新的请求,内核也可以处理新的事物,因此相互不影响,可以实现较大的同时并实现较高的IO 复用,因此异步非阻塞使用最多的一种通信方式。
Nginx****架构和安装
Nginx 介绍
Nginx : engine X , 2002 年开发,分为社区版和商业版 (nginx plus )
2019 年 3 月 11 日 F5 Networks 6.7 亿美元的价格收购
Nginx 是免费的、开源的、高性能的 HTTP 和反向代理服务器、邮件代理服务器、以及 TCP/UDP 代理服务器
解决 C10K 问题( 10K Connections )
Nginx 官网: http://nginx.org
nginx 的其它的二次发行版:
Tengine :由淘宝网发起的 Web 服务器项目。它在 Nginx 的基础上,针对大访问量网站的需求,添加
了很多高级功能和特性。 Tengine 的性能和稳定性已经在大型的网站如淘宝网,天猫商城等得到了
很好的检验。它的最终目标是打造一个高效、稳定、安全、易用的 Web 平台。从 2011 年 12 月开始,
Tengine 成为一个开源项目官网 : http://tengine.taobao.org/
OpenResty :基于 Nginx 与 Lua 语言的高性能 Web 平台, 章亦春团队开发,官网: http://openr
esty.org/cn/
Nginx 功能
● 静态的 web 资源服务器 html ,图片, js , css , txt 等静态资源
● http/https协议的反向代理
● 结合FastCGI/uWSGI/SCGI 等协议反向代理动态资源请求
● tcp/udp协议的请求转发(反向代理)
● imap4/pop3协议的反向代理
Nginx 进程间通信
工作进程是由主进程生成的,主进程使用 fork() 函数,在 Nginx 服务器启动过程中主进程根据配置文件决定启动工作进程的数量,然后建立一张全局的工作表用于存放当前未退出的所有的工作进程,主进程生成工作进程后会将新生成的工作进程加入到工作进程表中,并建立一个单向的管道并将其传递给工作进程,该管道与普通的管道不同,它是由主进程指向工作进程的单向通道,包含了主进程向工作进程发出的指令、工作进程ID 、工作进程在工作进程表中的索引和必要的文件描述符等信息。
主进程与外界通过信号机制进行通信,当接收到需要处理的信号时,它通过管道向相关的工作进程发送正确的指令,每个工作进程都有能力捕获管道中的可读事件,当管道中有可读事件的时候,工作进程就会从管道中读取并解析指令,然后采取相应的执行动作,这样就完成了主进程与工作进程的交互。
worker 进程之间的通信原理基本上和主进程与 worker 进程之间的通信是一样的,只要 worker 进程之间能够取得彼此的信息,建立管道即可通信,但是由于worker 进程之间是完全隔离的,因此一个进程想要知道另外一个进程的状态信息, 就只能通过主进程来实现。
为了实现 worker 进程之间的交互, master 进程在生成 worker 进程之后,在 worker 进程表中进行遍历,将该新进程的PID 以及针对该进程建立的管道句柄传递给 worker 进程中的其他进程,为 worker 进程之间的通信做准备,当worker 进程 1 向 worker 进程 2 发送指令的时候,首先在 master 进程给它的其他 worker 进程工作信息中找到2 的进程 PID ,然后将正确的指令写入指向进程 2 的管道, worker 进程 2 捕获到管道中的事件后,解析指令并进行相关操作,这样就完成了worker 进程之间的通信。
另 worker 进程可以通过共享内存来通讯的,比如 upstream 中的 zone ,或者 limit_req 、 limit_conn 中的zone等。操作系统提供了共享内存机制
Nginx****安装
Nginx 版本
● Mainline version 主要开发版本 , 一般为奇数版本号 , 比如 1.19
● Stable version 当前最新稳定版 , 一般为偶数版本 , 如 :1.20
● Legacy versions 旧的稳定版 , 一般为偶数版本 , 如 :1.18
Nginx 安装可以使用 yum 或源码安装,但是推荐使用源码编译安装
● yum的版本比较旧
● 编译安装可以更方便自定义相关路径
● 使用源码编译可以自定义相关功能,更方便业务的上的使用
Nginx 编译安装
先去官网右键复制你需要的nginx版本的链接
然后wgert下载
下载源码安装所需要的软件
[root@localhost ~]# dnf install gcc pcre-devel zlib-devel openssl-devel -y
添加nginx用户
useradd -s /sbin/nologin -M nginx
解压
[root@localhost ~]# tar zxf nginx-1.24.0.tar.gz
进入nginx-1.24.0目录
[root@localhost nginx-1.24.0]# vim auto//cc/gcc
先关掉Debug
编译
[root@localhost nginx-1.24.0]# ./configure --prefix=/usr/local/nginx --user=nginx --group=nginx --with-http_ssl_module --with-http_v2_module --with-http_realip_module --with-http_gzip_static_module --with-http_stub_status_module --with-pcre --with-stream --with-stream_ssl_module
[root@localhost nginx-1.24.0]# make install
[root@localhost ~]# source ~/.bash_profile
nginx的平滑升级
去官网拿到nginx-1.26.2的安装包
nginx服务的启动脚本编写
nginx全局配置参数优化调整
nginx 官方帮助文档: http://nginx.org/en/docs/
Nginx 的配置文件的组成部分:
● 主配置文件: nginx.conf
● 子配置文件: include conf.d/*.conf
● fastcgi, uwsgi , scgi 等协议相关的配置文件
● mime.types:支持的 mime 类型, MIME(Multipurpose Internet Mail Extensions) 多用途互联网邮
● 件扩展类型,MIME 消息能包含文本、图像、音频、视频以及其他应用程序专用的数据,是设定某
● 种扩展名的文件用一种应用程序来打开的方式类型,当该扩展名文件被访问的时候,浏览器会自动
● 使用指定应用程序来打开。多用于指定一些客户端自定义的文件名,以及一些媒体文件打开方式。
nginx 配置文件格式说明:
配置文件由指令与指令块构成
每条指令以 ; 分号结尾,指令与值之间以空格符号分隔
可以将多条指令放在同一行 , 用分号分隔即可 , 但可读性差 , 不推荐
指令块以 { } 大括号将多条指令组织在一起 , 且可以嵌套指令块
include 语句允许组合多个配置文件以提升可维护性
使用 # 符号添加注释,提高可读性
使用 $ 符号使用变量
部分指令的参数支持正则表达式
#全局配置端,对全局生效,主要设置nginx的启动用户/组,启动的工作进程数量,工作模式,Nginx的PID路
径,日志路径等。
user nginx nginx;
worker_processes 1; #启动工作进程数数量
events { #events #设置快,主要影响nginx服务器与用户的网络连接,比如是否允许同时接受多个
网络连接,使用哪种事件驱动模型
#处理请求,每个工作进程可以同时支持的
最大连接数,是否开启对多工作进程下的网络连接进行序列化等。
worker_connections 1024; #设置单个nginx工作进程可以接受的最大并发,作为web服务器
的时候最大并发数为 #worker_connections *
worker_processes,作为反向代理的时候为 #(worker_connections * worker_processes)/2
}
http { #http块是Nginx服务器配置中的重要部分,缓存、代理和日志格
式定义等绝大多数功能和第三方模块都可以在这设置,http块可
以包含多个server块,而一个server块中又可以包含多个location块,
#server块可以配置文件引入、MIME-Type定义、日志自定义、是
否启用sendfile、连接超时时间和 #单个链接的请求上限等。
include mime.types;
default_type application/octet-stream;
sendfile on; #作为web服务器的时候打开sendfile加快静态文件传输,指定是否使用
#sendfile系统调用来传输文件
#sendfile系统调用在两个文件描述符之间直接传递数据(完全在内核中操作)
从而避免了数据在内核缓冲区和用户缓冲区之间的拷贝,操作效率很高,被
称之为零拷贝,
#硬盘 >> kernel buffer (快速拷贝到kernelsocketbuffer) >>协议栈。
keepalive_timeout 65; #长连接超时时间,单位是秒
server { #设置一个虚拟机主机,可以包含自己的全局快,同时也可以包含多
个location模块
#比如本虚拟机监听的端口、本虚拟机的名称和IP配置,多个server
可以使用一个端口比如都使用 #80端口提供web服务
listen 80; #配置server监听的端口
server_name localhost; #本server的名称,当访问此名称的时候nginx会调用当前serevr内
部的配置进程匹配。
location / { #location其实是server的一个指令,为nginx服务器提供比较多而
且灵活的指令
#都是在location中体现的,主要是基于nginx接受到的请求字符串
#对用户请求的UIL进行匹配,并对特定的指令进行处理
#包括地址重定向、数据缓存和应答控制等功能都是在这部分实现
#另外很多第三方模块的配置也是在location模块中配置。
root html; #相当于默认页面的目录名称,默认是安装目录的相对路径,可以使
用绝对路径配置。
index index.html index.htm; #默认的页面文件名称
}
error_page 500 502 503 504 /50x.html; #错误页面的文件名称
location = /50x.html { #location处理对应的不同错误码的页面定义到/50x.html
#这个跟对应其server中定义的目录下。
root html; #定义默认页面所在的目录
}
}
#和邮件相关的配置
#mail {
# ...
# } mail 协议相关配置段
#tcp代理配置,1.9版本以上支持
#stream {
# ...
# } stream 服务器相关配置段
#导入其他路径的配置文件
#include /apps/nginx/conf.d/*.conf
}
全局配置说明 :
user nginx nginx; #启动Nginx工作进程的用户和组
worker_processes [number | auto]; #启动Nginx工作进程的数量,一般设为和CPU核心数相同
worker_cpu_affinity 00000001 00000010 00000100 00001000 | auto ;
#将Nginx工作进程绑定到指定的CPU核心,默认Nginx是不进
行进程绑定的,绑定并不是意味着当前nginx进程独占以一
核心CPU,但是可以保证此进程不运行在其他核心上,这就
极大减少了nginx的工作进程在不同的cpu核心上的来回跳
转,减少了CPU对进程的资源分配与回收以及内存管理等因
此可以有效的提升nginx服务器的性能。
CPU MASK: 00000001:0号CPU
00000010:1号CPU
10000000:7号CPU
#示例
worker_cpu_affinity 0001 0010 0100 1000;第0号---第3号CPU
worker_cpu_affinity 0101 1010;
#示例
worker_processes 4;
worker_cpu_affinity 00000010 00001000 00100000 10000000;
[root@centos8 ~]# ps axo pid,cmd,psr | grep nginx
31093 nginx: master process /apps 1
34474 nginx: worker process 1
34475 nginx: worker process 3
34476 nginx: worker process 5
34477 nginx: worker process 7
#错误日志记录配置,语法:error_log file [debug | info | notice | warn | error | crit
| alert | emerg]
#error_log logs/error.log;
#error_log logs/error.log notice;
error_log /usr/local/nginx/logs/error.log error;
#pid文件保存路径
pid /usr/local/nginx/logs/nginx.pid;
worker_priority 0; #工作进程优先级,-20~20(19)
worker_rlimit_nofile 65536; #所有worker进程能打开的文件数量上限,
#包括:Nginx的所有连接(例如与代理服务器的连接等)
#而不仅仅是与客户端的连接
#另一个考虑因素是实际的并发连接数不能超过系统级别的最大打开
文件数的限制
#最好与ulimit -n 或者limits.conf的值保持一致,
#修改pam限制
[root@Nginx ~]# sudo -u nginx ulimit -n
1024
[root@Nginx ~]# vim /etc/security/limits.conf
* - nofile 100000
[root@Nginx ~]# sudo -u nginx ulimit -n
100000
daemon off; #前台运行Nginx服务用于测试、docker等环境。
master_process off|on; #是否开启Nginx的master-worker工作模式,仅用于开发调试场
景,默认为on
events {
worker_connections 65535; #设置单个工作进程的最大并发连接数
use epoll; #使用epoll事件驱动,
#Nginx支持众多的事件驱动,
#比如:select、poll、epoll,只能设置在events模块中
设置
accept_mutex on; #on为同一时刻一个请求轮流由work进程处理,
#而防止被同时唤醒所有worker
#避免多个睡眠进程被唤醒的设置,默认为off
#新请求会唤醒所有worker进程,此过程也称为"惊群"
#因此nginx刚安装完以后要进行适当的优化。建议设置为on
multi_accept on; #on时Nginx服务器的每个工作进程可以同时接受多个新的网络连接
#此指令默认为off,
#即默认为一个工作进程只能一次接受一个新的网络连接
#打开后几个同接受多个。建议设置为on
}
nginx全局配置参数优化
设置同时打开文件最大上限
新建一个 PC web 站点
在浏览器上访问
root 与 alias
root :指定 web 的家目录,在定义 location 的时候,文件的绝对路径等于 root+location
root 示例:
location 的详细使用
● 在一个 server 中 location 配置段可存在多个,用于实现从 uri 到文件系统的路径映射;
● ngnix会根据用户请求的 URI 来检查定义的所有 location ,按一定的优先级找出一个最佳匹配,
● 而后应用其配置在没有使用正则表达式的时候,nginx 会先在 server 中的多个 location 选取匹配度最高的一个uri
● uri是用户请求的字符串,即域名后面的 web 文件路径
● 然后使用该location 模块中的正则 url 和字符串,如果匹配成功就结束搜索,并使用此 location 处理此请求。
#语法规则:
location [ = | ~ | ~* | ^~ ] uri { ... }
= #用于标准uri前,需要请求字串与uri精确匹配,大小敏感,如果
匹配成功就停止向下匹配并立即处理请求
^~ #用于标准uri前,表示包含正则表达式,并且匹配以指定的正则
表达式开头
#对uri的最左边部分做匹配检查,不区分字符大小写
~ #用于标准uri前,表示包含正则表达式,并且区分大小写
~* #用于标准uri前,表示包含正则表达式,并且不区分大写
不带符号 #匹配起始于此uri的所有的uri
\ #用于标准uri前,表示包含正则表达式并且转义字符。可以将 .
* ?等转义为普通符号
#匹配优先级从高到低: =, ^~, ~/~*, 不带符号
Nginx 账户认证功能
[root@localhost ~]# vim /usr/local/nginx/conf.d/vhost.conf
[root@localhost ~]# nginx -s reload
nginx自定义错误页面
[root@localhost ~]# mkdir -p /data/web/errorpage
[root@localhost ~]# echo error page > /data/web/errorpage/40x.html
[root@localhost ~]# nginx -s reload
nginx-自定义日志
[root@localhost ~]# vim /usr/local/nginx/conf.d/vhost.conf
[root@localhost ~]# mkdir /var/log/PPP.org
[root@localhost ~]# nginx -s reload
nginx中的文件检测
nginx中的长链接管理
[root@localhost ~]# vim /usr/local/nginx/conf/nginx.conf
下载测试工具
[root@localhost ~]# yum install telnet -y
nginx-下载服务器的设定及优化
下载内容放置目录
[root@localhost ~]# mkdir /data/web/download
[root@localhost ~]# dd if=/dev/zero of=/data/web/download/leefile bs=1M count=100
记录了100+0 的读入
记录了100+0 的写出
104857600字节(105 MB,100 MiB)已复制,0.0550208 s,1.9 GB/s
[root@localhost ~]# vim /usr/local/nginx/conf.d/vhost.conf
Nginx****高级配置
nginx的状态页面
Nginx 压缩功能
Nginx 支持对指定类型的文件进行压缩然后再传输给客户端,而且压缩还可以设置压缩比例,压缩后的文件大小将比源文件显著变小,样有助于降低出口带宽的利用率,降低企业的IT 支出,不过会占用相应的CPU 资源。
Nginx 对文件的压缩功能是依赖于模块 ngx_http_gzip_module, 默认是内置模块
#启用或禁用gzip压缩,默认关闭
gzip on | off;
#压缩比由低到高从1到9,默认为1,值越高压缩后文件越小,但是消耗cpu比较高。基本设定未4或者5
gzip_comp_level 4;
#禁用IE6 gzip功能,早期的IE6之前的版本不支持压缩
gzip_disable "MSIE [1-6]\.";
#gzip压缩的最小文件,小于设置值的文件将不会压缩
gzip_min_length 1k;
#启用压缩功能时,协议的最小版本,默认HTTP/1.1
gzip_http_version 1.0 | 1.1;
#指定Nginx服务需要向服务器申请的缓存空间的个数和大小,平台不同,默认:32 4k或者16 8k;
gzip_buffers number size;
#指明仅对哪些类型的资源执行压缩操作;默认为gzip_types text/html,不用显示指定,否则出错
gzip_types mime-type ...;
#如果启用压缩,是否在响应报文首部插入"Vary: Accept-Encoding",一般建议打开
gzip_vary on | off;
#预压缩,即直接从磁盘找到对应文件的gz后缀的式的压缩文件返回给用户,无需消耗服务器CPU
#注意: 来自于ngx_http_gzip_static_module模块
gzip_static on | off;
nginx中的变量的使用
● nginx 的变量可以在配置文件中引用,作为功能判断或者日志等场景使用
● 变量可以分为内置变量和自定义变量
● 内置变量是由nginx 模块自带,通过变量可以获取到众多的与客户端访问相关的值。
$remote_addr;
#存放了客户端的地址,注意是客户端的公网IP
$args;
#变量中存放了URL中的所有参数
#例如:https://search.jd.com/Search?keyword=手机&enc=utf-8
#返回结果为: keyword=手机&enc=utf-8
$is_args
#如果有参数为? 否则为空
$document_root;
#保存了针对当前资源的请求的系统根目录,例如:/webdata/nginx/timinglee.org/lee。
$document_uri;
#保存了当前请求中不包含参数的URI,注意是不包含请求的指令
#比如:http://lee.timinglee.org/var?\id=11111会被定义为/var
#返回结果为:/var
$host;
#存放了请求的host名称
limit_rate 10240;
echo $limit_rate;
#如果nginx服务器使用limit_rate配置了显示网络速率,则会显示,如果没有设置, 则显示0
$remote_port;
#客户端请求Nginx服务器时随机打开的端口,这是每个客户端自己的端口
$remote_user;
#已经经过Auth Basic Module验证的用户名
$request_body_file;
#做反向代理时发给后端服务器的本地资源的名称
$request_method;
#请求资源的方式,GET/PUT/DELETE等
$request_filename;
#当前请求的资源文件的磁盘路径,由root或alias指令与URI请求生成的文件绝对路径,
#如:webdata/nginx/timinglee.org/lee/var/index.html
$request_uri;
#包含请求参数的原始URI,不包含主机名,相当于:$document_uri?$args,
#例如:/main/index.do?id=20190221&partner=search
$scheme;
#请求的协议,例如:http,https,ftp等
$server_protocol;
#保存了客户端请求资源使用的协议的版本,例如:HTTP/1.0,HTTP/1.1,HTTP/2.0等
$server_addr;
#保存了服务器的IP地址
$server_name;
#虚拟主机的主机名
$server_port;
#虚拟主机的端口号
$http_user_agent;
#客户端浏览器的详细信息
$http_cookie;
#客户端的所有cookie信息
$cookie_<name>
#name为任意请求报文首部字部cookie的key名
$http_<name>
#name为任意请求报文首部字段,表示记录请求报文的首部字段,ame的对应的首部字段名需要为小写,如果有
横线需要替换为下划线
Nginx Rewrite 相关功能
● Nginx 服务器利用 ngx_http_rewrite_module 模块解析和处理 rewrite 请求
● 此功能依靠 PCRE(perl compatible regular expression) ,因此编译之前要安装 PCRE 库
● rewrite是 nginx 服务器的重要功能之一,用于实现 URL 的重写, URL 的重写是非常有用的功能
● 比如它可以在我们改变网站结构之后,不需要客户端修改原来的书签,也无需其他网站修改我们的链接,就可以设置为访问
● 另外还可以在一定程度上提高网站的安全性。
① if****指令
用于条件匹配判断,并根据条件判断结果选择不同的 Nginx 配置,可以配置在 server 或 location 块中进行配置,Nginx 的 if 语法仅能使用 if 做单次判断,不支持使用 if else 或者 if elif 这样的多重判断
使用正则表达式对变量进行匹配,匹配成功时 if 指令认为条件为 true ,否则认为 false ,变量与表达式之间使用以下符号链接:
= #比较变量和字符串是否相等,相等时if指令认为该条件为true,反之为false
!= #比较变量和字符串是否不相等,不相等时if指令认为条件为true,反之为false
~ #区分大小写字符,可以通过正则表达式匹配,满足匹配条件为真,不满足匹配条件为假
!~ #区分大小写字符,判断是否匹配,不满足匹配条件为真,满足匹配条件为假
~* #不区分大小写字符,可以通过正则表达式匹配,满足匹配条件为真,不满足匹配条件为假
!~* #不区分大小字符,判断是否匹配,满足匹配条件为假,不满足匹配条件为真
-f 和 !-f #判断请求的文件是否存在和是否不存在
-d 和 !-d #判断请求的目录是否存在和是否不存在
-x 和 !-x #判断文件是否可执行和是否不可执行
-e 和 !-e #判断请求的文件或目录是否存在和是否不存在(包括文件,目录,软链接)
#注意:
#如果$变量的值为空字符串或0,则if指令认为该条件为false,其他条件为true。
#nginx 1.0.1之前$变量的值如果以0开头的任意字符串会返回false
② set****指令
指定key并给其定义一个变量,变量可以调用Nginx内置变量赋值给key
另外 set 定义格式为 set $key value , value 可以是 text, variables 和两者的组合。
③ break****指令
用于中断当前相同作用域 (location) 中的其他 Nginx 配置
与该指令处于同一作用域的 Nginx 配置中,位于它前面的配置生效
位于后面的 ngx_http_rewrite_module 模块中指令就不再执行
Nginx 服务器在根据配置处理请求的过程中遇到该指令的时候,回到上一层作用域继续向下读取配置
该指令可以在 server 块和 locationif 块中使用
④ return****指令
return 用于完成对请求的处理,并直接向客户端返回响应状态码,比如 : 可以指定重定向 URL( 对于特殊重定向状态码,301/302 等 ) 或者是指定提示文本内容 ( 对于特殊状态码 403/500 等 ) ,处于此指令后的所有配置都将不被执行,return 可以在 server 、 if 和 location 块进行配置
rewrite****指令
通过正则表达式的匹配来改变 URI ,可以同时存在一个或多个指令,按照顺序依次对 URI 进行匹配,rewrite主要是针对用户请求的 URL 或者是 URI 做具体处理
语法格式 : rewrite regex replacement [flag];
正则表达式格式
. #匹配除换行符以外的任意字符
\w #匹配字母或数字或下划线或汉字
\s #匹配任意的空白符
\d #匹配数字
\b #匹配单词的开始或结束
^ #匹配字付串的开始
$ #匹配字符串的结束
* #匹配重复零次或更多次
+ #匹配重复一次或更多次
? #匹配重复零次或一次
(n) #匹配重复n次
{n,} #匹配重复n次或更多次
{n,m} #匹配重复n到m次
*? #匹配重复任意次,但尽可能少重复
+? #匹配重复1次或更多次,但尽可能少重复
?? #匹配重复0次或1次,但尽可能少重复
{n,m}? #匹配重复n到m次,但尽可能少重复
{n,}? #匹配重复n次以上,但尽可能少重复
\W #匹配任意不是字母,数字,下划线,汉字的字符
\S #匹配任意不是空白符的字符
\D #匹配任意非数字的字符
\B #匹配不是单词开头或结束的位置
[^x] #匹配除了x以外的任意字符
[^lee] #匹配除了magedu 这几个字母以外的任意字符
域名永久与临时重定向
Nginx****防盗链
防盗链基于客户端携带的 referer 实现, referer 是记录打开一个页面之前记录是从哪个页面跳转过来的标记信息,如果别人只链接了自己网站图片或某个单独的资源,而不是打开了网站的整个页面,这就是盗链,referer 就是之前的那个网站域名,正常的 referer 信息有以下几种:
Nginx****反向代理功能
反向代理: reverse proxy ,指的是代理外网用户的请求到内部的指定的服务器,并将数据返回给用户的一种方式,这是用的比较多的一种方式。
Nginx 除了可以在企业提供高性能的 web 服务之外,另外还可以将 nginx 本身不具备的请求通过某种预定义的协议转发至其它服务器处理,不同的协议就是Nginx 服务器与其他服务器进行通信的一种规范,主要在不同的场景使用以下模块实现不同的功能
ngx_http_proxy_module: #将客户端的请求以http协议转发至指定服务器进行处理
ngx_http_upstream_module #用于定义为proxy_pass,fastcgi_pass,uwsgi_pass
#等指令引用的后端服务器分组
ngx_stream_proxy_module: #将客户端的请求以tcp协议转发至指定服务器处理
ngx_http_fastcgi_module: #将客户端对php的请求以fastcgi协议转发至指定服务器助理
ngx_http_uwsgi_module: #将客户端对Python的请求以uwsgi协议转发至指定服务器处理
实现http反向代理
反向代理配置参数
#两台主机下载httpd,用于测试
[root@cat-web01 ~]# yum install httpd -y
[root@cat-web02 ~]# yum install httpd -y
#关闭防火墙
[root@cat-web01 ~]# systemctl stop firewalld
[root@cat-web01 ~]# setenforce 0
[root@cat-web02 ~]# systemctl stop firewalld
[root@cat-web02 ~]# setenforce 0
[root@cat-web01 ~]#echo This is 172.16.10.10 > /var/www/html/index.html
[root@cat-web01 ~]#echo This is 172.16.10.20 > /var/www/html/index.html
[root@nginx ~]# curl 172.16.10.10
This is 172.16.10.10
[root@nginx ~]# curl 172.16.10.20
This is 172.16.10.20
反向代理示例 : 缓存功能
缓存功能默认关闭状态 , 需要先动配置才能启用
proxy_cache zone_name | off; 默认off
#指明调用的缓存,或关闭缓存机制;Context:http, server, location
#zone_name 表示缓存的名称.需要由proxy_cache_path事先定义
proxy_cache_key string;
#缓存中用于"键"的内容,默认值:proxy_cache_key $scheme$proxy_host$request_uri;
proxy_cache_valid [code ...] time;
#定义对特定响应码的响应内容的缓存时长,定义在http{...}中
proxy_cache_path;
#定义可用于proxy功能的缓存;Context:http
proxy_cache_path path [levels=levels] [use_temp_path=on|off]
keys_zone=zone_name:size [inactive=time] [max_size=size] [manager_files=number]
[manager_sleep=time] [manager_threshold=time] [loader_files=number]
[loader_sleep=time] [loader_threshold=time] [purger=on|off]
[purger_files=number] [purger_sleep=time] [purger_threshold=time];
proxy_cache_path /var/cache/nginx/proxy_cache #定义缓存保存路径,proxy_cache会自动创建
levels=1:2:2 #定义缓存目录结构层次
#1:2:2可以生成 2^4x2^8x2^8=2^20=1048576个目录
inactive=120s #缓存有效时间
max_size=10g; #最大磁盘占用空间,磁盘存入文件内容的缓存空间最大值
#调用缓存功能,需要定义在相应的配置段,如server{...};或者location等
proxy_cache proxycache;
proxy_cache_key $request_uri; #对指定的数据进行MD5的运算做为缓存的key
proxy_cache_valid 200 302 301 10m; #指定的状态码返回的数据缓存多长时间
proxy_cache_valid any 1m; #除指定的状态码返回的数据以外的缓存多长时间,必须设置,
否则不会缓存
proxy_cache_use_stale error | timeout | invalid_header | updating | http_500 |
http_502 | http_503 | http_504 | http_403 | http_404 | off ; #默认是off
#在被代理的后端服务器出现哪种情况下,可直接使用过期的缓存响应客户端
cpp
[root@cat-web01 html]# ab -n1000 -c100 http://www.qwert.org/static/index.htmlThis is ApacheBench, Version 2.3 <$Revision: 1903618 $>
Copyright 1996 Adam Twiss, Zeus Technology Ltd, http://www.zeustech.net/
Licensed to The Apache Software Foundation, http://www.apache.org/
Benchmarking www.qwert.org (be patient)
Server Software: nginx/1.26.2
Server Hostname: www.qwert.org
Server Port: 80
Document Path: /static/index.html
Document Length: 21 bytes
Concurrency Level: 100
Time taken for tests: 0.070 seconds
Complete requests: 1000
Failed requests: 0
Total transferred: 272000 bytes
HTML transferred: 21000 bytes
Requests per second: 14302.88 [#/sec] (mean)
Time per request: 6.992 [ms] (mean)
Time per request: 0.070 [ms] (mean, across all concurrent requests)
Transfer rate: 3799.20 [Kbytes/sec] received
nginx的反向代理负载均衡
Nginx 可以将客户端的请求转发至单台后端服务器但是无法转发至特定的一组的服务器,而
且不能对后端服务器提供相应的服务器状态监测, Nginx 可以基于 ngx_http_upstream_module 模块提供服务器分组转发、权重分配、状态监测、调度算法等高级功能
PHP码源编译
限添加两个模块
./configure --prefix=/usr/local/nginx \
> --add-module=/root/echo-nginx-module-0.63 \
> --add-module=/root/memc-nginx-module-0.20 \
> --add-module=/root/srcache-nginx-module-0.33 \
> --user=nginx \
> --group=nginx \
> --with-http_v2_module \
> --with-http_realip_module \
> --with-http_stub_status_module \
> --with-http_gzip_static_module \
> --with-stream \
> --with-stream_ssl_module \
> --with-stream_realip_module \
> --with-pcre
make && make install
然后解压php包
进入php-8.3.9目录
[root@localhost php-8.3.9]# ./configure --prefix=/usr/local/php \
> --enable-fpm \
> --with-fpm-user=nginx \
> --with-fpm-group=nginx \
> --with-curl \
> --with-iconv \
> --with-mhash \
> --with-zlib \
> --with-openssl \
> --enable-mysqlnd \
> --with-mysqli \
> --with-pdo-mysql \
> --disable-debug \
> --enable-sockets \
> --enable-soap \
> --enable-xml \
> --enable-ftp \
> --enable-gd \
> --enable-exif \
> --enable-mbstring \
> --enable-bcmath \
> --with-fpm-systemd
[root@localhost php-8.3.9]# yum install systemd-devel -y
[root@localhost php-8.3.9]# dnf whatprovides */libxml-2.0*
[root@localhost php-8.3.9]# dnf install sqlite-devel.x86_64 -y
[root@localhost php-8.3.9]# dnf install libcurl-devel-7.76.1-14.el9.x86_64 -y
[root@localhost etc]# cp -p php-fpm.conf.default php-fpm.conf
[root@localhost etc]# vim php-fpm.conf