一、前言
Nginx不光可以實(shí)現(xiàn)Web Server,還可以作為HTTP負(fù)載均衡來(lái)分發(fā)流量給后端的應(yīng)用程序服務(wù)器,以此來(lái)提高性能。Nginx的負(fù)載均衡功能依賴(lài)于ngx_http_upstream_module模塊,所支持的代理方式有proxy_pass,fastcgi_pass,memcached_pass。
此外Nginx還支持四層傳輸層負(fù)載均衡,可以基于TCP/UDP的鏈接會(huì)話負(fù)載到后端的服務(wù)器中。
Nginx常用負(fù)載均衡算法:
輪詢(xún)(默認(rèn)算法):每個(gè)請(qǐng)求會(huì)依次分配給后端不同的應(yīng)用程序服務(wù)器,不理會(huì)后端服務(wù)器的實(shí)際壓力
最少連接:請(qǐng)求會(huì)被分配到連接數(shù)最少的后端服務(wù)器
加權(quán)輪詢(xún):權(quán)重越大的服務(wù)器,被分配到的次數(shù)就會(huì)越多,通常用于后端服務(wù)器性能不一致的情況
IP HASH:當(dāng)同IP進(jìn)行重復(fù)訪問(wèn)時(shí)會(huì)被指定到上次訪問(wèn)到的服務(wù)器,可以解決動(dòng)態(tài)網(wǎng)站SESSION共享問(wèn)題
附上wo
二、nginx的HTTP負(fù)載均衡

按照上述拓?fù)鋱D,部署lnamp環(huán)境,實(shí)現(xiàn)nginx負(fù)載均衡后端的兩個(gè)apache web服務(wù),要求在apache上搭建wordpress和pma應(yīng)用。
wordpress的下載鏈接:https://cn.wordpress.org/wordpress-4.9.4-zh_CN.tar.gz
pma的下載鏈接:https://files.phpmyadmin.net/phpMyAdmin/4.0.10.20/phpMyAdmin-4.0.10.20-all-languages.tar.gz
1、搭建應(yīng)用服務(wù)器
安裝PHP-fpm和數(shù)據(jù)庫(kù)等相關(guān)程序
[root@app ~]# yum install php php-fpm php-mcrypt php-mysql php-mbstring mariadb-server -y
編輯/etc/php-fpm.d/www.conf的內(nèi)容:
[root@app ~]# vim /etc/php-fpm.d/www.conf
listen = 0.0.0.0:9000
listen.allowed_clients = 192.168.0.83,192.168.0.84
pm.status_path = /status
ping.path = /ping
ping.response = pong
php_value[session.save_path] = /var/lib/php/session
隨后創(chuàng)建會(huì)話目錄并更改會(huì)話目錄的屬主屬組:
[root@app ~]# mkdir -pv /var/lib/php/session
mkdir: created directory ‘/var/lib/php/session’
[root@app ~]# chown apache:apache /var/lib/php/session/
隨后啟動(dòng)php-fpm服務(wù):
drwxrwx---. 2 root apache 6 Apr 12 15:04 /var/lib/php/session/
[root@app ~]# systemctl start php-fpm
[root@app ~]# ss -tnl
State Recv-Q Send-Q Local Address:Port Peer Address:Port
LISTEN 0 128 *:22 *:*
LISTEN 0 100 127.0.0.1:25 *:*
LISTEN 0 128 *:9000 *:*
LISTEN 0 128 :::22 :::*
LISTEN 0 100 ::1:25 :::*
接著創(chuàng)建web資源存放目錄:
[root@app ~]# mkdir -pv /data/apache/html
mkdir: created directory ‘/data’
mkdir: created directory ‘/data/apache’
mkdir: created directory ‘/data/apache/html’
創(chuàng)建php頁(yè)面:
[root@app ~]# vim /data/apache/html/index.php
<h1>This is app</h1>
<?php
phpinfo();
?>
下載wordpress和phpMyadmin到該目錄并解壓生成軟連接:
[root@app ~]# cd /data/apache/html
[root@app html]# wget https://cn.wordpress.org/wordpress-4.9.4-zh_CN.tar.gz
[root@app html]# wget https://files.phpmyadmin.net/phpMyAdmin/4.0.10.20/phpMyAdmin-4.0.10.20-all-languages.tar.gz
[root@app html]# tar xf wordpress-4.9.4-zh_CN.tar.gz
[root@app html]# tar xf phpMyAdmin-4.0.10.20-all-languages.tar.gz
[root@app html]# ln -sv phpMyAdmin-4.0.10.20-all-languages pma
‘pma’ -> ‘phpMyAdmin-4.0.10.20-all-languages’
[root@app html]# ln -sv wordpress blog
‘blog’ -> ‘wordpress
接著配置mariadb-server,編輯/etc/my.cnf文件:
#添加下面兩行配置
[root@app ~]# vim /etc/my.cnf
skip-name-resolve=ON
innodb-file-per-table=ON
隨后啟動(dòng)mariadb-server服務(wù):
[root@app ~]# systemctl start mariadb
接著設(shè)置mysql的root密碼:
[root@app ~]# mysql_secure_installation
NOTE: RUNNING ALL PARTS OF THIS SCRIPT IS RECOMMENDED FOR ALL MariaDB
SERVERS IN PRODUCTION USE! PLEASE READ EACH STEP CAREFULLY!
In order to log into MariaDB to secure it, we'll need the current
password for the root user. If you've just installed MariaDB, and
you haven't set the root password yet, the password will be blank,
so you should just press enter here.
Enter current password for root (enter for none):
OK, successfully used password, moving on...
Setting the root password ensures that nobody can log into the MariaDB
root user without the proper authorisation.
Set root password? [Y/n] y
New password:
Re-enter new password:
Password updated successfully!
Reloading privilege tables..
... Success!
在數(shù)據(jù)庫(kù)中創(chuàng)建wordpress數(shù)據(jù)庫(kù)并授權(quán)wpuser管理賬號(hào):
MariaDB [(none)]> create database wordpress;
Query OK, 1 row affected (0.00 sec)
MariaDB [(none)]> grant all on wordpress.* to 'wpuser'@'192.168.0.%' identified by "magedu";
Query OK, 0 rows affected (0.00 sec)
最后檢查關(guān)閉應(yīng)用服務(wù)器的firewalld和selinux:
[root@app ~]# systemctl stop firewalld
[root@app ~]# setenforce 0
2、搭建apache服務(wù)器
由于兩個(gè)apache服務(wù)器安裝的流程及步驟類(lèi)似,此處我們?nèi)∫慌_(tái)作為示例,剩下一臺(tái)的按照示例配置即可。
首先安裝http服務(wù):
[root@ap1 ~]# yum install -y httpd
接著創(chuàng)建web資源存放目錄:
[root@ap1 ~]# mkdir -pv /data/apache/html
mkdir: created directory ‘/data’
mkdir: created directory ‘/data/apache’
mkdir: created directory ‘/data/apache/html’
創(chuàng)建web主頁(yè)頁(yè)面:
[root@ap1 ~]# vim /data/apache/html/index.html
<h1>This is apache 1 192.168.0.83</h1>
創(chuàng)建php頁(yè)面:
[root@ap1 ~]# vim /data/apache/html/index.php
<h1>This is ap 1</h1>
<?php
phpinfo();
?>
下載wordpress和phpMyadmin到該目錄并解壓生成軟連接:
[root@ap1 ~]# cd /data/apache/html
[root@ap1 html]# wget https://cn.wordpress.org/wordpress-4.9.4-zh_CN.tar.gz
[root@ap1 html]# wget https://files.phpmyadmin.net/phpMyAdmin/4.0.10.20/phpMyAdmin-4.0.10.20-all-languages.tar.gz
[root@ap1 html]# tar xf wordpress-4.9.4-zh_CN.tar.gz
[root@ap1 html]# tar xf phpMyAdmin-4.0.10.20-all-languages.tar.gz
[root@ap1 html]# ln -sv phpMyAdmin-4.0.10.20-all-languages pma
‘pma’ -> ‘phpMyAdmin-4.0.10.20-all-languages’
[root@ap1 html]# ln -sv wordpress blog
‘blog’ -> ‘wordpress
編輯生成/etc/httpd/conf.d/vhosts.conf文件:
[root@ap1 html]# vim /etc/httpd/conf.d/vhosts.conf
<virtualhost *:80>
ServerName www.ilinux.io
DirectoryIndex index.html index.php
Documentroot /data/apache/html
ProxyRequests off
ProxyPassMatch ^/(.*\.php)$ fcgi://192.168.0.87:9000/data/apache/html/$1
ProxyPassMatch ^/(ping|status)$ fcgi://192.168.0.87:9000/$1
<Directory / >
options FollowSymLinks
Allowoverride none
Require all granted
</Directory>
</virtualHost>
保存后檢查httpd配置并啟動(dòng)httpd服務(wù):
[root@ap1 ~]# httpd -t
Syntax OK
[root@ap1 ~]# systemctl start httpd
最后檢查并關(guān)閉firewalld和selinux:
[root@ap1 ~]# systemctl stop firewalld
[root@ap1 ~]# setenforce 0
至此apache服務(wù)器的配置就已經(jīng)完成,按照上述步驟配置第二臺(tái)服務(wù)器即可。
3、配置nginx負(fù)載均衡服務(wù)器
安裝nginx服務(wù):
[root@nginx ~]# yum install nginx -y
編輯配置/etc/nginx/nginx.conf文件:
[root@nginx ~]# vim /etc/nginx/nginx.conf
#在http配置段添加下面配置
http {
upstream apserver {
server 192.168.0.83:80 max_fails=3;
server 192.168.0.84:80 max_fails=3;
server 127.0.0.1:80 backup;
}
server {
listen 80 default_server;
listen [::]:80 default_server;
server_name _;
root /usr/share/nginx/html;
# Load configuration files for the default server block.
include /etc/nginx/default.d/*.conf;
location / {
proxy_pass http://apserver; #代理到apserver upstream服務(wù)器組
}
error_page 404 /404.html;
location = /40x.html {
}
error_page 500 502 503 504 /50x.html;
location = /50x.html {
}
}
}
啟動(dòng)nginx服務(wù):
[root@nginx ~]# systemctl start nginx
檢查關(guān)閉firewalld和selinux:
[root@nginx ~]# systemctl stop firewalld
[root@nginx ~]# setenforce 0
測(cè)試訪問(wèn):


測(cè)試在訪問(wèn)wordpress時(shí),代理請(qǐng)求發(fā)送的host為apserver,與pma不一致,且頁(yè)面返回不完整。
在經(jīng)過(guò)查找資料及排錯(cuò)后,這問(wèn)題需要在nginx的負(fù)載均衡配置中修改相應(yīng)的請(qǐng)求報(bào)文的host首部,具體解釋可看下面的引用:
nginx為了實(shí)現(xiàn)反向代理的需求而增加了一個(gè)ngx_http_proxy_module模塊。其中proxy_set_header指令就是該模塊需要讀取的配置文件。在這里,所有設(shè)置的值的含義和http請(qǐng)求同中的含義完全相同,除了Host外還有X-Forward-For。
Host的含義是表明請(qǐng)求的主機(jī)名,因?yàn)閚ginx作為反向代理使用,而如果后端真是的服務(wù)器設(shè)置有類(lèi)似防盜鏈或者根據(jù)http請(qǐng)求頭中的host字段來(lái)進(jìn)行路由或判斷功能的話,如果反向代理層的nginx不重寫(xiě)請(qǐng)求頭中的host字段,將會(huì)導(dǎo)致請(qǐng)求失敗【默認(rèn)反向代理服務(wù)器會(huì)向后端真實(shí)服務(wù)器發(fā)送請(qǐng)求,并且請(qǐng)求頭中的host字段應(yīng)為proxy_pass指令設(shè)置的服務(wù)器】。
同理,X_Forward_For字段表示該條http請(qǐng)求是有誰(shuí)發(fā)起的?如果反向代理服務(wù)器不重寫(xiě)該請(qǐng)求頭的話,那么后端真實(shí)服務(wù)器在處理時(shí)會(huì)認(rèn)為所有的請(qǐng)求都來(lái)在反向代理服務(wù)器,如果后端有防攻擊策略的話,那么機(jī)器就被封掉了。因此,在配置用作反向代理的nginx中一般會(huì)增加兩條配置,修改http的請(qǐng)求頭:
proxy_set_header Host $http_host;
proxy_set_header X-Forward-For $remote_addr;
這里的$http_host和$remote_addr都是nginx的導(dǎo)出變量,可以再配置文件中直接使用。如果Host請(qǐng)求頭部沒(méi)有出現(xiàn)在請(qǐng)求頭中,則$http_host值為空,但是$host值為主域名。因此,一般而言,會(huì)用$host代替$http_host變量,從而避免http請(qǐng)求中丟失Host頭部的情況下Host不被重寫(xiě)的失誤。
引用鏈接:http://blog.51cto.com/4856809/1188931
另附上proxy_set_header設(shè)置的host的區(qū)別:https://blog.csdn.net/a19860903/article/details/49914131
因此需要在nginx服務(wù)器中添加如下配置:
[root@nginx ~]# vim /etc/nginx/nginx.conf
http {
upstream apserver {
server 192.168.0.83:80 max_fails=3;
server 192.168.0.84:80 max_fails=3;
server 127.0.0.1:80 backup;
}
server {
listen 80 default_server;
listen [::]:80 default_server;
server_name _;
root /usr/share/nginx/html;
# Load configuration files for the default server block.
include /etc/nginx/default.d/*.conf;
location / {
proxy_pass http://apserver;
proxy_set_header host $http_host; #設(shè)置代理請(qǐng)求報(bào)文的host為$http_host,即保持http請(qǐng)求的報(bào)文host不變;
proxy_set_header X-Forward-For $remote_addr; #設(shè)置轉(zhuǎn)發(fā)真實(shí)的客戶端訪問(wèn)IP;
add_header Cache-Control no-store; #添加不緩存的首部
}
error_page 404 /404.html;
location = /40x.html {
}
error_page 500 502 503 504 /50x.html;
location = /50x.html {
}
}
}
添加完成后新加載nginx服務(wù):
[root@nginx ~]# nginx -s reload
此時(shí)再去測(cè)試訪問(wèn)wordpress:

三、nginx的四層負(fù)載
在此前的拓?fù)渲?,我們?cè)趎ginx服務(wù)器上進(jìn)行如下操作即可實(shí)現(xiàn)nginx將ssh負(fù)載均衡到后端的兩個(gè)apache服務(wù)器上:
[root@nginx ~]# vim /etc/nginx/nginx.conf
#在main上下文添加stream配置段
stream {
upstream ssh {
server 192.168.0.83:22;
server 192.168.0.84:22;
}
server {
listen 192.168.0.81:9922;
proxy_pass ssh;
}
}
http {
....
}
[root@nginx ~]# nginx -s reload #重載nginx服務(wù)
[root@nginx ~]# ss -tnl
State Recv-Q Send-Q Local Address:Port Peer Address:Port
LISTEN 0 128 *:80 *:*
LISTEN 0 128 *:22 *:*
LISTEN 0 100 127.0.0.1:25 *:*
#此時(shí)相應(yīng)的監(jiān)聽(tīng)端口已正常啟動(dòng)
LISTEN 0 128 192.168.0.81:9922 *:*
LISTEN 0 128 :::80 :::*
LISTEN 0 128 :::22 :::*
LISTEN 0 100 ::1:25 :::*
測(cè)試訪問(wèn)連接:


測(cè)試的結(jié)果是因?yàn)槲覀兊膗pstream使用了輪詢(xún)的算法,所以訪問(wèn)192.168.0.81:9922的ssh請(qǐng)求會(huì)被負(fù)載均衡后ap1、ap2的兩臺(tái)服務(wù)器上去連接。