Nginx-LNMP架构

实现过程:

1、用户发起

user--->http--->nginx--->fastcgi--->php-fpm--->tcp--->mysql

2、返回给用户

mysql--->tcp--->php-fpm--->fastcgi--->nginx--->http--->user

安装流程

1、安装linux服务器
2、安装php
# 手动配置yum源

[root@oldxu ~]# cat /etc/yum.repos.d/php.repo

[webtatic-php] name = php Repository

baseurl = http://us east.repo.webtatic.com/yum/el7/x86_64/

gpgcheck = 0

#卸载低版本php

yum remove php-mysql-5.4 php php-fpm php-common

#安装高版本php

yum -y install php71w php71w-cli \

#开启并加入开机自启

systemctl start php-fpm.service
systemctl enable php-fpm.service

3、安装mariadb

yum install mariadb mariadb-server -y

#开启并加入开机自启

systemctl start mariadb.service
systemctl enable mariadb.service

4、nginx集成php
#fastcgi代理配置

vim /etc/nginx/conf.d/php.zjh.net.conf

server {
listen 80;
server_name php.zjh.net;
root /code/php;

location / {
index index.html index.php;
}

location ~ .php$ {
fastcgi_pass 127.0.0.1:9000;
fastcgi_param SCRIPT_FILENAME $document_root$fastcgi_script_name;
include /etc/nginx/fastcgi_params;

​ }

}

5、php集成mysql
#安装mysql/mariadb(安装方法同上)
#设定mysql密码(基于用户名与密码)

mysqladmin password 'zjh123'

#登录mysql

mysql -uroot -pzjh123

#编写php脚本测试链接数据库,如果链接成功则证明php与mysql集成没问题

vim /code/php/mysqli.php

产品交付

0、前置环境准备

#检查nginx和php的用户,属组属主,权限

ps -ef | grep nginx

ps -ef | grep php

groupadd -g 666 www

useradd -g 666 -u 666 www

1、编写nginx配置

vim /etc/nginx/conf.d/blog.zjh.net

server {
listen 80;
server_name blog.zjh.net;

​ root /code/wordpress;

​ location / {
​ index index.php;
​ }

​ location ~ .php$ {
​ fastcgi_pass 127.0.0.1:9000;
​ fastcgi_param SCRIPT_FILENAME $document_root$fastcgi_script_name;
​ include fastcgi_params;

​ }

}

#修改nginx配置文件的用户

sed -i '/^user/c user www;' /etc/nginx/nginx.conf

systemctl restart nginx

附加(若php版本不够高时):

#替换新版的php源

vim /etc/yum.repos.d/webtatic-php.repo

[webtatic-php]
name = php Repository
baseurl = http://us-east.repo.webtatic.com/yum/el7/x86_64
enabled = 1
gpgcheck = 0

若有冲突(例如mod_php71w-7.1.32-1.w7.x86_64冲突):

rpm -qa |grep php

yum remove mod_php71w-7.1.32-1.w7.x86_64

yum clean all

yum makecache

#安装php包

yum install -y php72w php72w-cli php72w-common php72w- devel php72w-embedded php72w-gd php72w-mcrypt php72w-mbstring php72w-pdo php72w-xml php72w-fpm php72w-mysqlnd php72w-opcache php72w-pecl-memcached php72w-pecl-redis php72w-pecl-mongodb

#修改php上传限制

vim /etc/php.ini

搜索upload,把默认2M修改为想要的大小

#修改php配置文件的用户与组

sed -i '/^user/c user = www' /etc/php-fpm.d/www.conf

sed -i '/^group/c group = www' /etc/php-fpm.d/www.conf

systemctl restart php-fpm.service

php-fpm -t (检查php-fpm语法)

2、下载代码,部署代码
3、创建mysql的库

mysql -uroot -pzjh123

create database wordpress;

show databases;

#修改wordpress文件属组属主

chown -R www.www /code/wordpress/

架构扩展

1、准备环境

​ 1、web节点:10.0.0.7

​ 2、db节点:10.0.0.51

2、在db节点上安装mariadb,检查端口是否挂载成功

yum install mariadb mariadb-server -y

netstat -lntp

3、在web节点上将旧数据库备份下来,并检查数据库是否备份正确

mysqldump -uroot -p --all-databases > /tmp/db.sql

du -sh /tmp/db.sql

4、将web节点上备份的数据推送到db节点

rsync /tmp/db.sql root@172.16.1.51:/tmp

5、db节点恢复数据到数据库中

mysql < /tmp/db.sql

systemctl restart mariadb.service

6、创建mysql远程账户

grant all privileges on *.* to 'app'@'%' identified by 'zjh123';

或仅允许172.16.1.%网段访问

grant all privileges on *.* to 'app'@'172.16.1.%' identified by 'zjh123';

#刷新权限

flush privileges;

7、测试远程连接是否成功

mysql -h 172.16.1.51 -uapp -pzjh123

8、将业务代码链接的数据库信息,修改到远程的db节点上
#web节点停止数据库服务

systemctl stop mariadb.service
systemctl disable mariadb.service

#修改业务代码链接至db节点的数据库上

cd /code/shop/ (进入对应服务的存储位置)

find ./ -type f | xargs grep -R "zjh123" (查询服务数据库的php文件)

vim shopxo-v2.1.0/config/database.php (修改为远端服务器的地址和用户名)

image-20250410103735293.png

扩展多台web服务器

准备环境:

1、准备一台就绪的web服务器

2、新增一台web节点10.0.0.8

环境构建(手动或ansible)

1、创建用户www

groupadd -g 666 www
useradd -g 666 -u 666 www

2、安装nginx(拉取就绪主机的repo文件)

rsync -avz root@172.16.1.7:/etc/yum.repos.d/nginx.repo /etc/yum.repos.d/

gzip /etc/yum.repos.d/epel.repo

yum install nginx -y

systemctl start nginx

systemctl enable nginx

​ 2.1、新增站点配置文件,修改nginx默认运行身份

​ rsync -avz root@172.16.1.7:/etc/nginx/ /etc/nginx/

​ systemctl start nginx
​ systemctl enable nginx

3、安装php

​ 3.1、修改php的运行身份

​ 3.2、拷贝之前的php.ini配置文件

​ rsync -avz root@172.16.1.7:/etc/php.ini /etc/php.ini

​ rsync -avz root@172.16.1.7:/etc/php-fpm.d/www.conf /etc/php-fpm.d/www.conf

​ php-fpm -t
​ systemctl start php-fpm.service
​ systemctl enable php-fpm.service

部署代码(jenkins)

1、部署业务代码

rsync -avz root@172.16.1.7:/code /

chmod -R www.www /var/lib/php/session

多节点静态资源共享

1、增加一台nfs共享存储服务器
2、统一用户身份www

groupadd -g 666 www

useradd -g 666 -u 666 www

3、安装nfs服务

yum install nfs-utils -y

4、配置共享的目录

mkdir /data

mount -t xfs /dev/sdb /data/

echo "/dev/sdb /data xfs defaults 0 0 " >> /etc/fstab

mount -a

df -h

vim /etc/exports

/data/blog 172.16.1.0/24(rw,all_squash,anonuid=666,anongid=666)

/data/zh 172.16.1.0/24(rw,all_squash,anonuid=666,anongid=666)

mkdir /data/blog
mkdir /data/zh
chown -R www.www /data/

systemctl start nfs

systemctl enable nfs

showmount -e 172.16.1.32

5、将代码的静态资源挂载到nfs共享存储服务器上
#在客户端上下载nfs

systemctl start nfs
systemctl enable nfs

#将静态资源上传目录挂载到nfs主机的目录上

mount -t nfs 172.16.1.32:/data/blog /code/wordpress/wp-content/uploads/

df -h

负载均衡引入

Nginx代理

nginx正向代理(为客户端提供服务)
Nginx反向代理(为服务端提供服务)

应用场景:路由功能,负载均衡,动静分离,数据缓存

用户 --> 正向代理(路由器) --> 反向代理(缓存)--> 服务器

Nginx可代理的协议

Nginx反向代理实践

1、配置web节点

vim /etc/nginx/conf.d/web.zjh.net.conf
mkdir /code/web
echo "web01..." > /code/web/index.html
nginx -t

2、配置proxy节点

gzip /etc/yum.repos.d/epel.repo
yum install nginx

gzip -d /etc/yum.repos.d/epel.repo.gz

rm -rf /etc/nginx/conf.d/default.conf

vim /etc/nginx/conf.d/proxy_web.zjh.net.conf
server {
listen 80;
server_name web.zjh.net;

location / {
proxy_pass http://10.0.0.7:8080;
}

}

systemctl start nginx
systemctl enable nginx

3、测试访问,使用抓包工具

代理配置参数

proxy_set_header

server {
listen 80;
server_name web.zjh.net;

​ location / {
​ proxy_pass http://10.0.0.7;
​ proxy_set_header Host $http_host; (变量会保留客户端请求中原始的Host头)
​ proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for; (传递客户端真实的ip地址给后端服务器)
​ }

}

proxy_http_version

server {
listen 80;
server_name web.zjh.net;

location / {
proxy_pass http://10.0.0.7;
proxy_set_header Host $http_host;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
proxy_http_version 1.1; (切换http协议版本为1.1)
proxy_set_header Connection ""; (清除客户端请求中的Connection头,避免向后端传递 Connection: close,从而允许保持持久连接)
}

}

proxy_connect_timeout proxy_read_timeout proxy_send_timeout

server {
listen 80;
server_name web.zjh.net;

location / {
proxy_pass http://10.0.0.7;
proxy_set_header Host $http_host;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
proxy_http_version 1.1;
proxy_set_header Connection "";
proxy_connect_timeout 120s; (设置Nginx与后端服务器建立TCP连接的超时时间)
proxy_read_timeout 120s; (设置Nginx等待后端服务器响应数据的超时时间)
proxy_send_timeout 120s; (设置Nginx向后端服务器发送请求数据的超时时间)
}

}

proxy_buffer

server {
listen 80;
server_name web.zjh.net;

location / {
proxy_pass http://10.0.0.7;
proxy_set_header Host $http_host;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
proxy_http_version 1.1;
proxy_set_header Connection "";
proxy_connect_timeout 120s;
proxy_read_timeout 120s;
proxy_send_timeout 120s;
proxy_buffering on; (开启缓冲)
proxy_buffer_size 8k; (设置读取后端响应头的缓冲区大小,超过则返回502)
proxy_buffers 4 64k; (读取后端响应体的缓冲区个数和缓冲区大小,超过则写入磁盘临时文件)
}

}

代理参数优化

vim /etc/nginx/proxy_params

proxy_set_header Host $http_host;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
proxy_http_version 1.1;
proxy_set_header Connection "";
proxy_connect_timeout 120s;
proxy_read_timeout 120s;
proxy_send_timeout 120s;
proxy_buffering on;
proxy_buffer_size 8k;
proxy_buffers 4 64k;

vim /etc/nginx/conf.d/proxy_web.zjh.net.conf (若之前有代理参数则需要删除或注释)

server {
listen 80;
server_name web.zjh.net;

location / {
proxy_pass http://10.0.0.7;
include proxy_params;
}
location /admin {
proxy_pass http://10.0.0.8;
include proxy_params;
}

}

多个域名分组

upstream login {

​ server a;

​ server b;

​ server c;

}

upstream admin {

​ server d;

​ server e;

}

负载均衡

四层与七层

四层优点:性能高

四层缺点:仅支持ip:port转发

通常用于mysql tcp 3306,redis,ssh等

七层优点:支持uri路径匹配,header改写,rewrite等

七层缺点:性能低,消耗随机端口

负载均衡配置场景
需要两个模块:

upstream 虚拟资源池模块 proxy_upstream_module

proxy_pass 代理模块 proxy_modules

配置web节点

1、web01(代理+相同的代码)

2、web02(代理+相同的代码)

配置proxy节点,统一调度
轮询机制

vim /etc/nginx/conf.d/proxy_node.zjh.net.conf

upstream node {
server 172.16.1.7:80;
server 172.16.1.8:80;
}

server {
listen 80;
server_name node.zjh.net;

location / {
proxy_pass http://node;
include proxy_params;

}

}

加权轮询机制 (通常用于给性能不同的服务器调整较多或较少的权重)

upstream node {
server 172.16.1.7:80 weight=5;
server 172.16.1.8:80 weight=1;
}

server {
listen 80;
server_name node.zjh.net;

location / {
proxy_pass http://node;
include proxy_params;

}

}

ip_hash (用于将同一客户端的请求始终分发到同一台后端服务器,从而实现基于客户端 IP 的会话保持)
(计算公式:ip%node_counts=index,ip地址对服务器数量取余)

upstream node {
ip_hash;
server 172.16.1.7:80;
server 172.16.1.8:80;
}

server {
listen 80;
server_name node.zjh.net;

location / {
proxy_pass http://node;
include proxy_params;

}

}

一致性hash(采用一致性hash算法,但仍然根据来源ip进行hash计算)

upstream node {
ip_hash;
hash $remote_addr consistent;
server 172.16.1.7:80;
server 172.16.1.8:80;
}

server {
listen 80;
server_name node.zjh.net;

​ location / {
​ proxy_pass http://node;
​ include proxy_params;

​ }

}

url_hash
配置后端节点

web01:

echo 'web1 url1' > /code/node/url1.html
echo 'web1 url2' > /code/node/url2.html

web02:

echo 'web2 url1' > /code/node/url1.html
echo 'web2 url2' > /code/node/url2.html

负载均衡节点配置url_hash:

upstream node {
hash $request_uri consistent;
server 172.16.1.7:80;
server 172.16.1.8:80;
}

server {
listen 80;
server_name node.zjh.net;

​ location / {
​ proxy_pass http://node;
​ include proxy_params;

​ }

}

least_conn (哪台服务器连接数少就分配给哪个服务器)

upstream node {

​ least_conn;

​ server 172.16.1.7:80;
​ server 172.16.1.8:80;
}

server {
listen 80;
server_name node.zjh.net;

location / {
proxy_pass http://node;
include proxy_params;

}

}

Nginx负载均衡后端状态

down(平滑关闭,通常用于维护)

upstream node {
server 172.16.1.7:80 down;
server 172.16.1.8:80;
}

server {
listen 80;
server_name node.zjh.net;

location / {
proxy_pass http://node;
include proxy_params;

}

}

backup(当其他常用的服务器挂掉后,则开启backup备用服务器,平时不启用)

upstream node {
server 172.16.1.7:80 backup;
server 172.16.1.8:80;
}

server {
listen 80;
server_name node.zjh.net;

location / {
proxy_pass http://node;
include proxy_params;

}

}

max_conns(最大连接数限制,超过连接数则显示错误)

upstream node {
server 172.16.1.7:80 max_conns=2;
server 172.16.1.8:80 max_conns=4;
}

server {
listen 80;
server_name node.zjh.net;

location / {
proxy_pass http://node;
include proxy_params;

}

}

keepalive(最大空闲连接数,需要配合长链接使用)

upstream node {
server 172.16.1.7:80 down;
server 172.16.1.8:80;

​ keepalive 32; (最大的空闲连接数)

​ keepalive_timeout 100s; (空闲连接的超时时间,超过则关闭会话)

}

server {
listen 80;
server_name node.zjh.net;

location / {
proxy_pass http://node;
proxy_http_version 1.1;
proxy_set_header Connection "";

}

}

max_fails与fail_timeout

upstream node {
server 172.16.1.7:80 max_fails=2 fail_timeout=10s;
server 172.16.1.8:80 max_fails=2 fail_timeout=5s;
}

server {
listen 80;
server_name node.zjh.net;

location / {
proxy_pass http://node;
include proxy_params;

}

}

Nginx负载均衡会话共享

如何实现会话保持(客户端:cookies,服务端sessionID)

1、粘性session

2、session复制

3、session共享

4、session持久化

session共享(Redis共享方案,共享时机器时间需要同步)
1、负载均衡修改为轮询机制
2、配置redis服务器

vim /etc/redis.conf

搜索bind

bind 127.0.0.1 172.16.1.41

3、修改所有应用服务器的php解析器,将session信息存储至redis中

复制官方自带的session配置

cat /etc/php.d/redis.ini

复制:session.save_handler = redis
session.save_path = "tcp://host1:6379?weight=1, tcp://host2:6379?weight=2&timeout=2.5, tcp://host3:6379?weight=2"

vim /etc/php.ini

搜索session,粘贴在session.save_handler = redis下

修改为:

session.save_handler = redis
session.save_path = "tcp://172.16.1.41:6379?weight=1&timeout=2.5"

vim /etc/php-fpm.d/www.conf

将文件最后的其中两条php注释掉:

;php_value[session.save_handler] = files
;php_value[session.save_path] = /var/lib/php/session

PS:除了session共享还能使用cookies植入会话
后端节点异常容错机制

/etc/nginx/conf.d/proxy_blog.zjh.net.conf" 17L, 321C 13,3-17 All
upstream blog {
server 172.16.1.7:80;
server 172.16.1.8:80;

}
server {
listen 80;
server_name blog.zjh.net;

​ location / {
​ proxy_pass http://blog;
​ proxy_next_upstream error timeout http_500 http_502 http_503 http_504;
​ proxy_next_upstream_tries 2;
​ proxy_next_upstream_timeout 3s;
​ include proxy_params;
​ }

}

根据不同的uri进行调度(路由)

upstream user_cluster {

​ server 172.16.1.7:8082;

​ server 172.16.1.7:8083;

}

upstream pass_cluster {

​ server 172.16.1.8:8082;

​ server 172.16.1.8:8083;

}

server {

​ listen 80;

​ server_name uri.zjh.net;

location /user {

​ proxy_pass http://user_cluster/;

​ include proxy_params;

​ }

location /pass {

​ proxy_pass http://pass_cluster/;

​ include proxy_params;

​ }

}

附加:proxy_pass http://pass_cluster/;域名处有斜线/与没斜线/的区别
没加斜线/

用户发起请求:uri.zjh.net/user

负载均衡接受请求:uri.zjh.net/user

负载均衡代理至后端:uri.zjh.net/user --> /code/user1/user

加斜线(负载均衡向后端请求时,会删除location匹配的关键字):

用户发起请求:uri.zjh.net/user

负载均衡接受请求:uri.zjh.net/user

负载均衡代理至后端:uri.zjh.net/ --> /code/user1/index.html

例:uri.zjh.net/user/test/app/123.html --> uri.zjh.net/test/app/123.html

根据设备进行调度

vim /etc/nginx/conf.d/proxy_agent.zjh.net.conf

upstream phone {
server 172.16.1.7:80;
}
upstream pc {
server 172.16.1.8:80;
}

server {
listen 80;
server_name agent.zjh.net;

​ location / {
​ default_type text/html;
​ if ($http_user_agent ~* "iphone|android|ipad") {
​ proxy_pass http://phone;
​ }
​ proxy_pass http://pc;
​ include proxy_params;

附加(IE浏览器版本落后容易导致代码执行出问题,若用户使用IE浏览器则显示403或跳转下载其他浏览器):

upstream phone {
server 172.16.1.7:80;
}
upstream pc {
server 172.16.1.8:80;
}

server {
listen 80;
server_name agent.zjh.net;

​ location / {
​ default_type text/html;
​ if ($http_user_agent ~* "iphone|android|ipad") {
​ proxy_pass http://phone;
​ }
​ if ($http_user_agent ~* "MSIE|Trident") {
​ #return 403; (返回403状态码)
​ return 200 'Please Change Browser'; (返回请更换浏览器)
​ #return 302 'https://www.firefox.com.cn/download/thanks/'; (自动跳转下载其他浏览器)
​ }
​ proxy_pass http://pc;
​ include proxy_params;
​ }

}

多级代理获取真实ip地址

基于代理(七层负载均衡)获取真实ip
配置一级代理:

[root@proxy01 conf.d]

# cat proxy_ip.oldxu.net.conf

server {

listen 80 ;

server_name ip.oldxu.net;

location / {

proxy_pass http://10.0.0.7;

proxy_http_version 1.1;

proxy_set_header Host $http_host;

proxy_set_header X-Real-IP $remote_addr;

proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;

​ }

}

配置二级代理:

[root@proxy01 conf.d]

# cat proxy_ip.oldxu.net.conf

server {

listen 80 ;

server_name ip.oldxu.net;

location / {

proxy_pass http://10.0.0.8;

proxy_http_version 1.1;

proxy_set_header Host $http_host;

proxy_set_header X-Real-IP $remote_addr;

proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;

​ }

}

配置应用节点:

[ root@web02 conf.d]# cat ip.oldxu.net.conf

server {

listen 80;

server_name ip.oldxu.net;

root /code;

location / {

index index.php index.html;

​ }

location ~ \.php$ {

fastcgi_pass 127.0.0.1:9000;

fastcgi_param SCRIPT_FILENAME $document_root$fastcgi_script_name;

include fastcgi_params;

​ }

}

基于Realip模块获取真实ip地址(Realip模块需要知道沿途经过的所有代理节点的ip地址)

[root@web02 conf.d]# cat ip.oldxu.net.conf
server {
listen 80;
server_name ip.oldxu.net;
root /code;
set_real_ip_from 10.0.0.5;
set_real_ip_from 10.0.0.7;
real_ip_header X-Forwarded-For;
real_ip_recursive on;

}

四层负载均衡

四层负载均衡应用场景

1、端口代理:应用于非http的应用(如mysql,redis,ssh等),只能用四层负载均衡

2、四层 + 七层实现大规模集群架构

image-20250422083555670.png

Nginx代理模式
Lvs转发模式

基于Mysql的四层负载均衡的实现

1、配置mysql,创建远程连接的用户与密码

[root@web01 ~]# mysql -uroot -pzjh123

MariaDB [(none)]> grant all privileges on . to 'app'@'%' identified by 'zjh123';
Query OK, 0 rows affected (0.00 sec)

2、配置nginx

vim /etc/nginx/nginx.conf

(需要添加在关键字http上)

stream {
upstream mysql {
server 172.16.1.7:3306;
server 172.16.1.51:3306;
}

​ server {
​ listen 3366;
​ proxy_pass mysql;
​ }

}

netstat -lntp (检查是否有监听到3366端口)
Active Internet connections (only servers)
Proto Recv-Q Send-Q Local Address Foreign Address State PID/Program name
tcp 0 0 0.0.0.0:3366 0.0.0.0:* LISTEN 1085/nginx: master

3、准备一台管理端并配置
测试通过远程登录数据库

mysql -h 10.0.0.5 -P3366 -uapp -pzjh123

查看当前数据库属于什么主机

MariaDB [(none)]> select @@hostname;

查看当前数据库的详情

MariaDB [(none)]> show databases;

基于tcp的端口代理

[root@proxy01 ~]# vim /etc/nginx/nginx.conf

events {
worker_connections 1024;
}

stream {
upstream mysql {
server 172.16.1.7:3306;
server 172.16.1.51:3306;
}

​ server {
​ listen 3366;
​ proxy_pass mysql;
​ }
​ server {
​ listen 6666;
​ proxy_pass 172.16.1.51:22;
​ }

}

http {

测试通过端口远程登录(可实现类似跳板机的功能)

[c:~]$ ssh root@10.0.0.5 6666

基于80端口代理

四层配置:

stream {
upstream web_cluster {
server 172.16.1.5:80;
server 172.16.1.6:80;
server 172.16.1.7:80;
}

​ server {
​ listen 80;
​ proxy_pass web_cluster;
​ }

}

七层配置:

upstream http {
server 172.16.1.10:80;
server 172.16.1.11:80;
server 172.16.1.12:80;
}
server {
listen 80;
server_name proxy.zjh.net;

​ location / {
​ proxy_pass http://xx;
​ include proxy_params;
​ }

}