阅读本文之前需要有 nginx 单节点部署 php 的实战能力,如果未掌握,可以看我上一篇文章:docker容器化部署nginx php项目
以及需要 nginx 的反向代理、负载均衡等理论知识,如果未掌握,可以看我另外一篇文章:一文搞懂nginx的反向代理 负载均衡
配置讲解
nginx 负载均衡,它提供了多种负载均衡算法, 最常见的有4种。我们只需修改对应 upstream 配置项即可。
1 轮询(默认)
轮流把用户的请求分配给每一台应用服务器。如果后端服务器down掉,会自动剔除。
# 多台应用服务器,大家权重一样,轮流分配
upstream backend_server {
server 192.168.0.11:8000;
server 192.168.0.12:8000;
server 192.168.0.13:8000 down; # 不参与负载均衡
server 192.168.0.14:8001 backup; # 热备
}
server {
# 监听端口
listen 80;
# 用户请求的域名
server_name www.nbmall.com;
# 转发。部署静态文件服务器时,或者python项目时,用这个
location / {
# 使用proxy_pass转发请求到 upstream配置项里定义的一组应用服务器
proxy_pass http://backend_server;
# 禁用重定向
proxy_redirect off;
# 下面几个参数都是设置请求头,目的是让应用服务器能得到真实的用户IP
proxy_set_header Host $host:$server_port;
proxy_set_header X-Real-IP $remote_addr;
proxy_set_header X-Real-PORT $remote_port;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
}
# 转发。部署PHP项目时用这个。
location ~ \.php(/|$) {
# 入口文件
fastcgi_index index.php;
# PHP项目的IP和端口。这是php-fpm的地址。由于nginx处理不了PHP代码,所以需要把请求转发给php-fpm进行处理。
fastcgi_pass backend_server;
fastcgi_param SCRIPT_FILENAME $document_root$fastcgi_script_name;
include fastcgi_params;
}
2 权重(weight)
通过weight指定轮询概率,访问比率与weight成正比,常用于后端服务器性能不均的情况。不怎么忙或性能好的服务器可以多承担些任务。
# weight越大,承担任务越多
upstream backend_server {
server 192.168.0.11:8000 weight=3;
server 192.168.0.12:8000 weight=1;
}
3 ip_hash
每个请求按访问ip的hash结果分配,这样每个访客固定访问一个后端服务器,可以解决session的问题。为固定的用户 ip 访问固定服务器时比较好用,比如用户上传文件。
upstream backend_server {
ip_hash;
server 192.168.0.11:8000;
server 192.168.0.12:8000;
}
4 url_hash
按访问 url 的 hash 结果来分配请求,使每个url定向到同一个后端服务器。为固定的 url 访问固定的服务器,比如缓存服务器。
# URL Hash
upstream backend_server {
hash $request_uri;
server 192.168.0.11:8000;
server 192.168.0.12:8000;
}
实践
1 准备两台服务器,各创建一个 PHP 节点。
# 启动第一个PHP节点,把PHP项目目录映射到容器内的 /www。
# 且需跟nginx的root参数的目录对应,这里处理请求时会处理nginx的root参数的目录对应到本容器同路径的代码。
docker run --name php7.4-note-1 -p 9001:9000 -v /home/tian/www:/www -d php:7.4-fpm
# 启动第二个PHP节点。同上。
docker run --name php7.4-note-2 -p 9002:9000 -v /home/tian/www:/www -d php:7.4-fpm
这是9001这台。我这台IP是10.0.3.15
这是9002这台。我这台IP是192.168.56.108
2 创建一个nginx节点。
有三个步骤
mkdir -p /opt/docker/nginx/conf.d
创建一个nginx的配置目录
vim nbmall.com.conf
创建一个空配置文件,输入对应的配置。配置文件在下面。
docker run --name nginx1.23 -p 80:80 -d -v /home/tian/www:/www -v /opt/docker/nginx/conf.d:/etc/nginx/conf.d nginx:1.23
创建并运行nginx容器
这是nbmall.com.conf配置文件的内容。
# 多台应用服务器,大家权重一样,轮流分配
upstream backend_server {
server 10.0.3.15:9001;
server 192.168.56.108:9002;
}
# 服务端配置节点
server {
# 监听端口。注意端口没被占用
listen 80;
# 此站点的域名。自己配置虚拟域名host文件,或者从阿里云等云服务器解析一个域名过来
server_name www.nbmall.com;
# 此站点的入口目录。这里要注意,这是当前容器内的路径。因为我把宿主机的thinkphp项目路径挂载到了容器内的/www/nbmall 目录。
# 访问这个路径就能访问到不同的服务器的同一个项目。
root /www/thinkphp6.0/nbmall/public;
# 入口目录里可识别的入口文件
index index.html index.htm index.php;
# 配置url。Thinkphp的伪静态设置
location / {
#访问路径的文件不存在则重写URL转交给ThinkPHP处理
if (!-e $request_filename) {
rewrite ^(.*)$ /index.php?s=$1 last; break;
}
}
# 配置url,图片等资源文件
location ~ .*\.(gif|jpg|jpeg|png|bmp|swf)$ {
# 缓存100天
expires 100d;
# 不写日志
error_log /dev/null;
access_log off;
}
# 配置url,前端的js css资源文件
location ~ .*\.(js|css)?$ {
expires 30d;
error_log /dev/null;
access_log off;
}
# 配置url,处理及转发PHP请求
location ~ \.php(/|$) {
# 入口文件
fastcgi_index index.php;
# PHP项目的IP和端口。这是php-fpm的地址。由于nginx处理不了PHP代码,所以需要把请求转发给php-fpm进行处理。
fastcgi_pass backend_server;
fastcgi_param SCRIPT_FILENAME $document_root$fastcgi_script_name;
include fastcgi_params;
}
# 用户的访问日志。注意,这目录必须存在,否则nginx将启动不了。由于我把宿主机的项目路径www挂载到了容器内的/www目录,所以宿主机的项目路径www里需要有wwwlogs目录。
access_log /www/wwwlogs/nbmall.com.log;
# 错误日志
error_log /www/wwwlogs/nbmall.com.error.log;
}
这个配置文件可随时修改,修改后需要重启nginx:docker restart nginx1.23
打开网站,大功告成。
后记:
本文使用的是一 nginx 服务器对应多 php 应用,nginx 直接转发到多个 php 应用。也可以一个 nginx 对应一个 php,然后再由一个总的 nginx 转发到其它 nginx。