Nginx詳解-服務器集群

jopen 9年前發布 | 36K 次閱讀 Nginx Web服務器

原文  http://www.cnblogs.com/jiekzou/p/4486447.html

Nginx 是什么

代理服務器 一般是指局域網內部的機器通過代理服務器發送請求到互聯網上的服務器 , 代理服務器一般作用在客戶端。應用比如: GoAgent ,FQ神器 .

Nginx詳解-服務器集群

 一個完整的代理請求過程為:客戶端首先與代理服務器創建連接,接著根據代理服務器所使用的代理協議,請求對目標服務器創建連接、或者獲得目標服務器的指定資源。  Web 代理( proxy )服務器是網絡的中間實體。 代理位于 Web 客戶端和 Web 服務器之間,扮演“中間人”的角色。 HTTP 的代理服務器即是 Web 服務器又是 Web 客戶端。

代理服務器是介于客戶端和 Web 服務器之間的另一臺服務器,有了它之后,瀏覽器不是直接到 Web 服務器去取回網頁而是向代理服務器發出請求,信號會先送到代理服務器,由代理服務器來取回瀏覽器所需要的信息并傳送給你的瀏覽器。

正向代理:是一個位于客戶端和原始服務器 (origin server) 之間的服務器,為了從原始服務器取得內容,客戶端向代理發送一個請求并指定目標 ( 原始服務器 ) ,然后代理向原始服務器轉交請求并將獲得的內容返回給客戶端。客戶端必須要進行一些特別的設置才能使用正向代理。

反向代理服務器:在服務器端接受客戶端的請求,然后把請求分發給具體的服務器進行處理,然后再將服務器的響應結果反饋給客戶端。 Nginx 就是其中的一種反向代理服務器軟件。

Nginx Nginx ("engine x")  Nginx ( engine x 是俄羅斯人 Igor Sysoev( 塞索耶夫 ) 編寫的一款高性能的  HTTP  和反向代理服務器。也是一個 IMAP/POP3/SMTP 代理服務器;也就是說, Nginx 本身就可以托管網站,進行 HTTP 服務處理,也可以作為反向代理服務器使用。

說明:客戶端必須設置正向代理服務器,當然前提是要知道正向代理服務器的 IP 地址,還有代理程序的端口。

反向代理正好與正向代理相反,對于客戶端而言代理服務器就像是原始服務器,并且客戶端不需要進行任何特別的設置。客戶端向反向代理的命名空間 (name-space) 中的內容發送普通請求,接著反向代理將判斷向何處 ( 原始服務器 ) 轉交請求,并將獲得的內容返回給客戶端。

Nginx詳解-服務器集群

用戶 A 始終認為它訪問的是原始服務器 B 而不是代理服務器 Z ,但實用際上反向代理服務器接 受用戶 A 的應答, 從原始資源服務器 B 中取得用戶 A 的需求資源,然后發送給用戶 A 。由于防火墻的作用,只允 許代理服務器 Z 訪問原始資源服務器 B 。盡管在這個虛擬的環境下,防火墻和反向代理的共同 作用保護了原始資源服務器 B ,但用戶 A 并不知情。 

Nginx 的應用現狀

Nginx 已經在俄羅斯最大的門戶網站──  Rambler Media www.rambler.ru )上運行了 3 年時間,同時俄羅斯超過 20% 的虛擬主機平臺采用 Nginx 作為反向代理服務器。 在國內,已經有 淘寶、新浪博客、新浪播客、網易新聞、六間房、 56.com Discuz! 、水木社區、豆瓣、 YUPOO 、海內、迅雷在線 等多家網站使用  Nginx  作為 Web 服務器或反向代理服務器。

Nginx 的特點

  • 跨平臺:Nginx  可以在大多數  Unix like OS 編譯運行,而且也有 Windows 的移植版本。
  • 配置異常簡單:非常容易上手。配置風格跟程序開發一樣,神一般的配置
  • 非阻塞、高并發連接:數據復制時,磁盤 I/O 的第一階段是非阻塞的。官方測試能夠支撐 5 萬并發連接,在實際生產環境中跑到 2 3 萬并發連接數 .( 這得益于 Nginx 使用了最新的 epoll 模型 )
  • 事件驅動:通信機制采用 epoll 模型,支持更大的并發連接。

Nginx 的事件處理機制

對于一個基本的 web 服務器來說,事件通常有三種類型,網絡事件、信號、定時器。 

首先看一個請求的基本過程:建立連接 --- 接收數據 --- 發送數據 。

再次看系統底層的操作 :上述過程(建立連接 --- 接收數據 --- 發送數據)在系統底層就是讀寫事件。

1 )如果采用阻塞調用的方式,當讀寫事件沒有準備好時,必然不能夠進行讀寫事件,那么久只好等待,等事件準備好了,才能進行讀寫事件。那么請求就會被耽擱 。阻塞調用會進入內核等待, cpu 就會讓出去給別人用了,對單線程的 worker 來說,顯然不合適,當網絡事件越多時,大家都在等待呢, cpu 空閑下來沒人用, cpu 利用率自然上不去了,更別談高并發了 。

2 )既然沒有準備好阻塞調用不行,那么采用非阻塞方式。非阻塞就是,事件,馬上返回 EAGAIN , 告訴你,事件還沒準備好呢,你慌什么,過會再來吧。好吧,你過一會,再來檢查一下事件,直到事件準備好了為止,在這期間,你就可以先去做其它事情,然后再 來看看事件好了沒。雖然不阻塞了,但你得不時地過來檢查一下事件的狀態,你可以做更多的事情了,但帶來的開銷也是不小的 

小結: 非阻塞通過不斷檢查事件的狀態來判斷是否進行讀寫操作,這樣帶來的開銷很大。

3 )因此才有了異步非阻塞的事件處理機制。具體到系統調用就是像 select/poll/epoll/kqueue 這樣的系統調用。他們提供了一種機制,讓你可以同時監控多個事件,調用他們是阻塞的,但可以設置超時時間,在超時時間之內,如果有事件準備好了,就返回。這種機制解決了我們上面兩個問題。 

epoll 為例:當事件沒有準備好時,就放入 epoll( 隊列 ) 里面。如果有事件準備好了,那么就去處理;如果事件返回的是 EAGAIN ,那么繼續將其放入 epoll 里面。從而,只要有事件準備好了,我們就去處理她,只有當所有時間都沒有準備好時,才在 epoll 里 面等著。這樣,我們就可以并發處理大量的并發了,當然,這里的并發請求,是指未處理完的請求,線程只有一個,所以同時能處理的請求當然只有一個了,只是在 請求間進行不斷地切換而已,切換也是因為異步事件未準備好,而主動讓出的。這里的切換是沒有任何代價,你可以理解為循環處理多個準備好的事件,事實上就是 這樣的。 

4 )與多線程的比較:

與多線程相比,這種事件處理方式是有很大的優勢的,不需要創建線程,每個請求占用的內存也很少,沒有上下文切換,事件處理非常的輕量級。并發數再多也不會導致無謂的資源浪費(上下文切換)。

小結: 通過異步非阻塞的事件處理機制, Nginx 實現由進程循環處理多個準備好的事件,從而實現高并發和輕量級。  

master/worker 結構:一個 master 進程,生成一個或多個 worker 進程

內存消耗小:處理大并發的請求內存消耗非常小。在 3 萬并發連接下,開啟的 10 Nginx  進程才消耗 150M 內存( 15M*10=150M ) 成本低廉: Nginx 為開源軟件,可以免費使用。而購買 F5 BIG-IP NetScaler 等硬件負載均衡交換機則需要十多萬至幾十萬人民幣

內置的健康檢查功能:如果 Nginx Proxy  后端的某臺  Web  服務器宕機了,不會影響前端訪問。

節省帶寬:支持 GZIP  壓縮,可以添加瀏覽器本地緩存的  Header  頭。

穩定性高:用于反向代理,宕機的概率微乎其微

Nginx 的不為人知的特點

1 nginx 代理和后端 web 服務器間無需長連接;

2 、接收用戶請求是異步的,即先將用戶請求全部接收下來,再一次性發送后后端 web 服務器,極大的減輕后端 web 服務器的壓力

3 、發送響應報文時,是邊接收來自后端 web 服務器的數據,邊發送給客戶端的

4 、網絡依賴型低。 NGINX 對網絡的依賴程度非常低,理論上講,只要能夠 ping 通就可以實施負載均衡,而且可以有效區分內網和外網流量

5 、支持服務器檢測。 NGINX 能夠根據應用服務器處理頁面返回的狀態碼、超時信息等檢測服務器是否出現故障,并及時返回錯誤的請求重新提交到其它節點上

Nginx的內部(進程)模型

Nginx詳解-服務器集群

nginx 是以多進程的方式來工作的,當然 nginx 也是支持多線程的方式的 , 只是我們主流的方式還是多進程的方式,也是 nginx 的默認方式。 nginx 采用多進程的方式有諸多好處  .

(1) nginx 在啟動后,會有一個 master 進程和多個 worker 進程。 master 進程主要用來管理 worker 進程,包含:接收來自外界的信號,向各 worker 進程發送信號,監控  worker 進程的運行狀態 , worker 進程退出后 ( 異常情況下 ) ,會自動重新啟動新的 worker 進程。而基本的網絡事件,則是放在 worker 進程中來處理了 。多個 worker 進程之間是對等的,他們同等競爭來自客戶端的請求,各進程互相之間是獨立的 。一個請求,只可能在一個 worker 進程中處理,一個 worker 進程,不可能處理其它進程的請求。  worker

(2)Master 接收到信號以后怎樣進行處理( ./nginx -s reload  ? 首先 master 進程在接到信號后,會先重新加載配置文件,然后再啟動新的進程,并向所有老的進程發送信號,告訴他們可以光榮退休了。新的進程在啟動后,就開始接收新的請求,而老的進程在收到來自 master 的信號后,就不再接收新的請求,并且在當前進程中的所有未處理完的請求處理完成后,再退出  .

(3) worker 進程又是如何處理請求的呢?我們前面有提到, worker 進程之間是平等的,每個進程,處理請求的機會也是一樣的。當我們提供 80 端口的 http 服務時,一個連接請求過來,每個進程都有可能處理這個連接,怎么做到的呢?首先,每個 worker 進程都是從 master 進程 fork 過來,在 master 進程里面,先建立好需要 listen socket 之后,然后再 fork 出多個 worker 進程,這樣每個 worker 進程都可以去 accept 這個 socket( 當然不是同一個 socket ,只是每個進程的這個 socket

(4): nginx 采用這種進程模型有什么好處呢?采用獨立的進程,可以讓互相之間不會影響,一個進程退出后,其它進程還在工作,服務不會中斷, master 進程則很快重新啟動新的 worker 進程。當然, worker 進程的異常退出,肯定是程序有 bug 了,異常退出,會導致當前 worker 上的所有請求失敗,不過不會影響到所有請求,所以降低了風險。當然,好處還有很多,大家可以慢慢體會。

(5). 有人可能要問了, nginx 采用多 worker 的方式來處理請求,每個 worker 里面只有一個主線程,那能夠處理的并發數很有限啊,多少個 worker 就能處理多少個并發,何來高并發呢?非也,這就是 nginx 的高明之處, nginx 采用了異步非阻塞的方式來處理請求,也就是說, nginx 是可以同時處理成千上萬個請求的  . 對于 IIS 服務器每個請求會獨占一個工作線程,當并發數上到幾千時,就同時有幾千的線程在處理請求了。這對操作系統來說,是個不小的挑戰,線程帶來的內存占用非常大,線程的上下文切換帶來的 cpu 開銷很大,自然性能就上不去了,而這些開銷完全是沒有意義的。我們之前說過,推薦設置 worker 的個數為 cpu 的核數,在這里就很容易理解了,更多的 worker 數,只會導致進程來競爭 cpu 資源了,從而帶來不必要的上下文切換。而且, nginx 為了更好的利用多核特性,提供了 cpu

Nginx 是如何處理一個請求

首先, nginx 在啟動時,會解析配置文件,得到需要監聽的端口與 ip 地址,然后在 nginx master 進程里面,先初始化好這個監控的 socket( 創建 socket ,設置 addrreuse 等選項,綁定到指定的 ip 地址端口,再 listen) ,然后再 fork( 一個現有進程可以調用 fork 函數創建一個新進程。由 fork 創建的新進程被稱為子進程  ) 出多個子進程出來,然后子進程會競爭 accept 新的連接。此時,客戶端就可以向 nginx 發起連接了。當客戶端與 nginx 進行三次握手,與

當然, nginx 也是可以作為客戶端來請求其它 server 的數據的(如 upstream 模塊),此時,與其它 server 創建的連接,也封裝在 ngx_connection_t 中。作為客戶端, nginx 先獲取一個 ngx_connection_t 結構體,然后創建 socket ,并設置 socket 的屬性( 比如非阻塞)。然后再通過添加讀寫事件,調用 connect/read/write 來調用連接,最后關掉連接,并釋放 ngx_connection_t 。 

說明:nginx 在實現時,是通過一個連接池來管理的,每個 worker 進程都有一個獨立的連接池,連接池的大小是 worker_connections 。這里的連接池里面保存的其實不是真實的連接,它只是一個 worker_connections 大小的一個 ngx_connection_t 結構的數組。并且, nginx 會通過一個鏈表 free_connections 來保存所有的空閑 ngx_connection_t ,每次獲取一個連接時,就從空閑連接鏈表中獲取一個,用完后,再放回空閑連接鏈表里面。 

在這里,很多人會誤解 worker_connections 這個參數的意思,認為這個值就是 nginx 所能建立連接的最大值。其實不然,這個值是表示每個 worker 進程所能建立連接的最大值,所以,一個 nginx 能建立的最大連接數,應該是 worker_connections * worker_processes 。當然,這里說的是最大連接數,對于 HTTP 請求本地資源來說,能夠支持的最大并發數量是 worker_connections * worker_processes ,而如果是 HTTP 作為反向代理來說,最大并發數量應該是 worker_connections * worker_processes/2 。因為作為反向代理服務器,每個并發會建立與客戶端的連接和與后端服務的連接,會占用兩個連接。 

Nginx典型的應用場景

Nginx詳解-服務器集群

負載均衡技術在現有網絡結構之上提供了一種廉價、有效、透明的方法,來擴展網絡設備和服務器的帶寬、增加吞吐量、加強網絡數據處理能力、提高網絡 的 靈活性和可用性。它有兩方面的含義:首先,大量的并發訪問或數據流量分擔到多臺節點設備上分別處理,減少用戶等待響應的時間;其次,單個重負載的運算分擔 到多臺節點設備上做并行處理,每個節點設備處理結束后,將結果匯總,返回給用戶,系統處理能力得到大幅度提高

Nginx 的應用

1 、到官網下載 Windows 版本,下載地址: http://nginx.org/en/download.html

2 、解壓到磁盤任一目錄

3 、修改配置文件:具體參考備注。

4 、啟動服務: 直接運行 nginx.exe ,缺點控制臺窗口關閉,服務關閉。 守護進程的方式啟動: start nginx.exe

5 、停止服務: nginx -s stop

重新加載配置: nginx -s  reload

Nginx 常見配置說明

worker_processes 8;

#nginx 進程數,建議設置為等于 CPU 總核心數

worker_connections 65535;

# 單個進程最大連接數(最大連接數 = 連接數 * 進程數)

client_header_buffer_size 32k; # 上傳文件大小限制

large_client_header_buffers 4 64k; # 設定請求緩

client_max_body_size 8m; # 設定請求緩

autoindex on; # 開啟目錄列表訪問,合適下載服務器,默認關閉。

tcp_nopush on; # 防止網絡阻塞

tcp_nodelay on; # 防止網絡阻塞

keepalive_timeout 120; # 長連接超時時間,單位是秒

gzip on; # 開啟 gzip 壓縮輸出

gzip_min_length 1k; # 最小壓縮文件大小

gzip_buffers 4 16k; # 壓縮緩沖區

gzip_http_version 1.0; # 壓縮版本(默認 1.1 ,前端如果是 squid2.5 請使用 1.0

gzip_comp_level 2; # 壓縮等級

upstream blog.ha97.com {

#upstream 的負載均衡, weight 是權重,可以根據機器配置定義權重。 weigth 參數表示權值,權值越高被分配到的幾率越大。

server 192.168.80.121:80 weight=3;

server 192.168.80.122:80 weight=2;

server 192.168.80.123:80 weight=3;

}

# 虛擬主機的配置

server

{

# 監聽端口

listen 80;

# 域名可以有多個,用空格隔開

server_name www.ha97.com ha97.com;

index index.html index.htm index.php;

root /data/www/ha97;

location ~ .*.(php|php5)?$

{

fastcgi_pass 127.0.0.1:9000;

fastcgi_index index.php;

include fastcgi.conf;

}

模塊參數

    #定義Nginx運行的用戶和用戶組        
    user www www;              
    #nginx進程數,建議設置為等于CPU總核心數。        
    worker_processes 8;        

    #全局錯誤日志定義類型,[ debug | info | notice | warn | error | crit ]  

    error_log ar/loginx/error.log info;  

    #進程文件  

    pid ar/runinx.pid;        

    #一個nginx進程打開的最多文件描述符數目,理論值應該是最多打開文件數(系統的值ulimit -n)與nginx進程數相除,但是nginx分配請求并不均勻,  
    所以建議與ulimit -n的值保持一致。  

    worker_rlimit_nofile 65535;               

    #工作模式與連接數上限        
    events        
    {        
    #參考事件模型,use [ kqueue | rtsig | epoll | /dev/poll | select | poll ]; epoll模型是Linux 2.6以上版本內核中的高性能網絡I/O模型,  
    如果跑在FreeBSD上面,就用kqueue模型。  

    use epoll;        
    #單個進程最大連接數(最大連接數=連接數*進程數)       
    worker_connections 65535;        
    }  

    #設定http服務器        
    http        
    {        
    include mime.types; #文件擴展名與文件類型映射表       
    default_type application/octet-stream; #默認文件類型        
    #charset utf-8; #默認編碼        
    server_names_hash_bucket_size 128; #服務器名字的hash表大小        
    client_header_buffer_size 32k; #上傳文件大小限制        
    large_client_header_buffers 4 64k; #設定請求緩       
    client_max_body_size 8m; #設定請求緩        
    sendfile on; #開啟高效文件傳輸模式,sendfile指令指定nginx是否調用sendfile函數來輸出文件,對于普通應用設為 on,如果用來進行下載等應用磁盤IO重負載應用,  
    可設置為off,以平衡磁盤與網絡I/O處理速度,降低系統的負載。注意:如果圖片顯示不正常把這個改成off。        
    autoindex on; #開啟目錄列表訪問,合適下載服務器,默認關閉。        
    tcp_nopush on; #防止網絡阻塞        
    tcp_nodelay on; #防止網絡阻塞        
    keepalive_timeout 120; #長連接超時時間,單位是秒       

    #FastCGI相關參數是為了改善網站的性能:減少資源占用,提高訪問速度。下面參數看字面意思都能理解。        
    fastcgi_connect_timeout 300;        
    fastcgi_send_timeout 300;        
    fastcgi_read_timeout 300;        
    fastcgi_buffer_size 64k;        
    fastcgi_buffers 4 64k;        
    fastcgi_busy_buffers_size 128k;        
    fastcgi_temp_file_write_size 128k;         

    #gzip模塊設置        
    gzip on; #開啟gzip壓縮輸出        
    gzip_min_length 1k; #最小壓縮文件大小        
    gzip_buffers 4 16k; #壓縮緩沖區        
    gzip_http_version 1.0; #壓縮版本(默認1.1,前端如果是squid2.5請使用1.0)        
    gzip_comp_level 2; #壓縮等級        
    gzip_types text/plain application/x-javascript text/css application/xml;  

    #壓縮類型,默認就已經包含textml,所以下面就不用再寫了,寫上去也不會有問題,但是會有一個warn。        
    gzip_vary on;        
    #limit_zone crawler $binary_remote_addr 10m; #開啟限制IP連接數的時候需要使用        


    upstream blog.ha97.com {        
    #upstream的負載均衡,weight是權重,可以根據機器配置定義權重。weigth參數表示權值,權值越高被分配到的幾率越大。        
    server 192.168.80.121:80 weight=3;        
    server 192.168.80.122:80 weight=2;        
    server 192.168.80.123:80 weight=3;        
    }               

    #虛擬主機的配置        
    server       
    {        
    #監聽端口        
    listen 80;        
    #域名可以有多個,用空格隔開        
    server_name www.ha97.com ha97.com;       
    index index.html index.htm index.php;        
    root /data/www/ha97;        
    location ~ .*.(php|php5)?$        
    {        
    fastcgi_pass 127.0.0.1:9000;        
    fastcgi_index index.php;        
    include fastcgi.conf;        
    }        
    #圖片緩存時間設置        
    location ~ .*.(gif|jpg|jpeg|png|bmp|swf)$        
    {        
    expires 10d;        
    }        
    #JS和CSS緩存時間設置        
    location ~ .*.(js|css)?$        
    {        
    expires 1h;        
    }        
    #日志格式設定        
    log_format access '$remote_addr - $remote_user [$time_local] "$request" '        
    '$status $body_bytes_sent "$http_referer" '        
    '"$http_user_agent" $http_x_forwarded_for';  

    #定義本虛擬主機的訪問日志       
    access_log ar/loginx/ha97access.log access;               

    #對 "/" 啟用反向代理        
    location / {        
    proxy_pass http://127.0.0.1:88;        
    proxy_redirect off;        
    proxy_set_header X-Real-IP $remote_addr;  

    #后端的Web服務器可以通過X-Forwarded-For獲取用戶真實IP        
    proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;  

    #以下是一些反向代理的配置,可選。  

    proxy_set_header Host $host;        
    client_max_body_size 10m; #允許客戶端請求的最大單文件字節數        
    client_body_buffer_size 128k; #緩沖區代理緩沖用戶端請求的最大字節數,        
    proxy_connect_timeout 90; #nginx跟后端服務器連接超時時間(代理連接超時)        
    proxy_send_timeout 90; #后端服務器數據回傳時間(代理發送超時)        
    proxy_read_timeout 90; #連接成功后,后端服務器響應時間(代理接收超時)        
    proxy_buffer_size 4k; #設置代理服務器(nginx)保存用戶頭信息的緩沖區大小        
    proxy_buffers 4 32k; #proxy_buffers緩沖區,網頁平均在32k以下的設置        
    proxy_busy_buffers_size 64k; #高負荷下緩沖大小(proxy_buffers*2)        
    proxy_temp_file_write_size 64k;  

    #設定緩存文件夾大小,大于這個值,將從upstream服務器傳        
    }  

    #設定查看Nginx狀態的地址        
    location /NginxStatus {        
    stub_status on;        
    access_log on;        
    auth_basic "NginxStatus";        
    auth_basic_user_file confpasswd;        
    #htpasswd文件的內容可以用apache提供的htpasswd工具來產生。        
    }  

    #本地動靜分離反向代理配置        
    #所有jsp的頁面均交由tomcat或resin處理        
    location ~ .(jsp|jspx|do)?$ {        
    proxy_set_header Host $host;        
    proxy_set_header X-Real-IP $remote_addr;        
    proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;        
    proxy_pass http://127.0.0.1:8080;        
    }  

    #所有靜態文件由nginx直接讀取不經過tomcat或resin        
    location ~ .*.(htm|html|gif|jpg|jpeg|png|bmp|swf|ioc|rar|zip|txt|flv|mid|doc|ppt|pdf|xls|mp3|wma)$        
    { expires 15d; }        
    location ~ .*.(js|css)?$        
    { expires 1h; }        
    }        
    }  

更詳細的模塊參數請參考: http://wiki.nginx.org/Main

Nginx+IIS 服務器搭建服務器集群

Nginx詳解-服務器集群

配置靜態資源

 location ~ \.(jpg|png|jpeg|bmp|gif|swf|css)$  {  
                expires 30d;  
                 root /nginx-1.4.7;#root:  break;  
            } 

擴展

負載均衡策略: http://baidutech.blog.51cto.com/4114344/1033718/

 本文由用戶 jopen 自行上傳分享,僅供網友學習交流。所有權歸原作者,若您的權利被侵害,請聯系管理員。
 轉載本站原創文章,請注明出處,并保留原始鏈接、圖片水印。
 本站是一個以用戶分享為主的開源技術平臺,歡迎各類分享!