12.17 Nginx負載均衡
要理解負載均衡,必須先搞清楚正向代理和反向代理
1、正向代理
正向代理類似一個跳板機,代理訪問外部資源,正向代理 是一個位於客戶端和原始服務器(origin server)之間的服務器,爲了從原始服務器取得內容,客戶端向代理髮送一個請求並指定目標(原始服務器),然後代理向原始服務器轉交請求並將獲得的內容返回給客戶端。客戶端必須要進行一些特別的設置才能使用正向代理。
正向代理的用途:
(1)訪問原來無法訪問的資源,如google
(2) 可以做緩存,加速訪問資源
(3)對客戶端訪問授權,上網進行認證
(4)代理可以記錄用戶訪問記錄(上網行爲管理),對外隱藏用戶信息
2、反向代理
客戶端是無感知代理的存在的,反向代理對外都是透明的,訪問者者並不知道自己訪問的是一個代理。因爲客戶端不需要任何配置就可以訪問。
反向代理(Reverse Proxy)實際運行方式是指以代理服務器來接受internet上的連接請求,然後將請求轉發給內部網絡上的服務器,並將從服務器上得到的結果返回給internet上請求連接的客戶端,此時代理服務器對外就表現爲一個服務器。
反向代理的作用:
(1)保證內網的安全,可以使用反向代理提供WAF功能,阻止web×××
大型網站,通常將反向代理作爲公網訪問地址,Web服務器是內網。
(2)負載均衡,通過反向代理服務器來優化網站的負載
3、nginx的負載均衡
nginx是通過反向代理實現網站的負載均衡。代理一臺機器爲代理,多臺機器,就叫負載均衡
Nginx負載均衡算法
(1)、輪詢(默認)
每個請求按時間順序逐一分配到不同的後端服務,如果後端某臺服務器死機,自動剔除故障系統,使用戶訪問不受影響。
(2)、weight(輪詢權值)
weight的值越大分配到的訪問概率越高,主要用於後端每臺服務器性能不均衡的情況下。或者僅僅爲在主從的情況下設置不同的權值,達到合理有效的地利用主機資源。
(3)、ip_hash
每個請求按訪問IP的哈希結果分配,使來自同一個IP的訪客固定訪問一臺後端服務器,並且可以有效解決動態網頁存在的session共享問題。
(4)、fair 第三方
比 weight、ip_hash更加智能的負載均衡算法,fair算法可以根據頁面大小和加載時間長短智能地進行負載均衡,也就是根據後端服務器的響應時間 來分配請求,響應時間短的優先分配。Nginx本身不支持fair,如果需要這種調度算法,則必須安裝upstream_fair模塊。
(5)、url_hash 第三方
按訪問的URL的哈希結果來分配請求,使每個URL定向到一臺後端服務器,可以進一步提高後端緩存服務器的效率。Nginx本身不支持url_hash,如果需要這種調度算法,則必須安裝Nginx的hash軟件包。
4、配置nginx負載均衡
通過dig可以查看到域名的解析IP地址,如果沒有這個命令可以安裝包
yum -y install bind-utils
我們用dig解析www.qq.com得到兩個IP,用來做實驗
[root@lnmp-server ~]# dig www.qq.com
; <<>> DiG 9.9.4-RedHat-9.9.4-61.el7 <<>> www.qq.com
;; global options: +cmd
;; Got answer:
;; ->>HEADER<<- opcode: QUERY, status: NOERROR, id: 12037
;; flags: qr rd ra; QUERY: 1, ANSWER: 2, AUTHORITY: 0, ADDITIONAL: 1
;; OPT PSEUDOSECTION:
; EDNS: version: 0, flags:; udp: 4096
;; QUESTION SECTION:
;www.qq.com. IN A
;; ANSWER SECTION:
www.qq.com. 95 IN A 59.37.96.63
www.qq.com. 95 IN A 58.60.9.21
上面得到有兩個IP 59.37.96.63和58.60.9.21,用來模擬nginx負載均衡的後端機器
先新建一個虛擬主機配置文件
[root@lnmp-server ~]# vi /usr/local/nginx/conf/vhost/ld.conf #寫入以下內容
upstream qq
{
ip_hash;
server 58.60.9.21:80;
server 59.37.96.63:80;
}
server
{
listen 80;
server_name www.qq.com;
location /
{
proxy_pass http://qq;
proxy_set_header Host $host;
proxy_set_header X-Real-IP $remote_addr;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
}
}
說明:
upstream qq : upstream是一個模塊,qq是模塊名,這個名字可以自定義,在代理的時候需要用到
ip_hash: nginx負載均衡算法之一,保持同一用戶始終在同一臺服務器上,可以解決會話共享問題
server 兩臺機器:後端服務器,這裏用dig解析出來的兩臺來模擬
listen 80; #定義監聽端口
server_name www.qq.com; #定義域名
proxy_pass http://qq; ##upstream定義的名稱,這個名稱代表着upstream裏定義的ip
編輯完之後保存退出,先不要重新加載配置文件,先測試一下用本機ip去訪問www.qq.com這個域名看看結果會是什麼:
[root@lnmp-server vhost]# curl -x127.0.0.1:80 www.qq.com
This is default server aaa
因爲還沒加載配置,所以www.qq.com解析到默認虛擬主機去了
檢測配置是否有錯並重載配置
[root@lnmp-server ~]# /usr/local/nginx/sbin/nginx -t
nginx: the configuration file /usr/local/nginx/conf/nginx.conf syntax is ok
nginx: configuration file /usr/local/nginx/conf/nginx.conf test is successful
[root@lnmp-server ~]# /usr/local/nginx/sbin/nginx -s reload
再用curl測試www.qq.com的結果
[root@lnmp-server ~]# curl -x127.0.0.1:80 www.qq.com
出現了qq網站的源代碼,說明配置成功
關於Nginx負載均衡方面要注意一點:
Nginx不支持直接代理https,只能代理http,也就是說443端口不支持只支持80端口。如果非要代理https,只能是用戶訪問Nginx代理服務器時使用https,然後Nginx去訪問後端的web服務器時使用http,屬於折中的一種方式,依然不能直接代理。
12.18 ssl原理
https就是使用ssl加密的http,是一種加密的超文本傳輸協議。如果http不加密的話,被人抓包或監聽了數據包,就能很輕易地看到數據包裏面的數據內容,那樣的話你的信息就泄露了。
如果使用的是https協議,那麼你的數據包就會被加密,即便被人抓包了,也沒有那麼輕易破解加密算法,因爲數據包只能使用服務器上的私鑰解密,而服務器根本不會在任何情況下發送私鑰,想要不通過私鑰來直接破解數據包幾乎是不可能的。
12.19 生成ssl密鑰對
理解了ssl原理後,現在我們可以在虛擬機上去生成ssl密鑰對,也就是自己製作證書。我們需要使用一個工具來生成密鑰對,把密鑰對放在nginx的conf目錄下
[root@lnmp-server ~]# cd /usr/local/nginx/conf/
生成ssl密鑰對需要使用到的工具是openssl,如果你虛擬機沒有此命令,需要自己安裝,安裝命令:
yum -y install openssl
生成私鑰
[root@lnmp-server conf]# openssl genrsa -des3 -out tmp.key 2048
Generating RSA private key, 2048 bit long modulus
........................................................................................................................................................+++
.....................+++
e is 65537 (0x10001)
Enter pass phrase for tmp.key:
Verifying - Enter pass phrase for tmp.key:
命令說明:生成rsa格式的私鑰,名字爲tmp.key 長度2048,生成的時候要求給tmp.key設置密碼
轉換key,取消密碼
由於生成私鑰時設置了密碼,這樣每次訪問https的網頁時都需要輸入密碼,過於麻煩,因此可以通過轉換key的方式將密碼取消
[root@lnmp-server conf]# openssl rsa -in tmp.key -out luo.key
Enter pass phrase for tmp.key:
writing RSA key
說明:把之前生成的需要密碼的tmp.key轉換成無需密碼的luo.key,這裏要求輸入之前給tmp.key設置的密碼
此時存在兩個key,tmp.key和luo.key,二者的內容完全相同,只是前者帶有密碼,後者沒有密碼,因此可將前者刪除
[root@lnmp-server conf]# rm -f tmp.key
生成證書請求文件
用轉換的私鑰luo.key生成證書請求文件luo.csr
[root@lnmp-server conf]# openssl req -new -key luo.key -out luo.csr
You are about to be asked to enter information that will be incorporated
into your certificate request.
What you are about to enter is what is called a Distinguished Name or a DN.
There are quite a few fields but you can leave some blank
For some fields there will be a default value,
If you enter '.', the field will be left blank.
-----
Country Name (2 letter code) [XX]:
State or Province Name (full name) []:
Locality Name (eg, city) [Default City]:
Organization Name (eg, company) [Default Company Ltd]:
Organizational Unit Name (eg, section) []:
Common Name (eg, your name or your server's hostname) []:
Email Address []:
Please enter the following 'extra' attributes
to be sent with your certificate request
A challenge password []:
An optional company name []:
說明 :這裏會要求你輸入一些信息,因爲做實驗默認直接回車,如果是購買的正式證書要認真填寫,後期可能會用到
生成公鑰文件
用生成的證書請求文件luo.csr和私鑰文件luo.key一起生成公鑰文件luo.crt
[root@lnmp-server conf]# openssl x509 -req -days 365 -in luo.csr -signkey luo.key -out luo.crt
Signature ok
subject=/C=XX/L=Default City/O=Default Company Ltd
Getting Private key
生成完成後conf目錄有三個文件
[root@lnmp-server conf]# ll luo*
-rw-r--r-- 1 root root 1103 7月 10 14:20 luo.crt
-rw-r--r-- 1 root root 952 7月 10 14:15 luo.csr
-rw-r--r-- 1 root root 1679 7月 10 14:11 luo.key
證書請求文件luo.csr,私鑰文件luo.key,公鑰文件luo.crt,至此,生成ssl密鑰對完成
12.20 Nginx配置ssl
生成完ssl密鑰對之後,需要在虛擬主機配置文件中配置ssl,這裏新建個ssl.conf配置文件
[root@lnmp-server conf]# vi /usr/local/nginx/conf/vhost/ssl.conf #加入以下內容
server
{
listen 443 ssl;
server_name luo.com;
index index.html index.php;
root /data/wwwroot/luo.com;
ssl on;
ssl_certificate luolinux.crt;
ssl_certificate_key luo.key;
ssl_protocols TLSv1 TLSv1.1 TLSv1.2;
}
解析說明:
server
{
listen 443 ssl; #ssl監聽端口,格式不能寫錯
server_name luo.com; #網站域名
index index.html index.php; #支持的默認索引頁
root /data/wwwroot/luo.com; #網站根目錄
ssl on; #開啓ssl
ssl_certificate luolinux.crt; #前面生成的公鑰文件
ssl_certificate_key luo.key; #前面生成的私鑰文件
ssl_protocols TLSv1 TLSv1.1 TLSv1.2; #支持的協議
}
檢測配置是否有錯
[root@lnmp-server conf]# /usr/local/nginx/sbin/nginx -t
nginx: [emerg] unknown directive "ssl" in /usr/local/nginx/conf/vhost/lemssl.conf:7
nginx: configuration file /usr/local/nginx/conf/nginx.conf test failed
在檢測時出現了報錯,原因是編譯Nginx時沒有添加ssl模塊,因此需要重新編譯Nginx,加上--with-http_ssl_modul,所以說源碼包不要刪除,後期增加一些配置的時候會用到:
cd /usr/local/src/nginx-1.12.1
./configure --prefix=/usr/local/nginx --with-http_ssl_module
make && make install
這裏省略重新編譯過程
重新檢測配置文件看到已經可以識別ssl了,重新加載配置
[root@lnmp-server conf]# /usr/local/nginx/sbin/nginx -t
nginx: the configuration file /usr/local/nginx//conf/nginx.conf syntax is ok
nginx: configuration file /usr/local/nginx//conf/nginx.conf test is successful
[root@lnmp-server conf]# /usr/local/nginx/sbin/nginx -s reload
檢測端口是否有443
[root@lnmp-server conf]# netstat -lnp |grep nginx
tcp 0 0 0.0.0.0:80 0.0.0.0:* LISTEN 5661/nginx: master
tcp 0 0 0.0.0.0:443 0.0.0.0:* LISTEN 5661/nginx: master
用https進行訪問測試
用curl測試不直觀,這裏我們用windows機器綁定hosts進行測試,先編輯一下hosts文件,文件路徑爲:
C:\Windows\System32\drivers\etc/hosts,在後面寫入:
192.168.66.132 luo.com
在網站根目錄下新建個index.html測試文件
[root@lnmp-server conf]# cat /data/wwwroot/luo.com/index.html
This is ssl test.
用瀏覽器進行https訪問
會提示一些不安全信息,這是因爲瀏覽器不信任這個證書,點開高級-繼續前往
可以看到,已經能正常https訪問了,想要沒有這些警告的話,可以自己去買正規受信任的證書。我們可以訪問https://www.12306.cn看看,相信這個網站大家都不陌生,訪問它的https也是會有警告:
這不是因爲政府沒錢買證書,而是不相信那些外部購買的證書,所以使用自己內部頒發的證書。
因此可以知道,顯示這個警告的原因僅僅是因爲瀏覽器沒有認可這個證書,並非是真的不安全
12.21 php-fpm的pool
pool是PHP-fpm的資源池,如果多個站點共用一個pool,則可能造成資源池中的資源耗盡,最終訪問網站時出現502。
爲了解決上述問題,我們可以配置多個pool,不同的站點使用不同的pool,保證充足的資源
編輯php-fpm配置文件,增加一個新的pool
vim /usr/local/php-fpm/etc/php-fpm.conf
[luo.com] //修改pool的名稱
listen = /tmp/luo.sock //修改sock文件名稱
listen.mode = 666
user = php-fpm
group = php-fpm
pm = dynamic
pm.max_children = 50
pm.start_servers = 20
pm.min_spare_servers = 5
pm.max_spare_servers = 35
pm.max_requests = 500
rlimit_files = 1024
//其餘選項按需更改
檢測文件&&重啓
/usr/local/php-fpm/sbin/php-fpm -t
/etc/init.d/php-fpm reload
查看系統進程
php-fpm 5707 0.0 0.4 227488 4772 ? S 11:30 0:00 php-fpm: pool www
php-fpm 5708 0.0 0.4 227488 4772 ? S 11:30 0:00 php-fpm: pool www
php-fpm 5709 0.0 0.4 227488 4776 ? S 11:30 0:00 php-fpm: pool www
php-fpm 5710 0.0 0.4 227488 4776 ? S 11:30 0:00 php-fpm: pool www
php-fpm 5711 0.0 0.4 227488 4776 ? S 11:30 0:00 php-fpm: pool www
php-fpm 5712 0.0 0.4 227488 4776 ? S 11:30 0:00 php-fpm: pool www
php-fpm 5713 0.0 0.4 227488 4772 ? S 11:30 0:00 php-fpm: pool luo.com
php-fpm 5714 0.0 0.4 227488 4772 ? S 11:30 0:00 php-fpm: pool luo.com
php-fpm 5715 0.0 0.4 227488 4772 ? S 11:30 0:00 php-fpm: pool luo.com
php-fpm 5716 0.0 0.4 227488 4772 ? S 11:30 0:00 php-fpm: pool luo.com
php-fpm 5717 0.0 0.4 227488 4776 ? S 11:30 0:00 php-fpm: pool luo.com
php-fpm 5718 0.0 0.4 227488 4776 ? S 11:30 0:00 php-fpm: pool luo.com
php-fpm 5719 0.0 0.4 227488 4776 ? S 11:30 0:00 php-fpm: pool luo.com
發現新的pool已經添加成功
將站點添加至新的pool中
server
{
listen 80 default_server;
server_name lem.com;
index index.html index.htm index.php;
root /data/wwwroot/luo.com;
location ~ \.php$
{
include fastcgi_params;
fastcgi_pass unix:/tmp/luo.sock; //要使站點使用某個pool,需要修改這裏,sock文件與pool中保持一致
fastcgi_index index.php;
fastcgi_param SCRIPT_FILENAME /data/wwwroot/luo.com$fastcgi_script_name; //對應站點的文件名
}
}
通過過include語法創建多個pool(類似於Nginx的vhost)
我們可以在php-fpm.conf配置中直接定義多個pool,也可以把多個pool拆分成不同的文件,編輯php-fpm配置文件,在[global]部分增加include = etc/php-fpm.d/*.conf這一行
[global]
pid = /usr/local/php-fpm/var/run/php-fpm.pid
error_log = /usr/local/php-fpm/var/log/php-fpm.log
include = etc/php-fpm.d/*.conf
創建並進入include所對應的目錄
mkdir /usr/local/php-fpm/etc/php-fpm.d/
cd /usr/local/php-fpm/etc/php-fpm.d/
創建各個pool的.conf文件
[root@lnmp-server conf]# vim /usr/local/php-fpm/etc/php-fpm.d/luo.com.conf #寫入下面的內容
[luo.com]
listen = /tmp/test.sock
;listen = 127.0.0.1:9000
listen.mode = 666
user = php-fpm
group = php-fpm
pm = dynamic
pm.max_children = 50
pm.start_servers = 20
pm.min_spare_servers = 5
pm.max_spare_servers = 35
pm.max_requests = 500
rlimit_files = 1024
[root@lnmp-server conf]# vim /usr/local/php-fpm/etc/php-fpm.d/www.conf #寫入下面的內容
[www]
listen = /tmp/php-fcgi.sock
listen.mode = 666
user = php-fpm
group = php-fpm
pm = dynamic
pm.max_children = 50
pm.start_servers = 20
pm.min_spare_servers = 5
pm.max_spare_servers = 35
pm.max_requests = 500
rlimit_files = 1024
可以看到兩個pool的sock文件是不一樣,不同的站點想使用不同的pool,只要修改對應的sock文件即可,定義完成後主配置文件php-fpm.conf定義的pool可以刪除歌者註釋掉
檢測並重載配置使其生效
/usr/local/php-fpm/sbin/php-fpm -t
/etc/init.d/php-fpm reload
12.22 php-fpm慢執行日誌
通過慢執行日誌,我們可以查看哪些PHP腳本執行的速度慢,非常實用,我們可以在站點使用的pool池中定義慢執行日誌
編輯pool的www.conf文件
vim /usr/local/php-fpm/etc/php-fpm.d/www.conf #在最後面增加下面兩行
request_slowlog_timeout = 2 //請求執行時間超出2秒鐘的日誌
slowlog = /usr/local/php-fpm/var/log/www-slow.log //定義慢執行日誌的位置
定義完後檢測並重載配置使其生效
/usr/local/php-fpm/sbin/php-fpm -t
/etc/init.d/php-fpm reload
在pool對應的站點中編寫PHP測試腳本,故意使其執行慢
vim /data/wwwroot/test.com/sleep.php
<?php echo
"test slow log";
sleep(2);
echo "done";
?>
效果測試
[root@lnmp-server conf]# curl -x127.0.0.1:80 test.com/sleep.php
test slow logdone[root@lnmp-server conf]# cat /usr/local/php-fpm/var/log/www-slow.log
[10-Jul-2018 15:25:39] [pool www] pid 1107
script_filename = /data/wwwroot/test.com/sleep.php //執行時間超過設置時間(2秒)的“慢腳本”的名稱
[0x00007f0f364cb280] sleep() /data/wwwroot/test.com/sleep.php:3 //該腳本具體哪一行執行的慢
正常PHP腳本的執行時間在1~2秒之間,因此設置超過兩秒的腳本記錄慢執行日誌即可
12.23 open_basedir
open_basedir 的作用是限制php在指定的目錄裏活動。
在php.ini中修改會針對所有站點生效,具有一定侷限性,因此可在不同的pool中進行配置,類似於在Apache中的虛擬主機配置文件中進行配置。
配置open_basedir
vim /usr/local/php-fpm/etc/php-fpm.d/www.conf//在最後面加入下面一行
php_admin_value[open_basedir]=/data/wwwroot/test.com:/tmp/ #不同的站點定義不同的網站根目錄和活動目錄
可以故意改錯open_basedir的路徑,並打開錯誤日誌,查看效果
修改php.ini配置文件
vim /usr/local/php-fpm/etc/php.ini
關閉瀏覽器報錯顯示
在生產環境中,直接將網站服務器報錯信息顯示在服務器上是不安全的,往往是將錯誤日誌記錄在指定的日誌文件中。在php.ini搜索關鍵字“display_errors"將其修改成Off
; Production Value: Off
; http://php.net/display-errors
display_errors = Off
打開錯誤日誌(在php.ini搜索關鍵字“log_errors"將其修改成On)
; Production Value: On
; http://php.net/log-errors
log_errors = On
定義錯誤日誌存放的路徑(搜索關鍵字log_errors,並在下面定義一行)
;error_log = php_errors.log
; Log errors to syslog (Event Log on Windows).
;error_log = syslog
error_log =/usr/local/php-fpm/var/log/php_errors.log
定義日誌級別(搜索關鍵字error_reporting)
; Default Value: E_ALL & ~E_NOTICE & ~E_STRICT & ~E_DEPRECATED
; Development Value: E_ALL
; Production Value: E_ALL & ~E_DEPRECATED & ~E_STRICT
; http://php.net/error-reporting
error_reporting = E_ALL & ~E_DEPRECATED & ~E_STRICT
創建錯誤日誌對應路徑文件,並賦予777權限
[root@lnmp-server conf]# touch /usr/local/php-fpm/var/log/php_errors.log
[root@lnmp-server conf]# chmod 777 /usr/local/php-fpm/var/log/php_errors.log
配置完後檢測並重載
[root@lnmp-server conf]# /usr/local/php-fpm/sbin/php-fpm -t
[10-Jul-2018 15:47:15] NOTICE: configuration file /usr/local/php-fpm/etc/php-fpm.conf test is successful
[root@lnmp-server conf]# /etc/init.d/php-fpm reload
Reload service php-fpm done
12.24 php-fpm進程管理
pm = dynamic //表示進程以動態的形式啓動,動態就是一開始爲一個數值,根據需求再自動生成,服務器比較閒的時候還會去銷燬,銷燬到一定程度還有自動生成;根據下面的設置去進行設定“start_servers ”、“min_spare_servers ”、“max_spare_servers ”、“max_requests ”
pm 也可以設置成是 static ,也就是靜態,一旦選擇這個設置,下面的pm的各種設置只會有一個max_children生效