IO模型:php
blocking、nonblocking、multiplexing、event-driven、AIOhtml
Nginx特性:non-blocking、event-driven、AIO前端
因此Nginx在典型的這幾項IO模型當中的所謂實現高併發服務器端編程的概念上都是支持的。node
Nginx其此版本號爲奇數的一般爲開發版,爲偶數的一般爲穩定版,固然做爲咱們來說,一般在生產環境中可以用到的應該是stable版本的。nginx
Nginx的開發也遵循這樣的一種特性,一旦它的某一個偶數版升級之後那麼隨之而來的比它大一個數字的奇數版將成爲新的開發板,這是須要注意的一點。在1.8.0當中,他已經引進了incorporating許多新特性包括幾個著名的新特性。web
之後要定義一個對應的Nginx線程,能支持多少個併發鏈接,能夠經過線程池定義,這是一個很強大的也是很新的特性。正則表達式
那這樣一來新特性的引入勢必可以更多的更強大的對於所謂代理模式下的鏈接的管理功能。算法
user USERNAME [GROUPNAME];
指定運行worker進程的用戶和組,組身份身份可省。它的組身份與用戶身份是統一使用同一個身份來定義的,這一點有別於httpd。若是在編譯時已經使用--user,--group指定了的話,那在配置文件中它頗有多是被註釋掉的,由於它默認就會使用那一個對應的用戶名來進行定義了。編程
例:user nginx nginx;後端
注意:每個指令必須使用分號結尾不然視爲語法錯誤。
pid /path/to/pid_file;
指定Nginx守護進程的pid文件的位置;若是在編譯時已指定在配置文件中可能被註釋掉代表使用編譯時指定的默認路徑;
例:pid /var/run/nginx/nginx.pid;
大多數守護進程都會有pid文件來保存其pid信息的,包括此前學的httpd,甚至因而以fpm模式工做的php,它們都有本身的pid文件;
worker_rlimit_nofile number;
指定全部worker進程(加起來)所可以打開的最大文件句柄數;說白了就是所可以打開的最大文件數量。由於worker進程都是以Nginx用戶的身份運行的,因此是一共可以打開的文件的總數。
Linux系統上包括管理員默認都受限於所可以運行的資源的數量。每一個用戶默認可以打開的文件數是1024個,可是對於任何一個服務器軟件來說,若是它要監聽在某個套接字上提供服務的話,那麼任何一個客戶端鏈接連入以後它都須要一個套接字文件來維持這個鏈接。由於Linux要靠此特性來達到一切皆文件的哲學思想或者說這樣一種目的。所以,站在這個角度來說,若是咱們Nginx下可以支持1萬個併發鏈接,那麼它至少須要維持1萬個套接字文件,還不包括本身打開本身的配置文件。對於要想可以支持更大的併發鏈接數,咱們對應的每個worker進程是否是應該設置它所可以單進程打開的文件數量提高呢?由於worker進程是以Nginx用戶的身份來運行的,所以咱們爲了可以worker進程接受更多的併發鏈接,運行worker進程的用戶得可以同時打開更多的文件才能夠的。默認狀況下的1024對於一個高併發的worker進程來說顯然是過小過小了,因此必要時咱們能夠經過調整此值對應於設置一個worker進程所可以打開的最大文件數。
worker_rlimit_core size;
用來指明全部的worker加起來所可以使用的整體的核心文件的最大大小。指的就是這個進程所可以使用的核心數量的或者說核心文件的最大文件體積大小。此指令通常不多須要咱們手動調整。
worker_processes #;
指定所可以打開的worker進程的個數;一般應該爲物理CPU核心數-1或-2,即一般應該略少於CPU物理核心數;要留出一個核爲系統本身所使用。可是如今Nginx的版本支持它的值爲auto,Tengine能夠設置爲auto表示自動設定,自動打開幾個,自動判斷。
worker_cpu_affinity cpumask …;
設定把worker進程綁定在哪些CPU上的。此處指明CPU用的是cpumask,cpumask爲CPU掩碼,CPU掩碼指的是什麼呢?假如主機上有四顆CPU,它可能用8位二進制來表示,那這四顆CPU怎麼標識呢?在其對應上爲1就表示那一顆CPU被選中了,如一號CPU爲0000 000一、二號CPU爲0000 00十、三號CPU爲0000 0100,四號爲0000 1000。因此這個worker_cpu_affinity後面所跟的若是隻綁定在前三顆上面,只寫前三個就可。
例如:worker_cpu_affinity 00000001 00000010 00000100;
但例如:0011表示第一和第二同時兩顆。
對於Nginx來說,咱們說過,它的工做特性是一個線程或者一個worker進程響應n個用戶請求的。那麼即使咱們啓動少於CPU的物理核心數的進程,可是它依然面臨一個問題,如咱們當前這個主機上所同時運行的進程數量可能會比較多,百十個進程應該是很常見的,因此即使有4個物理核心,在某一時刻,在當前CPU上所運行的也未必是Nginx的worker進程。那結果就是對於很是繁忙的worker進程來說,它有可能被頻繁的調度來調度去。那頗有可能咱們啓動了假設叫三個進程,這三個進程到底誰運行在哪一個CPU上是無法肯定的。咱們Linux的核心會動態的根據當前CPU的空閒數以及須要運行的進程數調度,所以多是不斷的在進行變化。這樣一來帶給咱們的最大壞處在於因爲在CPU上須要作進程切換(context switch),進程切換會消耗時間會浪費CPU,因此進程切換自己會帶來額外的CPU消耗,會產生CPU的沒必要要的消耗,所以爲了儘量的壓榨CPU,發揮CPU的最後一點一滴的性能,這就是咱們要設置進程數要少於CPU核心數的緣由。
咱們能夠這麼作,明確的指明把每個進程綁定在指定CPU上,好比一號進程明確說明綁定在一號上面,它毫不在其它CPU核心上運行,二號進程綁定在二號CPU上,三號進程綁定在三號CPU上。因此這樣一來,這三個進程必定不會被調度到其它核心上去了,可是其實這樣是不可能避免進程間的切換的,由於咱們雖然把它綁定在這顆CPU上並不意味着這個CPU不能運行其它進程。可是至少保證了這個對於Nginx這一個進程自己不用調度到其它CPU上去了,那帶來的好處是這個進程本身的緩存不會失效,說白了就是若是說這個Nginx在運行時,咱們這個Nginx進程加載了不少數據到CPU的二級緩存、一級緩存、一級指令緩存包括一級數據緩存,若是咱們不幸的把它調度到另一顆CPU上去,那在第一顆CPU的緩存的內容就會失效了,到另一顆CPU緩存還須要從新加載的,因此咱們一旦把進程綁定的話,咱們這個進程本身曾經加載到CPU上的緩存即使這個進程被調度出去,等一會它在回來運行時,那些緩存卻依然有效,因此保證了緩存的有效性。可是它卻沒辦法避免進程切換。
優勢:可以提高CPU緩存的命中率;
可是不能避免context switch,咱們真正要想極端去優化Nginx所在的服務器的話,還有一種方法;這種方法可能須要一些別的技能來支撐了。如:開機的時候設定主機上四顆CPU有三顆都不被內核使用,這叫CPU隔離,因此一開機咱們就事先說明,內核只能使用這一顆CPU。那這樣子一來,內核想調度任何進程就只能在第四顆CPU上調度。那開機完成之後,咱們還要隔離中斷,咱們系統可能有不少中斷,中斷可能由硬件產生也多是軟中斷,此處僅指硬件中斷,硬件中斷包括網卡上有報文到來或者咱們的硬盤上有IO完成等等。這些也都從CPU上隔離,因此它不處理中斷,也不接受任何進程調度。當啓動完之後,咱們明確說明第一個進程綁定在第一顆,第二個進程綁定在第二顆,第三個進程綁定在第三顆。那這三個進程不受內核調度,因此不再會有其它進程到這顆CPU上運行了,那這就意味着專CPU專用,第一顆CPU只爲運行Nginx,Nginx不再會被切換出去了。因此這個Nginx但凡須要運行,它就本身緊緊霸佔住第一顆CPU,充分發揮CPU每一時刻的運算能力來支撐Web服務的訪問。
那這樣一來,三個worker線程啓動起來之後,假如說每個worker線程能夠支持1萬個併發,那三萬個就很輕鬆拿下了。可是這須要作兩個前提,第一,咱們在啓動OS時須要隔離出來這三顆CPU,第二,咱們須要把中斷處理從這三顆CPU上剝離出去才能夠。
timer_resolution interval;
計時器解析度:下降此值,可減小gettimeofday()系統調用的次數;
這種無謂的系統調用次數或者是咱們用不到那麼高的時候,下降這個值減小這個次數會在必定意義上提高Nginx性能的或者提高咱們整個系統性能的。對於一個很是繁忙的服務器這點是不容忽略的。
可用來減小下降worker線程中的計時器的解析度,下降解析度之後帶來的結果是,說白了就是減小發起gettimeofday()這麼一個系統調用,任何一個進程運行過程中,若是系統調用不少,任何一次系統調用的發生必然會產生軟中斷,產生軟中斷的直接結果就是模式轉換,每一次的模式轉換必然會消耗時間。由於咱們說過不少次,一個生產力很是強的進程應該把大量時間用在用戶空間,那所以timer_resolution這個時間解析度爲何要用到這個東西呢?
咱們簡單舉個例子:好比任何一個請求到達Nginx的時候Nginx就得響應它,響應完之後就得記錄日誌了,可是到日誌中會記錄時間。那所以一旦有用戶請求到達,咱們這邊處理響應而要記錄日誌的話那麼它必需要獲取系統當前時間並記錄在日誌文件中。怎麼獲取系統時間呢?經過gettimeofdate來獲取時間然後把這個結果再保存到日誌文件中。而若是咱們的時間解析度過大的話,就可能帶來的結果是他一秒鐘就解析一千次,一秒鐘就發起一千次系統調用,若是我把這個下降一點,好比100ms解析一次,那就意味着一秒鐘只解析10次了。若是指定1s一次那就意味着1s鍾只解析1次,可是咱們知道時間解析度越低它的精準度就越小,時間解析度越高精度就越高,正如咱們的顯示器同樣,分辨率越高,顯示的就越逼真越清晰可是它所須要消耗的資源必定也是越大的。
那所以爲了提升性能,這個時間解析度應該是下降的。只要咱們對於它的時間解析度要求不是特別高的話。
worker_priority number;
指明worker進程的優先級(nice值)。
可是這個優先級是使用nice值來指明的,說白了其實這裏是指明nice值
nice值的範圍是-20~19,-20對應的優先級是100,19對應的優先級是139。數字越小優先級越高。默認狀況下每個進程它的nice值都是0,所以其優先級爲120,數字越小優先級越高,優先級越高它越被優先調度到CPU上被運行。
例如:worker_priority -20;指定其100的優先級。那麼如此高的優先級就說明咱們的Nginx但凡是有可能,只要沒有比它優先級更高的,那麼他將會被排在前面優先被調度到CPU上運行。這對於一個Web服務器來說尤爲是反代模式下的Web服務器或者是咱們支持更高併發的Web服務器來說這算是一個比較有效的設定。再次提醒,nice值越小,其對應的優先級越高。可是隻有管理員纔有權限調低nice值,好在咱們啓動Nginx的時候是以root用戶啓動的。只不過運行worker時,它們纔會由nginx普通用戶來運行它,在此以前它能夠徹底以root用戶的身份來設定其nice值。
以上是與系統優化相關的指令,這四項尤爲是前兩項,幾乎任什麼時候候咱們新配置一個Nginx都要本身手動指定,務必要理解他們指的是什麼。
即放在event當中的通常而言用於使用的相關配置。
accept_mutex {on|off};
master調度用戶請求至各worker進程時用的負載均衡鎖;on表示能讓多個worker輪流的、序列化的去響應新情求;
mutex稱爲互斥鎖,所謂互斥鎖就是獨佔的,通常而言,任何一個進程持有鎖之後其它進程都是被排除在外的,叫排它鎖。固然這樣解釋其實並不精確,只是爲了可以便於理解的。那麼這個accept_mutex有什麼用呢?
內部調用用戶請求至各worker時的負載均衡鎖,這是一個。說白了,做爲Nginx而言,它是由一個主控進程master生成多個worker進程響應用戶請求的,問題是當一個請求到達時咱們應該使用哪個worker來響應它呢?由於worker和請求之間並非一一對應的,因此當一個新的用戶請求到達時,新的用戶請求主控進程必須從這多個worker進程中來響應的,挑選誰呢?而accept_mutex其實就是實現這個功能的。
若是說咱們打開此功能,即啓用了accept_mutex,表示讓多個worker輪流的序列化的響應新請求。就是有先有後的、一個挨一個的來響應新的用戶請求,不然的話,咱們的master有可能隨機的。
accept_mutex_delay time;
若是說accept_mutex啓用了,若是某一個worker正在嘗試接受用戶請求的時候,那其它用戶請求咱們要延遲多長時間等待。因此要否則怎麼叫互斥鎖呢?一個請求來了你們不能搶,輪到誰了就讓誰來響應。可是這個worker有可能會忙不過來,那就須要指定延遲或等多長時間。這麼長時間之後,則有可能會選擇爲下一個。這個不是特別關鍵;
lock_file file;
accept_mutex用到的鎖文件路徑(互斥鎖鎖文件路徑);
既然咱們指明接受用戶請求的互斥鎖,那麼這個鎖的鎖文件應該是誰,就是lock_file。咱們在編譯時其實指明過這個鎖文件了。
use [epoll|rtsig(實時信號)|select|poll];
用於指明使用的事件模型或者是複用模型機制;不建議手動指定,建議讓Nginx自行選擇;
use method;注意此處的method可不是http協議的請求方法,而是指明鏈接處理方法,什麼叫鏈接處理方法?對於一個併發服務器來說,有多個用戶請求到達時,咱們怎麼去處理用戶請求呢?有多種機制,像基於事件驅動、基於複用器、基於select()來響應、基於poll()來響應、基於epoll()來響應或者叫基於event driven來響應等等。因此這裏的use定義使用的事件模型的。
Nginx會自行實現最優化選擇,好比在Linux主機上能使用epoll它就不會使用select,咱們說過epoll纔是真正支持事件驅動的機制,你要使用select就跟咱們的httpd prefork沒什麼區別了。它的併發鏈接數也勢必會大大的下降的。因此說對於Nginx而言,雖然咱們說它是支持使用event driven機制甚至是支持AIO的,可是事實上做爲用戶來說,能夠指明咱們到底使用哪種類型,就使用這個指令進行指定。
worker_connections #;
設定單個worker進程所可以處理的最大併發鏈接數量;
worker的鏈接數,即一個worker進程所可以接受的最大併發鏈接數。
例:假設worker_connections 10240;那請問當前Nginx最多能接受的最大併發鏈接爲多少個?不是10240,這取決於worker_proccesses有多少個,若是其定義了爲3個,這裏定義爲10240,那就是3*10240。固然若是前面定義爲8個,此處定義爲10240也沒用,由於不可能能達到8萬多個,由於咱們的套接字有限,可是至少咱們此處的這個數字不該該成爲限制。
所以它所可以接受的最大併發鏈接數等於worker_connections*work_processes。可是它有可能會小於這個值,由於這個值若是設定的大於65535個的話,通常來說他就不會真正有效了。爲了不單個進程自己不會由於的數量小於這個值的話,能夠直接定義worker_connections爲51200,不少人的配置中多是這麼定義的。因此說,這個參數也是常常必需要調的參數之一。
注意:要想可以打開調試功能,咱們在編譯時必需要使用—with-debug這個選項才能夠,不然調試功能是沒辦法啓用的。
daemon {on|off};
是否以守護進程方式運行Nginx;調試時應該設定爲off;
說白了就是若是爲on就把它運行爲守護進程,若是off就不運行爲守護進程。不運行爲守護進程就意味着它運行在前臺了。運行在前臺它能夠把各類日誌或者錯誤信息輸出到控制檯上來,咱們能夠在控制檯上看到。這叫作daemon模式,因此在調試時將它定義爲off,其它狀況下應該設定爲on。
master_process {on|off};
是否以master模型來運行Nginx;調試時能夠設置爲off;
正常狀況下應該以這種master模型運行Nginx,調試時能夠設定爲off;這就表示,你若是出於調試的目的只啓動一個worker進程直接接受用戶請求就不會說一個主進程一個子進程,由於主進程子進程兩種方式不容易調試問題所在。
error_log file | stderr | syslog:server=address[,parameter=value](記錄到遠程服務器) | memory:size(記錄到內存中,內存大小) [debug | info | notice | warn | error | crit | alert | emerg];
簡單來說,格式爲:
error_log 位置 級別;
若要使用debug級別,須要在編譯Nginx時使用了—with-debug選項;
這是用來而配置日誌功能的,全部的錯誤日誌相關信息都會指明保存在某文件中,用於幫咱們去排錯的。簡單來說,它的格式其實只有三段組成,第二段主要用於指明記錄到哪,第三部分主要用於指明日誌級別的。默認狀況下,咱們一般都記錄在本機指定位置下,而級別有可能爲對應的warn或者notice。
再次說明,只有使用—with-debug打開了調試功能時,咱們也纔可使用debug這個級別。不然即使指定了這個指令也無效。
以上是Nginx主配置段中經常使用到的一些參數,咱們作了一些簡要的說明。
總結:常須要進行調整的參數
再次說明,咱們未來在配置時,最經常使用須要修改的四個參數爲:worker_proccesses、worker_connections、worker_cpu_affinity以及worker_priority。都跟worker相關。
示例:
若指望修改的配置生效:
這樣Nginx就可以讀取新配置了。
只要不改Nginx端口,只須要使用nginx –s reload便可生效。
新改動配置生效的方式:
nginx –s reload #這表示向nginx的主控進程傳一個參數
除了reload接受的其它參數還有:stop、quit、reopen
Nginx全部跟WEB相關的配置都放在http這個上下文中,因此咱們稱之爲http的上下文或http的配置段。
這個配置段是由httpd的核心模塊引入的,咱們前面說過,Nginx的配置文件或者咱們整個Nginx它是由多個模塊組成的,這個模塊其中有核心模塊,像咱們剛纔講的都是由核心模塊提供的。那除了Nginx本身的核心模塊以外,他還有http的標準模塊、有可選的http模塊還有郵件相關的模塊以及第三方模塊。在這些衆多模塊當中,其中有一個叫作標準http的模塊,而標準http的模塊中有一項叫作http core,說白了就是爲了提供http協議相關的功能而提供的一個核心模塊。它用於實現控制端口、location、錯誤頁面、別名以及其它一些最基礎的相關配置,咱們稱爲HTTP core。
http {}:由ngx_http_core_module模塊所引入;
因此咱們只要用這個模塊就會用到http的相關配置的部分。它是用來作什麼的?說白了,http core是用來配置一個靜態的WEB服務器,它可以做爲像httpd同樣來工做的靜態WEB服務器。咱們若是想讓它工做在反向代理模式下,須要使用額外的反向代理模塊來實現。
這個配置段當中的配置框架或配置主體部分:
大致上遵循這樣的格式,首先:
http { upstream { #用到負載均衡或反向代理時會引入的上下文 … } server { location URL {#有點相似於DocumentRoot,可是location跟DocumentRoot還不徹底同樣,由於對於咱們的VirtualHost來說DocumentRoot只能有一個,
#可是對於一個虛擬主機server來說,location能夠有多個。因此它有點相似於咱們對應與httpd中的location容器,用來定義URL和本地的對應關係的。 root 「/path/to/somedir」; … }#相似於httpd的<Location>,用於定義URL與本地文件系統的映射關係;因此咱們說在一個server中能夠有n個location,
#由於在一個server中它對應的那個站點的URL的起始事件能夠多個,好比www.magedu.com下的images、bbs等等,每個路徑均可以單獨分別指定的把網頁放在不一樣位置。
#就這一點而言,它事實上比httpd要靈活。同一個路徑或同一組URL下能夠映射多組不一樣的路徑。而在location中,它還能夠對應一個URL,這個URL對應在什麼地方呢?
#那通常而言,它因爲要對本地文件系統創建映射關係,因此這裏邊一般會有一個root用來本地文件系統路徑。 location URL { if … { … } }#同時,在location中還能夠引入一個新的上下文叫if語句;若是符合某個條件,那麼應該…。它還能夠有條件判斷的功能; } #每個server有點相似於httpd中的<VirtualHost>;因此它是用來定義虛擬主機的 server{ … } }
注意:與http相關的配置指令必須僅可以放置於http、server、location、upstream、if上下文中。但有些指令僅應用於這5種上下文的某些中而非所有,即不一樣指令它的應用位置、可以生效的位置各不相同。
這些配置框架中常常用到的配置指令:
定義一個虛擬主機;
演示效果:
這是基於端口的虛擬主機,基於IP的只需不一樣的listen IP:PORT,基於名稱的時序server_name不一樣。
指定監聽的地址和端口;
listen address[:port]; listen port;
(能夠只指端口不指地址表示默認監聽本機上的全部地址,也能夠只指地址不指端口表示默認監聽在80端口)
對於Nginx來說,其listen有三種格式:
此前說過,Linux主機上表示套接字的地址家族有三種方式,一IPv4二IPv6三本機上通訊能夠基於Unix Socket文件。因此說咱們對應的Nginx的虛擬主機也能夠listen一個Unix的path路徑,表示本地的一個socket類型的文件,一旦監聽在socket類型的文件上,這意味着客戶端只能是本機了。
那這麼複雜的指令究竟是所謂哪般呢?爲什麼要這麼複雜呢?它所指明的這些參數應該很是容易理解,像:
ssl:表示若是咱們要啓用ssl功能,應該指定ssl;
spdy:這是Google改進的http協議的版本,它比1.1更加優越,可是如今http2.0版本已經出現了,依然取代spdy這種格式了。如有興趣,可自行了解。
rcvbuf:接收的緩衝的大小;
sndbuf:發送的緩衝大小;
accept_filter:接收時使用的過濾器;
因此咱們在一個listen指令上能夠定義很是複雜的選項,固然對於此處而言咱們徹底不必搞得這麼麻煩,只須要知道咱們有一個listen指令能夠指定監聽的地址和端口便可。
它的更爲複雜的功能其實咱們只有在特殊狀況下單獨設定其接受緩衝和發送緩衝大小時偶爾纔會用到,因此再也不說其更爲複雜的功能。
指定主機名,後可跟多個主機名;名稱還可使用正則表達式(使用正則表達式時須要以~開頭做爲引導)或通配符;
server_name只能用在server中,別的地方不能使用,因此每個指令的context表示他可用於的上下文是有要求的。
當咱們有多個server時,當用戶使用其中的某一個server時,咱們應該匹配到哪個server上?如:
server{ server_name www.test.com; } server{ server_name *.test.com }
當用戶匹配到www.test.com應該匹配到哪個上面?
因此此處有作匹配時的匹配法則:
(1)先作精確匹配檢查;
也就是說若你訪問到的主機名恰好與某一個server主機名如出一轍,並且他沒有所謂的通配的概念。那麼這個就徹底匹配到了,全部優先級最高的爲精確匹配檢查。
(2)左側通配符匹配檢查;
如寫成*.magedu.com,當用戶去訪問mail.magedu.com,第一個不匹配,因而去檢查第二個。而第二個這個通配符正好在左側,而有的是這樣寫的:
server { server_name www.test.com; } server { server_name *.test.com; } server { server_name mail.*; }
當用戶訪問mail.magedu.com的時候,第二個與第三個都能匹配,若是左側通配符能匹配因而就當即生效,不然再去檢查右側通配符。
(3)右側通配符匹配檢查,如mail.*;
(4)正則表達式匹配檢查,如:~^*\.magedu.com\.com$;
(5)default_server;
若默認服務器未定義,那就自上而下找第一個server來匹配。
因此說,當用戶請求到達時,而咱們當前主機上定義了n個虛擬主機,那咱們應該應用在哪一個虛擬主機之上,事實上是由server_name後面這麼一個固定的檢查法則檢查完之後進行肯定的。
設置資源路徑映射的;用於指明請求的URL所對應的資源所在的文件系統上的起始路徑;
放置的容器越大,範圍越大,優先級越低。
兩種用法:
location [ = | ~ | ~* | ^~ ] uri { ... } location @name { ... }
根據請求的URI設定特定請求的配置的。
功能:容許根據用戶請求的URI來匹配定義的各location;匹配到時,此請求將被相應的location配置塊中的配置所處理,例如作訪問控制等功能;
例:
當用戶在瀏覽器中輸入http://www.test.com/bbs/時,它到底應用在哪一個location上呢?第一個與第三個可以匹配到,那到底以哪一個爲準呢?因此說它也有相應的優先級了,好比:
=:精確匹配檢查;
即錯一個字符都不行;
所以若是訪問的是http://www.test.com/,並且location = /{...},那第一個就能匹配,但若是寫的是http://www.test.com/bbs/,而且location寫的是=,那它就不能被第一個匹配了。由於第一個必須是根,後面不能帶任何東西,這叫作精確匹配。若是不帶=表示,則起始路徑的均可以被匹配。
~:正則表達式模式匹配檢查,區分字符大小寫;
~*:正則表達式模式匹配檢查,不區分字符大小寫;
^~:URI的前半部分匹配,不支持正則表達式;
匹配的優先級:精確匹配(=)、^~、~、~*、不帶任何符號的location;
驗證:
由於此時匹配到的第三個到/vhosts/text下去找images,而後再images下找a.txt。
對於Nginx而言,location是很是關鍵的。
用於location配置段,實現定義路徑別名;
這與httpd中的alias並無兩樣。用來實現路徑映射;
注意:root表示指明路徑爲對應的location 「/」 URL;也就意味着你怎麼指root,它都相對於」/」這個起始路徑而言的。像剛纔咱們訪問images下面的a.txt,這個時候images自己也是相對於這個對應的/vhosts/下面補上這個images而言,說白了你不管路徑怎麼映射,它是起始於/images而言的。
alias表示路徑映射,即location指令後定義的URL是相對於alias所指明的路徑而言;
如:
root:
定義: location /images/ { root "/vhosts/web1"; } 例如: 訪問http://www.test.com/images/a.jpg表示訪問的是服務器路徑:/vhosts/web1/images/a.jpg
alias:
定義: location /images/ { alias "/www/pictures"; } 例如: 訪問http://www.magedu.com/images/a.jpg表示訪問的是服務器目錄下的:/www/pictures/a.jpg
驗證:
對於alias而言這個location URL路徑右側的根相對於這個整個alias後面的根,因此在images下的全部文件是直接在這個/vhosts/web1目錄直接去找的。而root是images左側這個根相對於/vhosts/web1而言。
這是一個新的叫作index的模塊所提供的;
默認主頁面:
index index.php index.html;
表示有兩個頁面自左而右能夠做爲主頁面,先搜索index.php找不着的話再去找index.html;
根據http響應狀態碼指明特用的錯誤頁面;
例如:
error_page 404 /404_customed.html
說明:404_customed.html放在什麼路徑下均可以,看error_page定義在什麼位置,對應的就相對於那個對應你所所在的location中的root而言的。
[=code]:可省略,若是要定義的話,表示以指定的響應碼進行響應,而不是默認的原來的響應碼;(好比找不到頁面可能用404響應,但我把它定義成302就能夠了);默認表示以新資源(即指定的網頁)的響應碼爲其響應碼。
例如:
這是Nginx自帶的404錯誤頁面;
自定義:
使用-t能夠測試語法錯誤;
咱們還能夠自行定義它的響應碼,如:
兩個相關指令:
基於IP的訪問能夠用在http、server、location中,看你的訪問控制有多大的範圍。
舉例:拒絕192.168.241.1訪問演示:
只容許192.168.241.0網段訪問:
支持兩種認證方式:basic、digest
要想作基於用戶的訪問控制,只須要在須要作訪問控制的配置段中使用以下指令:
auth_basic 「」; #至關於httpd的AuthName; auth_basic_user_file 「PATH/TO/PASSWORD_FILE」; #跟用戶相關的帳號密碼文件的位置;這個文件儘量隱藏起來,由於不是全部用戶都會使用ls –a 來查看這個文件的,
#因此隱藏一下總然是由好處的。
帳號密碼文件建議使用htpasswd建立;htpasswd這個命令是由httpd提供的,所以須要安裝httpd。
生成私鑰,生成證書籤署請求,並得到證書;
演示示例:
顯示不可靠,由於瀏覽器沒有導入CA的證書,因此它沒辦法驗證是否可靠。
狀態頁的啓用或關閉;
此指令僅能用於location上下文中;
在此結果示例中:
Active connections:活動鏈接數;指的是當前全部處於打開狀態的鏈接數。若是向客戶端代理的話也包括代理的。 server accepts handled requests #表示接收下來並已經處理的請求; 70 70 47 #第一個數字表示已經接受過的鏈接數,第二個爲已經處理過的鏈接數,第三個爲已經處理過的請求數。因爲咱們可能已經啓用了鏈接處理功能,
#因此請求數可能會大於鏈接數。在「保持鏈接」模式下,請求數量可能會多於鏈接數量。
Reading:正處於接收請求狀態的鏈接數;
Writing:請求已經接收完成,正處於處理請求或發送響應的過程當中的鏈接數;
Waiting:保持鏈接模式,且處於活動狀態的鏈接數;(要麼處於正在接收請求要麼正在發送請求的狀態中的鏈接數)
指的是URL rewrite,說白了是實現URL重寫的。你原本請求的是某一個特定URL,服務器處理以後將URL悄悄的換成別的URL。
例如:
rewrite ^/images/(.*\.jpg)$ /imgs/$1 break;
它所帶來的效果是,好比說用戶若是請求的是http://www.magedu.com/images/a/b/c/1.jpg,那它會把這個路徑自動換成http://www.magedu.com/imgs/a/b/c/1.jpg
URL重寫在何時用到呢?好比,咱們網站從a域名改到b域名了,可是兩個域名都是咱們的,咱們指望用戶之後訪問時看到的都是b域名,因此全部對於a域名的訪問都改爲b域名下的相關地址也是能夠的。再否則,咱們原本的網站某個頁面路徑在某個URL下如今換成新的URL像咱們這裏的images換成imgs也能夠基於URL重寫實現。
固然在完成某些SEO時也有用,好比說咱們把這個動態的路徑改爲靜態的方式,那麼這會使得咱們緩存服務器能緩存下來並且SEO時還能提升咱們的權重。
不過此處的flag倒是大有講究的;
flag:標識位
如:匹配規則有n條,用戶請求來以後,檢查第一條不匹配、第二條不匹配、…、第四條匹配了,後面的就不檢查了。此時由於一重寫已經成爲了一個新的URL,這個新的URL會再次被從新發給Nginx服務器,Nginx 服務器同樣會從第一條檢查、第二條、…,若是檢查第三條又被重寫了,所以又一次改爲新的URL再次發起請求從頭至尾來檢查。
完成當前這個重寫規則之後,重啓處理機制。
例如:咱們訪問http://www.magedu.com/images/a/b/c/1.jpg經過URL重寫會轉換成http://www.magedu.com/imgs/a/b/c/1.jpg,對於這個新的請求來說,瀏覽器會從新用新的URL對Web服務器發起新的請求,Web服務器即Nginx收到這個新情求後同樣會像此前處理任何一個請求同樣處理這個請求,即此時還會再次檢查這個規則,若是這個規則又能徹底匹配到它的話,還會再次重寫,因此這叫重啓。因此第一個請求咱們經過規則檢查匹配到了,因此改爲新的URL了,因此瀏覽器此時會從新對這個連接發新情求,這個新請求會通過規則的再次檢查,若是檢查之後沒有被匹配,所以就不會被重寫,因而請求就日後繼續處理了。
何時用到break呢?就是在很不幸的狀況下,兩條規則可能形成循環。例如:
... rewrite ^/images/(.*\.jpg)$ /imgs/$1 last; rewrite ^/images/(.*\jpg)$ /images/$1 last; ... 如:訪問http://www.test.com/images/a/b/c/1.jpg <--> http://www.test.com/imgs/a/b/c/1.jpg
何時纔會用302響應呢?若是說咱們替換成一個目標位置是以http協議開頭時是一個新的絕對路徑時,能夠以redirect實現。
舉例:
語法:
if (condition){…}
應用環境:server、location;
condition:
(1) 變量名;
變量值爲空串,或者以「0」開始,則爲false;其它的均爲true;
若是變量爲空串,即變量沒有值的話表示爲假不然爲真。所以任何空串或者任何爲0的值甚至於任何以0起始的字符串其都爲假不然則爲真。
(2) 以變量爲操做數構成的比較表達式
可以使用=、!=相似的比較操做符進行測試。
好比,看看某個變量的值是不是咱們所請求的某個值。
(3) 可實現正則表達式的模式匹配
~:區分大小寫的模式匹配檢查;
~*:不區分大小寫的模式匹配檢查;
!~和!~*:對上述兩種測試取反;
須要注意的是,並非在配置文件中用到模式正則表達式越高級越好,不用正則表達式是最好的,由於正則表達式引擎在匹配時必然會消耗更多的CPU使用週期,會下降性能的。
(4) 測試路徑爲文件的可能性
-f:表示是否存在;
!-f:表示是否不存在;
(5) 測試指定路徑爲目錄的可能性
-d
!-d
(6) 測試文件的存在性(無論是目錄仍是文件)
-e
!-e
(7) 檢查文件是否有執行權限
-x
!-x
例如:
if($http_user_agent ~* MSIE){ #若瀏覽器類型爲MSIE,即爲微軟瀏覽器 rewrite ^(.*)$ /msie/$1 break; } #http_user_agent爲內建變量,表示客戶端瀏覽器的類型;
有些時候的URL重寫是必須的,像根據客戶端瀏覽器的不一樣返回不一樣的站點,定向至不一樣的位置上去。這樣可讓用戶有更好的用戶體驗。能夠想象用戶使用手機打開電腦版的頁面的話那該是多麼痛苦。
假如站點的圖片只容許站內連接或者不是咱們所容許的域名一般都不容許連接。
locating ~* \.(jpg|gif|jpeg|png)$ { valid_referer none blocked www.test.com; #validreferer是Nginx自帶的一個內置的指令,它用於定義哪一種引用是合法的。valid表示合法的、容許的,referer表示引用者,所以valid_referer表示合法的引用者是誰。none blocked表示不作阻止的。 if($invalid_referer){ #$invalid_referer是咱們的refereer模塊所引入的一個變量,它表示但凡不可以被上面定義爲合法引用的,通通都會歸到不合法引用上面,因此若是說這個變量的值不爲空,就說明這一次引用多是不合法的。由於爲空就由於上面的已經被匹配了。 rewrite ^/ http://www.test.com/403.html; } }
使用log_format指令進行定義,相似於在httpd中使用的log_format指令;
若是想定義成兼容給咱們對應的日誌格式如出一轍的話,此處要使用log_format,並查找服務器端所提供的或者服務器上模塊所提供的內置的變量來相似使用兼容格式,叫combined來進行定義。log_format後接的爲格式名。一旦咱們要想本身定義訪問日誌的話,千萬要記得要使用access_log,如:
咱們未來把Nginx做爲一個反代服務器時有可能會用到。
例:前端使用Nginx做爲反代服務器,後端使用Tomcat做爲Web服務器,經過Nginx訪問Tomcat時老是會出現503超時,而直接訪問Tomcat時是正常的,可是經過前端Nginx訪問偶爾老是會出現超時,代理服務器上去取後端內容超時。出現這種狀況推測頗有多是Nginx反代時它會本身構建一個請求報文到後端Tomcat,可是構建這個請求等待Tomcat響應的時間默認設置的太短,而Tomcat本身的處理多是須要必定的時長的。一旦這個時間太短的話,對方還沒響應過來就超時了,事實上響應是正常的。
這一些都跟網絡鏈接相關,因此這個時候咱們就不得不調節這些跟網絡鏈接相關的超時時長。
保持鏈接或長鏈接的超時時長,默認爲75s;(對於負載均衡器來說,75有點大)
在一次長鏈接上所可以容許請求的最大資源數;
爲指定類型的User Agent禁用長鏈接;
禁用長鏈接,可是這種禁用並非禁用整個長鏈接的功能,而是隻爲特定類型的瀏覽器禁用長鏈接,由於有些瀏覽器在長鏈接的支持上是功能有限的。
是否對長鏈接使用TCP_NODELAY選項;
通常來說,若是想提升用戶體驗的話,讓用戶一請求當即就能獲得響應,咱們仍是應該啓用tcp_nodelay,不讓它延遲,每一個包都單獨發送,不管它有多小。
tcp是一種開銷比較大的鏈接類型,由於任何一次數據發送以前都要先三次握手然後要四次斷開。若是很不幸的是,某一個鏈接剛好它所發送的數據量很是小,訪問這個頁面下一共也只有幾個字節或者十幾個字節而已,若是咱們請求網站上的資源不少都是這很小的資源的話,會發現每個包單獨封裝並且沒有使用長鏈接結果是大量的資源開銷被浪費掉了,那爲了不這麼一種浪費,TCP在它的擁塞避免算法中有一種解決方案是它把屢次請求的小資源合併成一次大的響應過去,好比請求了不少東西每個都很小,把多個小的請求合併成一個響應報文響應過去了。這樣子能夠節約帶寬能夠節約請求次數。可是這樣一來會有問題,想象一下對於Web站點來說,用戶請求一個資源半天還沒響應,爲何呢?他等待跟其餘包合併呢?這是沒法接受的,因此在有些原本就具備的確擁有不少小資源的Web站點上,咱們不該該啓用tcp_delay的功能,因此咱們把tcp延遲功能關閉,tcp_nodelay就表示tcp是否是不延遲,on就能夠。
讀取http報文請求首部的超時時長;
若是我麼本身的服務器很繁忙本身帶寬不夠用,讀別人讀不到,由於別人擠不進來,那這個時候應該把此時長調長一些以便能讀進來別人的請求,不過即使時間延長用戶體驗也是不好了。
一個客戶端發請求過來了,全部的數據流依然都是要編碼成數據流式報文進行請求的。那咱們讀了第一個首部、讀第二個首部、…可是客戶端的帶寬過小了,半天讀不到一個,那到底應該等多長時間呢?
讀取http請求報文的body部分的超時時長。
發送響應報文的超時時長;
Nginx與php結合時他不能像httpd與php結合同樣把php直接作成Nginx的模塊,這是不支持的,因此若是你想構建LNMP,方法只能有一個,php要啓用爲fpm模型。
在Nginx上要想配置用戶請求php頁面時可以發給fpm的php來提供服務的話,方法很是簡單,配置文件中有示例:
fastcgi_params文件中定義瞭如何把用戶請求時的變量值映射提供給後端的fastcgi服務器的。