Nginx原理

一、Nginx的模塊

Nginx由內(nèi)核和模塊組成,其中,內(nèi)核的設(shè)計非常微小和簡潔,完成的工作也非常簡單,僅僅通過查找配置文件將客戶端請求映射到一個location block(location是Nginx配置中的一個指令,用于URL匹配),而在這個location中所配置的每個指令將會啟動不同的模塊去完成相應(yīng)的工作。

Nginx的模塊從結(jié)構(gòu)上分為核心模塊、基礎(chǔ)模塊和第三方模塊:

  • 核心模塊:HTTP模塊、EVENT模塊和MAIL模塊
  • 基礎(chǔ)模塊:HTTP Access模塊、HTTP FastCGI模塊、HTTP Proxy模塊和HTTP Rewrite模塊,
  • 第三方模塊:HTTP Upstream Request Hash模塊、Notice模塊和HTTP Access Key模塊。

Nginx的模塊從功能上分為如下三類。

  • Handlers(處理器模塊)。此類模塊直接處理請求,并進行輸出內(nèi)容和修改headers信息等操作。Handlers處理器模塊一般只能有一個。
  • Filters (過濾器模塊)。此類模塊主要對其他處理器模塊輸出的內(nèi)容進行修改操作,最后由Nginx輸出。
  • Proxies (代理類模塊)。此類模塊是Nginx的HTTP Upstream之類的模塊,這些模塊主要與后端一些服務(wù)比如FastCGI等進行交互,實現(xiàn)服務(wù)代理和負載均衡等功能。
image.png

Nginx本身做的工作實際很少,當它接到一個HTTP請求時,它僅僅是通過查找配置文件將此次請求映射到一個location block,而此location中所配置的各個指令則會啟動不同的模塊去完成工作,因此模塊可以看做Nginx真正的勞動工作者。通常一個location中的指令會涉及一個handler模塊和多個filter模塊(當然,多個location可以復用同一個模塊)。handler模塊負責處理請求,完成響應(yīng)內(nèi)容的生成,而filter模塊對響應(yīng)內(nèi)容進行處理。

Nginx的模塊直接被編譯進Nginx,因此屬于靜態(tài)編譯方式。啟動Nginx后,Nginx的模塊被自動加載,不像Apache,首先將模塊編譯為一個so文件,然后在配置文件中指定是否進行加載。在解析配置文件時,Nginx的每個模塊都有可能去處理某個請求,但是同一個處理請求只能由一個模塊來完成。

二、Nginx的多進程IO模型

1. IO模型:blocking I/O
image.png

從圖宏觀來看,左側(cè)為應(yīng)用程序,右側(cè)為內(nèi)核,當應(yīng)用程序的進程使用recvform函數(shù)發(fā)起對內(nèi)核的調(diào)用,內(nèi)核開始準備數(shù)據(jù),一般來說內(nèi)核需要收到一個完整的數(shù)據(jù)包(如UDP),不會很快,因此應(yīng)用程序的進程處于阻塞等待的狀態(tài),待內(nèi)核將數(shù)據(jù)準備好,它將數(shù)據(jù)從內(nèi)核拷貝到用戶內(nèi)存,內(nèi)核才會返回結(jié)果,然后應(yīng)用程序解除阻塞狀態(tài),去處理下一步請求,從本次過程,做過開發(fā)的基本都能理解,平時程序都是屬于這種阻塞的同步調(diào)用方式。

2. IO模型:nonblocking I/O
image.png

從圖可以看出,應(yīng)用程序進程當使用recvform函數(shù)對內(nèi)核發(fā)起調(diào)用時,內(nèi)核立即返回一個數(shù)據(jù)沒有準備好的結(jié)果,進程通過輪詢不斷的去請求內(nèi)核,詢問數(shù)據(jù)是否給老子準備好了,知道內(nèi)核返回結(jié)果,說已經(jīng)準備好了,進程才結(jié)束輪詢。

跟阻塞IO對比,進程本地不必阻塞等待,而是隔三差五的通過輪詢調(diào)用,在這個過程中,會大量的占用CPU的時間,所以一般Web服務(wù)器都不使用這種I/O模型。

3. IO模型:I/O multiplexing (select and poll)
image.png

多路復用模型新增了幾個函數(shù):select、poll、epoll(Linux2.6以后的內(nèi)核開始支持),這幾個函數(shù)也會使進程阻塞,但是和阻塞I/O所不同的,這兩個函數(shù)可以同時阻塞多個I/O操作,而且可以同時對多個讀操作,多個寫操作的I/O函數(shù)進行監(jiān)測,直到有數(shù)據(jù)可讀或可寫時,才真正調(diào)用I/O操作函數(shù),說直白一點就是他們可以監(jiān)控多個內(nèi)核的IO操作,一個頂仨,一個select會監(jiān)測多個socket,當內(nèi)核準備好其中一個數(shù)據(jù)時,select會立即通知進行,趕快使用recvform調(diào)用內(nèi)核,讓內(nèi)核抓緊開始拷貝數(shù)據(jù)到用戶內(nèi)存,如此,它比阻塞IO好處就是一次能處理多個連接,而阻塞IO只能處理一個。

其中還有一個點,就是epoll、poll要比select要高級一點,他們是無輪詢的,因為他們用callback,select需要通過遍歷Socket來完成調(diào)度,如果socket多,那肯定是需要浪費CPU時間的,而epoll和poll使用回調(diào)函數(shù),給套接字注冊個回調(diào)函數(shù),當他們活躍時,自動完成相關(guān)操作,就避免了輪詢,這些函數(shù)實際是阻塞進程的。

4. IO模型:signal driven I/O (SIGIO)
image.png

信號驅(qū)動IO,應(yīng)用程序進程建立SIGIO處理函數(shù)調(diào)用內(nèi)核,內(nèi)核會立即返回數(shù)據(jù)沒有準備好的信號,進程不再阻塞,待內(nèi)核準備好后,發(fā)送SIGIO信號給用戶進程,然后用戶進程通過阻塞的方式使用recvform函數(shù)調(diào)用內(nèi)核,讓內(nèi)核把數(shù)據(jù)拷貝到用戶內(nèi)存,并返回拷貝結(jié)果??吹酱颂幨遣皇撬圃嘧R,其實這有點回調(diào)的意思了。

5. IO模型:asynchronous I/O (the POSIX aio_functions)
image.png

異步IO,也就是AIO,這個過程其實就非常簡單,應(yīng)用程序進程調(diào)用內(nèi)核,內(nèi)核返回數(shù)據(jù)沒有準備好消息,進程繼續(xù)去干別的事情,待內(nèi)核準備好數(shù)據(jù),并且拷貝到用戶內(nèi)存,才通知進程已完成數(shù)據(jù)拷貝,因此,可以看出這種IO方式是效率最高的。

三、nginx的優(yōu)化

1. nginx.conf優(yōu)化
user nginx ;  
pid /var/run/nginx.pid;
worker_processes auto;          #定義了nginx對外提供web服務(wù)時的worder進程數(shù)。
worker_rlimit_nofile 100000;    #worker進程的最大打開文件數(shù)限制
2. Events模塊
events {
    worker_connections 2048;    #設(shè)置可由一個worker進程同時打開的最大連接數(shù)
    multi_accept on;            #告訴nginx收到一個新連接通知后接受盡可能多的連接
    use epoll;                  #用于復用客戶端線程的輪詢方法
}
3. HTTP 模塊
http {
    server_tokens off;          #關(guān)閉在錯誤頁面中的nginx版本
    sendfile on;                #
    tcp_nopush on;              #告訴nginx在一個數(shù)據(jù)包里發(fā)送所有頭文件,而不一個接一個的發(fā)送
    tcp_nodelay on;             #告訴nginx不要緩存數(shù)據(jù),而是一段一段的發(fā)送
                                #當需要及時發(fā)送數(shù)據(jù)時,就應(yīng)該給應(yīng)用設(shè)置這個屬性,
                                #這樣發(fā)送一小塊數(shù)據(jù)信息時就不能立即得到返回值。
    access_log off;
    error_log /var/log/nginx/error.log crit;
    ...
}
timeout設(shè)置
    keepalive_timeout 10;       #給客戶端分配keep-alive鏈接超時時間。服務(wù)器將在這個超時時間過后關(guān)閉鏈接。

    client_header_timeout 10;   #設(shè)置請求頭
    client_body_timeout 10;     #和請求體(各自)的超時時間。我們也可以把這個設(shè)置低些。

    reset_timedout_connection on;
                                #告訴nginx關(guān)閉不響應(yīng)的客戶端連接。這將會釋放那個客戶端所占有的內(nèi)存空間。
    send_timeout 10;            #在兩次客戶端讀取操作這段時間內(nèi),客戶端沒有讀取任何數(shù)據(jù),nginx就會關(guān)閉連接。
連接限制
    limit_conn_zone $binary_remote_addr zone=addr:5m;
                                #設(shè)置用于保存各種key(比如當前連接數(shù))的共享內(nèi)存的參數(shù)
    limit_conn addr 100;        #我們允許每一個IP地址最多同時打開有100個連接
type
    include /etc/nginx/mime.types;
    default_type text/html;
    charset UTF-8;
gzip
    gzip on;                            #采用gzip壓縮的形式發(fā)送數(shù)據(jù)
    gzip_disable "msie6";               #為指定的客戶端禁用gzip功能

    # gzip_static on;
    gzip_proxied any;                   #允許或者禁止壓縮基于請求和響應(yīng)的響應(yīng)流。我們設(shè)置為any,意味著將會壓縮所有的請求
    gzip_min_length 1000;               #設(shè)置對數(shù)據(jù)啟用壓縮的最少字節(jié)數(shù)
    gzip_comp_level 4;                  #設(shè)置數(shù)據(jù)的壓縮等級。這個等級可以是1-9之間的任意數(shù)值,9是最慢但是壓縮比最大的
    gzip_types text/plain
              text/css
              application/json
              application/x-javascript
              text/xml
              application/xml
              application/xml+rss
              text/javascript;          #設(shè)置需要壓縮的數(shù)據(jù)格式
file_cache
    open_file_cache max=100000 inactive=20s;
                                #打開緩存的同時也指定了緩存最大數(shù)目,以及緩存的時間。
                                #我們可以設(shè)置一個相對高的最大時間,這樣我們可以在它們不活動超過20秒后清除掉
    open_file_cache_valid 30s;  #在open_file_cache中指定檢測正確信息的間隔時間。
    open_file_cache_min_uses 2; #定義了open_file_cache中指令參數(shù)不活動時間期間里最小的文件數(shù)。
    open_file_cache_errors on;  #指定了當搜索一個文件時是否緩存錯誤信息

    include /etc/nginx/conf.d/*.conf;
buffer
    server_names_hash_bucket_size 128;  #服務(wù)器名字的hash表大小
    client_header_buffer_size 32k;      #用于設(shè)置客戶端請求的Header頭緩沖區(qū)的大小,一般1kb就夠用
    large_client_header_buffers 4 64k;  #設(shè)置客戶端請求的Header頭緩沖區(qū)大小,默認為4K??蛻舳苏埱笮胁荒艹^設(shè)置的第一個數(shù),請求的Header頭信息不能大于設(shè)置的第二個數(shù),否則會報"Request URI too large"(414)或“Bad request”(400)錯誤。如果客戶端的Cookie信息較大,則需增加緩沖區(qū)大小
    client_max_body_size 8m;            #上傳文件大小限制
4. proxy_pass
    proxy_buffering    off;
    proxy_buffer_size  128k;
    proxy_buffers 100  128k;
最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時請結(jié)合常識與多方信息審慎甄別。
平臺聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點,簡書系信息發(fā)布平臺,僅提供信息存儲服務(wù)。

相關(guān)閱讀更多精彩內(nèi)容

  • 什么是Nginx? Nginx是一個高性能的HTTP和反向代理服務(wù)器,也是一個IMAP/POP3/SMTP服務(wù)器N...
    jiangmo閱讀 2,650評論 1 9
  • Nginx才短短幾年,就拿下了web服務(wù)器大筆江山,眾所周知,Nginx在處理大并發(fā)靜態(tài)請求方面,效率明顯高于ht...
    松江野人閱讀 1,194評論 0 2
  • I/O模型Nginx介紹Nginx的安裝和目錄結(jié)構(gòu)Nginx的配置Nginx的編譯安裝 一、I/O模型 (一)I/...
    哈嘍別樣閱讀 986評論 0 4
  • 有人路過我的前世 亦有人流連于我的今生 年少輕狂時 總以為三年五載約等于一生一世 買過一對很漂亮的耳環(huán) 一分為二后...
    瓊樓小閣主閱讀 224評論 0 0
  • 說句心里話,這是第一次陪孩子進人校園,要不是孩子忘記帶作業(yè)給我這次機會,還不知道什么時候才能來過…… ...
    憶甜人生閱讀 288評論 1 3

友情鏈接更多精彩內(nèi)容