【Linux運維-叢集技術進階】Nginx+Keepalived+Tomcat搭建高可用/負載均衡/動靜分離的Web伺服器叢集
額,部落格名字有點長。。。
前言
終於到這篇文章了,心情是有點激動的。因為這篇文章會集中以前部落格講到的所有Nginx功能點,包括基本的負載均衡,還有動靜分離技術再加上這篇文章的重點,通過Keepalived實現的HA(High Available),為什麼要實現高可用呢?以前在搭建的時候只用了一臺Nginx伺服器,這樣的話如果Nginx伺服器宕機了,那麼整個網站就會掛掉,所以要實現Nginx的高可用,一臺掛掉還會有另一臺頂上去,從而保證網站可以持續的提供服務。關於負載均衡和動靜分離在前面部落格中都有相關的介紹,這篇部落格就不在詳細提了,只會在配置檔案中體現。不多說了,下面開始搭建。
拓撲環境
下面表格是這次測試需要的拓撲環境,幾臺伺服器,每臺伺服器上安裝什麼,都有介紹。
伺服器名稱 | 系統版本 | 預裝軟體 | IP地址/VIP |
---|---|---|---|
Nginx主伺服器 | CentOS 7 最小安裝 | Nginx +Keepalived | 192.168.22.227/192.168.22.231 |
Nginx從伺服器 | CentOS 7 最小安裝 | Nginx +Keepalived | 192.168.22.228/192.168.22.231 |
Web伺服器A | CentOS 7 最小安裝 | tomcat+jdk | 192.168.22.229 |
Web伺服器B | CentOS 7 最小安裝 | tomcat+jdk | 192.168.22.230 |
前置條件
原理圖
開始搭建
一、配置VIP
關於VIP(即虛擬IP)的作用,上篇部落格《Keepalived原理篇》已經介紹過了。227和228伺服器需要配置相同的VIP,虛擬IP在某時刻只能屬於某一個節點,另一個節點作為備用節點存在。當主節點不可用時,備用節點接管虛擬IP,成為主節點(即虛擬IP漂移至從節點),提供正常服務。這個VIP就像個牆頭草,兩頭跑,誰是主他就為誰服務。配置VIP的部落格,上面也有連結哦。
二、安裝軟體
按照上面的表格,在相應伺服器上安裝軟體,安裝過程不再多說了,有問題可以點選上面的部落格連結哦。
三、配置Nginx
227伺服器上的Nginx配置:
user nobody;
worker_processes 2;
events{
worker_connections 1024;
}
http{
#設定預設型別為二進位制流
default_type application/octet-stream;
server_names_hash_bucket_size 128;
#指定來自客戶端請求頭的headerbuffer大小,設定為32KB
client_header_buffer_size 32k;
#指定客戶端請求中較大的訊息頭的快取最大數量和大小,這裡是4個32KB
large_client_header_buffers 4 32k;
#上傳檔案大小
client_max_body_size 356m;
#nginx的HttpLog模組指定,指定nginx日誌的輸出格式,輸出格式為access
log_format access '$remote_addr - $remote_user [$time_local] "$request" '
'$status $body_bytes_sent "$http_referer" '
'"$http_user_agent" "$http_x_forwarded_for"';
#access日誌存在未知
access_log /usr/local/nginx/logs/access.log access;
#開啟高效模式檔案傳輸模式,將tcp_nopush和tcp_nodelay兩個指另設定為on,用於防止網路阻塞。
sendfile on;
tcp_nopush on;
tcp_nodelay on;
#設定客戶端連線保持活動的超時時間
keepalive_timeout 65;
server_tokens off;
#客戶端請求主體讀取快取
client_body_buffer_size 512k;
proxy_connect_timeout 5;
proxy_send_timeout 60;
proxy_read_timeout 5;
proxy_buffer_size 16k;
proxy_buffers 4 64k;
proxy_busy_buffers_size 128k;
proxy_temp_file_write_size 128k;
#fastcgi_connect_timeout 300;
#fastcgi_send_timeout 300;
#fastcgi_read_timeout 300;
#fastcgi_buffer_timeout 300;
#fastcgi_buffers 4 64k;
#fastcgi_busy_buffers_size 128k;
#fastcgi_temp_file_write_size 128k;
#開啟gzip
gzip on;
#允許壓縮的最小位元組數
gzip_min_length 1k;
#4個單位為16k的記憶體作為壓縮結果流快取
gzip_buffers 4 16k;
#設定識別HTTP協議版本,預設是1.1
gzip_http_version 1.1;
#gzip壓縮比,可在1~9中設定,1壓縮比最小,速度最快,9壓縮比最大,速度最慢,消耗CPU
gzip_comp_level 2;
#壓縮的型別
gzip_types text/plain application/x-javascript text/css application/xml;
#讓前端的快取伺服器混村經過的gzip壓縮的頁面
gzip_vary on;
upstream mycluster{
server 192.168.22.229:8080 weight=1;
server 192.168.22.230:8080 weight=1;
}
server{
listen 8088;
server_name 192.168.22.227;
charset utf-8; #設定編碼為utf-8
#root html;
#location / {
# root html;
# index index.html index.htm;
#}
#location ~ .*\.(jsp|do|action)$
location / {
proxy_next_upstream http_502 http_504 error timeout invalid_header;
proxy_pass http://mycluster;
# 真實的客戶端IP
proxy_set_header X-Real-IP $remote_addr;
# 請求頭中Host資訊
proxy_set_header Host $host;
# 代理路由資訊,此處取IP有安全隱患
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
# 真實的使用者訪問協議
proxy_set_header X-Forwarded-Proto $scheme;
}
#靜態檔案交給nginx處理
location ~ .*\.(htm|html|gif|jpg|jpeg|png|bmp|swf|ioc|rar|zip|txt|flv|mid|doc|ppt|pdf|xls|mp3|wma)$
{
root /usr/local/webapps;
expires 30d;
}
#靜態檔案交給nginx處理
location ~ .*\.(js|css)?$
{
root /usr/local/webapps;
expires 1h;
}
error_page 500 502 503 504 /50x.html;
location = /50x.html {
root html;
}
}
}
228伺服器上的Nginx配置:
user nobody;
worker_processes 2;
events{
worker_connections 1024;
}
http{
#設定預設型別為二進位制流
default_type application/octet-stream;
server_names_hash_bucket_size 128;
#指定來自客戶端請求頭的headerbuffer大小,設定為32KB
client_header_buffer_size 32k;
#指定客戶端請求中較大的訊息頭的快取最大數量和大小,這裡是4個32KB
large_client_header_buffers 4 32k;
#上傳檔案大小
client_max_body_size 356m;
#nginx的HttpLog模組指定,指定nginx日誌的輸出格式,輸出格式為access
log_format access '$remote_addr - $remote_user [$time_local] "$request" '
'$status $body_bytes_sent "$http_referer" '
'"$http_user_agent" "$http_x_forwarded_for"';
#access日誌存在未知
access_log /usr/local/nginx/logs/access.log access;
#開啟高效模式檔案傳輸模式,將tcp_nopush和tcp_nodelay兩個指另設定為on,用於防止網路阻塞。
sendfile on;
tcp_nopush on;
tcp_nodelay on;
#設定客戶端連線保持活動的超時時間
keepalive_timeout 65;
server_tokens off;
#客戶端請求主體讀取快取
client_body_buffer_size 512k;
proxy_connect_timeout 5;
proxy_send_timeout 60;
proxy_read_timeout 5;
proxy_buffer_size 16k;
proxy_buffers 4 64k;
proxy_busy_buffers_size 128k;
proxy_temp_file_write_size 128k;
#fastcgi_connect_timeout 300;
#fastcgi_send_timeout 300;
#fastcgi_read_timeout 300;
#fastcgi_buffer_timeout 300;
#fastcgi_buffers 4 64k;
#fastcgi_busy_buffers_size 128k;
#fastcgi_temp_file_write_size 128k;
#開啟gzip
gzip on;
#允許壓縮的最小位元組數
gzip_min_length 1k;
#4個單位為16k的記憶體作為壓縮結果流快取
gzip_buffers 4 16k;
#設定識別HTTP協議版本,預設是1.1
gzip_http_version 1.1;
#gzip壓縮比,可在1~9中設定,1壓縮比最小,速度最快,9壓縮比最大,速度最慢,消耗CPU
gzip_comp_level 2;
#壓縮的型別
gzip_types text/plain application/x-javascript text/css application/xml;
#讓前端的快取伺服器混村經過的gzip壓縮的頁面
gzip_vary on;
upstream mycluster{
server 192.168.22.229:8080 weight=1;
server 192.168.22.230:8080 weight=1;
}
server{
listen 8088;
server_name 192.168.22.228;
charset utf-8; #設定編碼為utf-8
#root html;
#location / {
# root html;
# index index.html index.htm;
#}
#location ~ .*\.(jsp|do|action)$
location / {
proxy_next_upstream http_502 http_504 error timeout invalid_header;
proxy_pass http://mycluster;
# 真實的客戶端IP
proxy_set_header X-Real-IP $remote_addr;
# 請求頭中Host資訊
proxy_set_header Host $host;
# 代理路由資訊,此處取IP有安全隱患
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
# 真實的使用者訪問協議
proxy_set_header X-Forwarded-Proto $scheme;
}
#靜態檔案交給nginx處理
location ~ .*\.(htm|html|gif|jpg|jpeg|png|bmp|swf|ioc|rar|zip|txt|flv|mid|doc|ppt|pdf|xls|mp3|wma)$
{
root /usr/local/webapps;
expires 30d;
}
#靜態檔案交給nginx處理
location ~ .*\.(js|css)?$
{
root /usr/local/webapps;
expires 1h;
}
error_page 500 502 503 504 /50x.html;
location = /50x.html {
root html;
}
}
}
另外還需要在227,228伺服器上新建一個目錄/usr/local/webapps/drp/img,在img資料夾中存放圖片girl.jpg。如果Nginx伺服器較多的話,可以使用Rsync做服務端自動同步或者使用NFS、MFS分散式共享儲存,避免一個個拷貝檔案。
還有,這塊Nginx配置是做過一些優化的,比如開啟gzip壓縮,開啟高效檔案傳輸模式,設定快取,動靜分離,負載均衡等,可以直接拿到專案中使用。
四、配置Keepalived
227伺服器上的Keepalived配置:
! Configuration File for keepalived
#配置郵件相關資訊
global_defs {
notification_email {
acassen@firewall.loc
failover@firewall.loc
sysadmin@firewall.loc
}
notification_email_from Alexandre.Cassen@firewall.loc
smtp_server 192.168.200.1
smtp_connect_timeout 30
router_id LVS_DEVEL
}
#配置Nginx健康監測指令碼
vrrp_script check_nginx {
script "</dev/tcp/127.0.0.1/8088"
interval 3
weight -2
}
vrrp_instance VI_1 {
state MASTER
#網絡卡名稱
interface eno16777736
virtual_router_id 151
priority 100
advert_int 1
authentication {
auth_type PASS
auth_pass 1111
}
track_script {
check_nginx
}
virtual_ipaddress {
192.168.22.231
}
}
228伺服器上的Keepalived配置:
! Configuration File for keepalived
global_defs {
notification_email {
acassen@firewall.loc
failover@firewall.loc
sysadmin@firewall.loc
}
notification_email_from Alexandre.Cassen@firewall.loc
smtp_server 192.168.200.1
smtp_connect_timeout 30
router_id LVS_DEVEL
}
vrrp_script check_nginx {
#script "/opt/chknginx.sh"
script "</dev/tcp/127.0.0.1/8088"
interval 3
weight -2
}
vrrp_instance VI_1 {
state MASTER
interface eno16777736
virtual_router_id 151
priority 99
advert_int 1
authentication {
auth_type PASS
auth_pass 1111
}
track_script {
check_nginx
}
virtual_ipaddress {
192.168.22.231
}
}
特別注意,Nginx健康監測指令碼。在本地寫一個shell指令碼,Keepalived監測不到。不知道為什麼,網上的部落格都是這麼寫的。但是在我這裡就不行。最後直接在Keepalived配置檔案的script標籤中寫了這段監測的指令碼,才得以成功。
vrrp_script chk_http_port {
script "</dev/tcp/192.168.22.227/80"
interval 1
weight -10
}
另外,如果你不明白某些配置的意思,可以檢視上篇部落格,裡面針對每條配置檔案都做了詳細解析。
五、Tomcat配置
229伺服器,新增預設頁
在Tomcat的webapps目錄下新建資料夾drp,並且建立index.jsp頁面
<%@ page language="java" contentType="text/html; charset=GB18030"
pageEncoding="GB18030"%>
<HTML>
<head>
<meta http-equiv="Content-Type" content="text/html; charset=GB18030">
<title>Nginx+Keepalived高可用,負載均衡,動靜分離測試</title>
</head>
<body>
<h1>您正在訪問伺服器:192.168.22.229</h1>
<img src="/drp/img/girl.jpg" alt="女孩" />
</body>
</html>
230伺服器同上
六、啟動服務並測試
分別啟動各個伺服器上的Nginx、Keepalived、Tomcat,並測試能否正常訪問。
①啟動測試Tomcat
可以看到229和230伺服器上的Tomcat已經可以正常訪問,圖片沒有加載出來,是因為圖片沒有在Tomcat伺服器上儲存,而放在了Nginx上。
②啟動測試Nginx
可以看到227和228上的Nginx啟動成功,並且實現了負載均衡和動靜分離的效果,圖片被成功的載入了出來。
③ 保證所有服務均可正常訪問後,啟動Keepalived測試。
192.168.22.231是咱們設定的虛擬ip,在訪問網站的時候不在通過Nginx的ip了,而要通過這個vip進行訪問。
Keepalived啟動後咱們可以通過檢視/var/log 下的messages檔案(日誌檔案),檢視主從狀態。
檢視227伺服器/var/log/messages:
可以看到227為Master伺服器,那麼咱們現在通過192.168.22.231訪問的就是227上的Nginx。
Nginx高可用測試
現在咱們通過兩個方面來測試高可用:
① 伺服器層的雙機熱備,模擬方式為關閉伺服器,或者關閉Keepalived。
a. 關閉227Keepalived程序
現在提供服務的是227伺服器,使用命令service keepalived stop將227上的Keepalived程序關閉掉之後。
檢視227伺服器messas日誌:
將192.168.22.231這個虛擬ip移除,關閉Keepalived。
檢視228伺服器messages日誌:
228原來為從伺服器,當227伺服器宕機後,228伺服器由從伺服器升級為主伺服器,並且繫結上192.168.22.231這個虛擬IP,以繼續提供服務,網站能夠繼續訪問。
b. 啟動227Keepalived
檢視227伺服器messas日誌:
Keepalived成功啟動後,227伺服器繼續接管192.168.22.231,成為MASTER伺服器,繼續提供服務。
檢視228伺服器messages日誌:
相應的228伺服器,轉變為BACKUP伺服器,並且移除VIP。
② 應用層的雙機熱備,模擬方式為Kill掉Nginx程序
a. 關閉227Nginx
檢視227伺服器messages日誌:
VRRP_Script(check_nginx) failed ,意思是健康監測指令碼執行失敗,表明Nginx服務壞掉,或者沒有啟動。然後Keepalived會使227伺服器轉變為BACKUP狀態,移除VIP。
檢視228伺服器messages日誌:
當然不出所料,228伺服器已經變為MASTER狀態,從而繼續提供服務。
b. 重新啟動227Nginx
檢視227伺服器messages日誌:
VRRP_Script(check_nginx) succeeded ,意思是健康監測指令碼執行成功,Nginx正常執行。然後227伺服器就會轉變為MASTER狀態,並提供服務。
檢視228伺服器messages日誌:
228伺服器已經變為BUCKUP狀態。
小結
至此,高可用的一系列測試就已經完成了。在整個測試過程中,無論是關閉某臺伺服器的Nginx,Keepalived還是整個伺服器宕機,網站一直沒有中斷提供服務,這已經達到了基本的高可用;但是還有個缺陷就是如果Nginx主伺服器不出問題的話,那麼備用伺服器將長期處於備份狀態,這樣的巨大資源浪費是不能容忍的。當然這也有相應的方案來解決:Nginx雙主叢集+DNS輪詢,敬請期待。。。
這就是一個架構不斷演變,進化的過程。