1. 程式人生 > >架構設計:負載均衡層設計方案(2)——Nginx安裝

架構設計:負載均衡層設計方案(2)——Nginx安裝

前一篇文章《架構設計:負載均衡層設計方案(1)——負載場景和解決方式》中我們描述了要搭設負載均衡層的業務場景和負載均衡層搭建和擴充套件思路。從這篇文章開始的後幾篇文章,我們將詳細介紹Nginx、LVS和Nginx+Keepalived、LVS+Keepalived和LVS+Nginx+Keepalived的安裝細節,以及它們的效能優化方式。

Nginx和LVS都是可以獨立工作的,Keepalived作為檢測機制,不但可以和Nginx、LVS整合也可以和其他軟體整合形成高可用方案(例如可以和MySQL資料庫整合、可以和Jetty伺服器整合、還可以和自己寫的程式整合)。所以首先我們先來詳細講述Nginx和LVS的核心工作原理、安裝過程和優化方式,再分別講解他們和Keepalived的整合方式。這樣的方式應該可以使您更快的掌握其中的核心,並能最快的融會貫通。

1、Nginx重要演算法介紹

Nginx是什麼,請自行百度。我們先介紹幾個關鍵的演算法,如果您還不瞭解這些演算法在Nginx中所起的作用,請不要著急,本文後半部分將說明它們的作用。

1.1、一致性Hash演算法

這裡寫圖片描述

一致性Hash演算法是現代系統架構中的最關鍵演算法之一,在分散式計算系統、分散式儲存系統、資料分析等眾多領域中廣泛應用。針對這個系列的博文,在負載均衡層、業務通訊層、資料儲存層都會有他的身影。

  • hash演算法的關鍵在於它能夠根據不同的屬性資料,生成一串不相同的hash值,並且能夠將這個hash值轉換為

    02321範圍整數(即上圖中的圓環)
  • 一臺伺服器的某個或者某一些屬性當然也可以進行hash計算(通常是這個伺服器的IP地址和開放埠),並且根據計算分佈在這個圓環上的某一個點。也就是圖中圓環上的藍色點。

  • 一個處理請求當然也可以根據這個請求的某一個或者某一些屬性進行hash計算(可以是這個請求的IP、埠、cookie值、URL值或者請求時間等等),並且根據計算記過分佈在這個圓環上的某一個點上。也就是上圖圓環上的黃色點。

  • 我們約定落在某一個藍點A左側和藍點B右側的黃色點所代表的請求,都有藍點A所代表的伺服器進行處理,這樣就完成解決了“誰來處理”的問題。在藍色點穩定存在的前提下,來自於同一個Hash約定的請求所落在的位置都是一樣的,這就保證了服務處理對映的穩定性。

  • 當某一個藍色點由於某種原因下線,其所影響到的黃色點也是有限的。即下一次客戶端的請求將由其他的藍色點所代表的伺服器進行處理。

1.2、輪詢與加權輪詢

這裡寫圖片描述

  • 當有任務需要傳遞到下層節點進行處理時,任務來源點會按照一個固定的順序,將任務依次分配到下層節點,如果下層可用的節點數量為X,那麼第N個任務的分配規則為:

    =(NmodX)+1
  • 輪詢處理在很多架構思想中都有體現:DNS解析多IP時、LVS向下轉發訊息時、Nginx向下轉發訊息時、Zookeeper向計算節點分配任務時。瞭解基本的輪詢過程有助於我們在進行軟體架構設計時進行思想借鑑。

  • 但是上面的輪詢方式是有缺陷的,由於各種客觀原因我們可能無法保證任務處理節點的處理能力都是一樣的(CPU、IO、記憶體頻率等不同)。所以A節點業務能同時處理100個任務,但是B節點可能同時只能處理50個任務。

  • 在這種情況下我們需要依據下層節點某個或者多個屬性設定權值。這個屬性可能是網路頻寬、CPU繁忙程度或者就是各一個固定的權值。

那麼加權輪詢的分配依據是什麼呢?有很多分配依據,例如:概率演算法(此演算法中包括蒙特卡羅演算法,拉斯維加斯演算法和舍伍德演算法,在網路上有很多介紹資料)、最大公約數法。這裡我們對最大公約數演算法進行介紹,因為該方法簡單實用:

這裡寫圖片描述

  • 首先按照某種規則計算得到每個處理節點的權值,上文已經說到計算規則可能是這個服務節點的CPU利用率、網路佔用情況或者在配置檔案中的固定權重。

  • 求這些權值的最大公約數,在上圖中三個節點的權值分別是100、80、60.那麼求得的最大公約數就是20(如果您忘記了最大公約數的定義,請自行復習)。那麼這三個節點的被除結果分別是5、4、3,求和值為12。

  • 得到以上的計算結果,就可以開始進行請求分配了,公式同樣為:

    (NmodX)+1=Y
    其中N表示當前的第N次任務;X表示整除後的求和結果;Y為處理節點。

總結一下:加權輪詢是輪詢方案的補充,通過將處理節點的屬性轉換成權值可以有效的描述處理節點的處理能力,實現更科學的處理任務分配。加權輪詢的關鍵在於加權演算法,最大公約數演算法簡單實用,定位效率高。

2、Nginx的安裝

2.1、準備工作

作業系統:centOS 6.5。

Nginx的下載地址:http://nginx.org/en/download.html。請下載stable的版本1.8.0。後續Nginx肯定還會有升級,官網上面會持續更新stable version。

最小必備元件:
yum -y install make zlib zlib-devel gcc gcc-c++ ssh libtool

2.2、正式安裝

  • 下載nginx1.8.0版本
    這裡寫圖片描述

  • 解壓nginx的tar檔案
    這裡寫圖片描述

  • 進行原始碼編譯
    這裡寫圖片描述

  • 再進行原始碼編譯安裝
    ./configure –prefix=/usr/nginx-1.8.0
    make && make install
    這裡寫圖片描述

  • 整個驗證、編譯、安裝過程不應該報任何錯誤。如果您使用prefix設定了安裝目標目錄,那麼可能您還需要在/etc/profix檔案中設定環境變數:
    這裡寫圖片描述

2.3、安裝驗證和啟動

下面介紹幾個nginx常用的命令,如果您可以正常使用這些命令,那麼說明nginx已經安裝成功了。

nginx:直接在命令列鍵入nginx,就可以啟動nginx。

nginx -t:檢查配置檔案是否正確。這個命令可以檢查nginx.conf配置檔案其格式、語法是否正確。如果配置檔案存在錯誤,則會出現相應提示;如果nginx.conf檔案正確,也會出現相應的成功提示。

nginx -s reload:重載入/重啟nginx——以新的nginx.conf配置檔案中的定義。

nginx -s stop:停止nginx。

3、進階

Nginx在安裝完成後,不用更改任何配置資訊就可以直接執行。但是很顯然這不會滿足我們生產環境的要求。所以我們要重點介紹Nginx的配置檔案,以及其中重要的配置項的含義。

3.1、重要配置項

如果您是按照本文的描述方式安裝的Nginx,那麼Nginx的主配置檔案在:/usr/nginx-1.8.0/conf/nginx.conf的位置,如果您在編譯安裝的時候並沒有指定安裝目錄,那麼Nginx的主配置檔案在:/usr/local/nginx/conf/nginx.conf的位置。當然您還可以在啟動Nginx的時候使用 -c 的引數人為指定Nginx的配置檔案位置(但是這種方式不建議)。

我們重新整理了Nginx的配置檔案,將其分塊,以便於講解:

#================================以下是全域性配置項
#指定執行nginx的使用者和使用者組,預設情況下該選項關閉(關閉的情況就是nobody)
#user  nobody nobody;     
#執行nginx的程序數量,後文詳細講解
worker_processes  1;      
#nginx執行錯誤的日誌存放位置。當然您還可以指定錯誤級別
#error_log  logs/error.log;    
#error_log  logs/error.log  notice;
#error_log  logs/error.log  info;
#指定主程序id檔案的存放位置,雖然worker_processes != 1的情況下,會有很多程序,管理程序只有一個
#pid        logs/nginx.pid;    

events {
    #每一個程序可同時建立的連線數量,後問詳細講解
    worker_connections  1024;   
    #連線規則,可以採用[kqueue rtsig epoll select poll eventport ],後文詳細講解
    use   epoll;    
}
#================================以上是全域性配置項

http {
    #================================以下是Nginx後端服務配置項
    upstream backendserver1 {
        #nginx向後端伺服器分配請求任務的方式,預設為輪詢;如果指定了ip_hash,就是hash演算法(上文介紹的演算法內容)
        #ip_hash    
        #後端伺服器 ip:port ,如果有多個服務節點,這裡就配置多個
        server 192.168.220.131:8080; 
        server 192.168.220.132:8080;    
        #backup表示,這個是一個備份節點,只有當所有節點失效後,nginx才會往這個節點分配請求任務
        #server 192.168.220.133:8080 backup;        
        #weight,固定權重,還記得我們上文提到的加權輪詢方式吧。
        #server 192.168.220.134:8080 weight=100;    
    }
    #================================以上是Nginx後端服務配置項

    #=================================================以下是 http 協議主配置
    #安裝nginx後,在conf目錄下除了nginx.conf主配置檔案以外,有很多模板配置檔案,這裡就是匯入這些模板檔案
    include       mime.types;
    #HTTP核心模組指令,這裡設定預設型別為二進位制流,也就是當檔案型別未定義時使用這種方式
    default_type  application/octet-stream;     
    #日誌格式
    #log_format  main  '$remote_addr - $remote_user [$time_local] "$request" '   
                      '$status $body_bytes_sent "$http_referer" '
                      '"$http_user_agent" "$http_x_forwarded_for"';

    #日誌檔案存放的位置
    #access_log  logs/access.log  main;         

    #sendfile 規則開啟
    sendfile        on;
    #指定一個連線的等待時間(單位秒),如果超過等待時間,連線就會斷掉。注意一定要設定,否則高併發情況下會產生效能問題。
    keepalive_timeout  65;                      

    #開啟資料壓縮,後文詳細介紹
    gzip  on;                                   
    #=================================================以上是 http 協議主配置

    #=================================================以下是一個服務例項的配置
    server {
        #這個代理例項的監聽埠
        listen       80;
        #server_name 取個唯一的例項名都要想半天?
        server_name  localhost; 
        #文字格式
        charset utf-8;  
        #access_log  logs/host.access.log  main;    

        #location將按照規則分流滿足條件的URL。"location /"您可以理解為“預設分流位置”。
        location / {
            #root目錄,這個html表示nginx主安裝目錄下的“html”目錄。
            root   html;   
            #目錄中的預設展示頁面
            index  index.html index.htm;        
        }

        #location支援正則表示式,“~” 表示匹配正則表示式。
        location ~ ^/business/ {   
            #方向代理。後文詳細講解。
            proxy_pass http://backendserver1;   
        }

        #redirect server error pages to the static page /50x.html
        #error_page  404              /404.html;
        error_page   500 502 503 504  /50x.html;
        location = /50x.html {
            root   html;
        }
    }
    #=================================================以上是一個服務例項的配置
}

以上是一個完整的nginx配置資訊,可以直接貼上使用,但不建議您這樣做。因為上文中很多關鍵的配置屬性都還沒有講解。這樣貼上複製不利於您的工作和學習。

3.1.1、use [ kqueue | rtsig | epoll | select | poll ]

科技在發展,社會在進步,滿足摩爾定義的IT行業更是這樣。以前所有的連線都是阻斷式的(blocking I/O)也就是說一個TCP連線執行緒在發出Request後,程式碼就不會再往下執行了,直到得到遠端的Response為止;伺服器端也一樣的,在處理完某一個客戶端的Request之前,其他客戶端的請求都會等待。這種處理方式使客戶端和伺服器端的通訊效能大打折扣。

很明顯多執行緒貌似能夠解決這個問題:一個執行緒處理不了,我可以再開執行緒來處理啊。但是多執行緒是有侷限性的:

  • 建立一個執行緒會消耗有限的資源。以JAVA JVM為例,建立一個新的執行緒JVM會單獨開放1MB的棧記憶體空間(通過-Xss引數可設定),雖然棧記憶體不受-Xmx和-Xms兩個引數影響,但是可以說明執行緒的建立是需要消耗額外資源的。

  • 多執行緒工作時,計算機的CPU會耗費大量的資源讓多執行緒在不同的狀態下進行切換。在後續的文章中本書還會介紹依據這樣的原理讓計算機的CPU呈波形變化的程式設計方式。

  • 在Linux作業系統下,單個使用者能夠建立的執行緒和程序總數、整個作業系統能夠建立的執行緒總數都是有限的。通過limit -a命令,您可以檢視相關的核心引數。

  • 所以依靠執行緒來解決bio的問題是不靠譜的,只能起到緩解處理並行請求的作用。您可以想象一次併發10萬個處理請求的問題,是不可能在計算機上同時建立10萬個執行緒來解決的。

基於上面的描述,NIO(no blocking I/O)技術就這樣誕生了。依靠event loop機制(想看這個機制的詳細分析,請持續關注我的部落格^_^),單個執行緒可以同時處理多個request請求,並在處理完產生response的時候,回撥相關的遠端事件。根據NIO實現機制的不同,技術名稱也就不同了。我要說什麼,您,應該懂了。

epoll、kqueue 等這些元件都是對多路複用網路I/O模型的實現,其中epoll是poll的升級版本,在linux環境下可以使用但限於linux2.6及以上版本。kqueue用在bsd上使用。

3.1.2、worker_processes和worker_connections

worker_processes:作業系統啟動多少個工作程序執行Nginx。注意是工作程序,不是有多少個nginx工程。在Nginx執行的時候,會啟動兩種程序,一種是主程序master process;一種是工作程序worker process。例如我在配置檔案中將worker_processes設定為4,啟動Nginx後,使用程序檢視命令觀察名字叫做nginx的程序資訊,我會看到如下結果:

這裡寫圖片描述

圖中可以看到1個nginx主程序,master process;還有四個工作程序,worker process。主程序負責監控埠,協調工作程序的工作狀態,分配工作任務,工作程序負責進行任務處理。一般這個引數要和作業系統的CPU核心數成倍數。

worker_connections:這個屬性是指單個工作程序可以允許同時建立外部連線的數量。無論這個連線是外部主動建立的,還是內部建立的。這裡需要注意的是,一個工作程序建立一個連線後,程序將開啟一個檔案副本。所以這個數量還受作業系統設定的,程序最大可開啟的檔案數有關。網上50%的文章告訴了您這個事實,並要求您修改worker_connections屬性的時候,一定要使用ulimit -n 修改作業系統對程序最大檔案數的限制,但是這樣更改只能在當次使用者的當次shell回話中起作用,並不是永久了。接著您繼續Google/百度,發現30%的文章還告訴您,要想使“程序最大可開啟的檔案數”永久有效,還需要修改/etc/security/limits.conf這個主配置檔案,但是您應該如何正確檢查“程序的最大可開啟檔案”的方式,卻沒有說。

下面本文告訴您全面的、正確的設定方式:

  • 更改作業系統級別的“程序最大可開啟檔案數”的設定
    首先您需要作業系統的root許可權:

    叫您的作業系統管理員給您。

    修改limits.conf主配置檔案

    vim /etc/security/limits.conf

    在主配置檔案最後加入下面兩句:

    * soft nofile 65535
    * hard nofile 65535

    注意“”是要加到檔案裡面的。這兩句話的含義是soft(應用軟體)級別限制的最大可開啟檔案數的限制,hard表示作業系統級別限制的最大可開啟檔案數的限制,“”表示所有使用者都生效。儲存這個檔案(只有root使用者能夠有許可權)。

    儲存這個檔案後,配置是不會馬上生效的,為了保證本次shell會話中的配置馬上有效,我們需要通過ulimit命令更改本次的shell會話設定(當然您如果要重啟系統,我也不能說什麼)。

    ulimit -n 65535

    執行命令後,配置馬上生效。您可以用ulimit -a 檢視目前會話中的所有核心配置:

    ulimit -a
    core file size (blocks, -c) 0
    data seg size (kbytes, -d) unlimited
    scheduling priority (-e) 0
    file size (blocks, -f) unlimited
    pending signals (-i) 7746
    max locked memory (kbytes, -l) 64
    max memory size (kbytes, -m) unlimited
    open files (-n) 65535
    pipe size (512 bytes, -p) 8
    POSIX message queues (bytes, -q) 819200
    real-time priority (-r) 0
    stack size (kbytes, -s) 10240
    cpu time (seconds, -t) unlimited
    max user processes (-u) 7746
    virtual memory (kbytes, -v) unlimited
    file locks (-x) unlimited

    請注意open files這一項。

  • 更改Nginx軟體級別的“程序最大可開啟檔案數”的設定:
    剛才更改的只是作業系統級別的“程序最大可開啟檔案”的限制,作為Nginx來說,我們還要對這個軟體進行更改。開啟nginx.conf主陪檔案。您需要配合worker_rlimit_nofile屬性。如下:

    user root root;
    worker_processes 4;
    worker_rlimit_nofile 65535;

    #error_log logs/error.log;
    #error_log logs/error.log notice;
    #error_log logs/error.log info;

    #pid logs/nginx.pid;
    events {
    use epoll;
    worker_connections 65535;
    }

    這裡只貼上了部分程式碼,其他的配置程式碼和主題無關,也就不需要貼上了。請注意程式碼行中加粗的兩個配置項,請一定兩個屬性全部配置。配置完成後,請通過nginx -s reload命令重新啟動Nginx。

  • 驗證Nginx的“程序最大可開啟檔案數”是否起作用:

    那麼我們如何來驗證配置是否起作用了呢?在linux系統中,所有的程序都會有一個臨時的核心配置檔案描述,存放路徑在/pro/程序號/limit。

    首先我們來看一下,沒有進行引數優化前的程序配置資訊:

    ps -elf | grep nginx
    1 S root 1594 1 0 80 0 - 6070 rt_sig 05:06 ? 00:00:00 nginx: master process /usr/nginx-1.8.0/sbin/nginx
    5 S root 1596 1594 0 80 0 - 6176 ep_pol 05:06 ? 00:00:00 nginx: worker process
    5 S root 1597 1594 0 80 0 - 6176 ep_pol 05:06 ? 00:00:00 nginx: worker process
    5 S root 1598 1594 0 80 0 - 6176 ep_pol 05:06 ? 00:00:00 nginx: worker process
    5 S root 1599 1594 0 80 0 - 6176 ep_pol 05:06 ? 00:00:00 nginx: worker process

    可以看到,nginx工作程序的程序號是:1596 1597 1598 1599。我們選擇一個程序,檢視其核心配置資訊:

    cat /proc/1598/limits

    這裡寫圖片描述

    請注意其中的Max open files ,分別是1024和4096。那麼更改配置資訊,並重啟Nginx後,配置資訊就是下圖所示了:

    這裡寫圖片描述

3.1.3、max client的計算方式:

這個小結我們主要來說明兩個在網上經常說的公式:

  • max_client = worker_processes * worker_connections

  • max_client = worker_processes * worker_connections / 4

這兩個公式分別說明,在Nginx充當伺服器(例如nginx上面裝載PHP)的時候,Nginx可同時承載的連線數量是最大工作執行緒 * 每個執行緒允許的連線數量;當Nginx充當反向代理服務的時候,其可同時承載的連線數量是最大工作執行緒 * 每個執行緒允許的連線數量 / 4。

第一個問題很好理解,關鍵是第二個問題:為什麼會除以4。網上的帖子給出的答案是。瀏覽器->Nginx、Nginx->後端伺服器、後端伺服器->Nginx、Nginx->瀏覽器,所以需要除以四,我想說TCP協議是雙向全雙工協議,為什麼需要這樣建立連線呢?所以這個說法肯定是錯誤的。

在nginx官方文件上有這樣一句話:

Since a browser opens 2 connections by default to a server and nginx uses the fds (file descriptors) from the same pool to connect to the upstream backend。

翻譯成中文的描述就是,瀏覽器會建立兩條連線到Nginx(注意兩條連線都是瀏覽器建立的),Nginx也會建立對應的兩條連線到後端伺服器。這樣就是四條連線了。

3.1.4、gzip

後文補講,放在這裡算是一個釦子^_^

3.2、健康檢查模組

後文補講,放在這裡算是一個釦子^_^

3.3、圖片處理模組

後文補講,放在這裡算是一個釦子^_^

3.4、Nginx的Rewrite功能

後文補講,放在這裡算是一個釦子^_^

4、後文介紹

我原本計劃一篇文章就把Nginx的主要特性都進行介紹,奈何Nginx的強大功能確實太多了。為了保證您對知識的全面消化,這邊文章就寫到這裡了。LVS的講解再往後拖一週左右吧,下篇文章我們繼續講解Nginx的強大功能,包括gzip功能、強大的rewrite功能,以及兩個擴充套件模組:健康檢查模組和圖片處理模組,至於Nginx整合PHP作為伺服器的特性,為了保證這個系列文章的中心線絡就不再講了,那又是一套完整的知識體系。敬請期待我的下一篇部落格,謝謝。另外,目前一週一篇文章的頻率我覺得是比較合適的,後面的文章我爭取保持這個速度。