Nginx-企业高性能web服务器

目录

一.Web 服务基础介绍

​编辑1.1 Web 服务介绍

1.1.1 Apache prefork 模型

1.1.2 Apache worker 模型

1.1.3 Apache event模型

1.2 Nginx-高性能的 Web 服务端

1.2.1 基于Nginx的工作场景:

1.2.2 服务端 I/O 流程

1.2.2.1 磁盘 I/O

1.2.2.2 网络 I/O

1.3 I/O 模型

1.3.1 I/O 模型相关概念

1.3.2 网络 I/O 模型 

1.3.2.1 阻塞型 I/O 模型(blocking IO)

1.3.2.2 非阻塞型 I/O 模型 (nonblocking IO)

1.3.2.3 多路复用 I/O 型(I/O multiplexing)

1.3.2.4 信号驱动式 I/O 模型 (signal-driven IO)

1.3.2.5 异步 I/O 模型 (asynchronous IO)

1.3.3 五种 IO 对比

1.3.4 I/O 的具体实现方式

1.3.4.1 I/O常见实现

1.3.4.2 常用I/O模型比较 

1.4 零拷贝

1.4.1 零拷贝介绍

1.4.1.1 传统 Linux中 I/O 的问题

1.4.1.2 什么是零拷贝

1.4.2 零拷页相关技术

1.4.2.1 MMAP ( Memory Mapping )

1.4.2.2 SENDFILE

1.4.2.3 DMA 辅助的 SENDFILE 

二.Nginx 架构和安装

2.1 Nginx 概述

2.1.1 Nginx 介绍

2.1.2 Nginx 功能介绍

2.1.3 基础特性

2.1.4 Web 服务相关的功能

2.2 Nginx 架构和进程

2.2.2 Nginx 进程结构

​编辑

 2.2.3 Nginx 进程间通信

 2.2.4 Nginx 启动和 HTTP 连接建立

2.2.5 HTTP 处理过程

2.3 Nginx 模块介绍

2.4 Nginx 安装

2.4.1 Nginx版本和安装方式

2.4.2.Nginx 编译安装

2.4.2.1 编译安装 Nginx

2.4.2.2 验证版本及编译参数

2.4.2.3使用安装完成的二进制文件nginx

2.4.2.2 Nginx启动文件

2.5 平滑升级和回滚

2.5.1 平滑升级流程

2.5.2 平滑升级和回滚

三、Nginx 核心配置

3.1 配置文件说明

3.2 全局核心配置参数优化

1、查看最大工作进程数

2、绑定cpu核心

3、查看并更改并发数 可以实现高并发

4、使用epoll模型:

5、将不同功能或不同站点的配置分离到多个小的配置文件中,便于管理和维护

6、创建nginx发布目录并用浏览器访问

3.3 root 与 alias

3.4 location 的详细使用

3.5 Nginx 账户认证功能

3.6 自定义错误页面

3.7 自定义错误日志

3.8 检测文件是否存在

3.9 长连接

3.10 作为下载服务器配置

四、Nginx高级配置

4.1 Nginx 状态页

4.2 Nginx 压缩功能

4.3 Nginx的版本隐藏

4.4 Nginx 变量使用

4.4.1 内置变量

4.4.2 自定义变量

五 Nginx Rewrite 相关功能

5.1 模块指令

5.1.1 if 指令

5.1.2 set 指令

5.1.3 break 指令

5.1.4 return 指令

5.2 rewrite 指令

5.2.1 rewrite flag 使用介绍

5.2.2 域名永久与临时重定向

5.2.2.1 永久重定向301

5.2.2.2 临时重定向302

5.2.3 rewrite 案例: break 与 last

5.2.4 全站加密-自动跳转 https

5.3 Nginx 防盗链

5.3.1 实现盗链

5.3.2 实现防盗链

六 Nginx 反向代理功能

6.1 反向代理

6.1.1 动静分离实现

6.1.2 缓存功能

6.2 反向代理负载均衡

6.2.1 七层反向代理负载均衡

6.2.2 Nginx四层负载均衡

6.2.2.1 MySQL

6.2.2.2 udp 负载均衡实例: DNS

6.3 实现 FastCGI

6.3.1 FastCGI配置指令

6.3.2 源码编译php

6.3.3 php相关配置优化

6.3.4 nginx和php的整合

6.3.5 nginx-memcache高速缓存

7 nginx 二次开发版本

7.1 openresty

7.2 编译安装 openresty


一.Web 服务基础介绍

正常情况下的单次web服务访问流程:

1.1 Web 服务介绍

1.1.1 Apache prefork 模型

  • 预派生模式,有一个主控制进程,然后生成多个子进程,使用select模型,最大并发1024
  • 每个子进程有一个独立的线程响应用户请求
  • 相对比较占用内存,但是比较稳定,可以设置最大和最小进程数
  • 是最古老的一种模式,也是最稳定的模式,适用于访问量不是很大的场景

优点:稳定

缺点:每个用户请求需要对应开启一个进程,占用资源较多,并发性差,不适用于高并发场景

1.1.2 Apache worker 模型

  • 一种多进程和多线程混合的模型
  • 有一个控制进程,启动多个子进程
  • 每个子进程里面包含固定的线程
  • 使用线程程来处理请求
  • 当线程不够使用的时候会再启动一个新的子进程,然后在进程里面再启动线程处理请求,
  • 由于其使用了线程处理请求,因此可以承受更高的并发

优点:相比prefork 占用的内存较少,可以同时处理更多的请求

缺点:使用keepalive的长连接方式,某个线程会一直被占据,即使没有传输数据,也需要一直等待到超 时才会被释放。如果过多的线程,被这样占据,也会导致在高并发场景下的无服务线程可用(该问题在 prefork模式下,同样会发生)

1.1.3 Apache event模型

  • Apache中最新的模式,2012年发布的apache 2.4.X系列正式支持event 模型,属于事件驱动模型(epoll)
  • 每个进程响应多个请求,在现在版本里的已经是稳定可用的模式
  • 它和worker模式很像,最大的区别在于,它解决了keepalive场景下长期被占用的线程的资源浪费问题 (某些线程因为被keepalive,空挂在哪里等待,中间几乎没有请求过来,甚至等到超时)
  • event MPM中,会有一个专门的线程来管理这些keepalive类型的线程
  • 当有真实请求过来的时候,将请求传递给服务线程,执行完毕后,又允许它释放。这样增强了高并发场 景下的请求处理能力

优点:单线程响应多请求,占据更少的内存,高并发下表现更优秀,会有一个专门的线程来管理keepalive类型的线程,当有真实请求过来的时候,将请求传递给服务线程,执行完毕后,又允许它释放

缺点:没有线程安全控制

1.2 Nginx-高性能的 Web 服务端

Nginx是由1994年毕业于俄罗斯国立莫斯科鲍曼科技大学的同学为俄罗斯rambler.ru公司开发的,开发 工作最早从2002年开始,第一次公开发布时间是2004年10月4日,版本号是0.1.0

2019年3月11日F5 与 NGINX达成协议,F5 将收购 NGINX 的所有已发行股票,总价值约为 6.7 亿美元。 6.7亿美金约合44.97亿人民币,nginx核心模块代码长度198430(包括空格、注释),所以一行代码约为 2.2万人民币

官网地址 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或者进行二次开发

1.2.1 基于Nginx的工作场景:

为什么选择Nginx

Nginx是一款自由的、开源的、高性能的HTTP服务器和反向代理服务器;同时也是一个IMAP、POP3、SMTP代理服务器;Nginx可以作为一个HTTP服务器进行网站的发布处理,另外Nginx可以作为反向代理进行负载均衡的实现。在Nginx网站上,其功能包括:

  • HTTP和HTTPS(TLS / SSL / SNI)
  • 超快速的Web服务器用于静态内容
  • FastCGI,WSGI,SCGI用于动态内容
  • 具有负载平衡和缓存功能的加速Web代理
  • 不间断实时二进制升级和配置
  • 压缩和内容过滤器
  • 虚拟主机
  • FLV和MP4的媒体流
  • 带宽和连接策略
  • 全面的访问控制
  • 自定义日志
  • 嵌入式脚本
  • 带有TLS的SMTP / IMAP / POP3的邮件代理
  • 逻辑,灵活,可扩展的配置
  • 在Linux,FreeBSD,Mac OS X,Solaris和Windows上运行

Nginx有如下优势

  1. IO多路复用 epoll(IO复用)
  2. 轻量级
  3. CPU亲和

1.2.2 服务端 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文件的读写
1.2.2.1 磁盘 I/O

磁盘I/O是进程向内核发起系统调用,请求磁盘上的某个资源比如是html 文件或者图片,然后内核通过相 应的驱动程序将目标文件加载到内核的内存空间,加载完成之后把数据从内核内存再复制给进程内存, 如果是比较大的数据也需要等待时间

机械磁盘的寻道时间、旋转延迟和数据传输时间: 寻道时间:是指磁头移动到正确的磁道上所花费的时间,寻道时间越短则I/O处理就越快,目前磁盘的寻道时 间一般在3-15毫秒左右。

旋转延迟:是指将磁盘片旋转到数据所在的扇区到磁头下面所花费的时间,旋转延迟取决于磁盘的转速,通常 使用磁盘旋转一周所需要时间的1/2之一表示,比如7200转的磁盘平均训传延迟大约为 60*1000/7200/2=4.17毫秒,公式的意思为 (每分钟60秒*1000毫秒每秒/7200转每分/2),如果是 15000转的则为60*1000/15000/2=2毫秒。

数据传输时间:指的是读取到数据后传输数据的时间,主要取决于传输速率,这个值等于数据大小除以传输速 率,目前的磁盘接口每秒的传输速度可以达到600MB,因此可以忽略不计。

常见的机械磁盘平均寻道时间值:

7200转/分的磁盘平均物理寻道时间:9毫秒

10000转/分的磁盘平均物理寻道时间:6毫秒

15000转/分的磁盘平均物理寻道时间:4毫秒

常见磁盘的平均延迟时间:

7200转的机械盘平均延迟:60*1000/7200/2 = 4.17ms

10000转的机械盘平均延迟:60*1000/10000/2 = 3ms

15000转的机械盘平均延迟:60*1000/15000/2 = 2ms

每秒最大IOPS的计算方法:

7200转的磁盘IOPS计算方式:1000毫秒/(9毫秒的寻道时间+4.17毫秒的平均旋转延迟时 间)=1000/13.13=75.9 IOPS

10000转的磁盘的IOPS计算方式:1000毫秒/(6毫秒的寻道时间+3毫秒的平均旋转延迟时 间)=1000/9=111IOPS 15000转的磁盘的IOPS计算方式:

15000毫秒/(4毫秒的寻道时间+2毫秒的平均旋转延迟时 间)=1000/6=166.6 IOPS

1.2.2.2 网络 I/O

网络通信就是网络协议栈到用户空间进程的IO就是网络IO

网络I/O 处理过程

  • 获取请求数据,客户端与服务器建立连接发出请求,服务器接受请求(1-3)
  • 构建响应,当服务器接收完请求,并在用户空间处理客户端的请求,直到构建响应完成(4)
  • 返回数据,服务器将已构建好的响应再通过内核空间的网络 I/O 发还给客户端(5-7)

不论磁盘和网络I/O

每次I/O,都要经由两个阶段:

  1. 第一步:将数据从文件先加载至内核内存空间(缓冲区),等待数据准备完成,时间较长
  2. 第二步:将数据从内核缓冲区复制到用户空间的进程的内存中,时间较短

1.3 I/O 模型

1.3.1 I/O 模型相关概念

同步/异步:关注的是消息通信机制,即调用者在等待一件事情的处理结果时,被调用者是否提供完成状态的通知。

  • 同步:synchronous,被调用者并不提供事件的处理结果相关的通知消息,需要调用者主动询问事 情是否处理完成
  • 异步:asynchronous,被调用者通过状态、通知或回调机制主动通知调用者被调用者的运行状态

阻塞/非阻塞:关注调用者在等待结果返回之前所处的状态

  • 阻塞:blocking,指IO操作需要彻底完成后才返回到用户空间,调用结果返回之前,调用者被挂起,干不了别的事情。
  • 非阻塞:nonblocking,指IO操作被调用后立即返回给用户一个状态值,而无需等到IO操作彻底完 成,在最终的调用结果返回之前,调用者不会被挂起,可以去做别的事情。

1.3.2 网络 I/O 模型 

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

1.3.2.1 阻塞型 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是否完成,这种 方式简单,但是比较慢,用的比较少。

1.3.2.2 非阻塞型 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时间,实 际使用很少

1.3.2.3 多路复用 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复用

1.3.2.4 信号驱动式 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完成后内核再通知进程。

1.3.2.5 异步 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 复用模型模式+多线程任务的架构基本可以满足需求

inux提供了AIO库函数实现异步,但是用的很少。目前有很多开源的异步IO库,例如libevent、libev、 libuv。

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

1.3.3 五种 IO 对比

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

1.3.4 I/O 的具体实现方式

1.3.4.1 I/O常见实现

Nginx支持在多种不同的操作系统实现不同的事件驱动模型,但是其在不同的操作系统甚至是不同的系统 版本上面的实现方式不尽相同,主要有以下实现方式:

1、select:

select库是在linux和windows平台都基本支持的 事件驱动模型库,并且在接口的定义也基本相同,只是 部分参数的含义略有差异,最大并发限制1024,是最早期的事件驱动模型。

2、poll:

在Linux 的基本驱动模型,windows不支持此驱动模型,是select的升级版,取消了最大的并发限制,在 编译nginx的时候可以使用--with-poll_module和--without-poll_module这两个指定是否编译select库。

3、epoll:

epoll是库是Nginx服务器支持的最高性能的事件驱动库之一,是公认的非常优秀的事件驱动模型,它和 select和poll有很大的区别,epoll是poll的升级版,但是与poll有很大的区别.epoll的处理方式是创建一个 待处理的事件列表,然后把这个列表发给内核,返回的时候在去轮询检查这个表,以判断事件是否发 生,epoll支持一个进程打开的最大事件描述符的上限是系统可以打开的文件的最大数,同时epoll库的 I/O效率不随描述符数目增加而线性下降,因为它只会对内核上报的“活跃”的描述符进行操作。

4、kqueue:

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

5、Iocp:

Windows系统上的实现方式,对应第5种(异步I/O)模型。

6、rtsig:

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

7、/dev/poll:

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

8、eventport:

该方案也是sun公司在开发Solaris的时候提出的事件驱动库,只是Solaris 10以上的版本,该驱动库看防 止内核崩溃等情况的发生。

1.3.4.2 常用I/O模型比较 
                        select                       pollepoll
操作方式遍历遍历回调
底层实现数组链表哈希表
IO效率每次调用都进行线性遍历,时间复杂度为O(n)同左事件通知方式,每当fd就绪,系统注册的回调函数就会被调用,将就绪的fd放到rdlist里,时间复杂度为O(1)
最大连接数

1024(x86)

2048(x64)

无上限无上限
fd拷贝每次调用select都需要把fd集合从用户拷贝到内核态每次调用poll都需要把fd集合从用户拷贝到内核态调用epoll_ctl时拷贝进内核并保存,之后每次epoll_wait不拷贝

Select: POSIX所规定,目前几乎在所有的平台上支持,其良好跨平台支持也是它的一个优点,本质上是通过设置 或者检查存放fd标志位的数据结构来进行下一步处理

缺点

单个进程能够监视的文件描述符的数量存在最大限制,在Linux上一般为1024,可以通过修改宏定 FD_SETSIZE,再重新编译内核实现,但是这样也会造成效率的降低单个进程可监视的fd数量被限制,默 认是1024,修改此值需要重新编译内核对socket是线性扫描,即采用轮询的方法,效率较低select 采取 了内存拷贝方法来实现内核将 FD 消息通知给用户空间,这样一个用来存放大量fd的数据结构,这样会使 得用户空间和内核空间在传递该结构时复制开销大

poll:

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

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减少复制开销

总结:

  1. epoll只是一组API,比起select这种扫描全部的文件描述符,epoll只读取就绪的文件描述符,再加入 基于事件的就绪通知机制,所以性能比较好
  2.  基于epoll的事件多路复用减少了进程间切换的次数,使得操作系统少做了相对于用户任务来说的无用 功。
  3. epoll比select等多路复用方式来说,减少了遍历循环及内存拷贝的工作量,因为活跃连接只占总并发 连接的很小一部分。

1.4 零拷贝

1.4.1 零拷贝介绍

1.4.1.1 传统 Linux中 I/O 的问题

传统的 Linux 系统的标准 I/O 接口(read、write)是基于数据拷贝的,也就是数据都是 copy_to_user 或者 copy_from_user,这样做的好处是,通过中间缓存的机制,减少磁盘 I/O 的操作,但是坏处也很明 显,大量数据的拷贝,用户态和内核态的频繁切换,会消耗大量的 CPU 资源,严重影响数据传输的性 能,统计表明,在Linux协议栈中,数据包在内核态和用户态之间的拷贝所用的时间甚至占到了数据包整 个处理流程时间的57.1% 

1.4.1.2 什么是零拷贝

零拷贝就是上述问题的一个解决方案,通过尽量避免拷贝操作来缓解 CPU 的压力。零拷贝并没有真正做 到“0”拷贝,它更多是一种思想,很多的零拷贝技术都是基于这个思想去做的优化

1.4.2 零拷页相关技术

1.4.2.1 MMAP ( Memory Mapping )

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

mmap是一种内存映射文件的方法,即将一个文件或者其它对象映射到进程的地址空间,实现文件磁盘 地址和进程虚拟地址空间中一段虚拟地址的一一对映关系。

实现这样的映射关系后,进程就可以采用指针的方式读写操作这一段内存,而系统会自动回写脏页面到 对应的文件磁盘上,即完成了对文件的操作而不必再调用read,write等系统调用函数。相反,内核空间对 这段区域的修改也直接反映用户空间,从而可以实现不同进程间的文件共享。

内存映射减少数据在用户空间和内核空间之间的拷贝操作,适合大量数据传输

上面左图为传统读写,右图为MMAP.两者相比mmap要比普通的read系统调用少了一次copy的过程。因为 read调用,进程是无法直接访问kernel space的,所以在read系统调用返回前,内核需要将数据从内核 复制到进程指定的buffer。但mmap之后,进程可以直接访问mmap的数据(page cache)。

1.4.2.2 SENDFILE

1.4.2.3 DMA 辅助的 SENDFILE 


二.Nginx 架构和安装

2.1 Nginx 概述

2.1.1 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/

2.1.2 Nginx 功能介绍

  • 静态的web资源服务器html,图片,js,css,txt等静态资源
  • http/https协议的反向代理
  • 结合FastCGI/uWSGI/SCGI等协议反向代理动态资源请求
  • tcp/udp协议的请求转发(反向代理)
  • imap4/pop3协议的反向代理

2.1.3 基础特性

  • 模块化设计,较好的扩展性
  • 高可靠性
  • 支持热部署:不停机更新配置文件,升级版本,更换日志文件
  • 低内存消耗:10000个keep-alive连接模式下的非活动连接,仅需2.5M内存
  • event-driven,aio,mmap,sendfile

2.1.4 Web 服务相关的功能

  • 虚拟主机(server)
  • 支持 keep-alive 和管道连接(利用一个连接做多次请求)
  • 访问日志(支持基于日志缓冲提高其性能)
  • url rewirte
  • 路径别名
  • 基于IP及用户的访问控制
  • 支持速率限制及并发数限制
  • 重新配置和在线升级而无须中断客户的工作进程

2.2 Nginx 架构和进程

2.2.2 Nginx 进程结构

web请求处理机制

  • 多进程方式:服务器每接收到一个客户端请求就有服务器的主进程生成一个子进程响应客户端,直 到用户关闭连接,这样的优势是处理速度快,子进程之间相互独立,但是如果访问过大会导致服务 器资源耗尽而无法提供请求
  • 多线程方式:与多进程方式类似,但是每收到一个客户端请求会有服务进程派生出一个线程和此客 户端进行交互,一个线程的开销远远小于一个进程,因此多线程方式在很大程度减轻了web服务器 对系统资源的要求,但是多线程也有自己的缺点,即当多个线程位于同一个进程内工作的时候,可 以相互访问同样的内存地址空间,所以他们相互影响,一旦主进程挂掉则所有子线程都不能工作 了,IIS服务器使用了多线程的方式,需要间隔一段时间就重启一次才能稳定。

Nginx是多进程组织模型,而且是一个由Master主进程和Worker工作进程组成。

主进程(master process)的功能:

  • 对外接口:接收外部的操作(信号)
  • 对内转发:根据外部的操作的不同,通过信号管理 Worker
  • 监控:监控 worker 进程的运行状态,worker 进程异常终止后,自动重启 worker 进程
  • 读取Nginx 配置文件并验证其有效性和正确性
  • 建立、绑定和关闭socket连接
  • 按照配置生成、管理和结束工作进程
  • 接受外界指令,比如重启、升级及退出服务器等指令
  • 不中断服务,实现平滑升级,重启服务并应用新的配置
  • 开启日志文件,获取文件描述符
  • 不中断服务,实现平滑升级,升级失败进行回滚处理
  • 编译和处理perl脚本

工作进程(worker process)的功能:

  • 所有 Worker 进程都是平等的
  • 实际处理:网络请求,由 Worker 进程处理
  • Worker进程数量:一般设置为核心数,充分利用CPU资源,同时避免进程数量过多,导致进程竞争
  • CPU资源,
  • 增加上下文切换的损耗
  • 接受处理客户的请求
  • 将请求依次送入各个功能模块进行处理
  • I/O调用,获取响应数据
  • 与后端服务器通信,接收后端服务器的处理结果
  • 缓存数据,访问缓存索引,查询和调用缓存数据
  • 发送请求结果,响应客户的请求
  • 接收主程序指令,比如重启、升级和退出等

 2.2.3 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等。操作系统提供了共享内存机制

 2.2.4 Nginx 启动和 HTTP 连接建立

  • Nginx 启动时,Master 进程,加载配置文件
  • Master 进程,初始化监听的 socket
  • Master 进程,fork 出多个 Worker 进程
  • Worker 进程,竞争新的连接,获胜方通过三次握手,建立 Socket 连接,并处理请求

2.2.5 HTTP 处理过程

2.3 Nginx 模块介绍

nginx 有多种模块

  • 核心模块:是 Nginx 服务器正常运行必不可少的模块,提供错误日志记录 、配置文件解析 、事件
  • 驱动机制 、进程管理等核心功能
  • 标准HTTP模块:提供 HTTP 协议解析相关的功能,比如: 端口配置 、 网页编码设置 、 HTTP响应头设置 等等
  • 可选HTTP模块:主要用于扩展标准的 HTTP 功能,让 Nginx 能处理一些特殊的服务,比如: Flash 
  • 多媒体传输 、解析 GeoIP 请求、 网络传输压缩 、 安全协议 SSL 支持等
  • 邮件服务模块:主要用于支持 Nginx 的 邮件服务 ,包括对 POP3 协议、 IMAP 协议和 SMTP协议的支持
  • Stream服务模块: 实现反向代理功能,包括TCP协议代理
  • 第三方模块:是为了扩展 Nginx 服务器应用,完成开发者自定义功能,比如: Json 支持、 Lua 支持等

nginx高度模块化,但其模块早期不支持DSO机制;1.9.11 版本支持动态装载和卸载

模块分类:

核心模块:core module
标准模块:
         HTTP 模块: ngx_http_*
         HTTP Core modules               #默认功能
         HTTP Optional modules         #需编译时指定
Mail 模块: ngx_mail_*
Stream 模块 ngx_stream_*
第三方模块

2.4 Nginx 安装

2.4.1 Nginx版本和安装方式

Nginx版本

  • Mainline version 主要开发版本,一般为奇数版本号,比如1.19
  • Stable version 当前最新稳定版,一般为偶数版本,如:1.20
  • Legacy versions 旧的稳定版,一般为偶数版本,如:1.18

Nginx安装可以使用yum或源码安装,但是推荐使用源码编译安装

  • yum的版本比较旧
  • 编译安装可以更方便自定义相关路径
  • 使用源码编译可以自定义相关功能,更方便业务的上的使用

2.4.2.Nginx 编译安装

编译器介绍

源码安装需要提前准备标准的编译器,GCC的全称是(GNU Compiler collection),其有GNU开发,并以 GPL即LGPL许可,是自由的类UNIX即苹果电脑Mac OS X操作系统的标准编译器,因为GCC原本只能处理C语 言,所以原名为GNU C语言编译器,后来得到快速发展,可以处理C++,Fortran,pascal,objective C, java以及Ada等其他语言,此外还需要Automake工具,以完成自动创建Makefile的工作,Nginx的一些模块 需要依赖第三方库,比如: pcre(支持rewrite),zlib(支持gzip模块)和openssl(支持ssl模块) 等。

2.4.2.1 编译安装 Nginx

官方源码包下载地址:

https://nginx.org/en/download.html

编译安装示例:

[root@nginx ~]# dnf install gcc pcre-devel zlib-devel openssl-devel -y
[root@nginx ~]# useradd -s /sbin/nologin -M nginx

[root@nginx ~]# tar zxf nginx-1.24.0.tar.gz
[root@nginx ~]# ls
anaconda-ks.cfg  nginx-1.24.0.tar.gz  nginx-1.24.0
Public           Desktop              nginx-1.26.1         Templates
Documents        Music                Videos               Downloads                       Pictures

=================================================================

# 编译安装
--prefix=/usr/local/nginx 指定了 Nginx 将被安装到 /usr/local/nginx 目录下。
执行完这个命令后,通常会生成一些配置文件和 Makefile,然后可以使用 make 命令进行编译,最后使用 make install 命令进行安装

[root@nginx nginx-1.24.0]# ./configure --prefix=/usr/local/nginx \
--user=nginx \                         # 指定nginx运行用户
--group=nginx \                        # 指定nginx运行组
--with-http_ssl_module \               # 支持https://
--with-http_v2_module \                # 支持http版本2
--with-http_realip_module \            # 支持ip透传
--with-http_stub_status_module \       # 支持状态页面 
--with-http_gzip_static_module \       # 支持压缩 
--with-pcre \                          # 支持正则
--with-stream \                        # 支持tcp反向代理
--with-stream_ssl_module \             # 支持tcp的ssl加密
--with-stream_realip_module            # 支持tcp的透传ip

[root@nginx nginx-1.24.0]# make && make install

#nginx完成安装以后,有四个主要的目录

[root@Nginx nginx-1.24.0]# ls /usr/local/nginx/

conf        html        logs        sbin

conf:保存nginx所有的配置文件,其中nginx.conf是nginx服务器的最核心最主要的配置文件,其他的.conf则是用来配置nginx相关的功能的,例如fastcgi功能使用的是fastcgi.conf和fastcgi_params两个文件,配置文件一般都有一个样板配置文件,是以.default为后缀,使用时可将其复制并将default后缀去掉即可。

html:目录中保存了nginx服务器的web文件,但是可以更改为其他目录保存web文件,另外还有一个50x的web文件是默认的错误页面提示页面。

logs:用来保存nginx服务器的访问日志错误日志等日志,logs目录可以放在其他路径,比
如/var/logs/nginx里面。

sbin:保存nginx二进制启动脚本,可以接受不同的参数以实现不同的功能。

2.4.2.2 验证版本及编译参数
#添加到系统的 PATH 环境变量中 
[root@nginx ~]# vim ~/.bash_profile
export PATH=$PATH:/usr/local/nginx/sbin

#配置立即生效
[root@nginx ~]# source ~/.bash_profile

#关闭debug功能
[root@nginx nginx-1.26.1]# vim auto/cc/gcc 
...
171 # debug
172 #CFLAGS="$CFLAGS -g"
...

Note:这样做的好处是,在终端中执行命令时,可以直接使用 /usr/local/nginx/sbin 目录下的可执行文件,而不需要输入完整的路径

2.4.2.3使用安装完成的二进制文件nginx
[root@nginx ~]# nginx -help
nginx version: nginx/1.24.0
Usage: nginx [-?hvVtTq] [-s signal] [-p prefix]
             [-e filename] [-c filename] [-g directives]

Options:
  -?,-h         : this help
  -v            : show version and exit        #查看版本
  -V            : show version and configure options then exit
                                               #显示版本和编译参数
  -t            : test configuration and exit
                                               #测试配置文件是否异常   
  -T            : test configuration, dump it and exit
                                               #测试并打印
  -q            : suppress non-error messages during configuration testing
                                               #静默模式      
  -s signal     : send signal to a master process: stop, quit, reopen, reload
                                               #发送信号,reload信号
  -p prefix     : set prefix path (default: /usr/local/nginx/)
                                               #指定nginx目录
  -e filename   : set error log file (default: logs/error.log)
                                               #指定错误日志
  -c filename   : set configuration file (default: conf/nginx.conf)
                                               #配置文件路径
  -g directives : set global directives out of configuration file
                                   #设置全局指令,注意和配置文件不要同时配置,否则冲突

可以自己创建一个nginx配置文件夹 如:

[root@nginx ~]# mkdir /usr/local/nginx/conf.d/ -p

但是要使它生效 就需要在主配置文件添加子配置文件路径

[root@nginx ~]# vim /usr/local/nginx/conf/nginx.conf

简单来说就是如果要使自定义文件夹conf.d启用的话 就要加上这句话

其他命令:

#前台运行
[root@nginx ~]# nginx -g "daemon off;"

#优雅地停止 Nginx 服务器,它会处理完当前的连接请求后再停止服务器
[root@nginx ~]# nginx -s quit
[root@nginx ~]# ps aux | grep nginx
avahi        853  0.0  0.1  15932  6656 ?        Ss   18:20   0:00 avahi-daemon: running [nginx.local]
root        1791  0.0  0.0 221796  2176 pts/0    S+   18:59   0:00 grep --color=auto nginx
2.4.2.2 Nginx启动文件
[root@nginx ~]# vim /lib/systemd/system/nginx.service 
[root@nginx ~]# cat /lib/systemd/system/nginx.service 
[Unit]
Description=The NGINX HTTP and reverse proxy server
After=syslog.target network-online.target remote-fs.target nss-lookup.target
Wants=network-online.target

[Service]
Type=forking
PIDFile=/usr/local/nginx/logs/nginx.pid
ExecStartPre=/usr/local/nginx/sbin/nginx -t
ExecStart=/usr/local/nginx/sbin/nginx
ExecReload=/usr/local/nginx/sbin/nginx -s reload
ExecStop=/bin/kill -s QUIT $MAINPID
PrivateTmp=true

[Install]
WantedBy=multi-user.target

=================================================================
#重新加载系统的守护进程配置
[root@nginx ~]# systemctl daemon-reload 

[root@nginx ~]# systemctl start nginx


2.5 平滑升级和回滚

有时候我们需要对Nginx版本进行升级以满足对其功能的需求,例如添加新模块,需要新功能,而此时 Nginx又在跑着业务无法停掉,这时我们就可能选择平滑升级

2.5.1 平滑升级流程

  • 将旧Nginx二进制文件换成新Nginx程序文件(注意先备份)
  • 向master进程发送USR2信号
  • master进程修改pid文件名加上后缀.oldbin,成为nginx.pid.oldbin
  • master进程用新Nginx文件启动新master进程成为旧master的子进程,系统中将有新旧两个Nginx主进程共同提供Web服务,当前新的请求仍然由旧Nginx的worker进程进行处理,将新生成的master进程的PID存放至新生成的pid文件nginx.pid
  • 向旧的Nginx服务进程发送WINCH信号,使旧的Nginx worker进程平滑停止
  • 向旧master进程发送QUIT信号,关闭老master,并删除Nginx.pid.oldbin文件
  • 如果发现升级有问题,可以回滚∶向老master发送HUP,向新master发送QUIT

2.5.2 平滑升级和回滚

停止nginx进程 

平滑升级

1、解压压缩包 编译新版本

[root@nginx ~]# tar zxf nginx-1.26.1.tar.gz 
[root@nginx ~]# tar zxf echo-nginx-module-0.63.tar.gz
[root@nginx ~]# cd nginx-1.26.1/

#编译新版本
[root@nginx nginx-1.26.1]# ./configure --prefix=/usr/local/nginx \
--user=nginx \
--group=nginx \
--add-module=/root/echo-nginx-module-0.63 \        #添加echo模块
--with-http_ssl_module \
--with-http_v2_module \
--with-http_realip_module \
--with-http_stub_status_module \
--with-http_gzip_static_module \
--with-pcre --with-stream \
--with-stream_ssl_module \
--with-stream_realip_module 

=============================================================================

#直接复制粘贴
./configure --prefix=/usr/local/nginx --user=nginx --group=nginx --add-module=/root/echo-nginx-module-0.63 --with-http_ssl_module --with-http_v2_module --with-http_realip_module --with-http_stub_status_module --with-http_gzip_static_module --with-pcre --with-stream --with-stream_ssl_module --with-stream_realip_module 
     

2、因为有旧版本 只需make 不需要make install

[root@nginx nginx-1.26.1]# make

3、查看两个版本 并把旧版备份

#查看两个版本
[root@nginx nginx-1.26.1]# ll objs/nginx /usr/local//nginx/sbin/nginx
-rwxr-xr-x 1 root root 6170600 Aug 15 16:22 objs/nginx
-rwxr-xr-x 1 root root 6090120 Aug 18 19:07 /usr/local//nginx/sbin/nginx

#把之前的旧版nginx命令备份
[root@nginx nginx-1.26.1]# cd /usr/local/nginx/sbin/
[root@nginx sbin]# cp nginx nginx.24

#把新版本的nginx命令复制过去
[root@nginx sbin]# \cp -f /root/nginx-1.26.1/objs/nginx /usr/local/nginx/sbin

[root@nginx sbin]# ls
nginx  nginx.24            #此刻nginx为新版


#检测是否有问题
[root@nginx sbin]# nginx -t
nginx: the configuration file /usr/local/nginx/conf/nginx.conf syntax is ok
nginx: configuration file /usr/local/nginx/conf/nginx.conf test is successful

4、启动新的nginx

[root@nginx sbin]# nginx        #启动
nginx: [emerg] bind() to 0.0.0.0:80 failed (98: Address already in use)
nginx: [emerg] bind() to 0.0.0.0:80 failed (98: Address already in use)
nginx: [emerg] bind() to 0.0.0.0:80 failed (98: Address already in use)
nginx: [emerg] bind() to 0.0.0.0:80 failed (98: Address already in use)
nginx: [emerg] bind() to 0.0.0.0:80 failed (98: Address already in use)

#先查看nginx进程
[root@nginx sbin]# ps aux | grep nginx
root        8387  0.0  0.1   9868  2068 ?        Ss   20:53   0:00 nginx: master process /usr/local/nginx/sbin/nginx
nginx       8388  0.0  0.2  14200  4884 ?        S    20:53   0:00 nginx: worker process
root       11924  0.0  0.1 221664  2176 pts/0    S+   21:01   0:00 grep --color=auto nginx


=================================================================================
[root@nginx sbin]# kill -USR2 8387

#8387 为nginx worker ID
#USR2 平滑升级可执行程序,将存储有旧版本主进程PID的文件重命名为nginx.pid.oldbin,并启动新的
nginx
#此时两个master的进程都在运行,只是旧的master不在监听,由新的master监听80
#此时Nginx开启一个新的master进程,这个master进程会生成新的worker进程,这就是升级后的Nginx进
程,此时老的进程不会自动退出,但是当接收到新的请求不作处理而是交给新的进程处理


#此时会出现两个master和两个worker
[root@nginx sbin]# ps aux | grep nginx
root        8387  0.0  0.1   9868  2452 ?        Ss   20:53   0:00 nginx: master process /usr/local/nginx/sbin/nginx
nginx       8388  0.0  0.2  14200  4884 ?        S    20:53   0:00 nginx: worker process
root       11925  0.0  0.3   9776  6400 ?        S    21:02   0:00 nginx: master process /usr/local/nginx/sbin/nginx
nginx      11926  0.0  0.2  14240  4880 ?        S    21:02   0:00 nginx: worker process
root       11928  0.0  0.1 221664  2176 pts/0    S+   21:02   0:00 grep --color=auto nginx

5、回收旧的nginx

#回收旧版
[root@nginx sbin]# kill -WINCH 8387
[root@nginx sbin]# ps aux | grep nginx
root        8387  0.0  0.1   9868  2452 ?        Ss   20:53   0:00 nginx: master process /usr/local/nginx/sbin/nginx
root       11925  0.0  0.3   9776  6400 ?        S    21:02   0:00 nginx: master process /usr/local/nginx/sbin/nginx
nginx      11926  0.0  0.2  14240  4880 ?        S    21:02   0:00 nginx: worker process
root       11933  0.0  0.1 221664  2176 pts/0    S+   21:04   0:00 grep --color=auto nginx



[root@nginx sbin]# curl -I localhost
HTTP/1.1 200 OK
Server: nginx/1.26.1        #已经升级
Date: Sun, 18 Aug 2024 13:04:38 GMT
Content-Type: text/html
Content-Length: 615
Last-Modified: Sun, 18 Aug 2024 12:48:19 GMT
Connection: keep-alive
ETag: "66c1ed93-267"
Accept-Ranges: bytes

类似问题再现:

nginx需要用pid文件来实现重启

[root@nginx sbin]# killall nginx

[root@nginx sbin]# ps aux | grep nginx
root       12368  0.0  0.0  11188  2436 ?        Ss   20:06   0:00 nginx: master process ngin
nginx      12369  0.0  0.1  15620  5380 ?        S    20:06   0:00 nginx: worker process
root       12371  0.0  0.0 221664  2176 pts/0    S+   20:06   0:00 grep --color=auto nginx

[root@nginx nginx-1.26.1]# nginx

[root@nginx sbin]# nginx -s reload

没有nginx这个用户 创建一个

[root@nginx nginx-1.26.1]# useradd -s /sbin/nologin -M nginx

版本回滚

1、将旧版的备份重新唤起

#将旧版的备份重新唤起
[root@nginx sbin]# ls
nginx  nginx.24

[root@nginx sbin]# cp nginx nginx.26
[root@nginx sbin]# ls
nginx  nginx.24  nginx.26

[root@nginx sbin]# mv nginx.24 nginx
mv: overwrite 'nginx'? y

2、重新拉起旧版本的worker

[root@nginx sbin]# ps aux | grep nginx
root        8387  0.0  0.1   9868  2452 ?        Ss   20:53   0:00 nginx: master process /usr/local/nginx/sbin/nginx
root       11925  0.0  0.3   9776  6400 ?        S    21:02   0:00 nginx: master process /usr/local/nginx/sbin/nginx
nginx      11926  0.0  0.2  14240  5136 ?        S    21:02   0:00 nginx: worker process
root       11955  0.0  0.1 221664  2176 pts/0    S+   21:07   0:00 grep --color=auto nginx
[root@nginx sbin]# kill -HUP 8387
[root@nginx sbin]# ps aux | grep nginx
root        8387  0.0  0.1   9868  2452 ?        Ss   20:53   0:00 nginx: master process /usr/local/nginx/sbin/nginx
root       11925  0.0  0.3   9776  6400 ?        S    21:02   0:00 nginx: master process /usr/local/nginx/sbin/nginx
nginx      11926  0.0  0.2  14240  5136 ?        S    21:02   0:00 nginx: worker process
nginx      11956  0.0  0.2  14200  5012 ?        S    21:08   0:00 nginx: worker process
root       11958  0.0  0.1 221664  2176 pts/0    S+   21:08   0:00 grep --color=auto nginx
[root@nginx sbin]# kill -WINCH 11925
[root@nginx sbin]# ps aux | grep nginx
root        8387  0.0  0.1   9868  2452 ?        Ss   20:53   0:00 nginx: master process /usr/local/nginx/sbin/nginx
root       11925  0.0  0.3   9776  6400 ?        S    21:02   0:00 nginx: master process /usr/local/nginx/sbin/nginx
nginx      11956  0.0  0.2  14200  5012 ?        S    21:08   0:00 nginx: worker process
root       11960  0.0  0.1 221664  2176 pts/0    S+   21:08   0:00 grep --color=auto nginx


三、Nginx 核心配置

3.1 配置文件说明

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 主配置文件的配置指令方式:

directive value [value2 ...];
注意
(1) 指令必须以分号结尾
(2) 支持使用配置变量
         内建变量:由Nginx模块引入,可直接引用
         自定义变量:由用户使用set命令定义,格式: set variable_name value;
         引用变量:$variable_name

主配置文件结构:四部分

main block:主配置段,即全局配置段,对http,mail都有效

#事件驱动相关的配置
event {
 ...
}  

#http/https 协议相关配置段
http {

...

}

#默认配置文件不包括下面两个块
#mail 协议相关配置段
mail {
 ...
}

#stream 服务器相关配置段
stream {
 ...

默认的nginx.conf 配置文件格式说明

#全局配置端,对全局生效,主要设置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 (快速拷贝到kernelsocket buffer) >>协议栈。
 
   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
}

3.2 全局核心配置参数优化

[root@nginx conf]# vim /usr/local/nginx/conf/nginx.conf

1、查看最大工作进程数

也可以通过auto (系统有几个核心就会有几个worker)

2、绑定cpu核心

例如:

3、查看并更改并发数 可以实现高并发

4、使用epoll模型:

[root@nginx ~]# vim /usr/local/nginx/conf/nginx.conf

5、将不同功能或不同站点的配置分离到多个小的配置文件中,便于管理和维护

[root@nginx ~]# mkdir -p /usr/local/nginx/conf.d

6、创建nginx发布目录并用浏览器访问

去网页访问 访问之前做好本地解析!!!


3.3 root 与 alias

root:

指定web的家目录,在定义location的时候,文件的绝对路径等于 root+location

server {
   listen 80;
   server_name www.exam.com;
   location / {
       root /data/web/html;    #默认发布目录
   }
   location /dirtest {         #必须建立/mnt/dirtest才能访问
       root /mnt;
   }
}

root示例

alias

定义路径别名,会把访问的路径重新定义到其指定的路径,文档映射的另一种机制;仅能用于 location上下文,此指令使用较少

示例:

server {
   listen 80;
   server_name www.exam.com;
   location / {
       root /data/web/html;        #默认发布目录 可以自主创建
   }
   location /dirtest {
       root /mnt;
   }
   location /alias {                #注意about后不要加/
                 #使用alias的时候uri后面如果加了斜杠,则下面的路径配置必须加斜杠,否则403
   
       alias /mnt/dirtest;         #当访问alias的时候,会显示alias定义的/mnt/dirtest
里面的内容 
   }
}

Note

location中使用root指令和alias指令的意义不同

  • root #给定的路径对应于location中的/uri左侧的/
  • alias #给定的路径对应于location中的/uri的完整路径

3.4 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前,表示包含正则表达式并且转义字符。可以将 . * ?等转义为普通符号

优先级排列

对目录(从高到低)

(~*        =        ~)        >        不带符号        >        ^~        >        =

对文件(从高到底)

=        >        (~*        =        ~)        >        不带符号        >        ^~

示例: 

#目录优先级
[root@nginx test1]# mkdir -p /data/web{1..5}
[root@nginx test1]# mkdir -p /data/web{1..5}/test


server {
        listen 80; 
        server_name www.exam.org;
        root /data/web/html;
        index index.html;
        location =  /test/ {
            root /data/web1;
        }   

        location /test {
            root /data/web2;
        }   

        location ^~ /t {
            root /data/web3;
        }   

        location ~* .HTML$ {
            root /data/web4;
        }   

        location ~ .html$ {
            root /data/web5;
        }   
}


#文件优先级
[root@nginx test1]# echo web1 > /data/web1/test/index.html
[root@nginx test1]# echo web2 > /data/web2/test/index.html
[root@nginx test1]# echo web3 > /data/web3/test/index.html
[root@nginx test1]# echo web4 > /data/web4/test/index.html
[root@nginx test1]# echo web5 > /data/web5/test/index.html


server {
    listen 80;
    server_name www.exam.com;
    root /data/web/html;
    index index.html;

    location /index.html {
    root /data/web11/test;
    }

     location = /index.html {
    root /data/web2/test;
    }

     location ^~ /index.html {
    root /data/web3/test;
    }

     location ~ /index.html {
    root /data/web4/test;
    }

     location ~* /index.html {
    root /data/web5/test;
    }

}


3.5 Nginx 账户认证功能

[root@nginx ~]# htpasswd -cm /usr/local/nginx/.htpasswd admin
New password: 
Re-type new password: 
Adding password for user admin
[root@nginx ~]# cat /usr/local/nginx/.htpasswd 
admin:$apr1$FpZQolny$CX5peL/Hxa3iw6GQXDRFh/

[root@nginx ~]# htpasswd -m /usr/local/nginx/.htpasswd howe
New password: 
Re-type new password: 
Adding password for user howe
[root@nginx ~]# cat /usr/local/nginx/.htpasswd 
admin:$apr1$FpZQolny$CX5peL/Hxa3iw6GQXDRFh/
howe:$apr1$.r6F4qwy$h6eqZboHclzrA3nFvMslb/
[root@nginx ~]# mkdir /data/web/howe
[root@nginx ~]# echo howe > /data/web/howe/index.html
[root@nginx ~]# vim /usr/local/nginx/conf.d/vhost.conf
[root@nginx ~]# cat /usr/local/nginx/conf.d/vhost.conf 
server {
        listen 80; 
        server_name www.exam.org;
        root /data/web/html;
        index index.html;
    
        location =  /howe {
            root /data/web;
            auth_basic "login password !!" 
            auth_basic_user_file "/usr/local/nginx/.htpasswd";
        }   
}

添加认证 

重启Nginx并访问测试

[root@nginx ~]# curl www.exam.com/login/ -u admin:nginx
login

网页测试


3.6 自定义错误页面

自定义错误页,同时也可以用指定的响应状态码进行响应, 可用位置:http, server, location, if in location

error_page code ... [=[response]] uri;

[root@nginx ~]# mkdir -p /data/web/errorpage
[root@nginx ~]# echo error page > /data/web/errorpage/40x.html
[root@nginx ~]# cat /usr/local/nginx/conf.d/vhost.conf 
server {
        listen 80;
        server_name www.exam.org;
        root /data/web/html;
        #index index.html;
        error_page 404 /40x.html;   #指定错误 就会去寻找40x.html
        
        location =  /howe {
            root /data/web;
            auth_basic "login password !!";
            auth_basic_user_file "/usr/local/nginx/.htpasswd";
        }

        location = /40x.html {
            root /data/web/errorpage;
        }
}

[root@nginx ~]# nginx -s reload


3.7 自定义错误日志

[root@nginx ~]# mkdir -p /var/log/superhowe.com/

[root@nginx ~]# curl 172.25.250.100
welcome to nginx
[root@nginx ~]# cat /var/log/superhowe.com/access.log 
172.25.250.100 - - [16/Aug/2024:14:32:05 +0800] "GET / HTTP/1.1" 200 17 "-" "curl/7.76.1"

重启nginx并访问不存在的页面进行测试并验证是在指定目录生成新的日志文件


3.8 检测文件是否存在

[root@nginx ~]# mkdir /data/web/html/error -p
[root@nginx ~]# echo error default > /data/web/html/error/default.html
[root@nginx ~]# cat /usr/local/nginx/conf.d/vhost.conf
server {
        listen 80; 
        server_name www.exam.org;
        root /data/web/html;
        #index index.html;
        error_page 404 /40x.html;
        error_log /var/log/superhowe.com/error.log;
        access_log /var/log/superhowe.com/access.log;
        try_files $uri $uri.html $uri/index.html /error/default.html;

	    location  /40x.html {
             root /data/web/errorpage;
         }
}


#如果检测到文件不存在就会出现如下信息
[root@nginx ~]# curl 172.25.250.100/super
error default


3.9 长连接

下载测试工具

[root@nginx ~]# dnf install telnet -y

测试

配置说明:

[root@nginx ~]# vim /usr/local/nginx/conf/nginx.conf

[root@nginx ~]# telnet www.exam.com 80
Trying 172.25.250.100...
Connected to www.exam.com.
Escape character is '^]'.

GET / HTTP/1.1        #1输入
HOST: www.exam.com    #2输入
#回车

HTTP/1.1 200 OK
Server: superhowe/2.0
Date: Fri, 16 Aug 2024 06:54:55 GMT
Content-Type: text/html
Content-Length: 17
Last-Modified: Fri, 16 Aug 2024 01:27:15 GMT
Connection: keep-alive
Keep-Alive: timeout=60
ETag: "66beaaf3-11"
Accept-Ranges: bytes

3.10 作为下载服务器配置

[root@nginx ~]# mkdir -p /data/web/download

[root@nginx ~]# dd if=/dev/zero of=/data/web/download/howefile bs=1M count=10
10+0 records in
10+0 records out
10485760 bytes (10 MB, 10 MiB) copied, 0.00656212 s, 1.6 GB/s

[root@nginx ~]# vim /usr/local/nginx/conf.d/vhost.conf
  ...   
        location /download {
            root /data/web;
            autoindex on; 
            autoindex_localtime on; 
            autoindex_exact_size off;
            limit_rate 1024k;
        } 
  ...
  

[root@nginx ~]# nginx -s reload


四、Nginx高级配置

4.1 Nginx 状态页

  • 基于nginx 模块 ngx_http_stub_status_module 实现,
  • 在编译安装nginx的时候需要添加编译参数 --with-http_stub_status_module
  • 否则配置完成之后监测会是提示法错误

Note:状态页显示的是整个服务器的状态,而非虚拟主机的状态

示例:

做好本地window解析

[root@nginx ~]# vim /usr/local/nginx/conf.d/status.conf

[root@nginx ~]# cat /usr/local/nginx/conf.d/status.conf 
server {
    listen 80;
    server_name status.exam.com;
    root /data/web/html;
    index index.html;		#指定默认的索引文件为 index.html

    location /status {
        stub_status;
        allow 172.25.250.1;   	#允许访问的主机
        deny all;			   #其他所有主机不能访问
    }
}

[root@nginx ~]# nginx -s reload
[root@nginx ~]# nginx -s reload
[root@nginx ~]# curl 172.25.250.100/status
<html>
<head><title>403 Forbidden</title></head>
<body>
<center><h1>403 Forbidden</h1></center>
<hr><center>superhowe/2.0</center>
</body>
</html>

#去windows测试is ok


4.2 Nginx 压缩功能

Nginx支持对指定类型的文件进行压缩然后再传输给客户端,而且压缩还可以设置压缩比例,压缩后的文件大小将比源文件显著变小,样有助于降低出口带宽的利用率,降低企业的IT支出,不过会占用相应的CPU资源。

Nginx对文件的压缩功能是依赖于模块 ngx_http_gzip_module,默认是内置模块

配置指令如下:

gzip on | off启用或禁用gzip压缩,默认关闭
gzip_comp_level 4压缩比由低到高从1到9,默认为1,值越高压缩后文件越小,但是消耗cpu比较高。基本设定未4或者5
gzip_disable "MSIE [1-6]\."禁用IE6 gzip功能,早期的IE6之前的版本不支持压缩
gzip_min_length 1kgzip压缩的最小文件,小于设置值的文件将不会压缩
gzip_http_version 1.0 | 1.1启用压缩功能时,协议的最小版本,默认HTTP/1.1
gzip_buffers number size指定Nginx服务需要向服务器申请的缓存空间的个数和大小,平台不同,默认:32 4k或者16 8k;
gzip_types mime-type ...指明仅对哪些类型的资源执行压缩操作;默认为gzip_types text/html,不用显示指定,否则出错
 
gzip_vary on | off如果启用压缩,是否在响应报文首部插入“Vary: Accept-Encoding”,一般建议打开
gzip_static on | off

预压缩,即直接从磁盘找到对应文件的gz后缀的式的压缩文件返回给用户,无需消耗服务器

注意: 来自于ngx_http_gzip_static_module模块

 示例:

[root@nginx web]# vim /usr/local/nginx/conf/nginx.conf
[root@nginx web]# cat /usr/local/nginx/conf/nginx.conf
...
    #gzip on
    gzip on; 
    gzip_comp_level 5;
    gzip_min_length 1k; 
    gzip_http_version 1.1;
    gzip_vary on; 
    gzip_types text/plain application/javascript application/x-javascript text/css application/x-http-php image/gif image/png;
...

[root@nginx web]# nginx -s reload
[root@nginx web]# echo hello superhowe > /data/web/html/small.html
[root@nginx web]# du -sh /usr/local/nginx/logs/access.log 
52K	/usr/local/nginx/logs/access.log
[root@nginx web]# cat /usr/local/nginx/logs/access.log > /data/web/html/big.html



#查看
[root@nginx web]# curl --head --compressed 172.25.250.100/small.html
HTTP/1.1 200 OK
Server: superhowe/2.0
Date: Fri, 16 Aug 2024 08:21:40 GMT
Content-Type: text/html
Content-Length: 16
Last-Modified: Fri, 16 Aug 2024 08:20:15 GMT
Connection: keep-alive
Keep-Alive: timeout=60
ETag: "66bf0bbf-10"
Accept-Ranges: bytes

[root@nginx web]# curl --head --compressed 172.25.250.100/big.html
HTTP/1.1 200 OK
Server: superhowe/2.0
Date: Fri, 16 Aug 2024 08:21:48 GMT
Content-Type: text/html
Last-Modified: Fri, 16 Aug 2024 08:21:18 GMT
Connection: keep-alive
Keep-Alive: timeout=60
Vary: Accept-Encoding
ETag: W/"66bf0bfe-c813"
Content-Encoding: gzip

#不是对文件进行压缩 而是对文件传输过程进行压缩

4.3 Nginx的版本隐藏

用户在访问nginx的时候,我们可以从报文中获得nginx的版本,相对于裸漏版本号的nginx,我们把其隐 藏起来更安全

例如:

[root@Nginx nginx-1.26.1]# vim src/core/nginx.h
#define nginx_version 1026001
#define NGINX_VERSION "2.0"
#define NGINX_VER "superme/" NGINX_VERSION

4.4 Nginx 变量使用

  • nginx的变量可以在配置文件中引用,作为功能判断或者日志等场景使用
  • 变量可以分为内置变量和自定义变量
  • 内置变量是由nginx模块自带,通过变量可以获取到众多的与客户端访问相关的值

4.4.1 内置变量

常用变量

$remote_addr存放了客户端的地址,注意是客户端的公网IP
$args;变量中存放了URL中的所有参数
$is_args如果有参数为? 否则为空
$document_root保存了针对当前资源的请求的系统根目录
$document_uri保存了当前请求中不包含参数的URI,注意是不包含请求的指令
$host存放了请求的host名称
$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请求生成的文件绝对路径,
$request_uri包含请求参数的原始URI,不包含主机名,相当于:$document_uri?$args,
$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的对应的首部字段名需要为小写,如果有 横线需要替换为下划线

示例:

server {
    listen 80;
    server_name var.timinglee.org;
    root /data/web/html;
    index index.html;

    location /var {
        default_type text/html;
        echo $remote_addr;
        echo $args;
        echo $is_args;
        echo $document_root;
        echo $document_uri;
        echo $host;
        echo $remote_port;
        echo $remote_user;
        echo $request_method;
        echo $request_filename;
        echo $request_uri;
        echo $scheme;
        echo $server_protocol;
        echo $server_addr;
        echo $server_name;
        echo $server_port;
        echo $http_user_agent;
        echo $http_cookie;
        echo $cookie_key2;
    }
}


[root@nginx conf.d]# curl www.exam.com/var
172.25.250.100


/data/web/html
/var
www.exam.com
52734

GET
/data/web/html/var
/var
http
HTTP/1.1
172.25.250.100
www.exam.com
80
curl/7.76.1

4.4.2 自定义变量

自定义变量名称和值,使用指令set $variable value;

语法格式:

        Syntax: set $variable value;

        Default: —

        Context: server, location, if

示例:

[root@nginx ~]# vim /usr/local/nginx/conf.d/vhost.conf
server {
    listen 80;
    server_name www.exam.com;
    root /data/web/html;
    
    location /var {
        default_type text/html;        
        set $name superhowe;
        echo $name;
        set $web_port $server_port;
        echo $web_port;
    }
}


#测试输出
[root@nginx ~]# curl www.exam.com/var
superhowe
80

五 Nginx Rewrite 相关功能

  • Nginx服务器利用 ngx_http_rewrite_module 模块解析和处理rewrite请求
  • 此功能依靠 PCRE(perl compatible regular expression),因此编译之前要安装PCRE库
  • rewrite是nginx服务器的重要功能之一,用于实现URL的重写,URL的重写是非常有用的功能
  • 比如它可以在我们改变网站结构之后,不需要客户端修改原来的书签,也无需其他网站修改我们的链接,就可以设置为访问
  • 另外还可以在一定程度上提高网站的安全性

5.1 模块指令

5.1.1 if 指令

用于条件匹配判断,并根据条件判断结果选择不同的Nginx配置,可以配置在server或location块中进行 配置,Nginx的if语法仅能使用if做单次判断,不支持使用if else或者if elif这样的多重判断

if (条件匹配) {
action
}

使用正则表达式对变量进行匹配,匹配成功时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

示例:

server {
    listen 80; 
    server_name var.exam.com;
    root /data/web/html;
    index index.html;

    location /test2 {
        if (!-e $request_filename ) { 
            echo "$request_filename is not exist";
        }   
    }   
}

此时不存在test2这个文件夹

创建一个test2后 再次访问

5.1.2 set 指令

指定key并给其定义一个变量,变量可以调用Nginx内置变量赋值给key 另外set定义格式为set $key value,value可以是text, variables和两者的组合。

server {
    listen 80; 
    server_name var.exam.com;
    root /data/web/html;
    index index.html;

    location /test2 {
        set $name howe;
        echo $name;
    }   
}

#测试
[root@nginx conf.d]# curl var.exam.com/test2
howe

5.1.3 break 指令

  • 用于中断当前相同作用域(location)中的其他Nginx配置
  • 与该指令处于同一作用域的Nginx配置中,位于它前面的配置生效
  • 位于后面的 ngx_http_rewrite_module 模块中指令就不再执行
  • Nginx服务器在根据配置处理请求的过程中遇到该指令的时候,回到上一层作用域继续向下读取配置
  • 该指令可以在server块和locationif块中使用

注意: 如果break指令在location块中后续指令还会继续执行,只是不执行 ngx_http_rewrite_module 模块的指令,其它指令还会执行

示例:

[root@nginx conf.d]# vim var.conf 
[root@nginx conf.d]# nginx -s reload
[root@nginx conf.d]# curl var.exam.com/break
howe
123123
[root@nginx conf.d]# cat var.conf 
server {
    listen 80;
    server_name var.exam.com;
    root /data/web/html;
    index index.html;

    location /test2 {
       if ( !-e $request_filename ){ 
          echo "$request_filename is not exist";
       }
    }
    
    location /break {
        default_type text/html;
        set $name howe;
        echo $name;
        set $id 123123;
        echo $id;
   }

}
[root@nginx conf.d]# vim var.conf 
[root@nginx conf.d]# nginx -s reload
[root@nginx conf.d]# curl var.exam.com/break
howe

[root@nginx conf.d]# cat var.conf 
server {
    listen 80;
    server_name var.exam.com;
    root /data/web/html;
    index index.html;

    location /test2 {
       if ( !-e $request_filename ){ 
          echo "$request_filename is not exist";
       }
    }
    
    location /break {
        default_type text/html;
        set $name howe;
        echo $name;
        if ( $http_user_agent = "curl/7.76.1"){
                break;
        }
        set $id 123123;
        echo $id;
   }
}

#指定到别的浏览器 break就不会跳出
[root@nginx conf.d]# curl -A "filehowe" var.exam.com/break
howe
123123

5.1.4 return 指令

return用于完成对请求的处理,并直接向客户端返回响应状态码,比如:可以指定重定向URL(对于特殊重 定向状态码,301/302等) 或者是指定提示文本内容(对于特殊状态码403/500等),处于此指令后的所有配 置都将不被执行,return可以在server、if 和 location块进行配置

语法格式:

return code;                          #返回给客户端指定的HTTP状态码
return code [text];                 #返回给客户端的状态码及响应报文的实体内容
                                             #可以调用变量,其中text如果有空格,需要用单或双引号
return code URL;                  #返回给客户端的URL地址

示例:

server {
    listen 80; 
    server_name var.exam.com;
    root /data/web/html;
    index index.html;

    location /return {
        default_type text/html;
            if ( !-e $request_filename ) { 
                echo "$request_filename is not exist";
                return 301 http://www.baidu.com;
            }   
            echo "$request_filename is not exist";
   }   
}

#测试 没有文件夹会出现301 并且定向到baidu
[root@nginx conf.d]# curl var.exam.com/return
<html>
<head><title>301 Moved Permanently</title></head>
<body>
<center><h1>301 Moved Permanently</h1></center>
<hr><center>nginx/1.26.1</center>
</body>
</html>

#创建文件夹 
[root@nginx conf.d]# mkdir -p /data/web/html/return
[root@nginx conf.d]# curl var.exam.com/return
/data/web/html/return is not exist

[root@nginx conf.d]# curl -I var.exam.com/return
HTTP/1.1 200 OK
Server: nginx/1.26.1
Date: Tue, 20 Aug 2024 10:05:10 GMT
Content-Type: text/html
Connection: keep-alive
Keep-Alive: timeout=60
Location: http://www.baidu.com

5.2 rewrite 指令

通过正则表达式的匹配来改变URI,可以同时存在一个或多个指令,按照顺序依次对URI进行匹配, rewrite主要是针对用户请求的URL或者是URI做具体处理

rewrite将用户请求的URI基于regex所描述的模式进行检查,匹配到时将其替换为表达式指定的新的URI

注意:如果在同一级配置块中存在多个rewrite规则,那么会自下而下逐个检查;被某条件规则替换完成 后,会重新一轮的替换检查,隐含有循环机制,但不超过10次;如果超过,提示500响应码,[flag]所表示的 标志位用于控制此循环机制

如果替换后的URL是以http://或https://开头,则替换结果会直接以重定向返回给客户端, 即永久重定向 301

.匹配除换行符以外的任意字符
\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 这几个字母以外的任意字符

5.2.1 rewrite flag 使用介绍

利用nginx的rewrite的指令,可以实现url的重新跳转,rewrite有四种不同的flag,分别是redirect(临时 重定向302)、permanent(永久重定向301)、break和last。其中前两种是跳转型的flag,后两种是代理型

  • 跳转型指由客户端浏览器重新对新地址进行请求
  • 代理型是在WEB服务器内部实现跳转

flag 说明

redirect;
#临时重定向,重写完成后以临时重定向方式直接返回重写后生成的新URL给客户端
#由客户端重新发起请求;使用相对路径,或者http://或https://开头,状态码:302

permanent;
#重写完成后以永久重定向方式直接返回重写后生成的新URL给客户端
#由客户端重新发起请求,状态码:301

break;
#重写完成后,停止对当前URL在当前location中后续的其它重写操作
#而后直接跳转至重写规则配置块之后的其它配置,结束循环,建议在location中使用
#适用于一个URL一次重写

last;
#重写完成后,停止对当前URI在当前location中后续的其它重写操作,
#而后对新的URL启动新一轮重写检查,不建议在location中使用
#适用于一个URL多次重写,要注意避免出现超过十次以及URL重写后返回错误的给用户

5.2.2 域名永久与临时重定向

域名的临时的调整,后期可能会变,之前的域名或者URL可能还用、或者跳转的目的域名和URL还会跳 转,这种情况浏览器不会缓存跳转,临时重定向不会缓存域名解析记录(A记录),但是永久重定向会缓存。

5.2.2.1 永久重定向301

域名永久型调整,即域名永远跳转至另外一个新的域名,之前的域名再也不使用,跳转记录可以缓存到客户端浏览器

永久重定向会缓存DNS解析记录, 浏览器中有 from disk cache 信息,即使nginx服务器无法访问,浏览器也会利用缓存进行重定向

[root@nginx conf.d]# vim var.conf 
server {
    listen 80;
    server_name var.exam.com;
    root /data/web/html;
    index index.html;

    location / {
        root /data/web/var;
        index index.html;

        rewrite / http://www.exam.com permanent;
    }
}

[root@nginx conf.d]# mkdir -p /data/web/var
[root@nginx conf.d]# echo var page > /data/web/var/index.html
[root@nginx conf.d]# nginx -s reload

5.2.2.2 临时重定向302

域名临时重定向,告诉浏览器域名不是固定重定向到当前目标域名,后期可能随时会更改,因此浏览器不会缓存当前域名的解析记录,而浏览器会缓存永久重定向的DNS解析记录,这也是临时重定向与永久重定向最大的本质区别。

即当nginx服务器无法访问时,浏览器不能利用缓存,而导致重定向失败

[root@nginx conf.d]# cat var.conf 
server {
    listen 80;
    server_name var.exam.com;
    root /data/web/html;
    index index.html;

    location / {
        root /data/web/var;
        index index.html;
        #rewrite / http://var.exam.com permanent;
        rewrite / http://var.exam.com redirect;
    }
}


5.2.3 rewrite 案例: break 与 last

测试:

访问break请求被rewrite至test1,而访问test1转递请求再次被rewrite发送至test2,此测试last和break 分别有什么区别

示例:

创建目录并写入
[root@nginx conf.d]# mkdir /data/web/html/{test1,test2,break,last} -p
[root@nginx conf.d]# echo test1 > /data/web/html/test1/index.html
[root@nginx conf.d]# echo test2 > /data/web/html/test2/index.html
[root@nginx conf.d]# echo break > /data/web/html/break/index.html
[root@nginx conf.d]# echo last > /data/web/html/last/index.html
[root@nginx conf.d]# nginx -s reload

[root@nginx conf.d]# cat break.conf 
server {
    listen 80;
    server_name var.exam.com;
    root /data/web/html;
    index index.html;
 
    location /break {
        rewrite ^/break/(.*) /test1/$1;
        rewrite ^/test1/(.*) /test2/$1;
    }
 
    location /last {
        rewrite ^/last/(.*) /test1/$1;
        rewrite ^/test1/(.*) /test2/$1;
    }
 
    location /test1 {
        default_type text/html;
        return 123 "nginx hahaha";
    }
 
    location /test2 {
        root /data/web/html;
    }
}

 
#测试访问:
[root@nginx conf.d]# curl var.exam.com/break/
test2
[root@nginx conf.d]# curl var.exam.com/last/
test2
[root@nginx conf.d]# curl var.exam.com/test1/
nginx hahaha
[root@nginx conf.d]# curl var.exam.com/test2/
test2
 
break和last效果示例:
[root@nginx conf.d]# vim /usr/local/nginx/conf.d/break.conf
server {
    listen 80;
    server_name var.exam.com;
    root /data/web/html;
    index index.html;
 
    location /break {
        root /data/web/html;
        rewrite ^/break/(.*) /test1/$1 break;  
        rewrite ^/test1/(.*) /test2/$1;
    }
 
    location /last {
    	root /data/web/html;
        rewrite ^/last/(.*) /test1/$1 last;
        rewrite ^/test1/(.*) /test2/$1 ;
    }
 
    location /test1 {
        default_type text/html;
        return 123 "nginx hahaha";
    }
 
    location /test2 {
        root /data/web/html;
    }
}
 
测试
[root@nginx ~]# nginx -s reload
[root@nginx ~]# curl -L var.exam.com/break/index.html 
test1
[root@nginx ~]# curl -L var.exam.com/last/index.html 
nginx hahaha

5.2.4 全站加密-自动跳转 https

1、制作证书 添加认证

[root@nginx certs]# openssl req -newkey rsa:2048 -nodes -sha256 -keyout /usr/local/nginx/certs/exam.com.key -x509 -days 365 -out /usr/local/nginx/certs/exam.com.crt

[root@nginx certs]# ls
exam.com.crt  exam.com.key

2、写配置文件

server {
    listen 443 ssl;
    listen 80;
    server_name www.exam.com;
    root /data/web/html;
    index index.html;
    ssl_certificate /usr/local/nginx/certs/exam.com.crt;
    ssl_certificate_key /usr/local/nginx/certs/exam.com.key;
    ssl_session_cache       shared:SSL:1m;
    ssl_session_timeout     5m;

    location / {
        if ( $scheme = http ) {
            rewrite /(.*) https://$host/$1 redirect;
        }
    }
}


5.3 Nginx 防盗链

防盗链基于客户端携带的referer实现,referer是记录打开一个页面之前记录是从哪个页面跳转过来的标 记信息,如果别人只链接了自己网站图片或某个单独的资源,而不是打开了网站的整个页面,这就是盗 链,referer就是之前的那个网站域名

环境准备:主机 172.25.250.100      客户端 172.25.250.10并使用Apache

图1

图2

说明:图1 在主机images文件夹下  /data/web/images/dashuai.jpg

           图2 在主机默认发布目录  /data/web/html/daolian.jpg

5.3.1 实现盗链

#客户端准备盗链web页面:

[root@client ~]# vim /var/www/html/index.html
[root@client ~]# cat /var/www/html/index.html
<html>

    <head>
        <meta http-equiv=Content-Type content="text/html;charset=utf-8">
        <title>盗链</title>
</head>
    
    <body>
        <img src="http://www.exam.com/images/dashuai.jpg" >
        <h1 style="color:red">诸位,可愿为本帅俯首</h1>
        <p><a href=http://www.exam.com>闲云野鹤</a>天下大同</p>
    </body>

</html>

#重启apache并访问http://172.25.254.10 测试
[root@client ~]# systemctl restart httpd

5.3.2 实现防盗链

基于访问安全考虑,nginx支持通过ngx_http_referer_module模块,检查访问请求的referer信息是否有效 实现防盗链功能

示例:

[root@nginx conf.d]# cat vhost.conf 
server {
    listen 80;
    server_name www.exam.com;
    root /data/web/html;

    location /images {
        valid_referers none blocked server_names *.exam.com ~/.baidu/.;
            if ( $invalid_referer ) {
            return 404;
            }
    }
}

这时访问images时出现404 

[root@nginx conf.d]# cat vhost.conf 
server {
    listen 80;
    server_name www.exam.com;
    root /data/web/html;

    location / {
        valid_referers none blocked server_names *.exam.com ~/.baidu/.;
            if ( $invalid_referer ) {
                return 404;
            }
    }
    
    location /images {
        valid_referers none blocked server_names *.exam.com ~/.baidu/.;
            if ( $invalid_referer ) {
                rewrite ^/  http://www.exam.com/daolian.jpg;
            }
    }
}

此时可以看到这不是想要看到的图片


六 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协议转发至指定服务器处理

6.1 反向代理

6.1.1 动静分离实现

环境

node作用需要的软件
172.25.250.100主机nginx
172.25.250.10客户端http php
172.25.250.20客户端http

client1

[root@client ~]# vim /var/www/html/index.php
[root@client ~]# cat /var/www/html/index.php 
<?php
    phpinfo();
?>

client2

[root@client2 html]# mkdir -p /var/www/html/static
[root@client2 html]# echo static 172.25.250.20 > /var/www/html/static/index.html
[root@client2 html]# systemctl restart httpd

host

server {
    listen 80; 
    server_name www.exam.com;

    location ~ \.php$ {
        proxy_pass http://172.25.250.10:80;
    }   

    location /static {
        proxy_pass http://172.25.250.20:8080;
    }   
}

6.1.2 缓存功能

缓存功能默认关闭状态,需要先动配置才能启用

压测:

[root@nginx ~]# ab -n1000 -c100 http://www.exam.com/static/index.html
This 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.exam.com (be patient)
Completed 100 requests
Completed 200 requests
Completed 300 requests
Completed 400 requests
Completed 500 requests
Completed 600 requests
Completed 700 requests
Completed 800 requests
Completed 900 requests
Completed 1000 requests
Finished 1000 requests


Server Software:        nginx/1.26.1
Server Hostname:        www.exam.com
Server Port:            80

Document Path:          /static/index.html
Document Length:        21 bytes

Concurrency Level:      100
Time taken for tests:   0.239 seconds
Complete requests:      1000
Failed requests:        0
Total transferred:      272000 bytes
HTML transferred:       21000 bytes
Requests per second:    4192.68 [#/sec] (mean)
Time per request:       23.851 [ms] (mean)
Time per request:       0.239 [ms] (mean, across all concurrent requests)
Transfer rate:          1113.68 [Kbytes/sec] received

Connection Times (ms)
              min  mean[+/-sd] median   max
Connect:        0    3   2.3      2      11
Processing:     6   20   6.4     20      35
Waiting:        1   19   6.5     19      35
Total:          9   22   5.3     22      38

Percentage of the requests served within a certain time (ms)
  50%     22
  66%     25
  75%     26
  80%     27
  90%     29
  95%     32
  98%     35
  99%     37
 100%     38 (longest request)

做缓存:

[root@nginx ~]# vim /usr/local/nginx/conf/nginx.conf

[root@nginx conf.d]# cat proxy.conf 
server {
   listen 80;
   server_name www.exam.com;
   
   location ~ \.php$ {
        proxy_pass http://172.25.250.10:80;
   }
 
   location /static {
        proxy_pass http://172.25.250.20:8080;
        proxy_cache proxycache;
        proxy_cache_key $request_uri;
        proxy_cache_valid 200 302 301 10m;
        proxy_cache_valid any 1m;
   }
}

#验证缓存目录结构及文件大小
[root@nginx ~]# tree /usr/local/nginx/proxy_cache/
/usr/local/nginx/proxy_cache/
└── e
    └── 50
        └── 99
            └── 319432ef3663735a9d3cb4e0c1d9950e

3 directories, 1 file

6.2 反向代理负载均衡

在上一个节中Nginx可以将客户端的请求转发至单台后端服务器但是无法转发至特定的一组的服务器,而 且不能对后端服务器提供相应的服务器状态监测,Nginx 可以基于ngx_http_upstream_module模块提 供服务器分组转发、权重分配、状态监测、调度算法等高级功能

6.2.1 七层反向代理负载均衡

#配置nginx反向代理
[root@nginx conf.d]# cat http.conf 
upstream webcluster {
   server 172.25.250.10:80 fail_timeout=15s max_fails=3;
   server 172.25.250.20:8080 fail_timeout=15s max_fails=3;
   server 172.25.250.100:80 backup;
}
  
server {
   listen 80;
   server_name www.exam.com;
   
   location / {
        proxy_pass http://webcluster;
   }
}

#轮询
[root@nginx conf.d]# nginx -s reload
 

测试

写入hash算法 使其访问时IP保持一致

upstream webcluster {
   ip_hash;        #使其ip请求保持一致
   server 172.25.250.10:80 fail_timeout=15s max_fails=3;
   server 172.25.250.20:8080 fail_timeout=15s max_fails=3;
   #server 172.25.250.100:80 backup;    #注释 防止调度到backup
}
  
server {
   listen 80; 
   server_name www.exam.com;
   
   location / { 
        proxy_pass http://webcluster;
   }   
}

hash一致性

upstream webcluster {
   #ip_hash;
   hash $request_uri consistent;
   server 172.25.250.10:80 fail_timeout=15s max_fails=3;
   server 172.25.250.20:8080 fail_timeout=15s max_fails=3;
   #server 172.25.250.100:80 backup;
}
  
server {
   listen 80; 
   server_name www.exam.com;
   
   location / { 
        proxy_pass http://webcluster;
   }   
}

对cookie进行hash

upstream webcluster {
   #ip_hash;
   #hash $request_uri consistent;
   hash $cookie_exam;
   server 172.25.250.10:80 fail_timeout=15s max_fails=3;
   server 172.25.250.20:8080 fail_timeout=15s max_fails=3;
   #server 172.25.250.100:80 backup;
}
  
server {
   listen 80; 
   server_name www.exam.com;
   
   location / { 
        proxy_pass http://webcluster;
   }   
}


6.2.2 Nginx四层负载均衡

6.2.2.1 MySQL负载均衡

主机和客户端服务器安装 MySQL

[root@client ~]# dnf install mariadb-server -y
[root@client ~]# vim /etc/my.cnf.d/mariadb-server.cnf

[root@client ~]# systemctl start mariadb

#10 20 主机配置mysql
MariaDB [(none)]> CREATE USER 'howe'@'%' IDENTIFIED BY 'redhat';
Query OK, 0 rows affected (0.011 sec)

MariaDB [(none)]> GRANT ALL PRIVILEGES ON *.* TO 'howe'@'%';
Query OK, 0 rows affected (0.001 sec)

MariaDB [(none)]> FLUSH PRIVILEGES;
Query OK, 0 rows affected (0.001 sec)

MariaDB [(none)]> quit
Bye


#查看

[root@client ~]# mysql -e "grant all on *.* to howe@'%' identified by 'redhat';"
[root@client ~]# mysql -uhowe -predhat -h172.25.250.10 -e "select @@server_id"
+-------------+
| @@server_id |
+-------------+
|          10 |
+-------------+

[root@client2 html]# mysql -e "grant all on *.* to howe@'%' identified by 'redhat';"
[root@client2 html]# mysql -uhowe -predhat -h172.25.250.20 -e "select @@server_id"
+-------------+
| @@server_id |
+-------------+
|          20 |
+-------------+

nginx配置

stream {
    upstream mysql_server {
    server 172.25.250.10:3306 max_fails=3 fail_timeout=30s;
    server 172.25.250.20:3306 max_fails=3 fail_timeout=30s;
}
    server {
    listen 172.25.250.100:3306;
    proxy_pass mysql_server;
    proxy_connect_timeout 30s;
    proxy_timeout 300s;
    }   
}

重启nginx并访问测试

测试通过nginx负载连接MySQL

[root@nginx conf.d]# nginx -s reload
nginx: [emerg] "stream" directive is not allowed here in /usr/local/nginx/conf.d/mysql.conf:1

Note:这是因为这是四层负载均衡 所以子配置目录要位于http模块的上面 先执行子配置文件  再执行http stream模块 并反向代理

#在nginx主机上连接
[root@nginx ~]# mysql -uhowe -p -h 172.25.250.100
Enter password: 
Welcome to the MariaDB monitor.  Commands end with ; or \g.
Your MariaDB connection id is 7
Server version: 10.5.22-MariaDB MariaDB Server

Copyright (c) 2000, 2018, Oracle, MariaDB Corporation Ab and others.

Type 'help;' or '\h' for help. Type '\c' to clear the current input statement.

MariaDB [(none)]> select @@server_id;
+-------------+
| @@server_id |
+-------------+
|          10 |
+-------------+
1 row in set (0.001 sec)

MariaDB [(none)]> quit
Bye



#重新退出再进
[root@nginx ~]# mysql -uhowe -p -h 172.25.250.100
Enter password: 
Welcome to the MariaDB monitor.  Commands end with ; or \g.
Your MariaDB connection id is 6
Server version: 10.5.22-MariaDB MariaDB Server

Copyright (c) 2000, 2018, Oracle, MariaDB Corporation Ab and others.

Type 'help;' or '\h' for help. Type '\c' to clear the current input statement.

MariaDB [(none)]> select @@server_id;
+-------------+
| @@server_id |
+-------------+
|          20 |
+-------------+
1 row in set (0.001 sec)

MariaDB [(none)]> quit
Bye

实现轮询 就实现了负载均衡


6.2.2.2 udp 负载均衡实例: DNS

客户端

[root@client ~]# dnf install bind -y

配置dns

vim /etc/named.conf

vim /etc/named.rfc1912.zones

[root@client ~]# cd /var/named/
[root@client named]# cp named.localhost exam.com.zone -p
[root@client named]# vim exam.com.zone

客户端2上 也可以使用scp命令直接把配置文件从客户端1传送到客户端2

需要更改zone的用户组!不然解析不到

#更改zone的用户组
[root@client2 ~]# chgrp named exam.com.zone

配置主机

stream {
    upstream dns_server {
        server 172.25.250.10:53 max_fails=3 fail_timeout=5;
        server 172.25.250.20:53 max_fails=3 fail_timeout=5;
    }   

    server {
        listen 53 udp reuseport;
        proxy_timeout 20s;
        proxy_pass dns_server;
    }   
}
#解析客户端1
[root@nginx conf.d]# dig www.exam.com @172.25.250.100

; <<>> DiG 9.16.23-RH <<>> www.exam.com @172.25.250.100
;; global options: +cmd
;; Got answer:
;; ->>HEADER<<- opcode: QUERY, status: NOERROR, id: 41175
;; flags: qr aa rd ra; QUERY: 1, ANSWER: 1, AUTHORITY: 0, ADDITIONAL: 1

;; OPT PSEUDOSECTION:
; EDNS: version: 0, flags:; udp: 1232
; COOKIE: c1b014401eeaeb970100000066c4ad362ad5252fca3c10c2 (good)
;; QUESTION SECTION:
;www.exam.com.			IN	A

;; ANSWER SECTION:
www.exam.com.		86400	IN	A	172.25.250.10

;; Query time: 0 msec
;; SERVER: 172.25.250.100#53(172.25.250.100)
;; WHEN: Tue Aug 20 22:50:30 CST 2024
;; MSG SIZE  rcvd: 85


#解析客户端2
[root@nginx conf.d]# dig www.exam.com @172.25.250.100

; <<>> DiG 9.16.23-RH <<>> www.exam.com @172.25.250.100
;; global options: +cmd
;; Got answer:
;; ->>HEADER<<- opcode: QUERY, status: NOERROR, id: 17948
;; flags: qr aa rd ra; QUERY: 1, ANSWER: 1, AUTHORITY: 0, ADDITIONAL: 1

;; OPT PSEUDOSECTION:
; EDNS: version: 0, flags:; udp: 1232
; COOKIE: 1f3bf28759bb1a800100000066c4ae39784897552ccecbcf (good)
;; QUESTION SECTION:
;www.exam.com.			IN	A

;; ANSWER SECTION:
www.exam.com.		86400	IN	A	172.25.250.20

;; Query time: 0 msec
;; SERVER: 172.25.250.100#53(172.25.250.100)
;; WHEN: Tue Aug 20 22:54:49 CST 2024
;; MSG SIZE  rcvd: 85


6.3 实现 FastCGI

为什么会有FastCGI?

CGI协议虽然解决了语言解析器和 Web Server 之间通讯的问题,但是它的效率很低,因为 Web Server 每收到一个请求都会创建一个CGI进程,PHP解析器都会解析php.ini文件,初始化环境,请求结束的时候 再关闭进程,对于每一个创建的CGI进程都会执行这些操作,所以效率很低,而FastCGI是用来提高CGI性 能的,FastCGI每次处理完请求之后不会关闭掉进程,而是保留这个进程,使这个进程可以处理多个请 求。这样的话每个请求都不用再重新创建一个进程了,大大提升了处理效率。

什么是PHP-FPM?
PHP-FPM(FastCGI Process Manager:

  • FastCGI进程管理器)是一个实现了Fastcgi的程序,并且提供进程管理的功能。
  • 进程包括master进程和worker进程。master进程只有一个,负责监听端口,接受来自web server的请求
  • worker进程一般会有多个,每个进程中会嵌入一个PHP解析器,进行PHP代码的处理。

6.3.1 FastCGI配置指令

Nginx基于模块ngx_http_fastcgi_module实现通过fastcgi协议将指定的客户端请求转发至php-fpm处 理,其配置指令如下:

fastcgi_pass address:port;           #转发请求到后端服务器,address为后端的fastcgi                 
                                      server的地址,可用位置:location, if in location

fastcgi_index name;                 #fastcgi默认的主页资源,示例:fastcgi_index index.php;

fastcgi_param parameter value [if_not_empty];
#设置传递给FastCGI服务器的参数值,可以是文本,变量或组合,可用于将Nginx的内置变量赋值给自定义key  

fastcgi_param REMOTE_ADDR $remote_addr;     #客户端源IP
fastcgi_param REMOTE_PORT $remote_port;     #客户端源端口
fastcgi_param SERVER_ADDR $server_addr;     #请求的服务器IP地址
fastcgi_param SERVER_PORT $server_port;     #请求的服务器端口
fastcgi_param SERVER_NAME $server_name;     #请求的server name   

Nginx默认配置示例:
location ~ \.php$ {
    root /scripts;
    fastcgi_pass 127.0.0.1:9000;
    fastcgi_index index.php;
    fastcgi_param SCRIPT_FILENAME /scripts$fastcgi_script_name;     #默认脚本路径
    #fastcgi_param SCRIPT_FILENAME $document_root$fastcgi_script_name;
    include fastcgi_params;             #此文件默认系统已提供,存放的相对路径为prefix/conf
}                          

6.3.2 源码编译php

环境准备:重新配置nginx

rm -rf /usr/local/nginx

源码编译nginx

停止nginx 然后编译安装

make && make install

下载所需软件包

#先下载所需软件包
yum install -y bzip2
yum install -y systemd-devel 
yum install -y libxml2-devel 
yum install -y sqlite-devel
yum install -y libpng-devel
yum install -y libcurl-devel
yum install -y oniguruma-devel

#oniguruma-devel下载方法
wget https://mirrors.aliyun.com/rockylinux/9.4/devel/x86_64/kickstart/Packages/o/oniguruma-devel-6.9.6-1.el9.5.x86_64.rpm

[root@nginx mnt]# wget   https://mirrors.aliyun.com/rockylinux/9.4/devel/x86_64/kickstart/Packages/o/oniguruma-devel-6.9.6-1.el9.5.x86_64.rpm
--2024-08-19 18:23:23--  https://mirrors.aliyun.com/rockylinux/9.4/devel/x86_64/kickstart/Packages/o/oniguruma-devel-6.9.6-1.el9.5.x86_64.rpm
Resolving mirrors.aliyun.com (mirrors.aliyun.com)... 112.46.177.207, 112.46.177.209, 112.46.177.206
Connecting to mirrors.aliyun.com (mirrors.aliyun.com)|112.46.177.207|:443... connected.
HTTP request sent, awaiting response... 200 OK
Length: 66534 (65K) [application/x-rpm]
Saving to: ‘oniguruma-devel-6.9.6-1.el9.5.x86_64.rpm.1’

oniguruma-devel-6.9.6 100%[=======================>]  64.97K  --.-KB/s    in 0.04s   

2024-08-19 18:23:23 (1.47 MB/s) - ‘oniguruma-devel-6.9.6-1.el9.5.x86_64.rpm.1’ saved [66534/66534]

#查看
[root@nginx mnt]# ls
hgfs  oniguruma-devel-6.9.6-1.el9.5.x86_64.rpm
#安装
[root@nginx mnt]# dnf install oniguruma-devel-6.9.6-1.el9.5.x86_64.rpm -y

编译

#解压php压缩包
[root@nginx ~]# tar zxf php-8.3.9.tar.gz 
[root@nginx ~]# cd php-8.3.9/
[root@nginx php-8.3.9]# 


#编译
[root@nginx php-8.3.9]# ./configure \
--prefix=/usr/local/php \
--with-config-file-path=/usr/local/php/etc \
--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

xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx

#直接复制
./configure --prefix=/usr/local/php --with-config-file-path=/usr/local/php/etc --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

#编译完成后执行
make && make install

编译完成后会出现license

6.3.3 php相关配置优化

1、更改环境配置

[root@nginx ~]# vim ~/.bash_profile 
[root@nginx ~]# cat ~/.bash_profile 
# .bash_profile

# Get the aliases and functions
if [ -f ~/.bashrc ]; then
	. ~/.bashrc
fi

# User specific environment and startup programs
export PATH=$PATH:/usr/local/nginx/sbin:/usr/local/php/bin:/usr/local/php/sbin

[root@nginx ~]# source ~/.bash_profile    #立即生效

2、添加nginx用户 供php使用

[root@nginx ~]# cd /usr/local/php/etc/
[root@nginx etc]# cp php-fpm.conf.default php-fpm.conf
[root@nginx etc]# vim php-fpm.conf

3、修改URL 监听端口

[root@nginx conf.d]# cd /usr/local/php/etc/php-fpm.d
[root@nginx php-fpm.d]# cp www.conf.default www.conf -p
[root@nginx php-fpm.d]# vim www.conf

4、生成主配置文件

[root@nginx ~]# cd php-8.3.9/
[root@nginx php-8.3.9]# cp php.ini-production /usr/local/php/etc/php.ini
[root@nginx php-8.3.9]# vim /usr/local/php/etc/php.ini 

5、生成启动文件

[root@nginx php-8.3.9]# cp sapi/fpm/php-fpm.service /lib/systemd/system/
[root@nginx php-8.3.9]# vim /lib/systemd/system/php-fpm.service

[root@nginx php-8.3.9]# systemctl daemon-reload
[root@nginx php-8.3.9]# systemctl start php-fpm.service 
[root@nginx php-8.3.9]# netstat -antlupe | grep php
tcp        0      0 127.0.0.1:9000          0.0.0.0:*               LISTEN      0          215325     169097/php-fpm: mas 


6.3.4 nginx和php的整合

测试php页面

[root@nginx ~]# mkdir /data/web/php -p
[root@nginx ~]# vim /data/web/php/index.php
[root@nginx ~]# cat /data/web/php/index.php
<?php
    phpinfo();
?>

创建nginx子配置目录 一定要写入nginx主配置文件

[root@nginx ~]# mkdir -p /usr/local/nginx/conf.d
[root@nginx ~]# cd /usr/local/nginx/conf.d/
[root@nginx conf.d]# ll
total 0
[root@nginx conf.d]# vim vhost.conf
[root@nginx conf.d]# cat vhost.conf 
server {
    listen 80;
    server_name php.exam.com;
    root /data/web/html;
    index index.html;

    location ~ \.php$ {
        fastcgi_pass 127.0.0.1:9000;
        fastcgi_index index.php;
        include fastcgi.conf;
    }
}
[root@nginx conf.d]# nginx -s reload

提示:先做好本地解析 hosts


6.3.5 nginx-memcache高速缓存

1、安装memcache模块

解压软件包 下载所需软件

[root@nginx ~]# tar zxf memcache-8.2.tgz 
[root@nginx ~]# cd memcache-8.2/
[root@nginx memcache-8.2]# yum install autoconf php-devel -y
[root@nginx memcache-8.2]# yum install php-cli-8.0.30-1.el9_2.x86_64 -y

#生成
[root@nginx memcache-8.2]# phpize
Configuring for:
PHP Api Version:         20230831
Zend Module Api No:      20230831
Zend Extension Api No:   420230831
Cannot find autoconf. Please check your autoconf installation and the
$PHP_AUTOCONF environment variable. Then, rerun this script.

编译

[root@nginx memcache-8.2]# ./configure && make && make install

2、配置文件

复制测试文件到发布目录

[root@nginx memcache-8.2]# cp example.php memcache.php /data/web/php/

[root@nginx memcache-8.2]# vim /data/web/php/memcache.php

[root@nginx memcache-8.2]# vim /usr/local/php/etc/php.ini
[root@nginx memcache-8.2]# systemctl restart php-fpm.service 

重启php-fpm 查看memcache模块是否成功添加

[root@nginx memcache-8.2]# php -m | grep m
...
mbstring
memcache        #如果有模块就添加好了
mysqli
mysqlnd
...

3、部署memcached

#下载memcache软件
[root@nginx ~]# dnf install memcached -y

#设置开机启动
[root@nginx ~]# systemctl enable --now memcached.service 
Created symlink /etc/systemd/system/multi-user.target.wants/memcached.service → /usr/lib/systemd/system/memcached.service.

[root@nginx ~]# netstat -antlupe | grep memcache
tcp        0      0 127.0.0.1:11211         0.0.0.0:*               LISTEN      980        229163     178247/memcached    
tcp6       0      0 ::1:11211               :::*                    LISTEN      980        229164     178247/memcached 

[root@nginx ~]# cat /etc/sysconfig/memcached 
PORT="11211"
USER="memcached"
MAXCONN="1024"
CACHESIZE="64"
OPTIONS="-l 127.0.0.1,::1"

4、测试

访问 http://php.timinglee.org/example.php     #不断刷新
访问 http://php.timinglee.org/memcache.php    #查看命中效果

不断刷新👆页面

再查看命中率

过程中遇到的问题

网页显示报错  原因是memcache模块添加失败

检查

安装路径是否正确

配置文件是否有错误


7 nginx 二次开发版本

7.1 openresty

Nginx 是俄罗斯人发明的, Lua 是巴西几个教授发明的,中国人章亦春把 LuaJIT VM 嵌入到 Nginx 中,实现了 OpenResty 这个高性能服务端解决方案

OpenResty® 是一个基于 Nginx 与 Lua 的高性能 Web 平台,其内部集成了大量精良的 Lua 库、第三方模块以及大多数的依赖项。用于方便地搭建能够处理超高并发、扩展性极高的动态 Web 应用、Web 服务和动态网关。

OpenResty® 通过汇聚各种设计精良的 Nginx 模块(主要由 OpenResty 团队自主开发),从而将Nginx有效地变成一个强大的通用 Web 应用平台。这样,Web 开发人员和系统工程师可以使用 Lua 脚本语言调动 Nginx 支持的各种 C 以及 Lua 模块,快速构造出足以胜任 10K 乃至 1000K 以上单机并发连接的高性能 Web 应用系统。

OpenResty 由于有功能强大且方便的的API,可扩展性更强,如果需要实现定制功能,OpenResty是个不错的选择

官网: http://openresty.org/cn/

7.2 编译安装 openresty

[root@nginx ~]# nginx -s stop        #停止nginx 释放80端口

[root@nginx ~]# cd openresty-1.25.3.1/
[root@nginx openresty-1.25.3.1]# ls
bundle  configure  COPYRIGHT  patches  README.markdown  README-windows.txt  util

[root@nginx openresty-1.25.3.1]# dnf install -y gcc pcre-devel openssl-devel perl

[root@nginx openresty-1.25.3.1]# cd /usr/local/src/
[root@nginx src]# wget https://openresty.org/download/openresty-1.17.8.2.tar.gz


[root@nginx openresty-1.25.3.1]# ./configure --prefix=/usr/local/openresty --with-http_ssl_module --with-http_v2_module --with-http_realip_module --with-http_stub_status_module --with-http_gzip_static_module --with-pcre --with-stream --with-stream_ssl_module --with-http_sub_module --without-http_memcached_module --with-stream_realip_module

[root@nginx openresty-1.25.3.1]# make && make install


[root@nginx openresty-1.25.3.1]# ln -s /usr/local/openresty/bin/* /usr/bin/

[root@nginx openresty-1.25.3.1]# openresty -v
nginx version: openresty/1.25.3.1


[root@nginx openresty-1.25.3.1]# vim ~/.bash_profile
export PATH=$PATH:/usr/local/nginx/sbin:/usr/local/php/bin:/usr/local/php/sbin:/usr/local/openresty/bin

[root@nginx openresty-1.25.3.1]# source ~/.bash_profile 

[root@nginx openresty-1.25.3.1]# openresty 
[root@nginx openresty-1.25.3.1]# ps -ef | grep nginx
nginx     180177  180175  0 19:16 ?        00:00:00 php-fpm: pool www
nginx     180178  180175  0 19:16 ?        00:00:00 php-fpm: pool www
root      199344       1  0 23:11 ?        00:00:00 nginx: master process openresty
nobody    199345  199344  0 23:11 ?        00:00:00 nginx: worker process
root      199347  180514  0 23:11 pts/5    00:00:00 grep --color=auto nginx

  • 26
    点赞
  • 22
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值