前一篇文章《架構設計:負載均衡層設計方案(1)——負載場景和解決方式》中咱們描述了要搭設負載均衡層的業務場景和負載均衡層搭建和擴展思路。從這篇文章開始的後幾篇文章,咱們將詳細介紹Nginx、LVS和Nginx+Keepalived、LVS+Keepalived和LVS+Nginx+Keepalived的安裝細節,以及它們的性能優化方式。html
Nginx和LVS都是能夠獨立工做的,Keepalived做爲檢測機制,不但能夠和Nginx、LVS集成也能夠和其餘軟件集成造成高可用方案(例如能夠和MySQL數據庫集成、能夠和Jetty服務器集成、還能夠和本身寫的程序集成)。因此首先咱們先來詳細講述Nginx和LVS的核心工做原理、安裝過程和優化方式,再分別講解他們和Keepalived的集成方式。這樣的方式應該可使您更快的掌握其中的核心,並能最快的融會貫通。linux
Nginx是什麼,請自行百度。咱們先介紹幾個關鍵的算法,若是您還不瞭解這些算法在Nginx中所起的做用,請不要着急,本文後半部分將說明它們的做用。nginx
一致性Hash算法是現代系統架構中的最關鍵算法之一,在分佈式計算系統、分佈式存儲系統、數據分析等衆多領域中普遍應用。針對這個系列的博文,在負載均衡層、業務通訊層、數據存儲層都會有他的身影。c++
hash算法的關鍵在於它可以根據不一樣的屬性數據,生成一串不相同的hash值,而且可以將這個hash值轉換爲web
一臺服務器的某個或者某一些屬性固然也能夠進行hash計算(一般是這個服務器的IP地址和開放端口),而且根據計算分佈在這個圓環上的某一個點。也就是圖中圓環上的藍色點。正則表達式
一個處理請求固然也能夠根據這個請求的某一個或者某一些屬性進行hash計算(能夠是這個請求的IP、端口、cookie值、URL值或者請求時間等等),而且根據計算記過度布在這個圓環上的某一個點上。也就是上圖圓環上的黃色點。算法
咱們約定落在某一個藍點A左側和藍點B右側的黃色點所表明的請求,都有藍點A所表明的服務器進行處理,這樣就完成解決了「誰來處理」的問題。在藍色點穩定存在的前提下,來自於同一個Hash約定的請求所落在的位置都是同樣的,這就保證了服務處理映射的穩定性。shell
當某一個藍色點因爲某種緣由下線,其所影響到的黃色點也是有限的。即下一次客戶端的請求將由其餘的藍色點所表明的服務器進行處理。數據庫
當有任務須要傳遞到下層節點進行處理時,任務來源點會按照一個固定的順序,將任務依次分配到下層節點,若是下層可用的節點數量爲X,那麼第N個任務的分配規則爲:編程
輪詢處理在不少架構思想中都有體現:DNS解析多IP時、LVS向下轉發消息時、Nginx向下轉發消息時、Zookeeper向計算節點分配任務時。瞭解基本的輪詢過程有助於咱們在進行軟件架構設計時進行思想借鑑。
可是上面的輪詢方式是有缺陷的,因爲各類客觀緣由咱們可能沒法保證任務處理節點的處理能力都是同樣的(CPU、IO、內存頻率等不一樣)。因此A節點業務能同時處理100個任務,可是B節點可能同時只能處理50個任務。
在這種狀況下咱們須要依據下層節點某個或者多個屬性設置權值。這個屬性多是網絡帶寬、CPU繁忙程度或者就是各一個固定的權值。
那麼加權輪詢的分配依據是什麼呢?有不少分配依據,例如:機率算法(此算法中包括蒙特卡羅算法,拉斯維加斯算法和舍伍德算法,在網絡上有不少介紹資料)、最大公約數法。這裏咱們對最大公約數算法進行介紹,由於該方法簡單實用:
首先按照某種規則計算獲得每一個處理節點的權值,上文已經說到計算規則多是這個服務節點的CPU利用率、網絡佔用狀況或者在配置文件中的固定權重。
求這些權值的最大公約數,在上圖中三個節點的權值分別是100、80、60.那麼求得的最大公約數就是20(若是您忘記了最大公約數的定義,請自行復習)。那麼這三個節點的被除結果分別是五、四、3,求和值爲12。
獲得以上的計算結果,就能夠開始進行請求分配了,公式一樣爲:
總結一下:加權輪詢是輪詢方案的補充,經過將處理節點的屬性轉換成權值能夠有效的描述處理節點的處理能力,實現更科學的處理任務分配。加權輪詢的關鍵在於加權算法,最大公約數算法簡單實用,定位效率高。
操做系統: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
下載nginx1.8.0版本
解壓nginx的tar文件
進行源碼編譯
咱們看到這時編譯檢查報錯,報錯寫得很清楚,爲了支持HTTP重寫模塊,Nginx須要PCRElib的支持。那咱們到http://ncu.dl.sourceforge.net/project/pcre/pcre/8.37/pcre-8.37.tar.gz下載一個穩定的pcre版本編譯安裝便可(不必定是8.37版本)。
再進行源碼編譯安裝
./configure –prefix=/usr/nginx-1.8.0
make && make install
整個驗證、編譯、安裝過程不該該報任何錯誤。若是您使用prefix設置了安裝目標目錄,那麼可能您還須要在/etc/profix文件中設置環境變量:
下面介紹幾個nginx經常使用的命令,若是您能夠正常使用這些命令,那麼說明nginx已經安裝成功了。
nginx:直接在命令行鍵入nginx,就能夠啓動nginx。
nginx -t:檢查配置文件是否正確。這個命令能夠檢查nginx.conf配置文件其格式、語法是否正確。若是配置文件存在錯誤,則會出現相應提示;若是nginx.conf文件正確,也會出現相應的成功提示。
nginx -s reload:重加載/重啓nginx——以新的nginx.conf配置文件中的定義。
nginx -s stop:中止nginx。
Nginx在安裝完成後,不用更改任何配置信息就能夠直接運行。可是很顯然這不會知足咱們生產環境的要求。因此咱們要重點介紹Nginx的配置文件,以及其中重要的配置項的含義。
若是您是按照本文的描述方式安裝的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配置信息,能夠直接粘貼使用,但不建議您這樣作。由於上文中不少關鍵的配置屬性都尚未講解。這樣粘貼複製不利於您的工做和學習。
科技在發展,社會在進步,知足摩爾定義的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上使用。
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後,配置信息就是下圖所示了:
這個小結咱們主要來講明兩個在網上常常說的公式:
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也會創建對應的兩條鏈接到後端服務器。這樣就是四條鏈接了。
後文補講,放在這裏算是一個釦子^_^
後文補講,放在這裏算是一個釦子^_^
後文補講,放在這裏算是一個釦子^_^
後文補講,放在這裏算是一個釦子^_^
我本來計劃一篇文章就把Nginx的主要特性都進行介紹,奈何Nginx的強大功能確實太多了。爲了保證您對知識的全面消化,這邊文章就寫到這裏了。LVS的講解再日後拖一週左右吧,下篇文章咱們繼續講解Nginx的強大功能,包括gzip功能、強大的rewrite功能,以及兩個擴展模塊:健康檢查模塊和圖片處理模塊,至於Nginx集成PHP做爲服務器的特性,爲了保證這個系列文章的中心線絡就再也不講了,那又是一套完整的知識體系。敬請期待個人下一篇博客,謝謝。另外,目前一週一篇文章的頻率我以爲是比較合適的,後面的文章我爭取保持這個速度。