1. 程式人生 > >【Linux運維-叢集技術進階】Nginx+Keepalived+Tomcat搭建高可用/負載均衡/動靜分離的Web伺服器叢集

【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輪詢,敬請期待。。。

這就是一個架構不斷演變,進化的過程。