web服务之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
http://nginx.org/en/docs/stream/ngx_stream_upstream_module.html

tcp负载均衡配置参数

stream { #定义stream相关的服务;Context:main
    upstream backend { #定义后端服务器
        hash $remote_addr consistent; #定义调度算法
        server backend1.example.com:12345 weight=5; #定义具体server
        server 127.0.0.1:12345 max_fails=3 fail_timeout=30s;
        server unix:/tmp/backend3;
}
    upstream dns { #定义后端服务器
       server 10.0.0.1:53535; #定义具体server
       server dns.example.com:53;
}
    server { #定义server
        listen 12345; #监听IP:PORT
        proxy_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;
    }
}

负载均衡实例 : Redis

后端服务器安装 redis
#安装两台redis服务器
[root@centos8 ~]# yum -y install redis

# 使用sed命令替换改下面的
[root@centos8 ~]# sed -i '/^bind /c bind 0.0.0.0' /etc/redis.conf
[root@centos8 ~]# systemctl enable --now redis
[root@centos8 ~]# ss -tnl | grep 6379
LISTEN 0 128 *:6379 *:*

# nginx 配置
[root@centos8 ~]# vim /apps/nginx/conf/nginx.conf
include /apps/nginx/conf/tcp/*.conf; #注意此处的include与http模块平级
[root@centos8 ~]# mkdir /apps/nginx/conf/tcp
[root@centos8 ~]# cat /apps/nginx/conf/tcp/tcp.conf
stream {
    upstream redis_server {
        #hash $remote_addr consistent;
        server 172.31.0.28:6379 max_fails=3 fail_timeout=30s;
        server 172.31.0.48:6379 max_fails=3 fail_timeout=30s;
    }
    server {
        listen 172.31.0.18:6379;
        proxy_connect_timeout 3s;
        proxy_timeout 3s;
        proxy_pass redis_server;
    }
}

# 重启nginx并访问测试
[root@centos8 ~]# systemctl restart nginx
[root@centos8 ~]# ss -tnl | grep 6379
LISTEN 0 128 172.31.0.18:6379 *:*

#测试通过nginx 负载连接redis:
[root@centos8 ~]# redis-cli -h 172.31.0.18 set name long
OK
[root@centos8 ~]# redis-cli -h 172.31.0.18 get name
(nil)
[root@centos8 ~]# redis-cli -h 172.31.0.18 get name
"long"

负载均衡实例: MySQL

# 安装MySQL服务
[root@centos8 ~]# yum -y install mariadb-server
[root@centos8 ~]# systemctl enable --now mariadb
MariaDB [(none)]> create user long@'172.31.0.%' identified by 'centos';
MariaDB [(none)]> FLUSH PRIVILEGES;
MariaDB [(none)]> exit

# nginx配置
[root@centos8 ~]# cat /apps/nginx/conf/tcp/tcp.conf
stream {
    upstream redis_server {
        server 172.31.0.28:6379 max_fails=3 fail_timeout=30s;
        server 172.31.0.48:6379 max_fails=3 fail_timeout=30s;
        #server 172.31.0.48:6379 max_fails=3 fail_timeout=30s backup;
    }
    upstream mysql_server {
        least_conn;
        server 172.31.0.28:3306 max_fails=3 fail_timeout=30s;
    }

    server {
        listen 172.31.0.18:3306;
        proxy_connect_timeout 6s;
        proxy_timeout 15s;
        proxy_pass mysql_server;
    }
    server {
        listen 172.31.0.18:6379;
        proxy_connect_timeout 3s;
        proxy_timeout 3s;
        proxy_pass redis_server;
    }
}

# 重启nginx并访问测试:
[root@centos8 ~]# systemctl restart nginx

# 测试通过nginx负载连接MySQL:
[root@centos8 ~]# mysql -ulong -pcentos -h172.31.0.18 -e 'show variables like "hostname"'
+---------------+-------------------------+
| Variable_name | Value |
+---------------+-------------------------+
| hostname | mysql-server1.longxuan.vip   |
+---------------+-------------------------+
[root@centos8 ~]# mysql -ulong -pcentos -h172.31.0.18 -e 'show variables like "hostname"'
+---------------+-------------------------+
| Variable_name | Value |
+---------------+-------------------------+
| hostname | mysql-server2.longxuan.vip   |
+---------------+-------------------------+

#在172.31.0.48停止MySQL服务
[root@centos8 ~]# systemctl stop mysqld
#再次测试访问,只会看到mysql-server1.longxuan.vip进行响应
[root@centos8 ~]# mysql -ulong -pcentos -h172.31.0.18 -e 'show variables like "hostname"'
+---------------+-------------------------+
| Variable_name | Value |
+---------------+-------------------------+
| hostname | mysql-server1.longxuan.vip   |
+---------------+-------------------------+

负载均衡实例: DNS

stream {
    upstream dns_servers {
        server 172.31.0.7:53;
        server 172.31.0.17:53;
    }
    server {
        listen 53 udp;
        proxy_pass dns_servers;
        proxy_timeout 1s;
        proxy_responses 1; #使用UDP协议时,设置代理服务器响应客户端期望的数据报数。该值作会话终止条件
        error_log logs/dns.log;
    }
}

FastCGI配置指令

什么是PHP-FPM?
PHP-FPM(FastCGI Process Manager:FastCGI进程管理器)是一个实现了Fastcgi的程序,并且提供进程
管理的功能。进程包括master进程和worker进程。master进程只有一个,负责监听端口,接受来自
web server的请求。worker进程一般会有多个,每个进程中会嵌入一个PHP解析器,进行PHP代码的处
理。

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

fastcgi_pass address:port;
#转发请求到后端服务器,address为后端的fastcgi server的地址,可用位置:location, if in
location
fastcgi_index name;
#fastcgi默认的主页资源,示例:fastcgi_index index.php;
fastcgi_param parameter value [if_not_empty];
#设置传递给FastCGI服务器的参数值,可以是文本,变量或组合,可用于将Nginx的内置变量赋值给自定义
key
fastcgi_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
}

fastcgi 缓存定义指令:注意使用fastcgi缓存,可能会导致源代码更新失败,生产慎用

fastcgi_cache_path path [levels=levels] [use_temp_path=on|off]
keys_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];
#定义fastcgi的缓存;
path   #缓存位置为磁盘上的文件系统路径
max_size=size   #磁盘path路径中用于缓存数据的缓存空间上限
levels=levels:缓存目录的层级数量,以及每一级的目录数量,levels=ONE:TWO:THREE,示例:
leves=1:2:2
keys_zone=name:size #设置缓存名称及k/v映射的内存空间的名称及大小
inactive=time #缓存有效时间,默认10分钟,需要在指定时间满足fastcgi_cache_min_uses 次数被视为活动缓存。

缓存调用指令:

fastcgi_cache zone | off;
#调用指定的缓存空间来缓存数据,可用位置:http, server, location
fastcgi_cache_key string;
#定义用作缓存项的key的字符串,示例:fastcgi_cache_key $request_uri;
fastcgi_cache_methods GET | HEAD | POST ...;
#为哪些请求方法使用缓存
fastcgi_cache_min_uses number;
#缓存空间中的缓存项在inactive定义的非活动时间内至少要被访问到此处所指定的次数方可被认作活动项
fastcgi_keep_conn on | off;
#收到后端服务器响应后,fastcgi服务器是否关闭连接,建议启用长连接
fastcgi_cache_valid [code ...] time;
#不同的响应码各自的缓存时长
fastcgi_hide_header field; #隐藏响应头指定信息
fastcgi_pass_header field; #返回响应头指定信息,默认不会将Status、X-Accel-...返回

FastCGI实战案例 : Nginx与php不在同一个服务器

nginx会处理静态请求,但是会转发动态请求到后端指定的php-fpm服务器,因此代码也需要放在后端的
php-fpm服务器,即静态页面放在Nginx服务器上,而动态页面放在后端php-fpm服务器,正常情况下,一般都是采用在同一个服务器

# yum安装较新版本php-fpm
[root@centos8 ~]# dnf -y install php-fpm php-mysqlnd php-json

# 验证安装路径:
[root@centos8 ~]#rpm -ql php-fpm
/etc/httpd/conf.d/php.conf
/etc/logrotate.d/php-fpm
/etc/nginx/conf.d/php-fpm.conf
...

# 修改php-fpm监听配置
php-fpm默认监听在127.0.0.1的9000端口,也就是无法远程连接,因此要做相应的修改。
# 修改监听配置
[root@centos8 ~]# vim /etc/php-fpm.d/www.conf
;listen = /run/php-fpm/www.sock #注释此行
listen = 9000 #指定监听端口
;listen.allowed_clients = 127.0.0.1 #注释此行

# 准备php测试页面
#准备php数据目录
[root@centos8 ~]# mkdir -p /data/php
[root@centos8 ~]# vim /data/php/index.php
<?php
phpinfo();
?>

# 启动并验证php-fpm
[root@centos8 ~]# systemctl enable --now php-fpm.service

# 验证php-fpm进程及端口:
[root@centos8 ~]# ps -ef | grep php-fpm
[root@centos8 ~]# lsof -i :9000
COMMAND   PID   USER   FD   TYPE DEVICE SIZE/OFF NODE NAME
php-fpm 12082   root    9u  IPv6  43393      0t0  TCP *:cslistener (LISTEN)
php-fpm 12083 apache   11u  IPv6  43393      0t0  TCP *:cslistener (LISTEN)
php-fpm 12084 apache   11u  IPv6  43393      0t0  TCP *:cslistener (LISTEN)
php-fpm 12085 apache   11u  IPv6  43393      0t0  TCP *:cslistener (LISTEN)
php-fpm 12086 apache   11u  IPv6  43393      0t0  TCP *:cslistener (LISTEN)
php-fpm 12087 apache   11u  IPv6  43393      0t0  TCP *:cslistener (LISTEN)

# Nginx配置转发
[root@centos8 ~]# vim /apps/nginx/conf/conf.d/pc.conf
location ~ \.php$ {
    root /data/php;
    fastcgi_pass 172.31.0.38:9000;
    fastcgi_index  index.php;
    #fastcgi_param  SCRIPT_FILENAME /data/php$fastcgi_script_name;
    fastcgi_param SCRIPT_FILENAME $document_root$fastcgi_script_name;
    include   fastcgi_params;
}
location ~ ^/(ping|status)$ {
    include fastcgi_params;
    fastcgi_pass 172.31.0.38:9000;
    fastcgi_param PATH_TRANSLATED $document_root$fastcgi_script_name;
}

# 重启nginx
[root@centos8 ~]# systemctl restart nginx

# 实现动静分离
要求:将客户端对除php以外的资源的访问转发至后端服务器 172.31.0.48上
配置 nginx 实现反向代理的动静分离
[root@centos8 ~]# vim /apps/nginx/conf/conf.d/pc.conf
location / {
    proxy_pass http://172.31.0.48;
    index index.html;
}
location ~ \.php$ {
    root /data/php;
    fastcgi_pass 172.31.0.38:9000;
    fastcgi_index index.php;
    #fastcgi_param SCRIPT_FILENAME /data/php$fastcgi_script_name;
    fastcgi_param SCRIPT_FILENAME $document_root$fastcgi_script_name;
    include fastcgi_params;
}

#在后端服务器172.31.0.48上安装httpd服务
[root@centos8 ~]# dnf -y install httpd
[root@centos8 ~]# systemctl enable --now httpd
[root@centos8 ~]# mkdir /var/www/html/images
[root@centos8 ~]# wget -O /var/www/html/images/long.jpg 'https://img1.baidu.com/it/u=3603866546,327523286&fm=26&fmt=auto&gp=0.jpg'

# 测试访问(可以看到后端刚才下载的图片)
http://www.longxuan.vip/images/long.jpg

项目实战:利用LNMP实现可道云私有云

可道云,原名芒果云,是基于Web技术的私有云在线文档管理解决方案。Kod,读音通code,意为“代码,编码”,中文名为“可道”。

官网: http://kodcloud.com/

环境说明

#部署规划:
172.31.0.17:CentOS7,Nginx1.16,php-fpm7.4,kodbox.1.20
172.31.0.38:CentOS8,MySQL8.0,Redis5.0

准备 MySQL 数据库

[root@centos8 ~]# yum -y install mysql-server
[root@centos8 ~]# systemctl enable --now mysqld
[root@centos8 ~]# mysql
mysql> create database kodbox;
Query OK, 1 row affected (0.00 sec)
mysql> create user kodbox@'172.31.0.%' identified by '123456';
Query OK, 0 rows affected (0.00 sec)
mysql> grant all on kodbox.* to kodbox@'172.31.0.%';
Query OK, 0 rows affected (0.00 sec)

准备 Redis 服务

[root@centos8 ~]# yum -y install redis
[root@centos8 ~]# vim /etc/redis.conf
bind 0.0.0.0 #修改此行
[root@centos8 ~]# systemctl enable --now redis

准备 Nginx 服务

[root@centos7 ~]# yum -y install nginx
[root@centos7 ~]# mkdir -pv /data/html
#创建配置文件
[root@centos7 ~]# vim /etc/nginx/conf.d/kodd.conf
server {
    listen 80;
    server_name cloud.longxuan.vip;
    root /data/html;
    location / {
        index index.php index.html;
    }
    location ~ \.php$ {
        fastcgi_pass 127.0.0.1:9000;
        fastcgi_index index.php;
        fastcgi_param SCRIPT_FILENAME $document_root$fastcgi_script_name;
        include fastcgi_params;
    }
}

[root@centos7 ~]# systemctl enabled --now nginx

安装和配置 php 支持 redis

[root@centos7 ~]# yum install https://mirror.tuna.tsinghua.edu.cn/remi/enterprise/remi-release-7.rpm
#安装必要的包
[root@centos7 ~]# yum -y install php74-php-fpm php74-php-mysqlnd php74-php-pecl-redis5 php74-php-mbstring php74-php-xml php74-php-gd

[root@localhost ~]# rpm -ql php74-php-fpm
/etc/logrotate.d/php74-php-fpm
/etc/opt/remi/php74/php-fpm.conf
/etc/opt/remi/php74/php-fpm.d
/etc/opt/remi/php74/php-fpm.d/www.conf

[root@centos7 ~]# grep -Ee 'php_value\[session\.' -e 'user' -e 'group' /etc/opt/remi/php74/php-fpm.d/www.conf
# 使用sed命令 一次性修改
[root@centos7 ~]# sed -ri -e 's@^(user =).*@\1 nginx@' -e 's#^(group =).*#\1 nginx#' -e 's#^(php_value\[session\.save_handler\] =).*#\1 redis#' -e 's@^(php_value\[session\.save_path\]    =).*@\1 "tcp://172.31.0.38:6379"@' /etc/opt/remi/php74/php-fpm.d/www.conf

# 再次检查是否已修改
[root@centos7 ~]# grep -Ee 'php_value\[session\.' -e 'user' -e 'group' /etc/opt/remi/php74/php-fpm.d/www.conf
user = nginx
group = nginx

# 文件最后修改下面两行
php_value[session.save_handler] = redis
php_value[session.save_path] = "tcp://172.31.0.38:6379"

# 启动
[root@localhost ~]# systemctl enable --now php74-php-fpm.service

准备可道云软件包

[root@centos7 ~]# wget https://static.kodcloud.com/update/download/kodbox.1.20.zip
[root@centos7 ~]# unzip kodbox.1.20.zip -d /data/html
[root@centos7 ~]# chown -R nginx.nginx /data/html

初始化和登录可道云

测试上传图片

验证数据库和 session 信息

# redis
[root@centos8 ~]# redis-cli
127.0.0.1:6379> keys *
(empty list or set)
127.0.0.1:6379> keys *
 1) "1899c_UserOption_User.tagList_1"
 2) "1899c_SystemOption_System.roleList"
 3) "1899c_UserOption__0"
 4) "1899c_SystemOption_"
 5) "1899c_GroupModel_getInfo_ID_1"
 6) "1899c_SystemOption_System.noticeList"
 7) "1899c_UserOption_editor_1"
 8) "1899c_Source_getContent_85c80bfea48af1571a8cadb93cccb41d"
 9) "1899c_UserFavModel_listData_ID_1"
10) "1899c_SystemOption_System.taskList"
11) "1899c_SystemOption_System.sourceAuthList"
12) "1899c_UserModel_getInfoSimple_ID_1"
13) "1899c_UserOption_flag_1"
14) "1899c_SystemOption_System.recordUserList"
15) "1899c_UserOption__1"
16) "1899c_UserModel_getInfoFull_ID_1"
17) "1899c_SystemOption_System.LightApp"
18) "354a6d93e43a7dc729832cc7c1ed1ce9"
19) "1899c_SystemOption_System.autoTask"
20) "1899c_Source_getContent_fc993ef64e883ff98da1bbc87b230504"
21) "1899c_%7Bsource%3A19%7D%2FattachmentTemp%2F"
22) "1899c_Source_getContent_ad9b596b2464a7e72ce4e9977fd8bac6"
23) "1899c_Source_getContent_95d1cfafbfdab706d6fd8b305f77d0c1"
24) "1899c_Source_getContent_7610e997326fb3d44fa6e6004e232599"
25) "1899c_GroupModel_getInfoSimple_ID_1"
26) "1899c_Source_getContent_592d2b10b7978b9b92700e903953e4b4"
27) "1899c_UserOption_User.noticeList_1"
28) "1899c_SystemOption_System.pluginList"
29) "1899c_UserModel_getInfo_ID_1"
30) "1899c_ShareModel_listSimple_ID_1"
31) "1899c_SystemOption_System.storageList"
32) "1899c_Source_getContent_bb092732fe01a004201b2a34ab3e7175"
33) "1899c_IO_hashMd5_shell"
34) "1899c_UserOption_recycle_1"
35) "1899c_UserTagSourceModel_listData_ID_1"
36) "1899c_Source_getContent_034277da6db6ce039095d1d8992c0918"
37) "1899c_IO_check_ff8ae4f3c49005cd92e204e75994db51"

# mysql
mysql> use kodbox
Reading table information for completion of table and column names
You can turn off this feature to get a quicker startup with -A
Database changed
mysql> show tables;
+-------------------+
| Tables_in_kodbox  |
+-------------------+
| comment           |
| comment_meta      |
| comment_praise    |
| group             |
| group_meta        |
| io_file           |
| io_file_contents  |
| io_file_meta      |
| io_source         |
| io_source_auth    |
| io_source_event   |
| io_source_history |
| io_source_meta    |
| io_source_recycle |
| share             |
| share_report      |
| share_to          |
| system_log        |
| system_option     |
| system_session    |
| user              |
| user_fav          |
| user_group        |
| user_meta         |
| user_option       |
+-------------------+
25 rows in set (0.00 sec)

优化内核参数

修改/etc/sysctl.conf

fs.file-max = 1000000
#表示单个进程较大可以打开的句柄数
net.ipv4.tcp_tw_reuse = 1
#参数设置为 1 ,表示允许将TIME_WAIT状态的socket重新用于新的TCP链接,这对于服务器来说意义重
大,因为总有大量TIME_WAIT状态的链接存在
net.ipv4.tcp_keepalive_time = 600
#当keepalive启动时,TCP发送keepalive消息的频度;默认是2小时,将其设置为10分钟,可更快的清理无
效链接
net.ipv4.tcp_fin_timeout = 30
#当服务器主动关闭链接时,socket保持在FIN_WAIT_2状态的较大时间
net.ipv4.tcp_max_tw_buckets = 5000
#表示操作系统允许TIME_WAIT套接字数量的较大值,如超过此值,TIME_WAIT套接字将立刻被清除并打印警
告信息,默认为8000,过多的TIME_WAIT套接字会使Web服务器变慢
net.ipv4.ip_local_port_range = 1024 65000
#定义UDP和TCP链接的本地端口的取值范围
net.ipv4.tcp_rmem = 10240 87380 12582912
#定义了TCP接受缓存的最小值、默认值、较大值
net.ipv4.tcp_wmem = 10240 87380 12582912
#定义TCP发送缓存的最小值、默认值、较大值
net.core.netdev_max_backlog = 8096
#当网卡接收数据包的速度大于内核处理速度时,会有一个列队保存这些数据包。这个参数表示该列队的较大值
net.core.rmem_default = 6291456
#表示内核套接字接受缓存区默认大小
net.core.wmem_default = 6291456
#表示内核套接字发送缓存区默认大小
net.core.rmem_max = 12582912
#表示内核套接字接受缓存区较大大小
net.core.wmem_max = 12582912
#表示内核套接字发送缓存区较大大小
注意:以上的四个参数,需要根据业务逻辑和实际的硬件成本来综合考虑
net.ipv4.tcp_syncookies = 1
#与性能无关。用于解决TCP的SYN攻击
net.ipv4.tcp_max_syn_backlog = 8192
#这个参数表示TCP三次握手建立阶段接受SYN请求列队的较大长度,默认1024,将其设置的大一些可使出现
Nginx繁忙来不及accept新连接时,Linux不至于丢失客户端发起的链接请求
net.ipv4.tcp_tw_recycle = 1
#这个参数用于设置启用timewait快速回收
net.core.somaxconn=262114
#选项默认值是128,这个参数用于调节系统同时发起的TCP连接数,在高并发的请求中,默认的值可能会导致
链接超时或者重传,因此需要结合高并发请求数来调节此值。
net.ipv4.tcp_max_orphans=262114
#选项用于设定系统中最多有多少个TCP套接字不被关联到任何一个用户文件句柄上。如果超过这个数字,孤立
链接将立即被复位并输出警告信息。这个限制指示为了防止简单的DOS攻击,不用过分依靠这个限制甚至认为
的减小这个值,更多的情况是增加这个值

PAM 资源限制优化

#在/etc/security/limits.conf 最后增加:
* soft nofile 65535
* hard nofile 65535
* soft nproc 65535
* hard nproc 65535
posted @ 2021-06-23 21:17  空白的旋律  阅读(307)  评论(0编辑  收藏  举报