企业高性能web服务器之Nginx

文章目录

Apache经典的web服务端

Apache prefork 模型
  • 预派生模式,有一个主控制进程,然后生成多个子进程,使用select模型,最大并发1024

  • 每个子进程有一个独立的线程响应用户请求

  • 相对比较占用内存,但是比较稳定,可以设置最大和最小进程数

  • 是最古老的一种模式,也是最稳定的模式,适用于访问量不是很大的场景

优点:稳定

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

Apache work 模型(适应市场)
  • 一种多进程和多线程混合的模型

  • 有一个控制进程,启动多个子进程

  • 每个子进程里面包含固定的线程

  • 使用线程程来处理请求

  • 当线程不够使用的时候会再启动一个新的子进程,然后在进程里面再启动线程处理请求,

  • 由于其使用了线程处理请求,因此可以承受更高的并发

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

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

Apache event 模型

Apache中最新的模式,2012年发布的apache 2.4.X系列正式支持event 模型,属于事件驱动模型(epoll)

每个进程响应多个请求,在现在版本里的已经是稳定可用的模式

它和worker模式很像,最大的区别在于,它解决了keepalive场景下长期被占用的线程的资源浪费问题(某些线程因为被keepalive,空挂在哪里等待,中间几乎没有请求过来,甚至等到超时)

event MPM中,会有一个专门的线程来管理这些keepalive类型的线程

当有真实请求过来的时候,将请求传递给服务线程,执行完毕后,又允许它释放。这样增强了高并发场景下的请求处理能力

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

缺点:没有线程安全控制

网络I/O


一个进程启动,会在内存中开辟相应的内存空间

内存空间用于进程存储数据使用,所以直接将Data拷贝到目标应用的内存之中,则完成了I/O流程。

网络I/O读取原理:

    网卡(接收到data) --- > 内核 ---> 应用程序(读取),应用程序无法直接访问计算机的硬件,所以中间会加上一个内核(可理解为中间件),可通过socket接口去调用内核,内核去检查网卡找数据;应用程序和内核在运行的过程中,相当于两个进程。那么在计算机的内存中都会开辟相应的空间,来存储数据,内核准备好数据,在内存中直接拷贝到应用程序的内存空间,则此应用程序成功接收到了相应数据。

网络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复用,因此异步非阻塞使用最多的一种通信方式。

五种IO对比

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

Nginx架构和安装

Nginx源码编译
环境准备

从RHEL9.4母盘中克隆出一台新的虚拟机,网络默认NAT模式

Nginx eth0 172.25.254.100 nginx-node1.exmaple.com

安装nginx

官网下载链接:https://nginx.org/en/download.html

选择稳定版,复制链接,在主机中用wget命令下载

bash 复制代码
[root@nginx-node1 ~]# wget https://nginx.org/download/nginx-1.26.2.tar.gz
--2024-08-16 10:12:07--  https://nginx.org/download/nginx-1.26.2.tar.gz
Resolving nginx.org (nginx.org)... 3.125.197.172, 52.58.199.22, 2a05:d014:5c0:2601::6, ...
Connecting to nginx.org (nginx.org)|3.125.197.172|:443... connected.
HTTP request sent, awaiting response... 200 OK
Length: 1244789 (1.2M) [application/octet-stream]
Saving to: 'nginx-1.26.2.tar.gz'

nginx-1.26.2.tar.gz   100%[======================>]   1.19M   563KB/s    in 2.2s    

2024-08-16 10:12:10 (563 KB/s) - 'nginx-1.26.2.tar.gz' saved [1244789/1244789]

[root@nginx-node1 ~]# ll
total 2308
-rw-------. 1 root root     992 Aug  4 00:54 anaconda-ks.cfg
drwxr-xr-x. 2 root root       6 Aug  4 00:54 Desktop
drwxr-xr-x. 2 root root       6 Aug  4 00:54 Documents
drwxr-xr-x. 2 root root       6 Aug  4 00:54 Downloads
drwxr-xr-x. 2 root root       6 Aug  4 00:54 Music
-rw-r--r--  1 root root 1112471 Aug 16 09:17 nginx-1.24.0.tar.gz
-rw-r--r--  1 root root 1244789 Aug 13 00:39 nginx-1.26.2.tar.gz
drwxr-xr-x. 2 root root       6 Aug  4 00:54 Pictures
drwxr-xr-x. 2 root root       6 Aug  4 00:54 Public
drwxr-xr-x. 2 root root       6 Aug  4 00:54 Templates
drwxr-xr-x. 2 root root       6 Aug  4 00:54 Videos

# 解压源码包
[root@nginx-node1 ~]# tar zxf nginx-1.24.0.tar.gz
[root@nginx-node1 ~]# ll
total 2308
-rw-------. 1 root root     992 Aug  4 00:54 anaconda-ks.cfg
drwxr-xr-x. 2 root root       6 Aug  4 00:54 Desktop
drwxr-xr-x. 2 root root       6 Aug  4 00:54 Documents
drwxr-xr-x. 2 root root       6 Aug  4 00:54 Downloads
drwxr-xr-x. 2 root root       6 Aug  4 00:54 Music
drwxr-xr-x  8 1001 1001     158 Apr 11  2023 nginx-1.24.0
-rw-r--r--  1 root root 1112471 Aug 16 09:17 nginx-1.24.0.tar.gz
-rw-r--r--  1 root root 1244789 Aug 13 00:39 nginx-1.26.2.tar.gz
drwxr-xr-x. 2 root root       6 Aug  4 00:54 Pictures
drwxr-xr-x. 2 root root       6 Aug  4 00:54 Public
drwxr-xr-x. 2 root root       6 Aug  4 00:54 Templates
drwxr-xr-x. 2 root root       6 Aug  4 00:54 Videos

[root@nginx-node1 nginx-1.24.0]# ll
total 812
drwxr-xr-x 6 1001 1001    326 Aug 16 10:16 auto
-rw-r--r-- 1 1001 1001 323312 Apr 11  2023 CHANGES
-rw-r--r-- 1 1001 1001 494234 Apr 11  2023 CHANGES.ru
drwxr-xr-x 2 1001 1001    168 Aug 16 10:16 conf
-rwxr-xr-x 1 1001 1001   2611 Apr 11  2023 configure   #检测环境
drwxr-xr-x 4 1001 1001     72 Aug 16 10:16 contrib
drwxr-xr-x 2 1001 1001     40 Aug 16 10:16 html
-rw-r--r-- 1 1001 1001   1397 Apr 11  2023 LICENSE
drwxr-xr-x 2 1001 1001     21 Aug 16 10:16 man
-rw-r--r-- 1 1001 1001     49 Apr 11  2023 README
drwxr-xr-x 9 1001 1001     91 Aug 16 10:16 src

# 检测当前的环境是否适合当前的选择
[root@nginx-node1 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 
checking for OS
 + Linux 5.14.0-427.13.1.el9_4.x86_64 x86_64
checking for C compiler ... not found

./configure: error: C compiler cc is not found

# 此时会报错,因为没有安装C语言的编译器,所以我们需要下载gcc
[root@nginx-node1 nginx-1.24.0]# dnf install gcc -y

# 安装完之后再执行检测环境
[root@nginx-node1 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 
bash 复制代码
# 报错,继续安装pcre开发包
[root@nginx-node1 nginx-1.24.0]# dnf search pcre
Updating Subscription Management repositories.
Unable to read consumer identity

This system is not registered with an entitlement server. You can use "rhc" or "subscription-manager" to register.

Last metadata expiration check: 0:32:37 ago on Fri 16 Aug 2024 10:50:42 AM CST.
============================ Name Exactly Matched: pcre =============================
pcre.x86_64 : Perl-compatible regular expression library
pcre.i686 : Perl-compatible regular expression library
=========================== Name & Summary Matched: pcre ============================
pcre-cpp.i686 : C++ bindings for PCRE
pcre-cpp.x86_64 : C++ bindings for PCRE
pcre-devel.i686 : Development files for pcre
pcre-devel.x86_64 : Development files for pcre
pcre-utf16.i686 : UTF-16 variant of PCRE
pcre-utf16.x86_64 : UTF-16 variant of PCRE
pcre-utf32.i686 : UTF-32 variant of PCRE
pcre-utf32.x86_64 : UTF-32 variant of PCRE
pcre2-devel.i686 : Development files for pcre2
pcre2-devel.x86_64 : Development files for pcre2
pcre2-syntax.noarch : Documentation for PCRE2 regular expressions
pcre2-utf16.i686 : UTF-16 variant of PCRE2
pcre2-utf16.x86_64 : UTF-16 variant of PCRE2
pcre2-utf32.x86_64 : UTF-32 variant of PCRE2
pcre2-utf32.i686 : UTF-32 variant of PCRE2
postfix-pcre.x86_64 : Postfix PCRE map support
================================ Name Matched: pcre =================================
pcre2.x86_64 : Perl-compatible regular expression library
pcre2.i686 : Perl-compatible regular expression library

[root@nginx-node1 nginx-1.24.0]# dnf install pcre-devel.x86_64 -y

安装完之后继续执行configure检测环境

bash 复制代码
[root@nginx-node1 nginx-1.24.0]# dnf search openssl
Updating Subscription Management repositories.
Unable to read consumer identity

This system is not registered with an entitlement server. You can use "rhc" or "subscription-manager" to register.

Last metadata expiration check: 0:35:35 ago on Fri 16 Aug 2024 10:50:42 AM CST.
=========================== Name Exactly Matched: openssl ===========================
openssl.x86_64 : Utilities from the general purpose cryptography library with TLS
               : implementation
========================== Name & Summary Matched: openssl ==========================
apr-util-openssl.x86_64 : APR utility library OpenSSL crypto support
openssl-devel.i686 : Files for development of applications which will use OpenSSL
openssl-devel.x86_64 : Files for development of applications which will use OpenSSL
openssl-fips-provider.x86_64 : FIPS module for OpenSSL
openssl-fips-provider.i686 : FIPS module for OpenSSL
openssl-perl.x86_64 : Perl scripts provided with OpenSSL
openssl-pkcs11.i686 : A PKCS#11 engine for use with OpenSSL
openssl-pkcs11.x86_64 : A PKCS#11 engine for use with OpenSSL
perl-Crypt-OpenSSL-Bignum.x86_64 : Perl interface to OpenSSL for Bignum
perl-Crypt-OpenSSL-RSA.x86_64 : Perl interface to OpenSSL for RSA
perl-Crypt-OpenSSL-Random.x86_64 : OpenSSL/LibreSSL pseudo-random number generator
                                 : access
rsyslog-openssl.x86_64 : TLS protocol support for rsyslog via OpenSSL library
xmlsec1-openssl.x86_64 : OpenSSL crypto plugin for XML Security Library
xmlsec1-openssl.i686 : OpenSSL crypto plugin for XML Security Library
=============================== Name Matched: openssl ===============================
compat-openssl11.i686 : Utilities from the general purpose cryptography library with
                      : TLS implementation
compat-openssl11.x86_64 : Utilities from the general purpose cryptography library
                        : with TLS implementation
openssl-libs.x86_64 : A general purpose cryptography library with TLS implementation
openssl-libs.i686 : A general purpose cryptography library with TLS implementation
============================= Summary Matched: openssl ==============================
perl-Net-SSLeay.x86_64 : Perl extension for using OpenSSL
qatengine.x86_64 : Intel QuickAssist Technology (QAT) OpenSSL Engine

[root@nginx-node1 nginx-1.24.0]# dnf install openssl-devel.x86_64 -y

继续检测

bash 复制代码
[root@nginx-node1 nginx-1.24.0]# dnf install zlib-devel -y

继续检测

bash 复制代码
# 看到这个界面就是检测全部通过,检测通过之后会生成一个Makefile的文件
[root@nginx-node1 nginx-1.24.0]# ls
auto     CHANGES.ru  configure  html     Makefile  objs    src
CHANGES  conf        contrib    LICENSE  man       README

# 将之前的操作还原
[root@nginx-node1 nginx-1.24.0]# make clean 
rm -rf Makefile objs
[root@nginx-node1 nginx-1.24.0]# ls
auto  CHANGES  CHANGES.ru  conf  configure  contrib  html  LICENSE  man  README  src

# 重新检测又会重新生成Makefile和objs
[root@nginx-node1 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-staream --with-stream_ssl_module 

[root@nginx-node1 nginx-1.24.0]# ls
auto     CHANGES.ru  configure  html     Makefile  objs    src
CHANGES  conf        contrib    LICENSE  man       README

[root@nginx-node1 nginx-1.24.0]# cd objs/
[root@nginx-node1 objs]# ls
autoconf.err  Makefile  ngx_auto_config.h  ngx_auto_headers.h  ngx_modules.c  src
[root@nginx-node1 objs]# cd ..
[root@nginx-node1 nginx-1.24.0]# ls
auto     CHANGES.ru  configure  html     Makefile  objs    src
CHANGES  conf        contrib    LICENSE  man       README
[root@nginx-node1 nginx-1.24.0]# make -j2

[root@nginx-node1 nginx-1.24.0]# ls
auto     CHANGES.ru  configure  html     Makefile  objs    src
CHANGES  conf        contrib    LICENSE  man       README
[root@nginx-node1 nginx-1.24.0]# cd objs/
[root@nginx-node1 objs]# ls
autoconf.err  nginx    ngx_auto_config.h   ngx_modules.c  src
Makefile      nginx.8  ngx_auto_headers.h  ngx_modules.o
[root@nginx-node1 objs]# cd src/
[root@nginx-node1 src]# ls
core  event  http  mail  misc  os  stream
[root@nginx-node1 src]# cd stream/
[root@nginx-node1 stream]# ls
ngx_stream_access_module.o      ngx_stream_set_module.o
ngx_stream_core_module.o        ngx_stream_split_clients_module.o
ngx_stream_geo_module.o         ngx_stream_ssl_module.o
ngx_stream_handler.o            ngx_stream_upstream_hash_module.o
ngx_stream_limit_conn_module.o  ngx_stream_upstream_least_conn_module.o
ngx_stream_log_module.o         ngx_stream_upstream.o
ngx_stream_map_module.o         ngx_stream_upstream_random_module.o
ngx_stream.o                    ngx_stream_upstream_round_robin.o
ngx_stream_proxy_module.o       ngx_stream_upstream_zone_module.o
ngx_stream_return_module.o      ngx_stream_variables.o
ngx_stream_script.o             ngx_stream_write_filter_module.o

# make install将目录里面的东西拷贝到指定的位置
[root@nginx-node1 nginx-1.24.0]# ls
auto     CHANGES.ru  configure  html     Makefile  objs    src
CHANGES  conf        contrib    LICENSE  man       README
[root@nginx-node1 nginx-1.24.0]# make install 


[root@nginx-node1 sbin]# useradd -s /sbin/nologin -M nginx
[root@nginx-node1 sbin]# id nginx 
uid=1001(nginx) gid=1001(nginx) groups=1001(nginx)
[root@nginx-node1 sbin]# ll
total 5516
-rwxr-xr-x 1 root root 5646216 Aug 16 11:46 nginx
[root@nginx-node1 sbin]# ./nginx 
[root@nginx-node1 sbin]# ps aux | grep nginx 
root       48860  0.0  0.0   9864  2052 ?        Ss   11:50   0:00 nginx: master process ./nginx
nginx      48861  0.0  0.1  14196  5124 ?        S    11:50   0:00 nginx: worker process
root       48865  0.0  0.0 221664  2304 pts/0    S+   11:50   0:00 grep --color=auto nginx
[root@nginx-node1 sbin]# netstat -antlupe | grep nginx 
tcp        0      0 0.0.0.0:80              0.0.0.0:*               LISTEN      0          79571      48860/nginx: master 
bash 复制代码
[root@nginx-node1 sbin]# du -sh nginx 
5.4M	nginx
[root@nginx-node1 sbin]# cd
# 关闭nginx
[root@nginx-node1 ~]# /usr/local/nginx/sbin/nginx -s stop
[root@nginx-node1 ~]# netstat -antlupe | grep nginx 
# 重启nginx
[root@nginx-node1 ~]# /usr/local/nginx/sbin/nginx -s restart


[root@nginx-node1 ~]# ls
anaconda-ks.cfg  Documents  Music         nginx-1.24.0.tar.gz  Pictures  Templates
Desktop          Downloads  nginx-1.24.0  nginx-1.26.2.tar.gz  Public    Videos
[root@nginx-node1 ~]# cd nginx-1.24.0/
[root@nginx-node1 nginx-1.24.0]# ls
auto     CHANGES.ru  configure  html     Makefile  objs    src
CHANGES  conf        contrib    LICENSE  man       README
[root@nginx-node1 nginx-1.24.0]# rm -rf /usr/local/nginx/
[root@nginx-node1 nginx-1.24.0]# make clean 
rm -rf Makefile objs
[root@nginx-node1 nginx-1.24.0]# ls
auto     CHANGES.ru  configure  html     man     src
CHANGES  conf        contrib    LICENSE  README

[root@nginx-node1 nginx-1.24.0]# vim auto/cc/gcc
# 注释下面那一行
bash 复制代码
# 重新检测
[root@nginx-node1 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@nginx-node1 nginx-1.24.0]# make && make install

# 把nginx软件的命令执行路径添加到环境变量中
[root@nginx-node1 nginx-1.24.0]# cd
[root@nginx-node1 ~]# vim ~/.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

[root@nginx-node1 ~]# source ~/.bash_profile 
[root@nginx-node1 ~]# du -sh /usr/local/nginx/sbin/nginx 
1.2M	/usr/local/nginx/sbin/nginx
[root@nginx-node1 ~]# nginx 

nginx启动后浏览器访问172.25.254.100

bash 复制代码
[root@nginx-node1 ~]# cd /usr/local/nginx/
[root@nginx-node1 nginx]# ls
client_body_temp  fastcgi_temp  logs        sbin       uwsgi_temp
conf              html          proxy_temp  scgi_temp
[root@nginx-node1 nginx]# cd conf/
[root@nginx-node1 conf]# ls
fastcgi.conf            koi-win             scgi_params
fastcgi.conf.default    mime.types          scgi_params.default
fastcgi_params          mime.types.default  uwsgi_params
fastcgi_params.default  nginx.conf          uwsgi_params.default
koi-utf                 nginx.conf.default  win-utf
[root@nginx-node1 conf]# curl -I 172.25.254.100
HTTP/1.1 200 OK
Server: nginx/1.24.0
Date: Fri, 16 Aug 2024 04:54:11 GMT
Content-Type: text/html
Content-Length: 615
Last-Modified: Fri, 16 Aug 2024 04:47:28 GMT
Connection: keep-alive
ETag: "66bed9e0-267"
Accept-Ranges: bytes
Nginx的平滑升级及版本回滚

先在官网上下载1.26.2版本的nginx

bash 复制代码
[root@nginx-node1 ~]# ll
total 2308
-rw-------. 1 root  root      992 Aug  4 00:54 anaconda-ks.cfg
drwxr-xr-x. 2 root  root        6 Aug  4 00:54 Desktop
drwxr-xr-x. 2 root  root        6 Aug  4 00:54 Documents
drwxr-xr-x. 2 root  root        6 Aug  4 00:54 Downloads
drwxr-xr-x. 2 root  root        6 Aug  4 00:54 Music
drwxr-xr-x  9 nginx nginx     186 Aug 16 12:46 nginx-1.24.0
-rw-r--r--  1 root  root  1112471 Aug 16 09:17 nginx-1.24.0.tar.gz
-rw-r--r--  1 root  root  1244789 Aug 13 00:39 nginx-1.26.2.tar.gz
drwxr-xr-x. 2 root  root        6 Aug  4 00:54 Pictures
drwxr-xr-x. 2 root  root        6 Aug  4 00:54 Public
drwxr-xr-x. 2 root  root        6 Aug  4 00:54 Templates
drwxr-xr-x. 2 root  root        6 Aug  4 00:54 Videos

加载模块

echo-nginx-module-0.63.tar.gz模块上传到系统中并解压

bash 复制代码
[root@nginx-node1 ~]# tar zxf echo-nginx-module-0.63.tar.gz 
[root@nginx-node1 ~]# ll
total 2364
-rw-------. 1 root  root      992 Aug  4 00:54 anaconda-ks.cfg
drwxr-xr-x. 2 root  root        6 Aug  4 00:54 Desktop
drwxr-xr-x. 2 root  root        6 Aug  4 00:54 Documents
drwxr-xr-x. 2 root  root        6 Aug  4 00:54 Downloads
drwxrwxr-x  5 root  root      174 Aug  1  2022 echo-nginx-module-0.63
-rw-r--r--  1 root  root    53421 Aug 16 09:17 echo-nginx-module-0.63.tar.gz
drwxr-xr-x. 2 root  root        6 Aug  4 00:54 Music
drwxr-xr-x  9 nginx nginx     186 Aug 16 12:46 nginx-1.24.0
-rw-r--r--  1 root  root  1112471 Aug 16 09:17 nginx-1.24.0.tar.gz
-rw-r--r--  1 root  root  1244789 Aug 13 00:39 nginx-1.26.2.tar.gz
drwxr-xr-x. 2 root  root        6 Aug  4 00:54 Pictures
drwxr-xr-x. 2 root  root        6 Aug  4 00:54 Public
drwxr-xr-x. 2 root  root        6 Aug  4 00:54 Templates
drwxr-xr-x. 2 root  root        6 Aug  4 00:54 Videos
bash 复制代码
# 解压nginx-1.26.2.tar.gz安装包
[root@nginx-node1 ~]# tar zxf nginx-1.26.2.tar.gz 
[root@nginx-node1 ~]# ll
total 2364
-rw-------. 1 root  root      992 Aug  4 00:54 anaconda-ks.cfg
drwxr-xr-x. 2 root  root        6 Aug  4 00:54 Desktop
drwxr-xr-x. 2 root  root        6 Aug  4 00:54 Documents
drwxr-xr-x. 2 root  root        6 Aug  4 00:54 Downloads
drwxrwxr-x  5 root  root      174 Aug  1  2022 echo-nginx-module-0.63
-rw-r--r--  1 root  root    53421 Aug 16 09:17 echo-nginx-module-0.63.tar.gz
drwxr-xr-x. 2 root  root        6 Aug  4 00:54 Music
drwxr-xr-x  9 nginx nginx     186 Aug 16 12:46 nginx-1.24.0
-rw-r--r--  1 root  root  1112471 Aug 16 09:17 nginx-1.24.0.tar.gz
drwxr-xr-x  8   502 games     158 Aug 13 00:39 nginx-1.26.2
-rw-r--r--  1 root  root  1244789 Aug 13 00:39 nginx-1.26.2.tar.gz
drwxr-xr-x. 2 root  root        6 Aug  4 00:54 Pictures
drwxr-xr-x. 2 root  root        6 Aug  4 00:54 Public
drwxr-xr-x. 2 root  root        6 Aug  4 00:54 Templates
drwxr-xr-x. 2 root  root        6 Aug  4 00:54 Videos

# 检测环境
[root@nginx-node1 ~]# cd nginx-1.26.2/
[root@nginx-node1 nginx-1.26.2]# ls
auto     CHANGES.ru  configure  html     man     src
CHANGES  conf        contrib    LICENSE  README
# 检测1.26.2版本的时候需要增加一个参数--add-module=/root/echo-nginx-module-0.63,在编译nginx这个版本的时候会把echo-nginx-module-0.63这个模块在nginx中加进去,让Nginx在内部可以具备echo命令的功能。
[root@nginx-node1 nginx-1.26.2]# ./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_gzip_static_module --with-http_stub_status_module --with-pcre --with-stream --with-stream_ssl_module 

[root@nginx-node1 nginx-1.26.2]# make

[root@nginx-node1 nginx-1.26.2]# cd objs/
[root@nginx-node1 objs]# ls
addon         Makefile  nginx.8            ngx_auto_headers.h  ngx_modules.o
autoconf.err  nginx     ngx_auto_config.h  ngx_modules.c       src
[root@nginx-node1 objs]# cd /usr/local/nginx/sbin/
[root@nginx-node1 sbin]# ls
nginx
[root@nginx-node1 sbin]# cp nginx nginx.24
[root@nginx-node1 sbin]# ls
nginx  nginx.old
[root@nginx-node1 sbin]# \cp -f /root/nginx-1.26.2/objs/nginx /usr/local/nginx/sbin/[root@nginx-node1 sbin]# ll
total 7208
-rwxr-xr-x 1 root root 6144176 Aug 16 14:32 nginx
-rwxr-xr-x 1 root root 1229024 Aug 16 14:31 nginx.old

[root@nginx-node1 sbin]# ps aux | grep nginx
root       55464  0.0  0.0   9864  2052 ?        Ss   14:48   0:00 nginx: master process nginx
nginx      55465  0.0  0.1  14200  5380 ?        S    14:48   0:00 nginx: worker process
root       55489  0.0  0.0 221664  2304 pts/0    S+   14:50   0:00 grep --color=auto nginx

#USR2 平滑升级可执行程序,将存储有旧版本主进程PID的文件重命名为nginx.pid.oldbin,并启动新的nginx
#此时两个master的进程都在运行,只是旧的master不在监听,由新的master监听80
#此时Nginx开启一个新的master进程,这个master进程会生成新的worker进程,这就是升级后的Nginx进程,此时老的进程不会自动退出,但是当接收到新的请求不作处理而是交给新的进程处理。
[root@nginx-node1 sbin]# kill -USR2 55464
[root@nginx-node1 sbin]# ps aux | grep nginx
root       55464  0.0  0.0   9864  2564 ?        Ss   14:48   0:00 nginx: master process nginx
nginx      55465  0.0  0.1  14200  5380 ?        S    14:48   0:00 nginx: worker process
root       55490  0.0  0.1   9764  6656 ?        S    14:50   0:00 nginx: master process nginx
nginx      55491  0.0  0.1  14228  5132 ?        S    14:50   0:00 nginx: worker process
root       55493  0.0  0.0 221664  2304 pts/0    S+   14:50   0:00 grep --color=auto nginx

# 回收旧版本
[root@nginx-node1 sbin]# kill -WINCH 55464

[root@nginx-node1 ~]# curl -I 172.25.254.100
HTTP/1.1 200 OK
Server: nginx/1.26.2   #新版本生效
Date: Fri, 16 Aug 2024 06:56:05 GMT
Content-Type: text/html
Content-Length: 615
Last-Modified: Fri, 16 Aug 2024 04:47:28 GMT
Connection: keep-alive
ETag: "66bed9e0-267"
Accept-Ranges: bytes


#回滚
#如果升级的版本发现问题需要回滚,可以重新拉起旧版本的worker
[root@nginx-node1 sbin]# kill -HUP 55464
[root@nginx-node1 sbin]# 
[root@nginx-node1 sbin]# ps aux | grep nginx
root       55464  0.0  0.0   9864  2564 ?        Ss   14:48   0:00 nginx: master process nginx
root       55490  0.0  0.1   9764  6656 ?        S    14:50   0:00 nginx: master process nginx
nginx      55491  0.0  0.1  14228  5388 ?        S    14:50   0:00 nginx: worker process
nginx      55497  0.0  0.1  14200  5124 ?        S    14:58   0:00 nginx: worker process
root       55499  0.0  0.0 221664  2304 pts/0    S+   14:58   0:00 grep --color=auto nginx
[root@nginx-node1 sbin]# kill -WINCH 55490
[root@nginx-node1 sbin]# ps aux | grep nginx
root       55464  0.0  0.0   9864  2564 ?        Ss   14:48   0:00 nginx: master process nginx
root       55490  0.0  0.1   9764  6656 ?        S    14:50   0:00 nginx: master process nginx
nginx      55497  0.0  0.1  14200  5124 ?        S    14:58   0:00 nginx: worker process
root       55501  0.0  0.0 221664  2304 pts/0    S+   14:59   0:00 grep --color=auto nginx

[root@nginx-node1 ~]# curl -I 172.25.254.100
HTTP/1.1 200 OK
Server: nginx/1.24.0   # 旧版本回滚完成
Date: Fri, 16 Aug 2024 06:59:50 GMT
Content-Type: text/html
Content-Length: 615
Last-Modified: Fri, 16 Aug 2024 04:47:28 GMT
Connection: keep-alive
ETag: "66bed9e0-267"
Accept-Ranges: bytes

自定义Nginx版本信息

目录:/root/nginx-1.24.0/src/core

文件:nginx.h

Nginx架构和进程

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调用,获取响应数据

  • 与后端服务器通信,接收后端服务器的处理结果

  • 缓存数据,访问缓存索引,查询和调用缓存数据

  • 发送请求结果,响应客户的请求

  • 接收主程序指令,比如重启、升级和退出等

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启动和HTTP建立连接
  • Nginx 启动时,Master 进程,加载配置文件

  • Master 进程,初始化监听的 socket

  • Master 进程,fork 出多个 Worker 进程

  • Worker 进程,竞争新的连接,获胜方通过三次握手,建立 Socket 连接,并处理请求

Nginx命令常用参数

bash 复制代码
Usage: nginx [-?hvVtTq] [-s signal] [-c filename] [-p prefix] [-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信号 会生成新的worker,但master不会重新生成
-p prefix : set prefix path (default: /etc/nginx/) #指定Nginx 目录
-c filename : set configuration file (default: /etc/nginx/nginx.conf) #配置文件路径
-g directives : set global directives out of configuration file #设置全局指令,注意和配置文件不要同时配置,否则冲突

[root@nginx-node1 sbin]# nginx -v
nginx version: nginx/1.26.2
[root@nginx-node1 sbin]# nginx -V
nginx version: nginx/1.26.2
built by gcc 11.4.1 20231218 (Red Hat 11.4.1-3) (GCC) 
built with OpenSSL 3.0.7 1 Nov 2022
TLS SNI support enabled
configure arguments: --prefix=/usr/local/nginx --user=nginx --group=ngino-nginx-module-0.63 --with-http_ssl_module --with-http_v2_module --with-h-http_gzip_static_module --with-http_stub_status_module --with-pcre --w_ssl_module
[root@nginx-node1 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
[root@nginx-node1 sbin]# nginx -s reload
[root@nginx-node1 sbin]# 
[root@nginx-node1 sbin]# ps axf | grep nginx
  55672 pts/0    S+     0:00  |           \_ grep --color=auto nginx
  55464 ?        Ss     0:00 nginx: master process nginx
  55490 ?        S      0:00  \_ nginx: master process nginx
  55669 ?        S      0:00  |   \_ nginx: worker process
  55534 ?        S      0:00  \_ nginx: worker process

Nginx服务的启动脚本

bash 复制代码
[root@nginx-node1 sbin]# ll
total 6004
-rwxr-xr-x 1 root root 6144176 Aug 16 22:04 nginx
[root@nginx-node1 sbin]# 
[root@nginx-node1 sbin]# 
[root@nginx-node1 sbin]# nginx 
[root@nginx-node1 sbin]# ps aux | grep nginx
root       55793  0.0  0.0   9896  2064 ?        Ss   22:05   0:00 nginx: master process nginx
nginx      55794  0.0  0.1  14240  5136 ?        S    22:05   0:00 nginx: worker process
root       55796  0.0  0.0 221664  2304 pts/0    S+   22:05   0:00 grep --color=auto nginx
[root@nginx-node1 sbin]# nginx -s stop
[root@nginx-node1 sbin]# ps aux | grep nginx
root       55799  0.0  0.0 221664  2304 pts/0    S+   22:05   0:00 grep --color=auto nginx
[root@nginx-node1 sbin]# nginx -v
nginx version: nginx/1.26.2

[root@nginx-node1 sbin]# vim /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 #指定哪些服务在启动Nginx的时候被激活
Wants=network-online.target  #期望什么服务在启动时被激活

[Service]
Type=forking  # 类型
PIDFile=/usr/local/nginx/logs/nginx.pid #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-node1 sbin]# systemctl daemon-reload 
[root@nginx-node1 sbin]# nginx -s stop
[root@nginx-node1 sbin]# ps aux | grep nginx
root       55844  0.0  0.0 221664  2304 pts/0    S+   22:07   0:00 grep --color=auto nginx
[root@nginx-node1 sbin]# systemctl enable --now nginx
Created symlink /etc/systemd/system/multi-user.target.wants/nginx.service → /usr/lib/systemd/system/nginx.service.
[root@nginx-node1 sbin]# ps aux | grep nginx
root       55887  0.0  0.0   9892  2068 ?        Ss   22:07   0:00 nginx: master process /usr/local/nginx/sbin/nginx
nginx      55888  0.0  0.1  14240  5012 ?        S    22:07   0:00 nginx: worker process
root       55890  0.0  0.0 221664  2304 pts/0    S+   22:07   0:00 grep --color=auto 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 主配置文件的配置指令方式:

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
}
全局配置

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

bash 复制代码
[root@nginx-node1 sbin]# cd
[root@nginx-node1 ~]# vim /usr/local/nginx/conf/nginx.conf
user  nginx;
worker_processes  auto;
worker_cpu_affinity 0001 0010;  # 双核

#error_log  logs/error.log;
#error_log  logs/error.log  notice;
#error_log  logs/error.log  info;

#pid        logs/nginx.pid;

================省略===============

[root@nginx-node1 ~]# nginx -s reload
# 此时就会出现两个核心
[root@nginx-node1 ~]# ps aux | grep nginx
root       55887  0.0  0.0  10024  3476 ?        Ss   22:07   0:00 nginx: master process /usr/local/nginx/sbin/nginx
nginx      55943  0.0  0.1  14364  5008 ?        S    22:29   0:00 nginx: worker process
nginx      55944  0.0  0.1  14364  5008 ?        S    22:29   0:00 nginx: worker process
root       55946  0.0  0.0 221664  2304 pts/0    S+   22:29   0:00 grep --color=auto nginx


# 修改pam限制
[root@nginx-node1 ~]# vim /etc/security/limits.conf
# 在文件末尾添加
nginx            -      nofile          100000

[root@nginx-node1 ~]# sudo -u nginx ulimit -a
real-time non-blocking time  (microseconds, -R) unlimited
core file size              (blocks, -c) 0
data seg size               (kbytes, -d) unlimited
scheduling priority                 (-e) 0
file size                   (blocks, -f) unlimited
pending signals                     (-i) 14261
max locked memory           (kbytes, -l) 8192
max memory size             (kbytes, -m) unlimited
open files                          (-n) 100000
pipe size                (512 bytes, -p) 8
POSIX message queues         (bytes, -q) 819200
real-time priority                  (-r) 0
stack size                  (kbytes, -s) 8192
cpu time                   (seconds, -t) unlimited
max user processes                  (-u) 14261
virtual memory              (kbytes, -v) unlimited
file locks                          (-x) unlimited


[root@nginx-node1 ~]# vim /usr/local/nginx/conf/nginx.conf
events {
    worker_connections  100000;  #修改会话连接数
}
[root@nginx-node1 ~]# nginx -s reload

# 测试
[root@nginx-node1 ~]# dnf install httpd-tools -y
[root@nginx-node1 ~]# ab -n 10000 -c 500 http://172.25.254.100/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 172.25.254.100 (be patient)
Completed 1000 requests
Completed 2000 requests
Completed 3000 requests
Completed 4000 requests
Completed 5000 requests
Completed 6000 requests
Completed 7000 requests
Completed 8000 requests
Completed 9000 requests
Completed 10000 requests
Finished 10000 requests


Server Software:        nginx/1.26.2
Server Hostname:        172.25.254.100
Server Port:            80

Document Path:          /index.html
Document Length:        615 bytes

Concurrency Level:      500
Time taken for tests:   0.496 seconds
Complete requests:      10000
Failed requests:        0
Total transferred:      8480000 bytes
HTML transferred:       6150000 bytes
Requests per second:    20146.79 [#/sec] (mean)
Time per request:       24.818 [ms] (mean)
Time per request:       0.050 [ms] (mean, across all concurrent requests)
Transfer rate:          16684.06 [Kbytes/sec] received

Connection Times (ms)
              min  mean[+/-sd] median   max
Connect:        0   10   3.0     10      19
Processing:     3   14   5.1     14      28
Waiting:        0   11   4.4     10      25
Total:         11   24   5.4     23      40

Percentage of the requests served within a certain time (ms)
  50%     23
  66%     26
  75%     28
  80%     29
  90%     32
  95%     34
  98%     36
  99%     37
 100%     40 (longest request)
root和alias
bash 复制代码
[root@nginx-node1 ~]# vim /usr/local/nginx/conf/nginx.conf
events {
    worker_connections  100000;
    use epoll;
}

====================省略====================

 #gzip  on;
    include "/usr/local/nginx/conf.d/*.conf";  #包含子配置文件
    
====================省略====================

[root@nginx-node1 ~]# mkdir -p /usr/local/nginx/conf.d
[root@nginx-node1 ~]# vim /usr/local/nginx/conf.d/vhost.conf
server {
    listen 80;
    server_name www.qwert.org;
    root /data/web/html;
    index index.html;
}
[root@nginx-node1 ~]# mkdir -p /data/web/html
[root@nginx-node1 ~]# echo www.qwert.org > /data/web/html/index.html
[root@nginx-node1 ~]# 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
[root@nginx-node1 ~]# nginx -s reload

在Windows解析文件上添加解析

172.25.254.100 www.qwert.org

浏览器访问测试

bash 复制代码
[root@nginx-node1 ~]# vim /usr/local/nginx/conf.d/vhost.conf
server {
    listen 80;
    server_name www.qwert.org;
    root /data/web/html;
    index index.html;
    location /test1/ {
        root /data/web;
    }
}

[root@nginx-node1 ~]# mkdir -p /data/web/test1
[root@nginx-node1 ~]# echo /data/web/test1 > /data/web/test1/index.html
[root@nginx-node1 ~]# 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
[root@nginx-node1 ~]# nginx -s reload

访问测试

bash 复制代码
[root@nginx-node1 ~]# vim /usr/local/nginx/conf.d/vhost.conf
server {
    listen 80;
    server_name www.qwert.org;
    root /data/web/html;
    index index.html;
    location /test1/ {
        root /data/web;
    }

   location /test2 {
        alias /data/web/test1;
    }
}
[root@nginx-node1 ~]# nginx -s reload

访问测试

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

#匹配优先级从高到低:
(~*|~)> 不带符号 > ^~ > =
bash 复制代码
[root@nginx-node1 ~]# vim /usr/local/nginx/conf.d/vhost.conf 
server {
    listen 80;
    server_name www.qwert.org;
    root /data/web/html;
    index index.html;

   location /test {
        root /data/web;
    }
    
    location = /test {
        root /data/web;
    }
}
[root@nginx-node1 ~]# mkdir -p /data/web/test
[root@nginx-node1 ~]# echo test test test > /data/web/test/index.html
[root@nginx-node1 ~]# nginx -s reload
bash 复制代码
[root@nginx-node1 ~]# vim /usr/local/nginx/conf.d/vhost.conf 
server {
    listen 80;
    server_name www.qwert.org;
    root /data/web/html;
    index index.html;

   location /test {
        root /data/web1;
    }

   location = /test {
        root /data/web2;
    }
}

[root@nginx-node1 ~]# mkdir /data/web{1,2}
[root@nginx-node1 ~]# mkdir /data/web{1,2}/test
[root@nginx-node1 ~]# echo web1 test > /data/web1/test/index.html
[root@nginx-node1 ~]# echo web2 test > /data/web2/test/index.html
[root@nginx-node1 ~]# nginx -s reload
bash 复制代码
[root@nginx-node1 ~]# vim /usr/local/nginx/conf.d/vhost.conf
server {
    listen 80;
    server_name www.qwert.org;
    root /data/web/html;
    index index.html;

   location /test {
        root /data/web1;
    }

   location = /test {
        root /data/web2;
    }

   location ^~ /t {  # 精确匹配以t开头的
        root /data/web1;
    }
}
[root@nginx-node1 ~]# mkdir -p /data/web1/{test1,tee}
[root@nginx-node1 ~]# echo test1 > /data/web1/test1/index.html
[root@nginx-node1 ~]# echo tee > /data/web1/tee/index.html
[root@nginx-node1 ~]# mkdir -p /data/web1/lee
[root@nginx-node1 ~]# echo lee > /data/web1/lee/index.html
[root@nginx-node1 ~]# 
[root@nginx-node1 ~]# nginx -s reload
[root@nginx-node1 ~]# 
bash 复制代码
[root@nginx-node1 ~]# vim /usr/local/nginx/conf.d/vhost.conf 
server {
    listen 80;
    server_name www.qwert.org;
    root /data/web/html;
    index index.html;

   location ~ \.html$ {  #以html结尾
        root /data/web1;
    }
}
[root@nginx-node1 ~]# nginx -s reload
bash 复制代码
[root@nginx-node1 ~]# vim /usr/local/nginx/conf.d/vhost.conf 
server {
    listen 80;
    server_name www.qwert.org;
    root /data/web/html;
    index index.html;

   location /test {
        root /data/web1;
    }

   location = /test {
        root /data/web2;
    }

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

   location ~* \.HTML$ {   #以html结尾,不区分大小写
        root /data/web1;
    }
}
[root@nginx-node1 ~]# nginx -s reload

优先级测试

bash 复制代码
[root@nginx-node1 ~]# mkdir -p /data/web{1..5}
[root@nginx-node1 ~]# mkdir -p /data/web{1..5}/test
[root@nginx-node1 ~]# echo web1 > /data/web1/test/index.html
[root@nginx-node1 ~]# echo web2 > /data/web2/test/index.html
[root@nginx-node1 ~]# echo web3 > /data/web3/test/index.html
[root@nginx-node1 ~]# echo web4 > /data/web4/test/index.html
[root@nginx-node1 ~]# echo web5 > /data/web5/test/index.html
[root@nginx-node1 ~]# vim /usr/local/nginx/conf.d/vhost.conf 
server {
    listen 80;
    server_name www.qwert.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-node1 ~]# nginx -s reload
bash 复制代码
[root@nginx-node1 ~]# vim /usr/local/nginx/conf.d/vhost.conf 
server {
    listen 80;
    server_name www.qwert.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-node1 ~]# nginx -s reload

取消注释交换web4和web5的位置最后浏览器访问还是web5,所以~~*的优先级是一样的

继续验证

bash 复制代码
[root@nginx-node1 ~]# vim /usr/local/nginx/conf.d/vhost.conf
server {
    listen 80;
    server_name www.qwert.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/web5;
   # }
   #location ~ .html$ {
   #     root /data/web4;
   # }
}
[root@nginx-node1 ~]# nginx -s reload
bash 复制代码
[root@nginx-node1 ~]# vim /usr/local/nginx/conf.d/vhost.conf 
server {
    listen 80;
    server_name www.qwert.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/web5;
   # }
   #location ~ .html$ {
   #     root /data/web4;
   # }


}

[root@nginx-node1 ~]# nginx -s reload

优先级排序:

精确匹配>正则匹配>一般匹配

Nginx下的用户认证
bash 复制代码
# 创建认证文件
[root@nginx-node1 ~]# htpasswd -cm /usr/local/nginx/.htpasswd admin
New password: 
Re-type new password: 
Adding password for user admin
[root@nginx-node1 ~]# cat /usr/local/nginx/.htpasswd 
admin:$apr1$L3M5h8XO$aBF8qjVg6z5SHy1uBaqfp0
[root@nginx-node1 ~]# htpasswd -m /usr/local/nginx/.htpasswd lee
New password: 
Re-type new password: 
Adding password for user lee
[root@nginx-node1 ~]# cat /usr/local/nginx/.htpasswd 
admin:$apr1$L3M5h8XO$aBF8qjVg6z5SHy1uBaqfp0
lee:$apr1$QNC.iHFe$ejcSQ9QwIOsUzL4OJYZ/o0

[root@nginx-node1 ~]# mkdir /data/web/lee
[root@nginx-node1 ~]# echo lee > /data/web/lee/index.html

[root@nginx-node1 ~]# vim /usr/local/nginx/conf.d/vhost.conf
server {
    listen 80;
    server_name www.qwert.org;
    root /data/web/html;
    index index.html;

    location /lee {
        root /data/web;
        auth_basic "input your password!";
        auth_basic_user_file "/usr/local/nginx/.htpasswd";
    }
}
[root@nginx-node1 ~]# nginx -s reload

输入账号密码登录访问到页面

Nginx自定义错误页面

最开始的错误页面是这样,现在重新自定义错误页面

bash 复制代码
[root@nginx-node1 ~]# vim /usr/local/nginx/conf.d/vhost.conf
server {
    listen 80;
    server_name www.qwert.org;
    root /data/web/html;
    index index.html;
    error_page 404 /40x.html;

    location /lee {
        root /data/web;
        auth_basic "input your password!";
        auth_basic_user_file "/usr/local/nginx/.htpasswd";
    }

    location = /40x.html {
        root /data/web/errorpage;
   }
}
[root@nginx-node1 ~]# mkdir -p /data/web/errorpage
[root@nginx-node1 ~]# echo error page > /data/web/errorpage/40x.html
[root@nginx-node1 ~]# nginx -s reload
Nginx下的自定义日志
bash 复制代码
[root@nginx-node1 ~]# vim /usr/local/nginx/conf.d/vhost.conf 
server {
    listen 80;
    server_name www.qwert.org;
    root /data/web/html;
    index index.html;
    error_page 404 /40x.html;
    error_log /var/log/qwert.org/error.log;
    access_log /var/log/qwert.org/access.log;

    location /lee {
        root /data/web;
        auth_basic "input your password!";
        auth_basic_user_file "/usr/local/nginx/.htpasswd";
    }

    location = /40x.html {
        root /data/web/errorpage;
   }
}
[root@nginx-node1 ~]# mkdir /var/log/qwert.org
[root@nginx-node1 ~]# nginx -s reload
[root@nginx-node1 ~]# vim /etc/hosts
127.0.0.1   localhost localhost.localdomain localhost4 localhost4.localdomain4
::1         localhost localhost.localdomain localhost6 localhost6.localdomain6
172.25.254.100	nginx-node1.example.com
172.25.254.100	www.qwert.org
[root@nginx-node1 ~]# curl www.qwert.org
www.qwert.org
[root@nginx-node1 ~]# cat /var/log/qwert.org/access.log 
172.25.254.100 - - [17/Aug/2024:14:37:52 +0800] "GET / HTTP/1.1" 200 14 "-" "curl/7.76.1"
[root@nginx-node1 ~]# curl www.qwert.org/aaa
error page
[root@nginx-node1 ~]# cat /var/log/qwert.org/error.log 
2024/08/17 14:38:26 [error] 56859#0: *10258 open() "/data/web/html/aaa" failed (2: No such file or directory), client: 172.25.254.100, server: www.qwert.org, request: "GET /aaa HTTP/1.1", host: "www.qwert.org"
[root@nginx-node1 ~]# 
Nginx下的文件检测
bash 复制代码
[root@nginx-node1 ~]# vim /usr/local/nginx/conf.d/vhost.conf
server {
    listen 80;
    server_name www.qwert.org;
    root /data/web/html;
    index index.html;
    error_page 404 /40x.html;
    error_log /var/log/qwert.org/error.log;
    access_log /var/log/qwert.org/access.log;
    try_files $uri $uri.html $uri/index.html /error/default.html;

    location /lee {
        root /data/web;
        auth_basic "input your password!";
        auth_basic_user_file "/usr/local/nginx/.htpasswd";
    }

    location = /40x.html {
        root /data/web/errorpage;
   }
}
[root@nginx-node1 ~]# nginx -s reload
[root@nginx-node1 ~]# curl www.qwert.org
www.qwert.org
[root@nginx-node1 ~]# rm -rf /data/web/html/index.html 
[root@nginx-node1 ~]# rm -rf /data/web/html/error
[root@nginx-node1 ~]# curl www.qwert.org
<html>
<head><title>500 Internal Server Error</title></head>
<body>
<center><h1>500 Internal Server Error</h1></center>
<hr><center>nginx/1.26.2</center>
</body>
</html>
[root@nginx-node1 ~]# mkdir -p /data/web/html/error
[root@nginx-node1 ~]# echo error default > /data/web/html/error/default.html
[root@nginx-node1 ~]# curl www.qwert.org
error default
Nginx长链接控制
keepalive_timeout timeout [header_timeout];
#设定保持连接超时时长,0表示禁止长连接,默认为75s
#通常配置在http字段作为站点全局配置

keepalive_requests 数字; 
#在一次长连接上所允许请求的资源的最大数量
#默认为100次,建议适当调大,比如:500
bash 复制代码
[root@nginx-node1 ~]# dnf install telnet -y
[root@nginx-node1 ~]# vim /usr/local/nginx/conf/nginx.conf

==================省略====================
    #keepalive_timeout  0;
    keepalive_timeout  65;
    keepalive_requests 2;
==================省略====================


[root@nginx-node1 ~]# nginx -s reload
[root@nginx-node1 ~]# telnet www.qwert.org 80
Trying 172.25.254.100...
Connected to www.qwert.org.
Escape character is '^]'.
GET / HTTP/1.1
HOST: www.qwert.org

HTTP/1.1 200 OK
Server: nginx/1.26.2
Date: Sat, 17 Aug 2024 07:12:19 GMT
Content-Type: text/html
Content-Length: 14
Last-Modified: Sat, 17 Aug 2024 07:09:20 GMT
Connection: keep-alive
ETag: "66c04ca0-e"
Accept-Ranges: bytes

www.qwert.org
GET / HTTP/1.1
HOST: www.qwert.org

HTTP/1.1 200 OK
Server: nginx/1.26.2
Date: Sat, 17 Aug 2024 07:12:34 GMT
Content-Type: text/html
Content-Length: 14
Last-Modified: Sat, 17 Aug 2024 07:09:20 GMT
Connection: close
ETag: "66c04ca0-e"
Accept-Ranges: bytes

www.qwert.org
Connection closed by foreign host.


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

==================省略====================
    #keepalive_timeout  0;
    keepalive_timeout  65 60;
    keepalive_requests 2;
==================省略====================
Nginx下载服务器
bash 复制代码
[root@nginx-node1 ~]# mkdir /data/web/download
[root@nginx-node1 ~]# 
[root@nginx-node1 ~]# dd if=/dev/zero of=/data/web/download/leefile bs=1M count=100
100+0 records in
100+0 records out
104857600 bytes (105 MB, 100 MiB) copied, 0.032775 s, 3.2 GB/s
[root@nginx-node1 ~]# 
[root@nginx-node1 ~]# vim /usr/local/nginx/conf.d/vhost.conf
server {
    listen 80;
    server_name www.qwert.org;
    root /data/web/html;
    index index.html;
    error_page 404 /40x.html;
    error_log /var/log/qwert.org/error.log;
    access_log /var/log/qwert.org/access.log;
    try_files $uri $uri.html $uri/index.html /error/default.html;

    location /lee {
        root /data/web;
        auth_basic "input your password!";
        auth_basic_user_file "/usr/local/nginx/.htpasswd";
    }

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

   location /download {
        root /data/web;
        autoindex on;
   }

}
[root@nginx-node1 ~]# nginx -s reload

[root@nginx-node1 ~]# curl www.qwert.org/download/
<html>
<head><title>Index of /download/</title></head>
<body>
<h1>Index of /download/</h1><hr><pre><a href="../">../</a>
<a href="leefile">leefile</a>                                            17-Aug-2024 07:49           104857600
</pre><hr></body>
</html>

把时间修改为本地时间

bash 复制代码
[root@nginx-node1 ~]# vim /usr/local/nginx/conf.d/vhost.conf
server {
    listen 80;
    server_name www.qwert.org;
    root /data/web/html;
    index index.html;
    error_page 404 /40x.html;
    error_log /var/log/qwert.org/error.log;
    access_log /var/log/qwert.org/access.log;
    try_files $uri $uri.html $uri/index.html /error/default.html;

    location /lee {
        root /data/web;
        auth_basic "input your password!";
        auth_basic_user_file "/usr/local/nginx/.htpasswd";
    }

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

   location /download {
        root /data/web;
        autoindex on;
        autoindex_localtime on;
   }

}
[root@nginx-node1 ~]# nginx -s reload
[root@nginx-node1 ~]# curl www.qwert.org/download/
<html>
<head><title>Index of /download/</title></head>
<body>
<h1>Index of /download/</h1><hr><pre><a href="../">../</a>
<a href="leefile">leefile</a>                                            17-Aug-2024 15:49           104857600
</pre><hr></body>
</html>

修改文件大小的单位

bash 复制代码
[root@nginx-node1 ~]# vim /usr/local/nginx/conf.d/vhost.conf
server {
    listen 80;
    server_name www.qwert.org;
    root /data/web/html;
    index index.html;
    error_page 404 /40x.html;
    error_log /var/log/qwert.org/error.log;
    access_log /var/log/qwert.org/access.log;
    try_files $uri $uri.html $uri/index.html /error/default.html;

    location /lee {
        root /data/web;
        auth_basic "input your password!";
        auth_basic_user_file "/usr/local/nginx/.htpasswd";
    }

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

   location /download {
        root /data/web;
        autoindex on;
        autoindex_localtime on;
        autoindex_exact_size off;
   }
}

限制下载速度

bash 复制代码
[root@nginx-node1 ~]# vim /usr/local/nginx/conf.d/vhost.conf
server {
    listen 80;
    server_name www.qwert.org;
    root /data/web/html;
    index index.html;
    error_page 404 /40x.html;
    error_log /var/log/qwert.org/error.log;
    access_log /var/log/qwert.org/access.log;
    try_files $uri $uri.html $uri/index.html /error/default.html;

    location /lee {
        root /data/web;
        auth_basic "input your password!";
        auth_basic_user_file "/usr/local/nginx/.htpasswd";
    }

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

   location /download {
        root /data/web;
        autoindex on;   #自动索引功能
        autoindex_localtime on;   #on表示显示本机时间而非GMT(格林威治)时间,默为为off显示GMT时间
        autoindex_exact_size off;   #计算文件确切大小(单位bytes),此为默认值,off只显示大概大小(单位kb、mb、gb)
        limit_rate 1024k;   #限速,默认不限速
   } 
}

Nginx高级配置

Nginx状态页
Active connections: 291
server accepts handled requests
16630948 16630948 31070465
上面三个数字分别对应accepts,handled,requests三个值
Reading: 6 Writing: 179 Waiting: 106
Active connections: #当前处于活动状态的客户端连接数
#包括连接等待空闲连接数=reading+writing+waiting

accepts: #统计总值,Nginx自启动后已经接受的客户端请求连接的总数。

handled: #统计总值,Nginx自启动后已经处理完成的客户端请求连接总数,通常等于accepts,除非有因worker_connections限制等被拒绝的连接

requests: #统计总值,Nginx自启动后客户端发来的总的请求数

Reading: #当前状态,正在读取客户端请求报文首部的连接的连接数,数值越大,说明排队现象严重,性能不足

Writing: #当前状态,正在向客户端发送响应报文过程中的连接数,数值越大,说明访问量很大

Waiting: #当前状态,正在等待客户端发出请求的空闲连接数
开启 keep-alive的情况下,这个值等于active --(reading+writing)
bash 复制代码
[root@nginx-node1 ~]# cd /usr/local/nginx/conf.d/
[root@nginx-node1 conf.d]# vim status.conf
server {
   listen 80;
   server_name status.qwert.org;
   root /data/web/html;
   index index.html;

   location /status {
        stub_status;
   }
}
[root@nginx-node1 conf.d]# nginx -s reload

在Windows本地解析文件中添加域名

172.25.254.100 www.qwert.org status.qwert.org

在浏览器访问测试

指定用户访问状态页

bash 复制代码
[root@nginx-node1 conf.d]# vim status.conf
server {
   listen 80;
   server_name status.qwert.org;
   root /data/web/html;
   index index.html;

   location /status {
        stub_status;
        #auth_basic "login";
        #auth_basic_user_file "/usr/local/nginx/.htpasswd";
        allow 172.25.254.1;  #Windows主机IP地址
        deny all;
   }
}
[root@nginx-node1 conf.d]# nginx -s reload
[root@nginx-node1 conf.d]# vim /etc/hosts
127.0.0.1   localhost localhost.localdomain localhost4 localhost4.localdomain4
::1         localhost localhost.localdomain localhost6 localhost6.localdomain6
172.25.254.100  nginx-node1.example.com
172.25.254.100  www.qwert.org
172.25.254.100  status.qwert.org

[root@nginx-node1 conf.d]# curl status.qwert.org/status
<html>
<head><title>403 Forbidden</title></head>
<body>
<center><h1>403 Forbidden</h1></center>
<hr><center>nginx/1.26.2</center>
</body>
</html>
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;
bash 复制代码
[root@nginx-node1 conf.d]# vim /usr/local/nginx/conf/nginx.conf

================省略==================
  #keepalive_timeout  0;
   keepalive_timeout  65 60;
   keepalive_requests 2;

   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/xml text/javascript application/x-httpd-php image/gif image/png;

================省略==================

[root@nginx-node1 conf.d]# 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
[root@nginx-node1 conf.d]# nginx -s reload

[root@nginx-node1 ~]# echo hello hello > /data/web/html/small.html[root@nginx-node1 ~]# du -sh /usr/local/nginx/logs/access.log 
1.1M	/usr/local/nginx/logs/access.log
[root@nginx-node1 ~]# cat /usr/local/nginx/logs/access.log > /data/web/html/big.html

[root@nginx-node1 ~]# curl --head --compressed 172.25.254.100/small.html
HTTP/1.1 200 OK
Server: nginx/1.26.2
Date: Sat, 17 Aug 2024 08:40:39 GMT
Content-Type: text/html
Content-Length: 12
Last-Modified: Sat, 17 Aug 2024 08:37:51 GMT
Connection: keep-alive
Keep-Alive: timeout=60
ETag: "66c0615f-c"
Accept-Ranges: bytes

[root@nginx-node1 ~]# curl --head --compressed 172.25.254.100/big.html
HTTP/1.1 200 OK
Server: nginx/1.26.2
Date: Sat, 17 Aug 2024 08:40:46 GMT
Content-Type: text/html
Last-Modified: Sat, 17 Aug 2024 08:39:14 GMT
Connection: keep-alive
Keep-Alive: timeout=60
Vary: Accept-Encoding
ETag: W/"66c061b2-106ac8"
Content-Encoding: gzip
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的对应的首部字段名需要为小写,如果有横线需要替换为下划线
bash 复制代码
[root@nginx-node1 conf.d]# vim var.conf
server {
    listen 80;
    server_name var.timinglee.org.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-node1 conf.d]# vim /etc/hosts
[root@nginx-node1 conf.d]# curl -b "key1=lee,key2=lee1" -u lee:lee var.timinglee.org/var?name=lee&&id=6666
172.25.254.100
name=lee
?
/data/web/html
/var
var.timinglee.org
36818
lee
GET
/data/web/html/var
/var?name=lee
http
HTTP/1.1
172.25.254.100
var.timinglee.org
80
curl/7.76.1
key1=lee,key2=lee1
lee1


[root@nginx-node1 conf.d]# vim zdyvar.conf
server {
    listen 80;
    server_name var.timinglee.org;
    root /data/web/html;
    index index.html;

    location /var {
        default_type text/html;
        set $timinglee lee;
        echo $timinglee;
    }
}
[root@nginx-node1 conf.d]# nginx -s reload
[root@nginx-node1 conf.d]# curl -b "key1=lee,key2=lee1" -u lee:lee var.timinglee.org/var?name=lee&&id=6666
lee
Rewrite相关功能
  • Nginx服务器利用 ngx_http_rewrite_module 模块解析和处理rewrite请求

  • 此功能依靠 PCRE(perl compatible regular expression),因此编译之前要安装PCRE库

  • rewrite是nginx服务器的重要功能之一,用于实现URL的重写,URL的重写是非常有用的功能

  • 比如它可以在我们改变网站结构之后,不需要客户端修改原来的书签,也无需其他网站修改我们的链接,就可以设置为访问

  • 另外还可以在一定程度上提高网站的安全性。

bash 复制代码
server {
    listen 80;
    server_name var.qwert.org;
    root /data/web/html;
    index index.html;

    location /var {
        default_type text/html;
        set $timinglee lee;
        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;
        echo $timinglee;
    }

    location /test2 {
    if ( !-e $request_filename ){
        echo "$request_filename is not exist";
     }
    }
}
[root@nginx-node1 conf.d]# nginx -s reload
[root@nginx-node1 conf.d]# curl var.qwert.org/rest2
[root@nginx-node1 conf.d]# curl var.qwert.org/test2
/data/web/html/test2 is not exist


[root@nginx-node1 conf.d]# vim var.conf
server {
    listen 80;
    server_name var.qwert.org;
    root /data/web/html;
    index index.html;

    location /var {
        default_type text/html;
        set $timinglee lee;
        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;
        echo $timinglee;
    }
    location /test2 {
    if ( !-e $request_filename ){
        echo "$request_filename is not exist";
     }
    }

    location /break {
        default_type text/html;
        set $name lee;
        echo $name;
        if ( $http_user_agent = "curl/7.76.1" ){
            break;
        }
        set $id 666;
        echo $id;
    }

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

    location / {
        root /data/web/var;
        index index.html;
        rewrite / http://www.timinglee.com permanent;
        #rewrite / http://www.timinglee.com redirect;
    }
}
[root@nginx-node1 conf.d]# curl var.qwert.org/break
lee

[root@nginx-node1 conf.d]# curl -A "firefox" var.qwert.org/break
lee
666
[root@nginx-node1 conf.d]# curl -I var.qwert.org/return
HTTP/1.1 301 Moved Permanently
Server: nginx/1.26.2
Date: Sun, 18 Aug 2024 11:08:42 GMT
Content-Type: text/html
Content-Length: 169
Connection: keep-alive
Keep-Alive: timeout=60
Location: http://www.baidu.com

[root@nginx-node1 conf.d]# mkdir -p /data/web/html/return
[root@nginx-node1 conf.d]# curl -I var.qwert.org/return
HTTP/1.1 200 OK
Server: nginx/1.26.2
Date: Sun, 18 Aug 2024 11:08:59 GMT
Content-Type: text/html
Connection: keep-alive
Keep-Alive: timeout=60
Vary: Accept-Encoding
[root@nginx-node1 conf.d]# curl -I var.qwert.org
HTTP/1.1 301 Moved Permanently
Server: nginx/1.26.2
Date: Sun, 18 Aug 2024 11:09:30 GMT
Content-Type: text/html
Content-Length: 169
Connection: keep-alive
Keep-Alive: timeout=60
Location: http://www.timinglee.com


# break和last
[root@nginx-node1 conf.d]# vim var.conf 
server {
    listen 80;
    server_name var.qwert.org;
    root /data/web/html;
    index index.html;

    location /break {
        root /data/web/html;
        rewrite ^/break/(.*) /test1/$1 break;
        rewrite ^/test1/(.*) /test2/$2;
    }

    location /last {
        root /data/web/html;
        rewrite ^/last/(.*) /test1/$1 last;
        rewrite ^/test1/(.*) /test2/$2;
    }

    location /test1 {
        default_type text/html;
        return 666 "qwert hahahahahaahhaahahaa";
    }

    location /test2 {
        root /data/web/html;
    }
}
[root@nginx-node1 conf.d]# nginx -s reload
[C:\~]$ curl var.qwert.org/break/index.html
  % Total    % Received % Xferd  Average Speed   Time    Time     Time  Current
                                 Dload  Upload   Total   Spent    Left  Speed
100     6  100     6    0     0    687      0 --:--:-- --:--:-- --:--:--  1000
test1

[C:\~]$ curl var.qwert.org/last/index.html
  % Total    % Received % Xferd  Average Speed   Time    Time     Time  Current
                                 Dload  Upload   Total   Spent    Left  Speed
100    26  100    26    0     0   5106      0 --:--:-- --:--:-- --:--:--  8666
qwert hahahahahaahhaahahaa
全站加密
bash 复制代码
[root@nginx-node1 conf.d]# cd /usr/local/nginx/
[root@nginx-node1 nginx]# mkdir certs
[root@nginx-node1 nginx]# openssl req  -newkey  rsa:2048 -nodes -sha256 -keyout /usr/local/nginx/certs/qwert.org.key -x509  -days 365 -out /usr/local/nginx/certs/qwert.org.crt
[root@nginx-node1 nginx]# vim /usr/local/nginx/conf.d/vhost.conf 
server {
    listen 80;
    listen 443 ssl;
    server_name www.qwert.org;
    root /data/web/html;
    index index.html;
    ssl_certificate /usr/local/nginx/certs/qwert.org.crt;
    ssl_certificate_key /usr/local/nginx/certs/qwert.org.key;
    ssl_session_cache    shared:SSL:1m;
    ssl_session_timeout  5m;

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

        if ( !-e $request_filename ){
            rewrite /(.*) https://$host/index.html redirect;
        }
    }
}
[root@nginx-node1 nginx]# nginx -s reload
防盗链

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

none: #请求报文首部没有referer首部,比如用户直接在浏览器输入域名访问web网站,就没有referer信息。

blocked: #请求报文有referer首部,但无有效值,比如为空。

server_names: #referer首部中包含本主机名及即nginx 监听的server_name。

arbitrary_string: #自定义指定字符串,但可使用*作通配符。

regular expression: #被指定的正则表达式模式匹配到的字符串,要使用~开头
bash 复制代码
[root@nginx-node1 ~]# mkdir -p /data/web/html/images
[root@nginx-node1 ~]# ll /data/web/html/images/
total 776
-rw-r--r-- 1 root root 791331 Aug 18 19:48 lee.jpg
[root@nginx-node1 ~]# ll /data/web/html
-rw-r--r-- 1 root root  598519 Aug 18 19:48 daolian.jpg
[root@nginx-node1 ~]# vim /usr/local/nginx/conf.d/vhost.conf
server {
    listen 80;
    listen 443 ssl;
    server_name www.qwert.org;
    root /data/web/html;
    index index.html;
    ssl_certificate /usr/local/nginx/certs/qwert.org.crt;
    ssl_certificate_key /usr/local/nginx/certs/qwert.org.key;
    ssl_session_cache    shared:SSL:1m;
    ssl_session_timeout  5m;

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

    }
}
[root@nginx-node1 nginx]# nginx -s reload
bash 复制代码
# web10主机,要下载httpd服务
[root@web10 html]# cd /var/www/html/
[root@web10 html]# vim index.html
<html>

  <head>
    <meta http-equiv=Content-Type content="text/html;charset=utf-8">
    <title>盗链</title>
</head>

  <body>
    <img src="http://www.qwert.org/images/lee.png" >
    <h1 style="color:red">欢迎大家</h1>
    <p><a href=http://www.qwert.org>hahahahahhaa</a>出门见喜</p>
  </body>

</html>
[root@web10 html]# systemctl restart httpd

继续点击hahahahahhaa链接

Nginx反向代理及动静分离实现

客户在需要访问后端真实的资源时,首先被定义到Nginx上,Nginx根据我们客户的请求,把资源分别定义到不同的位置,通过location来把资源定义到不同位置。

反向代理: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协议或者tcp协议访问后端服务器。静态

异构代理:用户访问的资源时需要经过处理后才能返回的,比如php,python,等等,这种访问资源需要经过处理才能被访问

配置参数

参数 说明
proxy_pass 用来设置将客户端请求转发给的后端服务器的主机,可以是主机名(将转发至后端服务做为主机头首部)、IP地址:端口的方式,也可以代理到预先设置的主机群组,需要模块ngx_http_upstream_module支持
proxy_hide_header field 用于nginx作为反向代理的时候,在返回给客户端http响应时,隐藏后端服务器相应头部的信息,可以设置在http,server或location块
proxy_pass_header field 透传,默认nginx在响应报文中不传递后端服务器的首部字段Date, Server, X-Pad, X-Accel等参数,如果要传递的话则要使用 proxy_pass_header field声明将后端服务器返回的值传递给客户端,field 首部字段大小不敏感
proxy_pass_request_headers on | off 是否将客户端的请求头部转发给后端服务器,可以设置在http,server或location块,默认即为开启
proxy_set_header 可更改或添加客户端的请求头部信息内容并转发至后端服务器,比如在后端服务器想要获取客户端的真实IP的时候,就要更改每一个报文的头部
proxy_connect_timeout time 配置nginx服务器与后端服务器尝试建立连接的超时时间,默认为60秒
proxy_read_timeout time 配置nginx服务器向后端服务器或服务器组发起read请求后,等待的超时时间,默认60s
proxy_send_timeout time 配置nginx项后端服务器或服务器组发起write请求后,等待的超时 时间,默认60s
proxy_http_version 1.0 用于设置nginx提供代理服务的HTTP协议的版本,默认http 1.0
proxy_ignore_client_abort off 当客户端网络中断请求时,nginx服务器中断其对后端服务器的请求。即如果此项设置为on开启,则服务器会忽略客户端中断并一直等着代理服务执行返回,如果设置为off,则客户端中断后Nginx也会中断客户端请求并立即记录499日志,默认为off。

搭建环境

一台nginx两台后端server

两台后端server下载httpd

bash 复制代码
[root@web10 html]# echo 172.25.254.10 > /var/www/html/index.html
[root@web10 html]# systemctl restart httpd

[root@web20 html]# echo 172.25.254.20 > /var/www/html/index.html
[root@web20 html]# systemctl restart httpd

[root@nginx-node1 ~]# curl 172.25.254.10
172.25.254.10
[root@nginx-node1 ~]# curl 172.25.254.20
172.25.254.20

[root@web20 html]# vim /etc/httpd/conf/httpd.conf
Listen 8080   #监听端口修改为8080

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

[root@web10 html]# dnf install php -y
[root@web10 html]# vim /var/www/html/index.php
<?php
  phpinfo();
?>
[root@web10 html]# systemctl restart httpd

[root@nginx-node1 ~]# cd /usr/local/nginx/conf.d/
[root@nginx-node1 conf.d]# vim vhost.conf 

server {
    listen 80;
    server_name www.qwert.org;

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

    location /static {
        proxy_pass http://172.25.254.20:8080;
    }
}
[root@nginx-node1 conf.d]# nginx -s reload
Nginx反向代理的缓存功能

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

bash 复制代码
[root@nginx-node1 conf.d]# vim /usr/local/nginx/conf/nginx.conf
#gzip  on;
    proxy_cache_path /usr/local/nginx/proxy_cache levels=1:2:2 keys_zone=proxycache:20m inactive=120 max_size=1g;   #添加在nginx.conf http配置段

[root@nginx-node1 conf.d]# vim /usr/local/nginx/conf.d/vhost.conf
server {
    listen 80;
    server_name www.qwert.org;

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

    location /static {
        proxy_pass http://172.25.254.20:8080;
        proxy_cache proxycache;  #指明调用的缓存,缓存名称为proxycache
        proxy_cache_key $request_uri;  ##缓存中用于"键"的内容,默认值:proxy_cache_key $scheme$proxy_host$request_uri
        proxy_cache_valid 200 302 301 10m;  #定义对特定响应码的响应内容的缓存时长,定义在http{...}中
        proxy_cache_valid any 1m;   ##必须指定哪些响应码的缓存
    }
}
[root@nginx-node1 conf.d]# nginx -s reload


[root@web10 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)
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.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

Connection Times (ms)
              min  mean[+/-sd] median   max
Connect:        0    1   0.7      1       4
Processing:     2    5   1.6      5      30
Waiting:        1    4   1.4      4      30
Total:          4    6   1.5      6      31

Percentage of the requests served within a certain time (ms)
  50%      6
  66%      6
  75%      6
  80%      7
  90%      8
  95%      8
  98%      8
  99%      9
 100%     31 (longest request)
[root@nginx-node1 conf.d]# cd /usr/local/nginx/
[root@nginx-node1 nginx]# ls
certs             conf.d        logs         sbin
client_body_temp  fastcgi_temp  proxy_cache  scgi_temp
conf              html          proxy_temp   uwsgi_temp
[root@nginx-node1 nginx]# tree proxy_cache/
proxy_cache/

0 directories, 0 files
[root@nginx-node1 nginx]# tree proxy_cache/
proxy_cache/
└── e
    └── 50
        └── 99
            └── 319432ef3663735a9d3cb4e0c1d9950e

3 directories, 1 file
Nginx的反向代理负载均衡

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

bash 复制代码
[root@nginx-node1 nginx]# cd /usr/local/nginx/conf.d
[root@nginx-node1 conf.d]# vim vhost.conf 
upstream webcluster {
    server 172.25.254.10:80 fail_timeout=15s max_fails=3;
    server 172.25.254.20:8080 fail_timeout=15s max_fails=3;
    server 172.25.254.100:80 backup;
}

server {
    listen 80;
    server_name www.qwert.org;

    location / {
        proxy_pass http://webcluster;
    }     
}   
[root@nginx-node1 conf.d]# nginx -s reload

测试,轮询访问

bash 复制代码
[root@nginx-node1 conf.d]# vim vhost.conf
upstream webcluster {
    ip_hash;
    server 172.25.254.10:80 fail_timeout=15s max_fails=3;
    server 172.25.254.20:8080 fail_timeout=15s max_fails=3;
    #server 172.25.254.100:80 backup;
}

server {
    listen 80;
    server_name www.qwert.org;

    location / {
        proxy_pass http://webcluster;
    }
}
[root@nginx-node1 conf.d]# nginx -s reload

[root@web10 html]# curl www.qwert.org
172.25.254.10
[root@web10 html]# curl www.qwert.org
172.25.254.10
[root@web10 html]# curl www.qwert.org
172.25.254.10
[root@web10 html]# curl www.qwert.org
172.25.254.10
bash 复制代码
[root@nginx-node1 conf.d]# vim vhost.conf
upstream webcluster {
    #ip_hash;
    hash $request_uri consistent;
    server 172.25.254.10:80 fail_timeout=15s max_fails=3;
    server 172.25.254.20:8080 fail_timeout=15s max_fails=3;
    #server 172.25.254.100:80 backup;
}

server {
    listen 80;
    server_name www.qwert.org;

    location / {
        proxy_pass http://webcluster;
    }
}
[root@nginx-node1 conf.d]# nginx -s reload

[root@web10 html]# mkdir -p /var/www/html/static
[root@web10 html]# echo 172.25.254.10 static > /var/www/html/static/index.html
bash 复制代码
[root@nginx-node1 conf.d]# vim vhost.conf 
upstream webcluster {
    #ip_hash;
    #hash $request_uri consistent;
    hash $cookie_lee;
    server 172.25.254.10:80 fail_timeout=15s max_fails=3;
    server 172.25.254.20:8080 fail_timeout=15s max_fails=3;
    #server 172.25.254.100:80 backup;
}

server {
    listen 80;
    server_name www.qwert.org;

    location / {
        proxy_pass http://webcluster;
    }
}
[root@nginx-node1 conf.d]# nginx -s reload

因为hash一致性,所以要与2^32取模

bash 复制代码
[root@nginx-node1 conf.d]# vim vhost.conf
upstream webcluster {
    #ip_hash;
    #hash $request_uri consistent;
    hash $cookie_lee;
    server 172.25.254.10:80 fail_timeout=15s max_fails=3 down;
    server 172.25.254.20:8080 fail_timeout=15s max_fails=3;
    #server 172.25.254.100:80 backup;
}

server {
    listen 80;
    server_name www.qwert.org;

    location / {
        proxy_pass http://webcluster;
    }
}
[root@nginx-node1 conf.d]# nginx -s reload

一直调度在web20上,不会报错是因为hash环

四层负载均衡
bash 复制代码
#在两台后端server上配置dns
[root@web10 html]# dnf install bind -y
[root@web10 html]# vim /etc/named.conf
options {
//      listen-on port 53 { 127.0.0.1; };
//      listen-on-v6 port 53 { ::1; };
        directory       "/var/named";
        dump-file       "/var/named/data/cache_dump.db";
        statistics-file "/var/named/data/named_stats.txt";
        memstatistics-file "/var/named/data/named_mem_stats.txt";
        secroots-file   "/var/named/data/named.secroots";
        recursing-file  "/var/named/data/named.recursing";
//      allow-query     { localhost; };
	
        recursion yes;

        dnssec-validation no;

        managed-keys-directory "/var/named/dynamic";
        geoip-directory "/usr/share/GeoIP";

        pid-file "/run/named/named.pid";
        session-keyfile "/run/named/session.key";

        /* https://fedoraproject.org/wiki/Changes/CryptoPolicy */
        include "/etc/crypto-policies/back-ends/bind.config";
};

[root@web10 html]# vim /etc/named.rfc1912.zones

=====================省略======================
zone "qwert.org" IN {
        type master;        file "qwert.org.zone";
        allow-update { none; };
};  
=====================省略======================

[root@web10 html]# cd /var/named/
[root@web10 named]# cp named.localhost qwert.org.zone -p
[root@web10 named]# vim qwert.org.zone 
$TTL 1D
@       IN SOA  ns.qwert.org.   root.qwert.org. (
                                        0       ; serial
                                        1D      ; refresh
                                        1H      ; retry
                                        1W      ; expire
                                        3H )    ; minimum
        NS      ns.qwert.org.
ns      A       172.25.254.10
www     A       172.25.254.10

[root@web10 named]# systemctl start named
[root@web10 named]# dig www.qwert.org @172.25.254.10

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

;; OPT PSEUDOSECTION:
; EDNS: version: 0, flags:; udp: 1232
; COOKIE: ac76c2625c58a2b50100000066c21c673b6be54bda182c28 (good)
;; QUESTION SECTION:
;www.qwert.org.			IN	A

;; ANSWER SECTION:
www.qwert.org.		86400	IN	A	172.25.254.10

;; Query time: 1 msec
;; SERVER: 172.25.254.10#53(172.25.254.10)
;; WHEN: Mon Aug 19 00:08:07 CST 2024
;; MSG SIZE  rcvd: 86

[root@web10 named]# scp -p /etc/named.{conf,rfc1912.zones} root@172.25.254.20:/etc/
[root@web10 named]# scp -p /var/named/qwert.org.zone root@172.25.254.20:/var/named/qwert.org.zone


# 在20上修改一下配置文件
[root@web20 html]# vim /var/named/qwert.org.zone
$TTL 1D
@       IN SOA  ns.qwert.org.   root.qwert.org. (
                                        0       ; serial
                                        1D      ; refresh
                                        1H      ; retry
                                        1W      ; expire
                                        3H )    ; minimum
        NS      ns.qwert.org.
ns      A       172.25.254.20
www     A       172.25.254.20

[root@web20 named]# chgrp named qwert.org.zone
[root@web20 named]# systemctl restart named
[root@web20 named]# dig www.qwert.org @172.25.254.20

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

;; OPT PSEUDOSECTION:
; EDNS: version: 0, flags:; udp: 1232
; COOKIE: 69374383c53f97260100000066c21e3117a5d87d2d22927d (good)
;; QUESTION SECTION:
;www.qwert.org.			IN	A

;; ANSWER SECTION:
www.qwert.org.		86400	IN	A	172.25.254.20

;; Query time: 0 msec
;; SERVER: 172.25.254.20#53(172.25.254.20)
;; WHEN: Mon Aug 19 00:15:45 CST 2024
;; MSG SIZE  rcvd: 86


# 在nginx主机上编辑配置文件
[root@nginx-node1 conf.d]# vim /usr/local/nginx/conf/nginx.conf
events {
    worker_connections  100000;
    use epoll;
}
include "/usr/local/nginx/tcpconf.d/*.conf";

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

[root@nginx-node1 conf.d]# vim dns.conf
[root@nginx-node1 conf.d]# ls
dns.conf  status.conf  var.conf  vhost.conf
[root@nginx-node1 conf.d]# mv dns.conf /usr/local/nginx/tcpconf.d/
[root@nginx-node1 conf.d]# ls
status.conf  var.conf  vhost.conf
[root@nginx-node1 conf.d]# cd /usr/local/nginx/tcpconf.d/
[root@nginx-node1 tcpconf.d]# ls
dns.conf
stream {
    upstream dns {
	server 172.25.254.10:53 fail_timeout=15s max_fails=3;
	server 172.25.254.20:53 fail_timeout=15s max_fails=3;
    }

    server {
	listen 53 udp reuseport;
	proxy_timeout 20s;
	proxy_pass dns;
    }
}
[root@nginx-node1 tcpconf.d]# 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
[root@nginx-node1 tcpconf.d]# nginx -s reload

# 轮询调度解析
[root@nginx-node1 tcpconf.d]# dig www.qwert.org @172.25.254.100

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

;; OPT PSEUDOSECTION:
; EDNS: version: 0, flags:; udp: 1232
; COOKIE: eb608cc0a3fc4e070100000066c22377c8d445162b401dd2 (good)
;; QUESTION SECTION:
;www.qwert.org.			IN	A

;; ANSWER SECTION:
www.qwert.org.		86400	IN	A	172.25.254.10

;; Query time: 0 msec
;; SERVER: 172.25.254.100#53(172.25.254.100)
;; WHEN: Mon Aug 19 00:38:15 CST 2024
;; MSG SIZE  rcvd: 86

[root@nginx-node1 tcpconf.d]# dig www.qwert.org @172.25.254.100

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

;; OPT PSEUDOSECTION:
; EDNS: version: 0, flags:; udp: 1232
; COOKIE: 29e380655c929b090100000066c223786b53bc42aa6617ab (good)
;; QUESTION SECTION:
;www.qwert.org.			IN	A

;; ANSWER SECTION:
www.qwert.org.		86400	IN	A	172.25.254.20

;; Query time: 1 msec
;; SERVER: 172.25.254.100#53(172.25.254.100)
;; WHEN: Mon Aug 19 00:38:16 CST 2024
;; MSG SIZE  rcvd: 86


#数据库,在两台后端server上安装mariadb-server
[root@web10 named]# dnf install mariadb-server -y
[root@web10 named]# vim /etc/my.cnf.d/mariadb-server.cnf
[mysqld]
server-id=10
datadir=/var/lib/mysql
socket=/var/lib/mysql/mysql.sock
log-error=/var/log/mariadb/mariadb.log
pid-file=/run/mariadb/mariadb.pid

[root@web10 named]# systemctl start mariadb.service 
[root@web20 named]# vim /etc/my.cnf.d/mariadb-server.cnf
[mysqld]
server-id=20
datadir=/var/lib/mysql
socket=/var/lib/mysql/mysql.sock
log-error=/var/log/mariadb/mariadb.log
pid-file=/run/mariadb/mariadb.pid

[root@web20 named]# systemctl start mariadb.service
[root@web10 named]# mysql
Welcome to the MariaDB monitor.  Commands end with ; or \g.
Your MariaDB connection id is 3
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)]> CREATE USER qwert@'%' identified by 'qwert';
Query OK, 0 rows affected (0.001 sec)

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


[root@web20 named]# mysql
Welcome to the MariaDB monitor.  Commands end with ; or \g.
Your MariaDB connection id is 3
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)]> CREATE USER qwert@'%' identified by 'qwert';
Query OK, 0 rows affected (0.001 sec)

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

MariaDB [(none)]> 

[root@nginx-node1 tcpconf.d]# vim dns.conf 
stream {
    upstream dns {
        server 172.25.254.10:53 fail_timeout=15s max_fails=3;
        server 172.25.254.20:53 fail_timeout=15s max_fails=3;
    }

    upstream mysql {
        server 172.25.254.10:3306 fail_timeout=15s max_fails=3;
        server 172.25.254.20:3306 fail_timeout=15s max_fails=3;
    }

    server {
        listen 3306;
        proxy_timeout 60s;
        proxy_pass mysql;
    }

    server {
        listen 53 udp reuseport;
        proxy_timeout 20s;
        proxy_pass dns;
    }
}
[root@nginx-node1 tcpconf.d]# nginx -s reload
[root@nginx-node1 tcpconf.d]# netstat -antlupe | grep 3306
tcp        0      0 0.0.0.0:3306            0.0.0.0:*               LISTEN      0          209412     55887/nginx: master 
[root@nginx-node1 tcpconf.d]# dnf install mariadb -y

#测试
[root@nginx-node1 tcpconf.d]# mysql -u qwert -p -h 172.25.254.100
Enter password: 
Welcome to the MariaDB monitor.  Commands end with ; or \g.
Your MariaDB connection id is 5
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.003 sec)

MariaDB [(none)]> exit
Bye
[root@nginx-node1 tcpconf.d]# mysql -u qwert -p -h 172.25.254.100
Enter password: 
Welcome to the MariaDB monitor.  Commands end with ; or \g.
Your MariaDB connection id is 4
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)]> exit
Bye

实现FastCGI

FastCGI介绍

**CGI:**通用网关接口(Common Gateway Interface/CGI)描述了客户端和服务器程序之间传输数据的一种标准,可以让一个客户端从网页浏览器向执行在网络服务器上的程序请求数据。CGI 独立于任何语言的,CGI 程序可以用任何脚本语言或者是完全独立编程语言实现,只要这个语言可以在这个系统上运行。

  • 用户通过浏览器访问服务器, 发送了一个请求, 请求的url如上
  • 服务器接收数据, 对接收的数据进行解析
  • nginx对于一些登录数据不知道如何处理, nginx将数据发送给了cgi程序
  • 服务器端会创建一个cgi进程,CGI进程执行
    • 加载配置, 如果有需求加载配置文件获取数据
    • 连接其他服务器: 比如数据库
    • 逻辑处理得到结果, 将结果发送给服务器
    • 线程结束生命退出
  • 服务器将cgi处理结果发送给客户端
  • 弊端:在服务器端CGI进程会被频繁的创建销毁,服务器开销大, 效率低

为什么会有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代码的处理。

FastCGI配置指令

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

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

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

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

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
}
FastCGI实战案例

源码编译php

bash 复制代码
# 解决php依赖问题
[root@nginx-node1 ~]# ls
anaconda-ks.cfg                nginx-1.26.2.tar.gz
Desktop                        oniguruma-devel-6.9.6-1.el9.5.x86_64.rpm
Documents                      package.xml
Downloads                      php-8.3.9
echo-nginx-module-0.63         php-8.3.9.tar.gz
echo-nginx-module-0.63.tar.gz  Pictures
memcache-8.2                   Public
memcache-8.2.tgz               srcache-nginx-module-0.33
memc-nginx-module-0.20         srcache-nginx-module-0.33.tar.gz
memc-nginx-module-0.20.tar.gz  Templates
Music                          Videos
nginx-1.26.2
[root@nginx-node1 ~]# yum install -y bzip2 systemd-devel libxml2-devel sqlite-devel libpng-devel libcurl-devel oniguruma-devel

# 解压源码并安装
[root@nginx-node1 ~]# cd nginx-1.26.2/
[root@nginx-node1 nginx-1.26.2]#  ./configure \
--prefix=/usr/local/php \ #安装路径
--with-config-file-path=/usr/local/php/etc \ #指定配置路径
--enable-fpm \ #用cgi方式启动程序
--with-fpm-user=nginx \ #指定运行用户身份
--with-fpm-group=nginx \
--with-curl \ #打开curl浏览器支持
--with-iconv \ #启用iconv函数,转换字符编码
--with-mhash \ #mhash加密方式扩展库
--with-zlib \ #支持zlib库,用于压缩http压缩传输
--with-openssl \ #支持ssl加密
--enable-mysqlnd \ #mysql数据库
--with-mysqli \
--with-pdo-mysql \
--disable-debug \ #关闭debug功能
--enable-sockets \ #支持套接字访问
--enable-soap \ #支持soap扩展协议
--enable-xml \ #支持xml
--enable-ftp \ #支持ftp
--enable-gd \ #支持gd库
--enable-exif \ #支持图片元数据
--enable-mbstring \ #支持多字节字符串
--enable-bcmath \ #打开图片大小调整,用到zabbix监控的时候用到了这个模块
--with-fpm-systemd #支持systemctl 管理cgi

php相关配置

bash 复制代码
[root@nginx-node1 ~]# cd /usr/local/php/etc
[root@nginx-node1 ~]# cd /usr/local/php/etc/
[root@nginx-node1 etc]# cp php-fpm.conf.default php-fpm.conf
[root@nginx-node1 etc]# vim php-fpm.conf
#去掉注释
pid = run/php-fpm.pid #指定pid文件存放位置

[root@nginx-node1 etc]# cd php-fpm.d/
[root@nginx-node1 php-fpm.d]# cp www.conf.default www.conf

#生成主配置文件
[root@nginx-node1 php-fpm.d]# cd /root/php-8.3.9/
[root@nginx-node1 php-8.3.9]# cp php.ini-production /usr/local/php/etc/php.ini
[root@nginx-node1 ~]# vim /usr/local/php/etc/php.ini
[Date]
; Defines the default timezone used by the date functions
; https://php.net/date.timezone
date.timezone = Asia/Shanghai #修改时区

#生成启动文件
[root@nginx-node1 ~]# cd /root/php-8.3.9/
[root@nginx-node1 php-8.3.9]# cp sapi/fpm/php-fpm.service /lib/systemd/system/
# Mounts the /usr, /boot, and /etc directories read-only for processes invoked by
this unit.
#ProtectSystem=full #注释该内容
[root@nginx-node1 php-8.3.9]# systemctl start php-fpm.service

准备php测试页面

bash 复制代码
[root@nginx-node1 ~]# mkdir -p /data/web/php
[root@nginx-node1 ~]# cat /data/web/php/index.php #php测试页面
<?php
phpinfo();
?>

Nginx配置转发

bash 复制代码
[root@nginx-node1 ~]# vim /usr/local/nginx/conf.d/vhost.conf
server {
    listen 80;
    server_name www.qwert.org;
    root /data/web/html;
    index index.html;

    location ~ \.php$ {
        root /data/web/php;
        fastcgi_pass 172.25.254.100:9000;
        fastcgi_index index.php;
        include fastcgi.conf;
    }
}
[root@nginx-node1 ~]# nginx -s reload
[root@nginx-node1 ~]# systemctl restart php-fpm.service

访问验证php测试页面

添加php环境变量

bash 复制代码
[root@nginx-node1 ~]# vim ~/.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-node1 ~]# source ~/.bash_profile
php的动态扩展模块(php的缓存模块)

安装memcache模块

bash 复制代码
[root@nginx-node1 ~]# tar zxf memcache-8.2.tgz
[root@nginx-node1 ~]# cd memcache-8.2/
[root@nginx-node1 memcache-8.2]# yum install autoconf -y
[root@nginx-node1 memcache-8.2]# phpize
[root@nginx-node1 memcache-8.2]# ./configure && make && make install
Installing shared extensions: /usr/local/php/lib/php/extensions/no-debug-non-zts-20230831/
[root@nginx-node1 memcache-8.2]# ls /usr/local/php/lib/php/extensions/no-debug-non-zts-
20230831/
memcache.so opcache.so

复制测试文件到nginx发布目录中

bash 复制代码
[root@nginx-node1 memcache-8.2]# cp example.php memcache.php /data/web/php/
[root@nginx-node1 memcache-8.2]# vim /data/web/php/memcache.php
$VERSION='$Id$';

define('ADMIN_USERNAME','admin');       // Admin Username
define('ADMIN_PASSWORD','lee');         // Admin Password
define('DATE_FORMAT','Y/m/d H:i:s');
define('GRAPH_SIZE',200);
define('MAX_ITEM_DUMP',50);

$MEMCACHE_SERVERS[] = '127.0.0.1:11211'; // add more as an array
#$MEMCACHE_SERVERS[] = 'mymemcache-server2:11211'; // add more as an array

配置php加载memcache模块

bash 复制代码
[root@nginx-node1 ~]# vim /usr/local/php/etc/php.ini
;extension=zip
extension=memcache
;zend_extension=opcache
[root@nginx-node1 ~]# systemctl reload php-fpm
[root@nginx-node1 no-debug-non-zts-20230831]# php -m | grep mem
memcache

部署memcached

bash 复制代码
[root@nginx-node1 ~]# yum install memcached -y
[root@nginx-node1 ~]# systemctl enable --now memcached.service
[root@nginx-node1 ~]# netstat -antlupe | grep memcache
tcp        0      0 127.0.0.1:11211         0.0.0.0:*               LISTEN      980        180281     191583/memcached    
tcp6       0      0 ::1:11211               :::*                    LISTEN      980        180282     191583/memcached    

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

#性能对比
[root@nginx-node1 ~]#  ab -n500 -c10 http://www.qwert.org/index.php
Concurrency Level: 10
Time taken for tests: 0.514 seconds
Complete requests: 500
Failed requests: 44
(Connect: 0, Receive: 0, Length: 44, Exceptions: 0)

[root@nginx-node1 ~]#  ab -n500 -c10 http://www.qwert.org/index.php
Concurrency Level: 10
Time taken for tests: 0.452 seconds
Complete requests: 500
Failed requests: 0

测试

php高速缓存

部署方法

在我们安装的nginx中默认不支持memc和srcache功能,需要借助第三方模块来让nginx支持此功能,所以nginx需要重新编译

bash 复制代码
[root@nginx-node1 ~]# tar zxf srcache-nginx-module-0.33.tar.gz
[root@nginx-node1 ~]# vim /usr/local/nginx/conf.d/vhost.conf
upstream memcache {
    server 127.0.0.1:11211;
    keepalive 512;
}

server {
    listen 80;
    server_name www.qwert.org;
    root /data/web/html;
    index index.html;

    location /memc {
        internal;
        memc_connect_timeout 100ms;
        memc_send_timeout 100ms;
        memc_read_timeout 100ms;
        set $memc_key $query_string;
        set $memc_exptime 300;
        memc_pass memcache;
    }

    location ~ \.php$ {
        root /data/web/php;
        set $key $uri$args;
        srcache_fetch GET /memc $key;
        srcache_store PUT /memc $key;
        fastcgi_pass 172.25.254.100:9000;
        fastcgi_index index.php;
        include fastcgi.conf;
    }
}
[root@nginx-node1 ~]# nginx -s reload

#测试结果
[root@nginx-node1 ~]# ab -n500 -c10 http://www.qwert.org/index.php
Concurrency Level: 10
Time taken for tests: 0.255 seconds
Complete requests: 500
Failed requests: 0

nginx二次开发版本

bash 复制代码
[root@nginx-node1 ~]# killall -9 nginx
[root@nginx-node1 ~]# ps aux | grep nginx
nginx     198165  0.0  0.9 265356 17824 ?        S    18:01   0:00 php-fpm: pool www
nginx     198166  0.0  0.9 265356 16288 ?        S    18:01   0:00 php-fpm: pool www
root      204714  0.0  0.1 221664  2432 pts/3    S+   20:52   0:00 grep --color=auto nginx

[root@nginx-node1 ~]# dnf -yq install gcc pcre-devel openssl-devel perl
[root@nginx-node1 ~]# useradd -r -s /sbin/nologin nginx
[root@nginx-node1 ~]# cd /usr/local/src
[root@nginx-node1 src]# wget https://openresty.org/download/openresty-1.25.3.1.tar.gz
[root@nginx-node1 src]# tar zxf openresty-1.25.3.1.tar.gz
[root@nginx-node1 src]# cd openresty-1.25.3.1/
[root@nginx-node1 openresty-1.25.3.1]# ./configure \
--prefix=/usr/local/openresty \
--with-stream_realip_module \
--with-http_realip_module \
--with-http_ssl_module \
--with-http_v2_module \
--with-http_stub_status_module \
--with-http_gzip_static_module \
--with-pcre \
--with-http_sub_module \
--without-http_memcached_module \
--with-stream \
--with-stream_ssl_module 

[root@nginx-node1 openresty-1.25.3.1]# gmake -j2 && gmake install
[root@nginx-node1 openresty-1.25.3.1]# cd /usr/local/openresty/
[root@nginx-node1 openresty]# ls
bin  COPYRIGHT  luajit  lualib  nginx  pod  resty.index  site
[root@nginx-node1 openresty]# cd bin/
[root@nginx-node1 bin]# ls
md2pod.pl  nginx-xml2pod  openresty  opm  resty  restydoc  restydoc-index
[root@nginx-node1 bin]# ll
total 168
-rwxr-xr-x 1 root root 19185 Aug 19 21:12 md2pod.pl
-rwxr-xr-x 1 root root 15994 Aug 19 21:12 nginx-xml2pod
lrwxrwxrwx 1 root root    37 Aug 19 21:12 openresty -> /usr/local/openresty/nginx/sbin/nginx
-rwxr-xr-x 1 root root 63650 Aug 19 21:12 opm
-rwxr-xr-x 1 root root 36881 Aug 19 21:12 resty
-rwxr-xr-x 1 root root 14957 Aug 19 21:12 restydoc
-rwxr-xr-x 1 root root  8873 Aug 19 21:12 restydoc-index
[root@nginx-node1 bin]# vim ~/.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:/usr/
local/openresty/bin
[root@nginx-node1 bin]# source ~/.bash_profile
[root@nginx-node1 bin]# openresty 
[root@nginx-node1 bin]# netstat -antlulpe | grep 80
tcp        0      0 127.0.0.1:11211         0.0.0.0:*               LISTEN      980        180281     191583/memcached    
tcp        0      0 0.0.0.0:80              0.0.0.0:*               LISTEN      0          227829     215315/nginx: maste 
tcp6       0      0 ::1:11211               :::*                    LISTEN      980        180282     191583/memcached    
相关推荐
m0_748237052 分钟前
Monorepo pnpm 模式管理多个 web 项目
大数据·前端·elasticsearch
JinSoooo5 分钟前
pnpm monorepo 联调方案
前端·pnpm·monorepo
m0_7482449613 分钟前
【AI系统】LLVM 前端和优化层
前端·状态模式
明弟有理想13 分钟前
Chrome RCE 漏洞复现
前端·chrome·漏洞·复现
平行线也会相交14 分钟前
云图库平台(二)前端项目初始化
前端·vue.js·云图库平台
shimmer00816 分钟前
抖音小程序登录(前端通过tt.login获取code换取openId)
前端·小程序·状态模式
嘤嘤怪呆呆狗26 分钟前
【开发问题记录】使用 Docker+Jenkins+Jenkins + gitee 实现自动化部署前端项目 CI/CD(centos7为例)
前端·vue.js·ci/cd·docker·gitee·自动化·jenkins
沛沛老爹29 分钟前
CI/CD是什么?
运维·git·ci/cd
鱼钓猫的小鱼干31 分钟前
table 表格转成 excell 导出
前端·vue·excel
一只搬砖的猹33 分钟前
cJson系列——常用cJson库函数
linux·前端·javascript·python·物联网·mysql·json