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 (修改为远端服务器的地址和用户名)
扩展多台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、四层 + 七层实现大规模集群架构
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;
}
}