1.1 Nginx 概述
1.1.1 Nginx简介
Nginx:engine X ,2002年开发,分为社区版和商业版(nginx plus )
2019年3月11日 F5 Networks 6.7亿美元的价格收购
Nginx是免费的、开源的、高性能的HTTP和反向代理服务器、邮件代理服务器、以及TCP/UDP代理服务器。用于解决C10K问题(10K Connections)
Nginx官网:http://nginx.org
nginx的其它的二次发行版:
-
Tengine:由淘宝网发起的Web服务器项目。它在Nginx的基础上,针对大访问量网站的需求,添加了很多高级功能和特性。Tengine的性能和稳定性已经在大型的网站如淘宝网,天猫商城等得到了很好的检验。它的最终目标是打造一个高效、稳定、安全、易用的Web平台。从2011年12月开始,Tengine成为一个开源项目官网: http://tengine.taobao.org/
-
OpenResty:基于 Nginx 与 Lua 语言的高性能 Web 平台, 章亦春团队开发,官网:http://openresty.org
1.1.2 Nginx的功能和基础特性
-
Nginx的功能
- 静态的web资源服务器html,图片,js,css,txt等静态资源
- http/https协议的反向代理
- 结合FastCGI/uWSGI/SCGI等协议反向代理动态资源请求
- tcp/udp协议的请求转发(反向代理)
- imap4/pop3协议的反向代理
-
Nginx的基础特性
-
模块化设计,较好的扩展性
-
高可靠性
-
支持热部署:不停机更新配置文件,升级版本,更换日志文件
-
低内存消耗:10000个keep-alive连接模式下的非活动连接,仅需2.5M内存
-
event-driven,aio,mmap,sendfile
-
1.1.3 Nginx与web服务的相关
- 虚拟主机(server)
- 支持 keep-alive 和管道连接(利用一个连接做多次请求)
- 访问日志(支持基于日志缓冲提高其性能)
- url rewirte
- 路径别名
- 基于IP及用户的访问控制
- 支持速率限制及并发数限制
- 重新配置和在线升级而无须中断客户的工作进程
1.2 Nginx 架构和进程
1.2.1 Nginx 进程结构
-
web请求处理机制
- 多进程方式:服务器每接收到一个客户端请求就有服务器的主进程生成一个子进程响应客户端,直到用户关闭连接,这样的优势是处理速度快,子进程之间相互独立,但是如果访问过大会导致服务器资源耗尽而无法提供请求
- 多线程方式:与多进程方式类似,但是每收到一个客户端请求会有服务进程派生出一个线程和此客户端进行交互,一个线程的开销远远小于一个进程,因此多线程方式在很大程度减轻了web服务器对系统资源的要求,但是多线程也有自己的缺点,即当多个线程位于同一个进程内工作的时候,可以相互访问同样的内存地址空间,所以他们相互影响,一旦主进程挂掉则所有子线程都不能工作了,IIS服务器使用了多线程的方式,需要间隔一段时间就重启一次才能稳定。
-
Nginx是多进程组织模型,而且是一个由Master主进程和Worker工作进程组成
- Nginx的进程
1.2.2 Nginx进程间的通信
工作进程是由主进程生成的,主进程使用fork()函数,在Nginx服务器启动过程中主进程根据配置文件决定启动工作进程的数量,然后建立一张全局的工作表用于存放当前未退出的所有的工作进程,主进程生成工作进程后会将新生成的工作进程加入到工作进程表中,并建立一个单向的管道并将其传递给工作进程,该管道与普通的管道不同,它是由主进程指向工作进程的单向通道,包含了主进程向工作进程发出的指令、工作进程ID、工作进程在工作进程表中的索引和必要的文件描述符等信息。
主进程与外界通过信号机制进行通信,当接收到需要处理的信号时,它通过管道向相关的工作进程发送正确的指令,每个工作进程都有能力捕获管道中的可读事件,当管道中有可读事件的时候,工作进程就会从管道中读取并解析指令,然后采取相应的执行动作,这样就完成了主进程与工作进程的交互。
-
Nginx的通信过程:
1.2.3 Nginx 启动和HTTP连接建立
- Nginx 启动时,Master 进程,加载配置文件
- Master 进程,初始化监听的 socket
- Master 进程,fork 出多个 Worker 进程
- Worker 进程,竞争新的连接,获胜方通过三次握手,建立 Socket 连接,并处理请求
1.2.4 HTTP处理过程
1.3 Nginx模块介绍
nginx 有多种模块
- 核心模块:是 Nginx 服务器正常运行必不可少的模块,提供错误日志记录 、配置文件解析 、事件驱动机制 、进程管理等核心功能
- 标准HTTP模块:提供 HTTP 协议解析相关的功能,比如: 端口配置 、 网页编码设置 、 HTTP响应头设置 等等
- 可选HTTP模块:主要用于扩展标准的 HTTP 功能,让 Nginx 能处理一些特殊的服务,比如: Flash
- 多媒体传输 、解析 GeoIP 请求、 网络传输压缩 、 安全协议 SSL 支持等
- 邮件服务模块:主要用于支持 Nginx 的 邮件服务 ,包括对 POP3 协议、 IMAP 协议和 SMTP协议的支持
- Stream服务模块: 实现反向代理功能,包括TCP协议代理
- 第三方模块:是为了扩展 Nginx 服务器应用,完成开发者自定义功能,比如: Json 支持、 Lua 支持等
nginx高度模块化,但其模块早期不支持DSO机制;1.9.11 版本支持动态装载和卸载
模块分类:
1.4 Nginx安装
1.4.1 Nginx版本和安装方式
-
Nginx版本
- Mainline version 主要开发版本,一般为奇数版本号,比如1.19
- Stable version 当前最新稳定版,一般为偶数版本,如:1.20
- Legacy versions 旧的稳定版,一般为偶数版本,如:1.18
-
Nginx安装可以使用yum或源码安装,但是推荐使用源码编译安装
- yum的版本比较旧
- 编译安装可以更方便自定义相关路径
- 使用源码编译可以自定义相关功能,更方便业务的上的使用
1.4.2 源码编辑器的安装
编辑器介绍:
编辑器的安装:
[root@nginx ~]# yum install gcc -y
1.4.3 Nginx源码编译安装
官方源码包下载地址:https://nginx.org/en/download.html
源码编译安装:
1.# 安装gcc以及Nginx需要的依赖库
[root@nginx ~]# dnf install gcc pcre-devel zlib-devel openssl-devel -y # 安装Nginx的依赖库,加入在这一步没有安装相关的依赖库,可以通过编译时的error提示来安装相关的依赖库
2.# 创建nginx用户及用户组
[root@nginx ~]# useradd -s /sbin/nologin -M nginx
[root@nginx ~]# id nginx
用户id=1001(nginx) 组id=1001(nginx) 组=1001(nginx)
3.# 下载Nginx的源码包
[root@nginx ~]# wget https://nginx.org/download/nginx-1.24.0.tar.gz
4.# 解压编译Nginx
[root@nginx ~]# tar zxf nginx-1.24.0.tar.gz # 解压nginx源码包
[root@nginx ~]# cd nginx-1.24.0/ # 进入解压目录
[root@nginx nginx-1.24.0]# ls
auto CHANGES.ru configure html man src
CHANGES conf contrib LICENSE README -- 通过configure环境检测来检测Nginx缺少的依赖库
[root@nginx nginx-1.24.0]# ./configure --help # 查看configure环境差检测的参数,来定义需要使用的环境参数
[root@nginx nginx-1.24.0]# vim auto/cc/gcc # 关闭debug功能
# debug
CFLAGS="$CFLAGS -g" -- 注释关闭debug的调试,使生成的二进制文件更小,在安装时的文件占用空间减小
# 开始编译版本
[root@Nginx nginx-1.24.0]# ./configure --prefix=/usr/local/nginx \ # 通过转义符来继续输入下一个参数
> --user=nginx \ # 指定nginx运行用户
> --group=nginx \ # 指定nginx运行组
> --with-http_ssl_module \ # 支持https://
> --with-http_v2_module \ # 支持http版本2
> --with-http_realip_module \ # 支持ip透传
> --with-http_stub_status_module \ # 支持状态页面
> --with-http_gzip_static_module \ # 支持压缩
> --with-pcre \ # 支持正则
> --with-stream \ # 支持tcp反向代理
> --with-stream_ssl_module \ # 支持tcp的ssl加密
> --with-stream_realip_module # 支持tcp的透传ip
[root@Nginx nginx-1.24.0]# make && make install # 最后通过make完成安装
[root@nginx ~]# du -sh /usr/local/nginx//sbin/nginx # 关闭debug功能后的软件包大小
1.2M /usr/local/nginx//sbin/nginx
nginx完成安装以后,有四个主要的目录:
[root@nginx nginx-1.24.0]# ls /usr/local/nginx/
conf html logs sbin
1.4.4 验证版本及编译参数
[root@nginx ~]# vim ~/.bash_profile # 把nginx软件的命令执行路径添加到环境变量中
# User specific environment and startup programs
export PATH=$PATH:/usr/local/nginx/sbin
[root@nginx ~]# source ~/.bash_profile # 刷新环境变量,应用更改的配置,并立即生效
# 此时可以直接调用nginx命令来执行
例如:
# 查看nginx的版本号
[root@nginx ~]# nginx -v 或 -V
nginx version: nginx/1.24.0
# 或在版本中进行查看
[root@nginx ~]# curl -I 172.25.254.60 # 需要先开启nginx -- 此IP为本虚拟机IP
# 打开nginx
[root@nginx ~]# nginx
# 关闭nginx
[root@nginx ~]# nginx -s stop
此时不能使用systemctl来查看nginx的状态,但可通过查看进程来确认是否已经启动或关闭
[root@nginx ~]# ps aux | grep nginx
测试:
[root@nginx ~]# netstat -antlpue | grep nginx # 查看nginx的80端口是否已经监听上
[root@nginx nginx-1.24.0]# echo nginx-172.25.254.60 > /usr/local/nginx/html/index.html
[root@nginx nginx-1.24.0]# curl 172.25.254.60
nginx-172.25.254.60
1.4.5 配置Nginx启动文件
注意::在配置Nginx的启动文件前需要将其nginx服务先关闭,否则当配置完文件再启动时会出现端口占用的情况,导致配置文件无法使用,出现error。
[root@nginx ~]# nginx -s stop
[root@nginx ~]# 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
Wants=network-online.target
[Service]
Type=forking
PIDFile=/usr/local/nginx/logs/nginx.pid
ExecStartPre=/usr/local/nginx/sbin/nginx -t
ExecStart=/usr/local/nginx/sbin/nginx
ExecReload=/usr/local/nginx/sbin/nginx -s reload
ExecStop=/bin/kill -s QUIT $MAINPID
PrivateTmp=true
[Install]
WantedBy=multi-user.target
[root@nginx ~]# systemctl daemon-reload # 通知 systemd 重新加载守护进程的配置文件
[root@nginx ~]# systemctl start nginx # 使用systemctl命令启动nginx服务
1.4.6 隐藏Nginx的版本号
注意:需要在源码编译时进行更改
[root@nginx ~]# vim /root/nginx-1.24.0/src/core/nginx.h
[root@nginx ~]# curl -I 172.25.254.60
HTTP/1.1 200 OK
Server: haha/1.0 # 自定义的名称及版本号
Date: Sat, 17 Aug 2024 14:34:03 GMT
Content-Type: text/html
Content-Length: 20
Last-Modified: Sat, 17 Aug 2024 14:29:08 GMT
Connection: keep-alive
ETag: "66c0b3b4-14"
Accept-Ranges: bytes
1.5 Nginx的命令参数
格式:nginx [参数]
参数 | 作用 |
---|---|
-v | 显示版本和退出 |
-V | 显示版本和编译参数 |
-t | 测试配置文件是否有误 |
-T | 测试并打印 |
-q | 静默模式 |
-s signal | 发送信号,reload信号会生成新的worker,但master不会重新生成(signal — stop, quit, reopen, reload) |
-p prefix | 指定Nginx目录(default: /etc/nginx/) |
-c filename | 配置文件路径(default: /etc/nginx/nginx.conf) |
-g directives | 设置全局指令,注意和配置文件不要同时配置,否则冲突 |
命令参数的使用:
1.# nginx -v --显示版本和退出
[root@nginx ~]# nginx -v
nginx version: nginx/1.24.0
2.# nginx -V --显示版本和编译参数
[root@nginx ~]# nginx -V
nginx version: nginx/1.24.0
built by gcc 11.3.1 20220421 (Red Hat 11.3.1-2) (GCC)
built with OpenSSL 3.0.1 14 Dec 2021
TLS SNI support enabled
configure arguments: --prefix=/usr/local/nginx --user=nginx --group=nginx --with-http_ssl_module --with-http_v2_module --with-http_realip_module --with-http_stub_status_module --with-pcre --with-stream --with-stream_ssl_module --with-http_gzip_static_module --with-stream_realip_module
3. # nginx -t -- 检测nginx的配置文件是否有误
[root@nginx ~]# nginx -t
nginx: the configuration file /usr/local/nginx/conf/nginx.conf syntax is ok
nginx: configuration file /usr/local/nginx/conf/nginx.conf test is successful
4.# nginx -T -- 测试并打印
[root@nginx ~]# 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
# configuration file /usr/local/nginx/conf/nginx.conf:
. . . . . .
5.# nginx -s [stop, quit, reopen, reload]
[root@nginx ~]# nginx -s stop --停止nginx服务
[root@nginx ~]# nginx -s reload -- 在不关闭nginx的情况下重新加载配置文件
6.# nginx -g "worker_processes 6;" -- 可指定开启的worker子进程
[root@nginx ~]# vim /usr/local/nginx/conf/nginx.conf -- 进入nginx的配置文件
#user nobody;
worker_processes 1; -- 需要关闭默认指定开启的worker数量,若指定了这个配置参数,不可指定worker子进程数量
[root@nginx ~]# nginx -s stop -- 先停止nginx服务
[root@nginx ~]# nginx -g "worker_processes 6;" -- 指定开启多个worker
[root@nginx ~]# ps aux | grep nginx -- 查看进程数量
root 47933 0.0 0.0 9836 928 ? Ss 11:33 0:00 nginx: master process nginx -g worker_processes 6;
nginx 47934 0.0 0.2 13724 4828 ? S 11:33 0:00 nginx: worker process
nginx 47935 0.0 0.2 13724 4880 ? S 11:33 0:00 nginx: worker process
nginx 47936 0.0 0.2 13724 4880 ? S 11:33 0:00 nginx: worker process
nginx 47937 0.0 0.2 13724 4880 ? S 11:33 0:00 nginx: worker process
nginx 47938 0.0 0.2 13724 4880 ? S 11:33 0:00 nginx: worker process
nginx 47939 0.0 0.2 13724 4828 ? S 11:33 0:00 nginx: worker process
root 47941 0.0 0.1 221680 2348 pts/0 S+ 11:33 0:00 grep --color=auto nginx
或
[root@Nginx ~]# nginx -g "daemon off;" # nginx在前台运行
1.6 Nginx的平滑升级和版本回滚
有时候我们需要对Nginx版本进行升级以满足对其功能的需求,例如添加新模块,需要新功能,而此时Nginx又在跑着业务无法停掉,这时我们就可能选择平滑升级
1.6.1 平滑升级流程
1.6.2 Nginx的平滑升级和版本回滚案例
1.6.2.1 Nginx的平滑升级
echo-nginx-module
是一个第三方的Nginx模块,由 OpenResty 团队开发,提供了一个灵活的方式来输出文本、变量、子请求结果等内容到客户端响应中。
-
主要功能:
- 输出文本或变量:可以输出指定的文本或变量到客户端响应。
- 支持条件输出:可以根据条件进行选择性输出内容。
- 嵌套和组合:支持在输出中嵌套其他指令或组合多个输出操作。
- 子请求支持:可以发起子请求,并将结果输出到客户端响应。
-
使用场景:
echo-nginx-module
通常用于需要更复杂的响应逻辑的场景,例如:- 动态地返回基于请求信息的内容。
- 测试和调试,输出某些特定的信息。
- 处理和调度复杂的响应过程,比如输出来自不同源的数据。
下载支持Nginx的echo模块,在编译时添加新的功能进行编译;
地址:https://github.com/openresty/echo-nginx-module
下载完成后将其远程传送到Linux虚拟机中,并解压其源码包
[root@nginx ~]# tar zxf echo-nginx-module-0.63.tar.gz # 解压Nginx的echo模块源码包
[root@nginx ~]# wget https://nginx.org/download/nginx-1.26.2.tar.gz # 下载Nginx目前最新的稳定版本
[root@nginx ~]# tar zxf nginx-1.26.2.tar.gz # 解压nginx源码包
[root@nginx ~]# cd nginx-1.26.2/ # 进入解压目录
#开始编译新版本
[root@nginx 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_stub_status_module \
> --with-http_gzip_static_module \
> --with-pcre \
> --with-stream \
> --with-stream_ssl_module \
> --with-stream_realip_module
# 只要make无需要make install
[root@nginx nginx-1.26.2]# make
# 查看两个版本
[root@nginx nginx-1.26.2]# ll objs/nginx /usr/local/nginx/sbin/nginx
# 把之前的旧版的nginx命令备份
[root@nginx nginx-1.26.2]# cd /usr/local/nginx/sbin/
[root@nginx sbin]# cp nginx nginx.24
# 把新版本的nginx命令复制过去
[root@nginx sbin]# \cp -f /root/nginx-1.26.2/objs/nginx /usr/local/nginx/sbin
# 检测一下有没有问题
[root@nginx sbin]# nginx -t
nginx: the configuration file /usr/local/nginx/conf/nginx.conf syntax is ok
nginx: configuration file /usr/local/nginx/conf/nginx.conf test is successful
# 平滑升级
[root@nginx ~]# ps aux | grep nginx # 查看进程ID
[root@Nginx sbin]# kill -USR2 43645 # nginx master worker ID
#USR2 平滑升级可执行程序,将存储有旧版本主进程PID的文件重命名为nginx.pid.oldbin,并启动新的nginx
#此时两个master的进程都在运行,只是旧的master不在监听,由新的master监听80
#此时Nginx开启一个新的master进程,这个master进程会生成新的worker进程,这就是升级后的Nginx进程,此时老的进程不会自动退出,但是当接收到新的请求不作处理而是交给新的进程处理。
# 再查看进程
[root@nginx ~]# ps aux | grep nginx
# 查看此时的版本
[root@nginx sbin]# curl -I localhost
HTTP/1.1 200 OK
Server: nginx/1.24.0 -- 依旧是旧版生效
Date: Sat, 17 Aug 2024 14:59:17 GMT
Content-Type: text/html
Content-Length: 20
Last-Modified: Sat, 17 Aug 2024 14:29:08 GMT
Connection: keep-alive
ETag: "66c0b3b4-14"
Accept-Ranges: bytes
# 也可以使用循环测试来检测在切换版本时naginx是否会掉线
[root@nginx ~]# while true
> do
> curl 172.25.254.60 ; sleep 1
> done
nginx-172.25.254.60
nginx-172.25.254.60
nginx-172.25.254.60
. . . . . .
# 回收旧版本
[root@nginx sbin]# kill -WINCH 43645 -- 回收旧msater的进程ID
[root@nginx sbin]# ps aux | grep nginx
root 43645 0.0 0.1 9836 2596 ? Ss 22:30 0:00 nginx: master process /usr/local/nginx/sbin/nginx
root 46999 0.0 0.3 9872 6076 ? S 22:36 0:00 nginx: master process /usr/local/nginx/sbin/nginx
nginx 47000 0.0 0.2 13760 4720 ? S 22:36 0:00 nginx: worker process
root 47064 0.0 0.1 221812 2340 pts/0 S+ 23:30 0:00 grep --color=auto nginx
# 检测版本信息
[root@nginx sbin]# curl -I localhost
HTTP/1.1 200 OK
Server: nginx/1.26.2 -- 回收完旧版本后切换到新版本
Date: Sat, 17 Aug 2024 15:30:28 GMT
Content-Type: text/html
Content-Length: 20
Last-Modified: Sat, 17 Aug 2024 14:29:08 GMT
Connection: keep-alive
ETag: "66c0b3b4-14"
Accept-Ranges: bytes
1.6.2.2 Nginx的版本回滚
如果升级的版本发现问题需要回滚,可以重新拉起旧版本的worker
# 回滚
[root@nginx sbin]# cp nginx nginx.26 # 将1.26版本的nginx进行备份
[root@nginx sbin]# ls
nginx nginx.24 nginx.26
# 重新启用1.24版本的nginx
[root@nginx sbin]# mv nginx.24 nginx
mv:是否覆盖'nginx'? yes
# 优雅重新加载nginx的配置文件,而不需要停止进程
[root@nginx sbin]# kill -HUP 43645 -- HUP旧master进程
[root@nginx sbin]# ps aux | grep nginx
root 43645 0.0 0.1 9836 2596 ? Ss 22:30 0:00 nginx: master process /usr/local/nginx/sbin/nginx
root 46999 0.0 0.3 9872 6076 ? S 22:36 0:00 nginx: master process /usr/local/nginx/sbin/nginx
nginx 47000 0.0 0.2 13760 4720 ? S 22:36 0:00 nginx: worker process
nginx 47076 0.0 0.2 13724 4796 ? S 23:38 0:00 nginx: worker process
root 47078 0.0 0.1 221812 2296 pts/0 S+ 23:38 0:00 grep --color=auto nginx
# 回收1.26版本的master进程ID
[root@nginx sbin]# ps aux | grep nginx
root 43645 0.0 0.1 9836 2596 ? Ss 22:30 0:00 nginx: master process /usr/local/nginx/sbin/nginx
root 46999 0.0 0.3 9872 6076 ? S 22:36 0:00 nginx: master process /usr/local/nginx/sbin/nginx
nginx 47076 0.0 0.2 13724 4796 ? S 23:38 0:00 nginx: worker process
root 47081 0.0 0.1 221812 2332 pts/0 S+ 23:40 0:00 grep --color=auto nginx
[root@nginx sbin]# kill -9 46999
[root@nginx sbin]# ps aux | grep nginx # 再次查看发现1.26版本的进程已经被关掉
# 查看nginx版本
[root@nginx sbin]# curl -I localhost
HTTP/1.1 200 OK
Server: nginx/1.24.0 # 版本回滚完成
Date: Sat, 17 Aug 2024 15:40:53 GMT
Content-Type: text/html
Content-Length: 20
Last-Modified: Sat, 17 Aug 2024 14:29:08 GMT
Connection: keep-alive
ETag: "66c0b3b4-14"
Accept-Ranges: bytes