keepalive第二彈---構建輕量級的nginx高可用

一、簡單的原理描述

   在上一期的博文中我們簡單的瞭解了什麼是keepalive和如何實現keepalive + httpd的高可用。我們都知道相對於httpd來說還有更加輕量級的nginx服務能爲我們提供網頁web能力。並且還能夠實現反向代理功能。那麼什麼是nginx呢?它又具有一些什麼樣的優勢和特性呢?接下來我們就簡單的給大家描述一下。


   傳統上基於進程或線程模型架構的web服務通過每進程或每線程處理併發連接請求,這勢必會在網絡和I/O操作時產生阻塞,其另一個必然結果則是對內存或CPU的利用率低下。生成一個新的進程/線程需要事先備好其運行時環境,這包括爲其分配堆內存和棧內存,以及爲其創建新的執行上下文等。這些操作都需要佔用CPU,而且過多的進程/線程還會帶來線程抖動或頻繁的上下文切換,系統性能也會由此進一步下降。


   在設計的最初階段,nginx的主要着眼點就是其高性能以及對物理計算資源的高密度利用,因此其採用了不同的架構模型。受啓發於多種操作系統設計中基於“事件”的高級處理機制,nginx採用了模塊化、事件驅動、異步、單線程及非阻塞的架構,並大量採用了多路複用及事件通知機制。在nginx中,連接請求由爲數不多的幾個僅包含一個線程的進程worker以高效的迴環(run-loop)機制進行處理,而每個worker可以並行處理數千個的併發連接及請求。


   如果負載以CPU密集型應用爲主,如SSL或壓縮應用,則worker數應與CPU數相同;如果負載以IO密集型爲主,如響應大量內容給客戶端,則worker數應該爲CPU個數的1.5或2倍。


   Nginx會按需同時運行多個進程:一個主進程(master)和幾個工作進程(worker),配置了緩存時還會有緩存加載器進程(cache loader)和緩存管理器進程(cache manager)等。所有進程均是僅含有一個線程,並主要通過“共享內存”的機制實現進程間通信。主進程以root用戶身份運行,而worker、cache loader和cache manager均應以非特權用戶身份運行。

主進程主要完成如下工作:

1. 讀取並驗正配置信息;

2. 創建、綁定及關閉套接字;

3. 啓動、終止及維護worker進程的個數;

4. 無須中止服務而重新配置工作特性;

5. 控制非中斷式程序升級,啓用新的二進制程序並在需要時回滾至老版本;

6. 重新打開日誌文件,實現日誌滾動;

7. 編譯嵌入式perl腳本;


   這些功能都是站在前人的基礎上做出的更加優秀的改進,因此我們在實現簡單web應用的時候更加傾向於使用nginx。由此,我們在這裏爲大家提供一個基於nginx的keepalive高可用平臺的搭建過程。拓撲如下:

二、安裝配置nginx

1、安裝規劃

rhel6.4-32虛擬機兩臺host1:172.16.12.61、host2:172.16.12.62

2、解決依賴關係

編譯安裝nginx需要事先需要安裝開發包組"Development Tools"和 "Development Libraries"。還需要專門安裝pcre-devel包。同時還需要同步兩臺服務器的時間:

# yum -y gourpinstall "Development Tools" "Development Libraries"
# yum -y install pcre-devel
# ntpdate 172.16.0.1                #172.16.0.1是搭建的時間服務器

3、安裝nginx

首先添加用戶nginx,實現以之運行nginx服務進程:

# groupadd -r nginx
# useradd -r -g nginx nginx
# tar xf nginx-1.4.1.tar.gz
# cd nginx-1.4.1

接着進行編譯及安裝:

# ./configure \
  --prefix=/usr \                                           #安裝路徑
  --sbin-path=/usr/sbin/nginx \                             #二進制命令
  --conf-path=/etc/nginx/nginx.conf \                       #配置文件
  --error-log-path=/var/log/nginx/error.log \               #錯誤日誌
  --http-log-path=/var/log/nginx/access.log \               #訪問日誌
  --pid-path=/var/run/nginx/nginx.pid  \                    #PID路徑
  --lock-path=/var/lock/nginx.lock \                        #鎖文件
  --user=nginx \                                            #用戶
  --group=nginx \                                           #組
  --with-http_ssl_module \                                  #支持ssl認證模塊
  --with-http_flv_module \                                  #支持流媒體
  --with-http_stub_status_module \                          #支持統計頁面
  --with-http_gzip_static_module \                          #支持頁面壓縮
  --http-client-body-temp-path=/var/tmp/nginx/client/ \     #用戶請求主體緩存目錄
  --http-proxy-temp-path=/var/tmp/nginx/proxy/ \            #代理數據
  --http-fastcgi-temp-path=/var/tmp/nginx/fcgi/ \           #fastcgi
  --http-uwsgi-temp-path=/var/tmp/nginx/uwsgi \             #支持python框架
  --http-scgi-temp-path=/var/tmp/nginx/scgi \               #scgi
  --with-pcre                                               #pcre
# make && make install

說明:在安裝過程中不同的機器可能有些軟件包的安裝不同,在編譯安裝的過程可能會出現不同的報錯信息,大家不用擔心,依照錯誤提示安裝所需要的軟件包即可。如遇到問題可以留言,也可以自行在網上搜索。

4、爲nginx提供SysV init腳本:

新建文件/etc/rc.d/init.d/nginx,內容如下:

#!/bin/sh
#
# nginx - this script starts and stops the nginx daemon
#
# chkconfig:   - 85 15
# description:  Nginx is an HTTP(S) server, HTTP(S) reverse \
#               proxy and IMAP/POP3 proxy server
# processname: nginx
# config:      /etc/nginx/nginx.conf
# config:      /etc/sysconfig/nginx
# pidfile:     /var/run/nginx.pid
                                                                                                                                                                                                                                                                                    
# Source function library.
. /etc/rc.d/init.d/functions
                                                                                                                                                                                                                                                                                    
# Source networking configuration.
. /etc/sysconfig/network
                                                                                                                                                                                                                                                                                    
# Check that networking is up.
[ "$NETWORKING" = "no" ] && exit 0
                                                                                                                                                                                                                                                                                    
nginx="/usr/sbin/nginx"
prog=$(basename $nginx)
                                                                                                                                                                                                                                                                                    
NGINX_CONF_FILE="/etc/nginx/nginx.conf"
                                                                                                                                                                                                                                                                                    
[ -f /etc/sysconfig/nginx ] && . /etc/sysconfig/nginx
                                                                                                                                                                                                                                                                                    
lockfile=/var/lock/subsys/nginx
                                                                                                                                                                                                                                                                                    
make_dirs() {
   # make required directories
   user=`nginx -V 2>&1 | grep "configure arguments:" | sed 's/[^*]*--user=\([^ ]*\).*/\1/g' -`
   options=`$nginx -V 2>&1 | grep 'configure arguments:'`
   for opt in $options; do
       if [ `echo $opt | grep '.*-temp-path'` ]; then
           value=`echo $opt | cut -d "=" -f 2`
           if [ ! -d "$value" ]; then
               # echo "creating" $value
               mkdir -p $value && chown -R $user $value
           fi
       fi
   done
}
                                                                                                                                                                                                                                                                                    
start() {
    [ -x $nginx ] || exit 5
    [ -f $NGINX_CONF_FILE ] || exit 6
    make_dirs
    echo -n $"Starting $prog: "
    daemon $nginx -c $NGINX_CONF_FILE
    retval=$?
    echo
    [ $retval -eq 0 ] && touch $lockfile
    return $retval
}
                                                                                                                                                                                                                                                                                    
stop() {
    echo -n $"Stopping $prog: "
    killproc $prog -QUIT
    retval=$?
    echo
    [ $retval -eq 0 ] && rm -f $lockfile
    return $retval
}
                                                                                                                                                                                                                                                                                    
restart() {
    configtest || return $?
    stop
    sleep 1
    start
}
                                                                                                                                                                                                                                                                                    
reload() {
    configtest || return $?
    echo -n $"Reloading $prog: "
    killproc $nginx -HUP
    RETVAL=$?
    echo
}
                                                                                                                                                                                                                                                                                    
force_reload() {
    restart
}
                                                                                                                                                                                                                                                                                    
configtest() {
  $nginx -t -c $NGINX_CONF_FILE
}
                                                                                                                                                                                                                                                                                    
rh_status() {
    status $prog
}
                                                                                                                                                                                                                                                                                    
rh_status_q() {
    rh_status >/dev/null 2>&1
}
                                                                                                                                                                                                                                                                                    
case "$1" in
    start)
        rh_status_q && exit 0
        $1
        ;;
    stop)
        rh_status_q || exit 0
        $1
        ;;
    restart|configtest)
        $1
        ;;
    reload)
        rh_status_q || exit 7
        $1
        ;;
    force-reload)
        force_reload
        ;;
    status)
        rh_status
        ;;
    condrestart|try-restart)
        rh_status_q || exit 0
            ;;
    *)
        echo $"Usage: $0 {start|stop|status|restart|condrestart|try-restart|reload|force-reload|configtest}"
        exit 2
esac

而後爲此腳本賦予執行權限:

# chmod +x /etc/rc.d/init.d/nginx

添加至服務管理列表,並讓其開機自動啓動:

# chkconfig --add nginx
# chkconfig nginx on

而後就可以啓動服務並測試了:

# service nginx start
# vim /usr/html/index.html
    <h1>master.wangej.com</h1>
# vim /usr/html/index.html
    <h1>slaves.wangej.com</h1>

實例如圖:

三、安裝keepalive

安裝規劃:高可用的流動IP爲172.16.12.254

1、安裝軟件

因爲在rhel6.4中已經自帶的有keepalive,所以我們這裏就直接使用yum安裝,請自行配置好yum源(keepalive有依賴關係,如果不能自行解決依賴關係就請使用yum安裝)

# yum install keepalived -y

2、修改配置文件

# cd /etc/keepalived/
# vim keepalived.conf

! Configuration File for keepalived
global_defs {
   notification_email {
        root@localhost
   }
   notification_email_from root@localhost
   smtp_server 127.0.0.1
   smtp_connect_timeout 30
   router_id LVS_DEVEL
}
vrrp_script chk_nginx {
    script "killall -0 nginx"
    interval 2
    weight -2
    fall 2
    rise 1
}
vrrp_script chk_schedown {
   script "[[ -f /etc/keepalived/down ]] && exit 1 || exit 0"
   interval 2
   weight -2
}
vrrp_instance VI_1 {
    state MASTER
    interface eth0
    virtual_router_id 61
    priority 101
    advert_int 1
    authentication {
        auth_type PASS
        auth_pass nginxpass
    }
    virtual_ipaddress {
        172.16.12.254/16 dev eth0 label eth0:0
    }
    track_script {
        chk_nginx
        chk_schedown
    }
    notify_master "/etc/keepalived/notify.sh master"
    notify_backup "/etc/keepalived/notify.sh backup"
    notify_fault "/etc/keepalived/notify.sh fault"
}

在從服務器上只需修改以下兩項即可:

state BACKUP
priority 100

3、提供一個手動停止節點的腳本

# vim notify.sh                                 #創建一個腳本

#!/bin/bash
# Author: WangEJ <[email protected]>
# description: An example of notify script
#
ifalias=${2:-eth0:0}
interface=$(echo $ifalias | awk -F: '{print $1}')
vip=$(ip addr show $interface | grep $ifalias | awk '{print $2}')
#contact='[email protected]'
contact='root@localhost'
workspace=$(dirname $0)
notify() {
    subject="$ip change to $1"
    body="$ip change to $1 $(date '+%F %H:%M:%S')"
    echo $body | mail -s "$1 transition" $contact
}
case "$1" in
    master)
        notify master
        exit 0
    ;;
    backup)
        notify backup
        /etc/rc.d/init.d/nginx restart
        exit 0
    ;;
    fault)
        notify fault
        exit 0
    ;;
    *)
        echo 'Usage: $(basename $0) {master|backup|fault}'
        exit 1
    ;;
esac

添加到開機啓動的服務列表中:

# chkconfig keepalived on

接下來就可以啓動服務,測試服務:

# service keepalived start

接下來我們手動關閉主節點,將IP流轉到從節點上測試一下:

同時觀察一下兩個節點的IP狀況:

四、補充說明

   至此我們基於nginx的keepalive高可用服務就已經搭建完成,如果諸位有什麼疑問,或者文章中有什麼疏漏的話請留言,大家一起共同討論,共同進步!


發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章