当前位置: 首页 > news >正文

服务器之光:Nginx--反向代理模块详解及演练

6.Nginx 反向代理功能

image-20250723143815997

6.1 反向代理

反向代理:reverse proxy,指的是代理外网用户的请求到内部的指定的服务器,并将数据返回给用户的一种方式,这是用的比较多的一种方式。

Nginx 除了可以在企业提供高性能的web服务之外,另外还可以将 nginx 本身不具备的请求通过某种预定义的协议转发至其它服务器处理,不同的协议就是Nginx服务器与其他服务器进行通信的一种规范,主要在不同的场景使用以下模块实现不同的功能

ngx_http_proxy_module:		# 将客户端的请求以http协议转发至指定服务器进行处理
ngx_http_upstream_module 	# 用于定义为proxy_pass,fastcgi_pass,uwsgi_pass# 等指令引用的后端服务器分组ngx_stream_proxy_module:	# 将客户端的请求以tcp协议转发至指定服务器处理
ngx_http_fastcgi_module:	# 将客户端对php的请求以fastcgi协议转发至指定服务器助理
ngx_http_uwsgi_module:		# 将客户端对Python的请求以uwsgi协议转发至指定服务器处理
6.1.1 逻辑调用关系

image-20250723143833376

6.1.2 访问逻辑图

image-20250723143849879

6.1.3 同构代理

用户不需要其他程序的参与,直接通过http协议或者tcp协议访问后端服务器

6.1.4 异构代理

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

image-20250723143911077

6.2 实现 http 反向代理

官方文档: https://nginx.org/en/docs/http/ngx_http_proxy_module.html

6.2.1 http 协议反向代理
1.反向代理配置参数
# 官方文档:https://nginx.org/en/docs/http/ngx_http_proxy_module.html#proxy_pass proxy_pass; 	# 用来设置将客户端请求转发给的后端服务器的主机# 可以是主机名(将转发至后端服务做为主机头首部)、IP地址:端口的方式# 也可以代理到预先设置的主机群组,需要模块ngx_http_upstream_module支持# 示例:location /web {index index.html;proxy_pass http://172.25.254.30:8080; 	# 8080后面无uri,即无 / 符号,# 需要将location后面url 附加到proxy_pass指定的url后面# 此行为类似于root# proxy_pass指定的uri不带斜线将访问的/web# 等于访问后端服务器proxy_pass http://172.25.254.40:8080/;   # 8080后面有uri,即有 / 符号# 相当于置换,即访问/web时实际返回proxy_pass后面uri内容# 此行为类似于alias # proxy_pass指定的uri带斜线# 等于访问后端服务器的# http://172.25.254.40:8080/index.html# 内容返回给客户端}  									# http://nginx/web/index.html ==> http://1:8080# 重启Nginx测试访问效果:
# curl -L http://www.timinglee.org/web# 如果location定义其uri时使用了正则表达式模式(包括~,~*,但不包括^~),则proxy_pass之后必须不能使用uri
# 即不能有/ ,用户请求时传递的uri将直接附加至后端服务器之后
server {...server_name HOSTNAME;location ~|~* /uri/ {proxy_pass http://host:port; 		# proxy_pass后面的url 不能加/}...}http://HOSTNAME/uri/ --> http://host/uri/
proxy_hide_header field;	# 用于nginx作为反向代理的时候# 在返回给客户端http响应时# 隐藏后端服务器相应头部的信息# 可以设置在http,server或location块# 示例: 隐藏后端服务器ETag首部字段location /web {index index.html;proxy_pass http://10.0.0.18:8080/; proxy_hide_header ETag;}
proxy_pass_header field;		# 透传
# 默认nginx在响应报文中不传递后端服务器的首部字段Date, Server, X-Pad, X-Accel等参数
# 如果要传递的话则要使用 proxy_pass_header field声明将后端服务器返回的值传递给客户端
# field 首部字段大小不敏感# 示例:透传后端服务器的Server和Date首部给客户端,同时不再响应报中显示前端服务器的Server字段
proxy_pass_header Server;
proxy_pass_header Date;
proxy_pass_request_body on | off; 
# 是否向后端服务器发送HTTP实体部分,可以设置在http,server或location块,默认即为开启
proxy_pass_request_headers on | off; 
# 是否将客户端的请求头部转发给后端服务器,可以设置在http,server或location块,默认即为开启
proxy_set_header; 
# 可更改或添加客户端的请求头部信息内容并转发至后端服务器,比如在后端服务器想要获取客户端的真实IP的时候,就要更改每一个报文的头部# 示例: location ~ /web {proxy_pass http://172.25.254.20:80;proxy_hide_header ETag;proxy_pass_header Server;proxy_pass_request_body on;proxy_pass_request_headers on;proxy_set_header X-Forwarded-For $remote_addr;}
[root@apache20 ~]# vim /etc/httpd/conf/httpd.confLogFormat "\"%{X-Forwarded-For}i\" %l %u %t \"%r\" %>s %b \"%{Referer}i\" \"%{User-Agent}i\"" combined访问后看后端服务器日志
proxy_connect_timeout time;
# 配置nginx服务器与后端服务器尝试建立连接的超时时间,默认为60秒用法如下:proxy_connect_timeout 6s; 
# 60s为自定义nginx与后端服务器建立连接的超时时间,超时会返回客户端504响应码
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。
2.实战案例: 反向代理单台 web 服务器

要求:将用户对域 www.timinglee.org 的请求转发给后端服务器处理

[root@centos8 ~]# cat /apps/nginx/conf/conf.d/pc.conf
server {listen 80;server_name www.timinglee.org;location / {proxy_pass http://172.25.254.30;}
}
# 重启Nginx 并访问测试
3.实战案例: 指定 location 实现反向代理
  • 针对指定的 location
server {listen 80;server_name www.timinglee.org;location / {proxy_pass http://172.25.254.30;}location ~ /static {proxy_pass http://172.25.254.20:8080;}
}# 后端web服务器必须要有相对于的访问URL
[root@apache20 ~]# mkdir  /var/www/html/static
[root@apache20 ~]# echo static 172.25.254.20 > /var/www/html/static/index.html[root@apache30 ~]# echo 172.25.254.30 > /var/www/html/index.html# 重启Nginx并访问测试:
[2024-07-25 17:09.35]  ~
[Administrator.DESKTOP-P19CNDN]curl www.timinglee.org/static/
static 172.25.254.20[2024-07-25 17:09.39]  ~
[Administrator.DESKTOP-P19CNDN]curl www.timinglee.org
172.25.254.30
  • 针对特定的资源实现代理
image-20250723144020298
[root@Nginx ~]# vim /apps/nginx/conf.d/vhost.conf
server {listen 80;server_name www.timinglee.org;location / {proxy_pass http://172.25.254.30;}location ~ \.(png|jpg|gif) {proxy_pass http://172.25.254.20:8080;}
}
6.2.2 反向代理示例: 缓存功能

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

proxy_cache zone_name | off; 默认off
# 指明调用的缓存,或关闭缓存机制;Context:http, server, location
# zone_name 表示缓存的名称.需要由proxy_cache_path事先定义
proxy_cache_key string;
# 缓存中用于“键”的内容,默认值:proxy_cache_key $scheme$proxy_host$request_uri;
proxy_cache_valid [code ...] time;
# 定义对特定响应码的响应内容的缓存时长,定义在http{...}中示例:proxy_cache_valid 200 302 10m;proxy_cache_valid 404 1m;
proxy_cache_path;
# 定义可用于proxy功能的缓存;Context:http 
proxy_cache_path path [levels=levels] [use_temp_path=on|off] 
keys_zone=zone_name:size [inactive=time] [max_size=size] [manager_files=number] 
[manager_sleep=time] [manager_threshold=time] [loader_files=number] 
[loader_sleep=time] [loader_threshold=time] [purger=on|off] 
[purger_files=number] [purger_sleep=time] [purger_threshold=time];# 示例:在http配置定义缓存信息
proxy_cache_path /var/cache/nginx/proxy_cache # 定义缓存保存路径,proxy_cache会自动创建levels=1:2:2 					  		  # 定义缓存目录结构层次# 1:2:2可以生成2^4x2^8x2^8=2^20=1048576个目录keys_zone=proxycache:20m 	     # 指内存中缓存的大小,主要用于存放key和metadata(如:使用次数)# 一般1M可存放8000个左右的keyinactive=120s  				     # 缓存有效时间max_size=10g; 				     # 最大磁盘占用空间,磁盘存入文件内容的缓存空间最大值
# 调用缓存功能,需要定义在相应的配置段,如server{...};或者location等
proxy_cache proxycache;
proxy_cache_key $request_uri; 		# 对指定的数据进行MD5的运算做为缓存的key
proxy_cache_valid 200 302 301 10m; 	# 指定的状态码返回的数据缓存多长时间
proxy_cache_valid any 1m;   		# 除指定的状态码返回的数据以外的缓存多长时间,必须设置,否则不会缓存proxy_cache_use_stale error | timeout | invalid_header | updating | http_500 | http_502 | http_503 | http_504 | http_403 | http_404 | off ; 	# 默认是off
# 在被代理的后端服务器出现哪种情况下,可直接使用过期的缓存响应客户端
# 示例
proxy_cache_use_stale error http_502 http_503;proxy_cache_methods GET | HEAD | POST ...;
# 对哪些客户端请求方法对应的响应进行缓存,GET和HEAD方法总是被缓存
1.非缓存场景压测
# 准备后端httpd服务器
# RS-1	172.25.254.100	
# RS-2	172.25.254.200	
[root@RS-1 static]# pwd
/var/www/html/static[root@RS-1 static]# cat /var/log/messages > ./log.html			 # 准备测试页面[root@RS-2 ~]# ab -n1000 -c100 http://www.dhj.org/static/index.html
Concurrency Level:      100
Time taken for tests:   25.904 seconds
Complete requests:      1000
Failed requests:        1(Connect: 0, Receive: 0, Length: 1, Exceptions: 0)
Non-2xx responses:      1002
Total transferred:      601866 bytes
HTML transferred:       220 bytes
Requests per second:    38.60 [#/sec] (mean)
Time per request:       2590.352 [ms] (mean)
Time per request:       25.904 [ms] (mean, across all concurrent requests)
Transfer rate:          22.69 [Kbytes/sec] received
2.准备缓存配置
[root@web-a ~]# vim /usr/local/nginx/conf/nginx.conf
proxy_cache_path /usr/local/nginx/cache levels=1:2:2 keys_zone=proxycache:20m inactive=120s max_size=10g;		
# 要写入Nginx的主配置文件中的http段,如下图:[root@web-a ~]# nginx -t
[root@web-a ~]# nginx -s reload[root@Nginx ~]# vim /apps/nginx/conf.d/vhost.conf
server{listen          80;server_name     www.dhj.org;location / {proxy_pass      http://www.dhj.org;proxy_cache     proxycache;					proxy_cache_key $request_uri;proxy_cache_valid 200 302 301 10m;proxy_cache_valid 404 1m;}
}[root@web-a ~]# nginx -t
[root@web-a ~]# nginx -s reload# 将服务重载之后,则会自动生成缓存目录
[root@web-a ~]# ll -d  /usr/local/nginx/cache/
drwx------ 2 nobody root 6 Jul 27 17:52 /usr/local/nginx/cache/

image-20250727174730833

3.访问并验证缓存文件
# 建议一个大文件,并测试
[root@RS-1 ~]# history >> /var/www/html/index.html
[root@RS-1 ~]# history >> /var/www/html/index.html
[root@RS-1 ~]# history >> /var/www/html/index.html
[root@RS-1 ~]# history >> /var/www/html/index.html
[root@RS-1 ~]# history >> /var/www/html/index.html
[root@RS-1 ~]# du -sh  /var/www/html/index.html
8.0K    /var/www/html/index.html# 再次进行压测,并跟前面进行比对
[root@RS-2 ~]# ab -n10000 -c500  http://172.25.254.10/index.html
Concurrency Level:      500
Time taken for tests:   0.813 seconds
Complete requests:      10000
Failed requests:        0
Total transferred:      2440000 bytes
HTML transferred:       140000 bytes
Requests per second:    12300.83 [#/sec] (mean)
Time per request:       40.648 [ms] (mean)
Time per request:       0.081 [ms] (mean, across all concurrent requests)
Transfer rate:          2931.06 [Kbytes/sec] received
6.3 http 反向代理负载均衡

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

官方文档: https://nginx.org/en/docs/http/ngx_http_upstream_module.html

6.3.1 http upstream配置参数
# 自定义一组服务器,配置在http块内
upstream name { server ...........
}#示例
upstream backend {server backend1.example.com weight=5;server 127.0.0.1:8080  max_fails=3 fail_timeout=30s;server unix:/tmp/backend3;server backup1.example.com backup;
}
server address [parameters];
# 配置一个后端web服务器,配置在upstream内,至少要有一个server服务器配置。
# server支持的parameters如下:
weight=number		# 设置权重,默认为1,实现类似于LVS中的WRR,WLC等max_conns=number	# 给当前后端server设置最大活动链接数,默认为0表示没有限制max_fails=number	# 后端服务器的下线条件,当客户端访问时,对本次调度选中的后端服务器连续进行检测多少次,如果都失败就标记为不可用,默认为1次,当客户端访问时,才会利用TCP触发对探测后端服务器健康性检查,而非周期性的探测fail_timeout=time 	# 后端服务器的上线条件,对已经检测到处于不可用的后端服务器,每隔此时间间隔再次进行检测是否恢复可用,如果发现可用,则将后端服务器参与调度,默认为10秒backup  			# 设置为备份服务器,当所有后端服务器不可用时,才会启用此备用服务器down    			# 标记为down状态,可以平滑下线后端服务器resolve 			# 当server定义的是主机名的时候,当A记录发生变化会自动应用新IP而不用重启Nginx
hash KEY [consistent];
# 基于指定请求报文中首部字段或者URI等key做hash计算,使用consistent参数,将使用ketama一致性hash算法,适用于后端是Cache服务器(如varnish)时使用,consistent定义使用一致性hash运算,一致性hash基于取模运算hash $request_uri consistent; 	# 基于用户请求的uri做hash
hash $cookie_sessionid			# 基于cookie中的sessionid这个key进行hash调度,实现会话绑定
ip_hash;
# 源地址hash调度方法,基于的客户端的remote_addr(源地址IPv4的前24位或整个IPv6地址)做hash计算,以实现会话保持
least_conn;
# 最少连接调度算法,优先将客户端请求调度到当前连接最少的后端服务器,相当于LVS中的WLC
6.3.2 反向代理示例: 后端多台 web服务器
1.环境说明
172.25.254.10  # Nginx 代理服务器
172.25.254.100  # 后端web A,Apache部署
172.25.254.200  # 后端web B,Apache部署
2.部署后端 Apache服务器
[root@RS1 ~]# yum install httpd -y
[root@RS1 ~]# echo "web1 172.25.254.100" > /var/www/html/index.html
[root@RS1 ~]# systemctl enable --now httpd[rootRS2  ~]# yum install httpd -y
[root@RS2  ~]# echo "web2 172.25.254.200" >> /var/www/html/index.html
[root@RS2  ~]# systemctl enable --now httpd# 访问测试
[root@Nginx ~]# curl 172.25.254.100
web1 172.25.254.100
[root@Nginx ~]# curl 172.25.254.200
web2 172.25.254.200
3.配置 nginx 反向代理

注意: 本节实验过程中先关闭缓存

[root@Nginx ~]# vim /usr/local/nginx/conf.d/vhost.conf
upstream webserver {#hash $cookie_dhj;server 172.25.254.100:80  weight=1 fail_timeout=15s max_fails=3;server 172.25.254.200:80  weight=1 fail_timeout=15s max_fails=3;
}server{listen          80;server_name     www.dhj.org;location / {proxy_pass      http://www.dhj.org;#       proxy_cache     proxycache;#       proxy_cache_key $request_uri;#       proxy_cache_valid 200 302 301 10m;#       proxy_cache_valid 404 1m;}}[root@Nginx ~]# nginx -t[root@Nginx ~]# nginx -s reload[Administrator.DESKTOP-P19CNDN]curl www.dhj.org
172.25.254.100 web
[Administrator.DESKTOP-P19CNDN]curl www.dhj.org
172.25.254.200 web 
image-20250727185931723
6.3.3 实战案例: 基于Cookie 实现会话绑定
[root@Nginx ~]# vim  /apps/nginx/conf.d/vhost.conf
upstream webserver {hash $cookie_dhj;server 172.25.254.100:80  weight=1 fail_timeout=15s max_fails=3;server 172.25.254.200:80  weight=1 fail_timeout=15s max_fails=3;
}server{listen          80;server_name     www.dhj.org;location / {proxy_pass      http://webserver;#       proxy_cache     proxycache;#       proxy_cache_key $request_uri;#       proxy_cache_valid 200 302 301 10m;#       proxy_cache_valid 404 1m;}}#测试
[root@Nginx ~]# nginx -s reload[root@Nginx ~]# curl -b "dhj=cccc" www.dhj.org
web2 172.25.254.200
[root@Nginx ~]# curl -b "dhj=aaaa" www.dhj.org
web1 172.25.254.100
[root@Nginx ~]# curl -b "dhj=cccc" www.dhj.org
web2 172.25.254.200
[root@Nginx ~]# curl -b "dhj=aaaa" www.dhj.org
web1 172.25.254.100
image-20250727190319017
6.4 实现 Nginx 四层负载均衡

Nginx在1.9.0版本开始支持tcp模式的负载均衡,在1.9.13版本开始支持udp协议的负载,udp主要用于DNS的域名解析,其配置方式和指令和http 代理类似,其基于ngx_stream_proxy_module模块实现tcp负载,另外基于模块ngx_stream_upstream_module实现后端服务器分组转发、权重分配、状态监测、调度算法等高级功能。

如果编译安装,需要指定 --with-stream 选项才能支持ngx_stream_proxy_module模块

官方文档:
https://nginx.org/en/docs/stream/ngx_stream_proxy_module.html

image-20250727191303102
6.4.1 tcp负载均衡配置参数

[!WARNING]

tcp的负载均衡要卸载http语句块之外

stream { 											# 定义stream相关的服务;Context:mainupstream backend { 								# 定义后端服务器hash $remote_addr consistent; 				# 定义调度算法server backend1.example.com:12345 weight=5; 	# 定义具体serverserver 127.0.0.1:12345      max_fails=3 fail_timeout=30s;server unix:/tmp/backend3;}upstream dns {  									# 定义后端服务器server 10.0.0.1:53;  						# 定义具体serverserver dns.example.com:53;}server { 										# 定义serverlisten 12345; 								# 监听IP:PORTproxy_connect_timeout 1s; 					# 连接超时时间proxy_timeout 3s; 							# 转发超时时间proxy_pass backend; 							# 转发到具体服务器组}server {listen 127.0.0.1:53 udp reuseport;proxy_timeout 20s;proxy_pass dns;}server {listen [::1]:12345;proxy_pass unix:/tmp/stream.socket;}
}
6.4.2 负载均衡实例: MySQL
1.后端服务器安装 MySQL
# 在apache20中安装mysql
[root@apache20 ~]# yum install mariadb-server  -y
[root@apache20 ~]# vim /etc/my.cnf.d/mariadb-server.cnf
[mysqld]
server-id=20[root@apache20 ~]# systemctl start mariadb
[root@apache20 ~]# mysql -e "grant all on *.* to lee@'%' identified by 'lee';"
[root@apache30 ~]# mysql -ulee -plee -h172.25.254.20 -e "select @@server_id"
+-------------+
| @@server_id |
+-------------+
|          20 |
+-------------+# 在apache30重复以上步骤并在apache20上测试
2.nginx配置
[root@Nginx ~]# vim /apps/nginx/conf/tcp/tcp.conf
stream {upstream mysql_server {server 172.25.254.20:3306  max_fails=3 fail_timeout=30s;server 172.25.254.30:3306  max_fails=3 fail_timeout=30s;}server {listen 172.25.254.10:3306;proxy_pass mysql_server;proxy_connect_timeout 30s;proxy_timeout 300s;}
}# 重启nginx并访问测试:
[root@Nginx ~]# nginx -s reload# 测试通过nginx负载连接MySQL:
[root@apache30 ~]# mysql -ulee -plee -h172.25.254.10 -e "select @@server_id"
+-------------+
| @@server_id |
+-------------+
|          20 |
+-------------+
[root@apache30 ~]# mysql -ulee -plee -h172.25.254.10 -e "select @@server_id"
+-------------+
| @@server_id |
+-------------+
|          30 |
+-------------+# 在10.0.0.28停止MySQL服务
[root@apache20 ~]# systemctl stop mariadb# 再次测试访问,只会看到mysql-server1.timinglee.org进行响应
[root@apache30 ~]# mysql -ulee -plee -h172.25.254.10 -e "select @@server_id"
+-------------+
| @@server_id |
+-------------+
|          30 |
+-------------+
[root@apache30 ~]# mysql -ulee -plee -h172.25.254.10 -e "select @@server_id"
+-------------+
| @@server_id |
+-------------+
|          30 |
+-------------+
6.4.3 udp 负载均衡实例: DNS
# 在RS-2相同的操作同样在RS-1上进行(下面使用了scp进行传输)
[root@RS-2 ~]# cd /var/named/
[root@RS-2 named]# cp -p named.localhost dhj.org.zone[root@RS-2 named]# vim dhj.org.zone
[root@RS-2 ~]# systemctl start named[root@RS-2 named]# scp dhj.org.zone root@172.25.254.100:/var/named/dhj.org.zone[root@RS-1 ~]# cd /var/named/
[root@RS-1 named]# ll
-rw-r----- 1 root  root   172 Jul 27 19:31 dhj.org.zone
[root@RS-1 ~]# systemctl start named[root@RS-1 named]# chgrp named dhj.org.zone
[root@RS-1 named]# ll
-rw-r----- 1 root  named  172 Jul 27 19:31 dhj.org.zone[root@RS-1 named]# vim dhj.org.zone[root@RS-1 ~]# vim /etc/named.rfc1912.zones
[root@RS-2 ~]# vim /etc/named.rfc1912.zones
zone "dhj.org" IN {type master;file "dhj.org.zone";allow-update { none; };
};[root@RS-1 ~]# dig @172.25.254.100  dns.dhj.org
[root@RS-2 ~]# dig @172.25.254.200  dns.dhj.org
image-20250727191711521 image-20250727193427149 image-20250727195243065
[root@Nginx ~]# cd /usr/local/nginx/tcp.d/
[root@Nginx tcp.d]# vim dns.conf
stream {upstream dns {server 172.25.254.100:53 max_fails=3 fail_timeout=5;server 172.25.254.200:53 max_fails=3 fail_timeout=5;}server {listen 53 udp;proxy_pass dns;}
}[root@Nginx tcp.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 tcp.d]# nginx -s reload# 检测一下是否两个端口都打开了(80,53)
[root@Nginx tcp.d]# netstat -antlupe | grep nginx
tcp        0      0 0.0.0.0:80              0.0.0.0:*               LISTEN      0          24761      850/nginx: master p
udp        0      0 0.0.0.0:53              0.0.0.0:*                           0          34696      850/nginx: master p# 如果想将53端口也开放的话,如下即可
[root@Nginx tcp.d]# vim dns.conf
stream {upstream dns {server 172.25.254.100:53 max_fails=3 fail_timeout=5;server 172.25.254.200:53 max_fails=3 fail_timeout=5;}server {listen 53 udp;proxy_pass dns;}server {listen 53;proxy_pass dns;}
}[root@Nginx tcp.d]# nginx -t
[root@Nginx tcp.d]# nginx -s reload
[root@Nginx ~]# netstat -antlupe | grep nginx
tcp        0      0 0.0.0.0:80              0.0.0.0:*               LISTEN      0          24761      850/nginx: master p
tcp        0      0 0.0.0.0:53              0.0.0.0:*               LISTEN      0          38925      850/nginx: master p
udp        0      0 0.0.0.0:53              0.0.0.0:*                           0          34696      850/nginx: master p# 开始测验,此时的Nginx服务器并没有配置Dns服务,dig-->172.25.254.10即可看到差别[root@Nginx ~]# dig @172.25.254.10 dns.dhj.org
;; ANSWER SECTION:
dns.dhj.org.            86400   IN      A       172.25.254.100[root@Nginx ~]# dig @172.25.254.10 dns.dhj.org
;; ANSWER SECTION:
dns.dhj.org.            86400   IN      A       172.25.254.200
image-20250727201042190 image-20250727201342196
6.5 实现 FastCGI

image-20250723144058697

image-20250723144108750

CGI的由来:

最早的Web服务器只能简单地响应浏览器发来的HTTP请求,并将存储在服务器上的HTML文件返回给浏览器,也就是静态html文件,但是后期随着网站功能增多网站开发也越来越复杂,以至于出现动态技术,比如像php(1995年)、java(1995)、python(1991)语言开发的网站,但是nginx/apache服务器并不能直接运行 php、java这样的文件,apache实现的方式是打补丁,但是nginx缺通过与第三方基于协议实现,即通过某种特定协议将客户端请求转发给第三方服务处理,第三方服务器会新建新的进程处理用户的请求,处理完成后返回数据给Nginx并回收进程,最后nginx在返回给客户端,那这个约定就是通用网关接口(common gateway interface,简称CGI),CGI(协议) 是web服务器和外部应用程序之间的接口标准,是cgi程序和web服务器之间传递信息的标准化接口。

image-20250723144124565

为什么会有FastCGI?

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

什么是PHP-FPM?

PHP-FPM(FastCGI Process Manager:

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

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

fastcgi_pass address:port;
# 转发请求到后端服务器,address为后端的fastcgi server的地址,可用位置:location, if in locationfastcgi_index name;
# fastcgi默认的主页资源,示例:fastcgi_index index.php;fastcgi_param parameter value [if_not_empty];
# 设置传递给FastCGI服务器的参数值,可以是文本,变量或组合,可用于将Nginx的内置变量赋值给自定义keyfastcgi_param REMOTE_ADDR        $remote_addr; #客户端源IP
fastcgi_param REMOTE_PORT        $remote_port; #客户端源端口
fastcgi_param SERVER_ADDR        $server_addr; #请求的服务器IP地址
fastcgi_param SERVER_PORT        $server_port; #请求的服务器端口
fastcgi_param SERVER_NAME        $server_name; #请求的server name
Nginx默认配置示例:location ~ \.php$ {root           /scripts;fastcgi_pass   127.0.0.1:9000;fastcgi_index index.php;fastcgi_param SCRIPT_FILENAME /scripts$fastcgi_script_name; #默认脚本路径#fastcgi_param SCRIPT_FILENAME $document_root$fastcgi_script_name;include       fastcgi_params;    #此文件默认系统已提供,存放的相对路径为prefix/conf}
6.5.2 FastCGI实战案例 : Nginx与php-fpm在同一服务器

编译安装更方便自定义参数或选项,所以推荐大家使用源码编译

官方网站:www.php.net

源码编译php

# 根据自身情况(可选),需要先升级依赖
[root@Nginx ~]# rpm -Uvh oniguruma-6.9.6-1.el9.6.x86_64.rpm[root@Nginx ~]# rpm -ivh oniguruma-devel-6.9.6-1.el9.6.x86_64.rpm# 解决php依赖
[root@Nginx ~]# dnf install -y bzip2 systemd-devel libxml2-devel sqlite-devel libpng-devel libcurl-devel oniguruma-devel# 解压并进入,进行编译及安装
[root@Nginx ~]# tar -zxf php-8.3.9.tar.gz
[root@Nginx ~]# cd php-8.3.9/
[root@Nginx php-8.3.9]# ./configure --prefix=/usr/local/php  --with-config-file-path=/usr/local/php/etc --enable-fpm  --with-fpm-user=nginx --with-fpm-group=nginx  --with-curl  --with-iconv --with-mhash --with-zlib --with-openssl --enable-mysqlnd --with-mysqli --with-pdo-mysql --disable-debug --enable-sockets --enable-soap --enable-xml --enable-ftp --enable-gd --enable-exif --enable-mbstring --enable-bcmath  --with-fpm-systemd[root@Nginx php-8.3.9]# make && make install# 相关解释
[root@Nginx ~]# ./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相关配置优化

[root@Nginx ~]# cd /usr/local/php/etc
[root@Nginx etc]# cp php-fpm.conf.default php-fpm.conf
[root@Nginx etc]# vim php-fpm.conf
去掉注释
pid = run/php-fpm.pid		# 指定pid文件存放位置[root@Nginx etc]# cd php-fpm.d/
[root@Nginx  php-fpm.d]# cp www.conf.default www.conf# 生成主配置文件
[root@Nginx php-fpm.d]# cd /root/php-8.3.9/
[root@Nginx php-8.3.9]# cp php.ini-production /usr/local/php/etc/php.ini
[root@Nginx ~]# 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 ~]# cd /root/php-8.3.9/
[root@Nginx php-8.3.9]# cp sapi/fpm/php-fpm.service  /lib/systemd/system/php-fpm.service[root@Nginx php-8.3.9]# vim /lib/systemd/system/php-fpm.service
# Mounts the /usr, /boot, and /etc directories read-only for processes invoked by this unit.
#ProtectSystem=full			# 注释该内容[root@Nginx php-8.3.9]# systemctl daemon-reload
[root@Nginx php-8.3.9]# systemctl start php-fpm.service
[root@Nginx php-8.3.9]# systemctl enable --now php-fpm.service[root@Nginx php-8.3.9]# netstat -antlupe | grep php
tcp        0      0 127.0.0.1:9000          0.0.0.0:*               LISTEN      0          820758     176202/php-fpm: mas
image-20250729110354700 image-20250729110855455

准备php测试页面

[root@Nginx ~]# mkdir /usr/local/php/ -p[root@Nginx ~]# vim /usr/local/php/index.php
[root@Nginx ~]# more /usr/local/php/index.php
<?php
phpinfo();
?>

Nginx配置转发

Nginx安装完成之后默认生成了与fastcgi的相关配置文件,一般保存在nginx的安装路径的conf目录当中,比如/apps/nginx/conf/fastcgi.conf、/apps/nginx/conf/fastcgi_params。

[root@Nginx ~]# vim /usr/local/nginx/conf.d/vhost.conf
server{listen          80;server_name     www.dhj.org;location ~ \.php$ {fastcgi_pass 127.0.0.1:9000;fastcgi_index index.php;include fastcgi.conf;fastcgi_param SCRIPT_FILENAME   /scripts$fastcgi_script_name;}
}[root@Nginx ~]# nginx -t
[root@Nginx ~]# nginx -s reload# 打开浏览器,进行测试
www.dhj.org/php/

访问验证php测试页面

image-20250729112212279

添加php环境变量

[root@Nginx ~]# 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:$HOME/bin:/apps/nginx/sbin:/usr/local/php/bin
[root@Nginx ~]# source  .bash_profile
6.5.3 php的动态扩展模块(php的缓存模块)

软件下载:http://pecl.php.net/package/memcache

image-20250723144216641

安装memcache模块

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

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

[root@Nginx ~]# cd memcache-8.2/
[root@Nginx memcache-8.2]# ls[root@Nginx memcache-8.2]# cp example.php  memcache.php  /data/php/
[root@Nginx ~]# vim /usr/local/nginx/html/memcache.php
define('ADMIN_USERNAME','admin');   // Admin Username
define('ADMIN_PASSWORD','admin');   // 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

image-20250729142427144

配置php加载memcache模块

[root@Nginx ~]# vim /usr/local/php/etc/php.ini
;extension=zip
extension=memcache
;zend_extension=opcache[root@Nginx ~]# systemctl reload  php-fpm
[root@Nginx no-debug-non-zts-20230831]# php -m | grep mem
memcache
image-20250729142636007

部署memcached

[root@Nginx ~]# yum install memcached -y
[root@Nginx ~]# systemctl enable --now memcached.service
[root@Nginx ~]# netstat -antlupe | grep memcache
tcp        0      0 127.0.0.1:11211         0.0.0.0:*               LISTEN      976        1037243    186762/memcached[root@Nginx ~]# cat /etc/sysconfig/memcached
PORT="11211"
USER="memcached"
MAXCONN="1024"
CACHESIZE="64"
OPTIONS="-l 127.0.0.1,::1"

测试:

http://www.dhj.org/example.php		# 不断刷新
http://www.dhj.org/memcache.php		# 查看命中状态

image-20250729151042831

性能对比

[root@Nginx ~]# ab -n1000 -c500 http://www.dhj.org/index.php
Concurrency Level:      500
Time taken for tests:   0.253 seconds
Complete requests:      1000
Failed requests:        100[root@Nginx ~]# ab -n1000 -c500 http://www.dhj.org/example.php
Concurrency Level:      500
Time taken for tests:   0.383 seconds
Complete requests:      1000
Failed requests:        0
6.5.4 php高速缓存

image-20250723144301876

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

[root@Nginx ~]# systemctl stop nginx[root@Nginx ~]# cp -p /usr/local/nginx/conf.d/vhost.conf /mnt/vhost.conf[root@Nginx ~]# cp -p /usr/local/nginx/conf/nginx.conf /mnt/nginx.conf[root@Nginx ~]# rm -rf /usr/local/nginx/
[root@Nginx ~]# rm -rf /usr/local/php/[root@Nginx ~]# rm -rf nginx-1.26.1[root@Nginx ~]# tar zxf nginx-1.26.1.tar.gz
[root@Nginx ~]# tar zxf srcache-nginx-module-0.33.tar.gz
[root@Nginx ~]# tar zxf memc-nginx-module-0.20.tar.gz[root@Nginx ~]# cd nginx-1.26.1/
[root@Nginx nginx-1.26.1]# ./configure --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-http_gzip_static_module --with-pcre --with-stream --with-stream_ssl_module --with-stream_realip_module --add-module=/root/echo-nginx-module-0.63/ --add-module=/root/memc-nginx-module-0.20 --add-module=/root/srcache-nginx-module-0.33  && make && make install[root@Nginx nginx-1.26.1]# nginx -v[root@Nginx nginx-1.26.1]# nginx -t[root@Nginx nginx-1.26.1]# mkdir -p /usr/local/nginx/conf.d/
[root@Nginx nginx-1.26.1]# cp -p /mnt/vhost.conf /usr/local/nginx/conf.d/vhost.conf
[root@Nginx nginx-1.26.1]# cp -p /mnt/nginx.conf /usr/local/nginx/conf/nginx.conf
cp: overwrite '/usr/local/nginx/conf/nginx.conf'? y[root@Nginx nginx-1.26.1]# systemctl enable --now nginx
[root@Nginx nginx-1.26.1]# systemctl status nginx[root@Nginx ~]# vim /usr/local/nginx/conf.d/vhost.conf
upstream memcache {server 127.0.0.1:11211;keepalive 512;
}server{listen          80;server_name     www.dhj.org;root /usr/local/nginx/html;location /memc {internal;memc_connect_timeout 100ms;memc_send_timeout 100ms;memc_read_timeout 100ms;set $memc_key $query_string;		# 使用内置变量$query_string来作为keyset $memc_exptime 300;				# 缓存失效时间300秒memc_pass memcache;}location ~ \.php$ {set $key $uri$args;					# 设定key的值srcache_fetch GET /memc $key;		# 检测mem中是否有要访问的phpsrcache_store PUT /memc $key;		# 缓存为加载的php数据fastcgi_pass 127.0.0.1:9000;fastcgi_index index.php;fastcgi_param SCRIPT_FILENAME   /scripts$fastcgi_script_name;include fastcgi.conf;}
}[root@Nginx ~]# nginx -t
[root@Nginx ~]# nginx -s reload

测试结果:

# 编写一个php测试文件
[root@Nginx ~]# cd /usr/local/nginx/html/
[root@Nginx html]# vim index.php
[root@Nginx html]# more index.php
<?php
phpinfo();
?># 进行压测发现高速且0报错
[root@Nginx html]# ab -n500 -c10 http://www.dhj.org/index.php
Concurrency Level:      10
Time taken for tests:   0.034 seconds
Complete requests:      500
Failed requests:        0					# 0出错# 此时修改,将其注释掉,如下图:
[root@Nginx ~]# vim /usr/local/nginx/conf.d/vhost.conf
location ~ \.php$ {#set $key $uri$args;#srcache_fetch GET /memc $key;#srcache_store PUT /memc $key;fastcgi_pass 127.0.0.1:9000;fastcgi_index index.php;fastcgi_param SCRIPT_FILENAME   /scripts$fastcgi_script_name;include fastcgi.conf;}[root@Nginx ~]# nginx -s reload# 重新测试,发现出现错误
[root@Nginx ~]# ab -n500 -c10 http://www.dhj.org/index.php
Concurrency Level:      10
Time taken for tests:   0.106 seconds
Complete requests:      500
Failed requests:        47					# 会出错# 测试完记得将注释删去并重载服务!
image-20250729160603463

7.nginx 二次开发版本

http://www.dtcms.com/a/304168.html

相关文章:

  • PHP性能优化与高并发处理:从基础到高级实践
  • Rust 实战三 | HTTP 服务开发及 Web 框架推荐
  • AI 数字人在处理音频时,如何确保声音的自然度?
  • 使用 Canvas 替代 <video> 标签加载并渲染视频
  • Vue 2.0响应式原理深度解析
  • 艾体宝方案 | 数据孤岛终结者:GWI + DOMO 联手打造一体化增长引擎
  • 系统调用追踪技术于VPS服务器性能分析的实施流程
  • linux系统的启动过程
  • Linux 系统启动过程及相关实验(破解密码;明文密文加密;修复grub2目录和boot目录)
  • 前端优化之虚拟列表实现指南:从库集成到手动开发
  • 【24】C# 窗体应用WinForm ——日历MonthCalendar属性、方法、实例应用
  • 算法精讲:二分查找(一)—— 基础原理与实现
  • vscode remote ssh相关问题
  • 车载刷写架构 --- 刷写思考扩展
  • Git 从入门到精通
  • 【数据库】—— 分区字段为null的时候在未指定最大分区的情况下数据无法插入?
  • 【C++算法】81.BFS解决FloodFill算法_岛屿的最大面积
  • echarts图表点击legend报错问题(折线图)
  • [ java泛型 ] 只闻其名---->“浅浅“了解
  • Java面试宝典:MySQL中的锁
  • 如何在在NPM发布一个React组件
  • Kafka运维实战 16 - kafka 分区重新分配【实战】
  • numpy瑞士军刀 第三卷:实战演练 第七章 组合大阵
  • 【C++算法】77.优先级队列_数据流的中位数
  • Day23-二叉树的层序遍历(广度优先搜素)
  • React 图标库发布到 npm 仓库
  • 试用SAP BTP 02C:试用SAP HANA Schemas HDI Containers
  • 构建特定领域的大模型
  • OV IP证书如何满足PCI DSS要求
  • 网络通信基础(一)