nginx是一個非常好的技術點,javaWeb可以用到。php更是與nginx有lnmp的組合說法。網站開發可以說nginx是炙手可熱的一個技術點了。本篇博客把我對nginx的瞭解記載下來。後續對nginx的瞭解也會補充到這篇文章。文章會從如下幾方面進行記載。
一.nginx是幹什麼用的?
Nginx是一款輕量級高性能的Web服務器/反向代理服務器及電子郵件(IMAP/POP3)代理服務器
(1)上述說的反向代理服務器是什麼?
反向代理(Reverse Proxy)方式是指以代理服務器(nginx)來接受Internet上的連接請求,然後將請求轉發給內部網絡上的服務器(真實處理請求的服務器),並將從內部網絡上的服務器上得到的結果返回給Internet上請求連接的客戶端。
比如你想訪問一個PHP網站。此時你只需要訪問nginx上配置的域名www.hello.com→(172.30.22.173)並監聽listen一個port 80。 而你真實請求的資源來源是 192.3.4.5:9000這個端口給的。
而你打開網站訪問的是www.hello.com你根本不知道192.3.4.5:9000 的存在。
正向代理指的是,一個位於客戶端和原始服務器之間的服務器,爲了從原始服務器取得內容,客戶端向代理髮送一個請求並指定目標(原始服務器),然後代理向原始服務器轉交請求並將獲得的內容返回給客戶端。
比如你想訪問Google 被牆了。這時你可以訪問谷歌在中國的代理服務器,然後代理服務器根據你的請求去Google服務器獲取相應並返回給你。
二. nginx的優勢是什麼?
Nginx可以輕鬆處理高併發。而且佔用的資源相對其他服務器較少,CPU消耗時間少。
性價比高。沒有那麼多線程之間切換的花銷。
其他優勢:延遲處理,SSL(安全套接字層),靜態內容,壓縮和緩存,連接和請求限制所需的關鍵功能,甚至可以從應用程序中傳輸HTTP媒體流層到更有效的Web服務器層。
三.Nginx的優勢是怎麼做到的?
Nginx 採用的是多進程(單線程) & 多路IO複用模型(epoll)。使用了 I/O 多路複用技術是”併發事件驅動“的服務器。
1.進程&線程&協程之間的關係是什麼?
進程(Process)是計算機中的程序關於某數據集合上的一次運行活動,是系統進行資源分配和調度的基本單位,也是基本的執行單元,是操作系統結構的基礎。
每個進程都有自己的獨立內存空間,不同進程通過(管道,信號量,共享內存,socket,消息隊列等)來通信。由於進程比較重量,佔據獨立的內存,所以進程間的切換開銷(棧、寄存器、虛擬內存、文件句柄等)比較大,但相對比較穩定安全。
線程是操作系統能夠進行運算調度的最小單位!!意味着一定是通過多線程來實現多核CPU的利用的。它被包含在進程之中,是進程中的實際運作單位。一條線程指的是進程中一個單一順序的控制流,一個進程中可以併發多個線程,每條線程並行執行不同的任務。
線程自己基本上不擁有系統資源,只擁有一點在運行中必不可少的資源(如程序計數器,一組寄存器和棧),但是它可與同屬一個進程的其他的線程共享進程所擁有的全部資源。線程間通信主要通過共享內存,上下文切換很快,資源開銷較少,但相比進程不夠穩定容易丟失數據。
協程是一種用戶態的輕量級線程,協程的調度完全由用戶控制。協程擁有自己的寄存器上下文和棧。協程調度切換時,將寄存器上下文和棧保存到其他地方,在切回來的時候,恢復先前保存的寄存器上下文和棧,直接操作棧則基本沒有內核切換的開銷,可以不加鎖的訪問全局變量,所以上下文的切換非常快。
關於協程的一些額外描述:
一個線程可以多個協程,即一個內核線程對應多個用戶協程(用戶進程)。
進程、線程,都是有內核進行調度,有CPU時間片的概念,進行搶佔式調度(有多種調度算法)
協程的調度與內核無關,完全有程序進行控制。只能進行非搶佔式調度。
線程進程都是同步機制,而協程則是異步。
協程能保留上一次調用時的狀態,每次過程重入時,就相當於進入上一次調用的狀態
在實現多任務時, 線程切換從系統層面遠不止保存和恢復 CPU上下文這麼簡單。
操作系統爲了程序運行的高效性,每個線程都有自己緩存Cache等數據,操作系統會自動實現數據的恢復操作,所以線程的切換非常耗性能。
但是協程的切換隻是單純的操作CPU的上下文,所以一秒鐘切換個上百萬次系統都抗的住。
以上:如果是單線程所述的異步都是由協程完成的。但是還是由一個CPU調度的,線程是CPU調度的最小單位。即使我們看到的現象是一個異步的現象。但底層實際上是一個線程不斷切換協程來實現的。所以單核的切換速度並不變快反而更慢。
一個線程運行多個協程就像一個人推箱子,先推箱子A,推一會推箱子B,箱子AB的位置是被保留現場的。但實際上就一個人。多個人推多個箱子就像多線程多協程工作。
因此如果想利用多核CPU的優勢,要麼開啓多線程,使多協程多線程一起跑。 要麼開多進程,使多進程多協程一起跑,來達到異步的效果。
而Nginx就是採用的多進程多協程的事件驅動運行方式來實現的。
golang python 都是有協程的這個概念的。 golang的 goroutines Python的gevent 查了一下發現java居然也有,但是我沒用過。。 看網上說java的Quasar也是可以的。
2.什麼叫多路IO複用?
IO多路複用,將IO過程分爲等待內核數據準備好和讀取/寫入內核兩部分。一個IO函數監控多個IO可讀/可寫事件,任意1個IO設備準備好時返回(需要代碼中輪詢查看是哪個IO文件描述符,什麼事件),再調用對應的read/write函數操作,減少不必要的等待時間,高效了很多。具體的實現有select、poll和epoll三種。
nginx採用的是epoll ,線程主函數不斷接收請求。epoll的實現是通過事件驅動。
通過3個函數來實現,更加高效,當前使用也最多。在epoll_ctl中註冊事件到epoll文件描述符中,把fd全部拷貝進內核,而不是在epoll_wait中重複拷貝。實現中內核通過爲每個fd指定一個回調函數,當fd就緒時調用回調函數把就緒fd加入一個就緒鏈表,epoll_wait只需要查看這個就緒鏈表是否有就緒fd就可。可監控文件描述符數是系統可同時打開文件數
原型:
int epoll_create(int size); //返回epoll文件描述符,size表示要監聽的數目 (這個返回的fd要記得close)
int epoll_ctl(int epfd, int op, int fd, struct epoll_event *event); //epoll事件註冊函數
epfd是epoll_create返回的值
op是動作:EPOLL_CTL_ADD/EPOLL_CTL_MOD/EPOLL_CTL_DEL分別表示:註冊fd到epfd,修改已註冊的fd,從epfd刪除1個fd
fd是要監聽的fd
event是告訴內核要監聽什麼事件
struct epoll_event{
__uint32_t events; //epoll events
epoll_data_t data; //user data variable
}
event是宏的集合:EPOLLIN可讀;EPOLLOUT可寫;EPOLLPRI緊急數據可讀;EPOLLERR發生錯誤;EPOLLHUP被掛斷;EPOLLET將EPOLL設置爲邊緣觸發模式;EPOLLONESHOT只監聽1次事件
int epoll_wait(int epfd, struct epoll_event *events, int maxevents, int timeout); //等待事件發生,events是返回的事件鏈表;maxevents是events鏈表元素個數,timeout是等待毫秒數(0表示立即返回,非阻塞;正值表示等待的毫秒數;負值表示無限等待,阻塞模式 ),函數返回值是需要處理的事件數,通過events返回需要處理的事件。(通過events[i].data.fd和events[i].events匹配判斷)
當某個進程調用epoll_create方法時,linux內核會創建一個eventpoll結構體,這個結構體中有兩個成員與epoll的使用方式密切相關。
struct eventpoll
{
struct rb_root rbr;//紅黑樹的根結點,這棵樹中存儲着所有添加到epoll中的事件,也就是這個epoll監控的事件。線程間共享內存。一個全局變量相當於。
struct list_head rdllist;//雙向鏈表rdllist保存着將要通過epoll_wait返回給用戶的滿足條件的事件
};
每一個epoll對象都有一個獨立的eventpoll結構體,這個結構體會在內核空間中創造獨立的內存,用於存儲使用epoll_ctl方法向epoll對象中添加進來的事件。這些事件都會掛到rbr紅黑樹中,這樣,重複添加的事件就可以通過紅黑樹高效地識別出來。
當相應的事件發生時會調用這裏的回調方法,這個回調方法在內核中叫做ep_poll_callback,它會把這樣的事件放到上面的rdllist雙向鏈表中。當調用epoll_wait檢查是否有發生事件的連接時,只是檢查eventepoll對象中的rdllist雙向鏈表是否有epitem元素而已,如果rdllist鏈表不爲空,則把這裏的事件複製到用戶態內存中,同時將事件數量返回給用戶。
3.什麼叫事件驅動?
有了線程之後,我們處理併發最直觀的做法就是加線程,爲了減少線程的啓動時間,我們開始使用線程池,預先啓動一些線程。隨着併發進一步提高,加上外部請求基本上都是IO密集型,使用線程帶來的效益開始下降,也就是說在線程的生命週期中IO等待時間遠遠大於CPU計算時間,另外每個線程大約需要4M的內存,由於內存的限制,單機線程數不會很多。所以初期的Apache、tomcat服務器通常只能處理幾千的併發。爲了突破單機下的併發問題,以nginx爲首的一種叫事件驅動的方案開始流行。
事件驅動編程的架構是預先設計一個事件循環,這個事件循環程序不斷地檢查目前要處理的信息,根據要處理的信息運行一個觸發函數。
在一個進程一個線程中,server接收客戶端的請求。創建function解決IO,如果發生阻塞就執行別的請求。不斷的循環。
事件驅動和協程的對比
共性
其目的都是爲了消除IO阻塞的問題
都是使用單個或少量的線程,減少線程切換帶來的性能消耗
不同點
事件驅動較之比較初級,需要用異步回調的方式來寫代碼
協程可以使用同步的方式寫代碼,通過庫或者語言的調度來實現併發
四.配置文件相關。
可以在nginx.conf中引用別的配置文件。很清晰。 include /etc/nginx/conf.d/*.conf; 這個指令寫在http裏面。然後加一個配置文件 xxx.conf 引用外部的配置文件,拆的比較清晰。
server {
listen 80;
server_name www.hello.com;
root /etc/nginx/html;
index index.html;
location / {
}
}
需要注意這裏面的 server_name 所配置的域名。如果你想訪問得在 /etc/hosts中配置 127.0.0.1 www.hello.com 使本地dns可以解析到。
然後你其他機器想訪問配置 www.hello.com 到上面這個主機的ip就行了。
幾個頂級指令
events 一般連接處理
http HTTP協議流量
mail Mail協議流量
stream TCP協議流量
內部指令
location有兩種類型的參數: 前綴字符串和正則表達式
前綴字符串
location /home/asd {
}
正則表達式
location ~ \.php { # ~ 表示區分大小寫。 ~* \.php 這個 ~*表示不區分大小寫 其餘規則就是Perl中的正則表達式。
}
nginx 日誌相關
nginx日誌相關的配置有:access_log(訪問日誌)、log_format(日誌格式)、open_log_file_cache、log_not_found、log_subrequest、rewrite_log、error_log。
下面以一個nginx配置文件的所有配置爲例。
#定義Nginx運行的用戶和用戶組
user www www;
#nginx進程數,通常設置成和cpu的數量相等 #這個是配置用幾個CPU跑nginx。 相似的go裏面的goroutines設置的 runtime.GOMAXPROCS 一個意思。
worker_processes 4;
#全局錯誤日誌定義類型,[debug | info | notice | warn | error | crit] #error_log file level 錯誤日誌可配置全局和server的。level儘量高,不然垃圾日誌多。
#error_log /data/nginx/logs/error.log;
#error_log /data/nginx/logs/error.log notice;
#日誌文件存放路徑 access_log path [format [buffer=size | off]]
access_log /data/nginx/logs/lazyegg.com/web/access.log combinedio; #這個就是客戶端訪問生成的日誌。比如訪問403 404 等等你可以來這裏看、
#combinedio 是日誌格式名稱 access_log file format gzip
#進程pid文件 裏面存一個數。這個數正好是ps 命令查出來的那個進程的pid
#root 15774 1 0 Dec10 ? 00:00:00 nginx: master process /usr/sbin/nginx -g daemon on; master_process on;
#pid logs/nginx.pid;
#指定進程可以打開的最大描述符:數目
#工作模式與連接數上限
##這個指令是指當(一個nginx進程!!!!)打開的最多文件描述符數目,理論值應該是最多打開文件數(ulimit -n)與nginx進程數相除,但是nginx分配請求並不是那麼均勻,所以最好與ulimit -n 的值保持一致。
#這是因爲nginx調度時分配請求到進程並不是那麼的均衡,所以假如填寫10240,總併發量達到3-4萬時就有進程可能超過10240了,這時會返回502錯誤。
worker_rlimit_nofile 65535;
event
########## events ####### 這個模塊一般配置的是全局的一些東西,連接、請求等等。
events {
#參考事件模型,use [ kqueue | rtsig | epoll | /dev/poll | select | poll ]; epoll模型
use epoll #epoll 是最頂級的模型
#單個進程最大連接數(最大連接數=連接數+進程數)
worker_connections 1024;
#默認是on 使每個可用的worker進程逐個接受新連接。 設置成off會導致驚羣現象。會喚醒不必要的worker進程。
accept_mutex on;
#keepalive 超時時間
keepalive_timeout 60;
#客戶端請求頭部的緩衝區大小。
client_header_buffer_size 4k;
#這個將爲打開文件指定緩存,默認是沒有啓用的,max指定緩存數量,建議和打開文件數一致,inactive是指經過多長時間文件沒被請求後刪除緩存。
open_file_cache max=65535 inactive=60s;
#這個是指多長時間檢查一次緩存的有效信息。
open_file_cache_valid 80s;
#open_file_cache指令中的inactive參數時間內文件的最少使用次數,如果超過這個數字,文件描述符一直是在緩存中打開的,如上例,如果有一個文件在inactive時間內一次沒被使用,它將被移除。
open_file_cache_min_uses 1;
#語法:open_file_cache_errors on | off 默認值:open_file_cache_errors off 使用字段:http, server, location 這個指令指定是否在搜索一個文件是記錄cache錯誤.
open_file_cache_errors on;
}
http
############################## http ##################################
#設定http服務器,利用它的反向代理功能提供負載均衡支持
http{
#文件擴展名與文件類型映射表
#Nginx通過服務器端文件的後綴名來判斷這個文件屬於什麼類型,再將該數據類型寫入HTTP頭部的Content-Type字段中,發送給客戶端。
#比如,當我們打開一個頁面,看到一個PNG格式的圖片的時候,Nginx是這樣發送格式信息的:
#服務器上有asd.png這個文件,後綴名是png;
#根據mime.types,這個文件的數據類型應該是image/png;
#將Content-Type的值設置爲image/png,然後發送給客戶端。
include mime.types;
#默認文件類型 這個類型是直接下載而不是瀏覽。下載文件的時候可以用這個類型。
default_type application/octet-stream;
#默認編碼
charset utf-8;
#服務器名字的hash表大小
server_names_hash_bucket_size 128;
#客戶端請求頭部的緩衝區大小。
client_header_buffer_size 32k;
#客戶請求頭緩衝大小。
large_client_header_buffers 4 64k;
#允許客戶端請求的最大單個文件字節數
client_max_body_size 8m;
#開啓高效文件傳輸模式,sendfile指令指定nginx是否調用sendfile函數來輸出文件,對於普通應用設爲 on,如果用來進行下載等應用磁盤IO重負載應用,可設置爲off,以平衡磁盤與網絡I/O處理速度,降低系統的負載。注意:如果圖片顯示不正常把這個改成off。
sendfile on;
#開啓目錄列表訪問,適合下載服務器,默認關閉。
autoindex on;
#此選項允許或禁止使用socke的TCP_CORK的選項,此選項僅在使用sendfile的時候使用
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壓縮輸出。 在響應給client時進行壓縮,可以有效的節約帶寬,提高響應速度。 不建議壓圖片視頻還有大文件資源,消耗CPU。
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; #壓縮類型,默認就已經包含text/html,所以下面就不用再寫了,寫上去也不會有問題,但是會有一個warn。
gzip_vary on;
#開啓限制IP連接數的時候需要使用
#limit_zone crawler $binary_remote_addr 10m;
upstream 負載均衡(這個也是屬於http下面)
upstream lazyegg.net {
#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;
#nginx的upstream目前支持4種方式的分配
#1、輪詢(默認)
#每個請求按時間順序逐一分配到不同的後端服務器,如果後端服務器down掉,能自動剔除。
#2、weight
#指定輪詢機率,weight和訪問比率成正比,用於後端服務器性能不均的情況。
#例如:
#upstream bakend { #注意此處的bakend(名稱自定義) 在配置server的時候需要配置 proxy_pass http://bakend; 代理到這個服務器組中的一臺機器上。
#某臺Server允許請求失敗的次數,超過最大次數後,在fail_timeout時間內,新的請求將不會分配給這臺機器。如果設置爲0,Nginx會將這臺Server置爲永久無效狀態
#默認爲10秒。某臺Server達到max_fails次失敗請求後,在fail_timeout期間內,nginx會認爲這臺Server暫時不可用,不會將請求分配給它
# server 192.168.0.14 weight=10 max_fails=3 fail_timeout=15; #max_fails默認爲1
# server 192.168.0.15 backup; # 後面註明backup表示其餘機器掛掉了/都忙時使用這個機器。備胎、
# server 192.168.0.16 max_conns=100; # 默認爲0.不限制 表示限制分配給這臺機器的最大連接數量。
#}
#2、ip_hash
#每個請求按訪問ip的hash結果分配,這樣每個訪客固定訪問一個後端服務器,可以解決session的問題。
#一個主機多次請求時訪問的是一個後臺服務器。但是這個掛掉了,就涼了。別的機器沒有用戶的session
#例如:
#upstream bakend {
# ip_hash; #這塊加這條命令就代表使用ip_hash方式
# server 192.168.0.14:88;
# server 192.168.0.15:80;
#}
#3、fair(第三方)
#按後端服務器的響應時間來分配請求,響應時間短的優先分配。 就是誰處理的快就表示誰請求少,就讓他處理。
#upstream backend {
# server server1;
# server server2;
# fair;
#}
#4、url_hash(第三方)
#按訪問url的hash結果來分配請求,使每個url定向到同一個後端服務器,後端服務器爲緩存時比較有效。
#例:在upstream中加入hash語句,server語句中不能寫入weight等其他的參數,hash_method是使用的hash算法
#upstream backend {
# server squid1:3128;
# server squid2:3128;
# hash $request_uri;
# hash_method crc32;
#}
#tips:
#upstream bakend{#定義負載均衡設備的Ip及設備狀態}{
# ip_hash;
# server 127.0.0.1:9090 down;
# server 127.0.0.1:8080 weight=2;
# server 127.0.0.1:6060;
# server 127.0.0.1:7070 backup;
#}
#在需要使用負載均衡的server中增加 proxy_pass http://bakend/;
#每個設備的狀態設置爲:
#1.down表示單前的server暫時不參與負載
#2.weight爲weight越大,負載的權重就越大。
#3.max_fails:允許請求失敗的次數默認爲1.當超過最大次數時,返回proxy_next_upstream模塊定義的錯誤
#4.fail_timeout:max_fails次失敗後,暫停的時間。
#5.backup: 其它所有的非backup機器down或者忙的時候,請求backup機器。所以這臺機器壓力會最輕。
#nginx支持同時設置多組的負載均衡,用來給不用的server來使用。
#client_body_in_file_only設置爲On 可以講client post過來的數據記錄到文件中用來做debug
#client_body_temp_path設置記錄文件的目錄 可以設置最多3層目錄
#location對URL進行匹配.可以進行重定向或者進行新的代理 負載均衡
}
server (server也是屬於http的)
#虛擬主機的配置
server {
#監聽端口
listen 80;
#域名可以有多個,用空格隔開
server_name lazyegg.net;
#默認入口文件名稱 這個是相對於root的相對路徑
index index.html index.htm index.php;
#你要訪問的項目的目錄 這個要絕對路徑
root /data/www/lazyegg;
#對******進行負載均衡
location ~ .*.(php|php5)?$
{
fastcgi_pass 127.0.0.1:9000;
fastcgi_index index.php;
#配置URL重寫和重定向 這個語法是 rewrite src desc command; 將src的請求重定向到 desc 注意這個是在當前location的基礎上搞得。
#這個重定向操作是很有價值的。
rewrite .*.a.php /found/ redirect;
include fastcgi.conf;
}
#圖片緩存時間設置
location ~ .*.(gif|jpg|jpeg|png|bmp|swf)$
{
expires 10d;
}
#JS和CSS緩存時間設置
location ~ .*.(js|css)?$
{
expires 1h;
}
#日誌格式設定
#$remote_addr與$http_x_forwarded_for用以記錄客戶端的ip地址;
#$remote_user:用來記錄客戶端用戶名稱;
#$time_local: 用來記錄訪問時間與時區;
#$request: 用來記錄請求的url與http協議;
#$status: 用來記錄請求狀態;成功是200,
#$body_bytes_sent :記錄發送給客戶端文件主體內容大小;
#$http_referer:用來記錄從那個頁面鏈接訪問過來的;
#$http_user_agent:記錄客戶瀏覽器的相關信息;
#通常web服務器放在反向代理的後面,這樣就不能獲取到客戶的IP地址了,通過$remote_add拿到的IP地址是反向代理服務器的iP地址。反向代理服務器在轉發請求的http頭信息中,可以增加x_forwarded_for信息,用以記錄原有客戶端的IP地址和原來客戶端的請求的服務器地址。
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 /usr/local/nginx/logs/host.access.log main;
access_log /usr/local/nginx/logs/host.access.404.log log404;
#對 "/connect-controller" 啓用反向代理
location /connect-controller {
proxy_pass http://192.168.1.100:8888; #不能監聽127.0.0.1:80
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;
#緩衝區代理緩衝用戶端請求的最大字節數,
#如果把它設置爲比較大的數值,例如256k,那麼,無論使用firefox還是IE瀏覽器,來提交任意小於256k的圖片,都很正常。如果註釋該指令,使用默認的client_body_buffer_size設置,也就是操作系統頁面大小的兩倍,8k或者16k,問題就出現了。
#無論使用firefox4.0還是IE8.0,提交一個比較大,200k左右的圖片,都返回500 Internal Server Error錯誤
client_body_buffer_size 128k;
#表示使nginx阻止HTTP應答代碼爲400或者更高的應答。
proxy_intercept_errors on;
#後端服務器連接的超時時間_發起握手等候響應超時時間
#nginx跟後端服務器連接超時時間(代理連接超時)
proxy_connect_timeout 90;
#後端服務器數據回傳時間(代理髮送超時)
#後端服務器數據回傳時間_就是在規定時間之內後端服務器必須傳完所有的數據
proxy_send_timeout 90;
#連接成功後,後端服務器響應時間(代理接收超時)
#連接成功後_等候後端服務器響應時間_其實已經進入後端的排隊之中等候處理(也可以說是後端服務器處理請求的時間)
proxy_read_timeout 90;
#設置代理服務器(nginx)保存用戶頭信息的緩衝區大小
#設置從被代理服務器讀取的第一部分應答的緩衝區大小,通常情況下這部分應答中包含一個小的應答頭,默認情況下這個值的大小爲指令proxy_buffers中指定的一個緩衝區的大小,不過可以將其設置爲更小
proxy_buffer_size 4k;
#proxy_buffers緩衝區,網頁平均在32k以下的設置
#設置用於讀取應答(來自被代理服務器)的緩衝區數目和大小,默認情況也爲分頁大小,根據操作系統的不同可能是4k或者8k
proxy_buffers 4 32k;
#高負荷下緩衝大小(proxy_buffers*2)
proxy_busy_buffers_size 64k;
#設置在寫入proxy_temp_path時數據的大小,預防一個工作進程在傳遞文件時阻塞太長
#設定緩存文件夾大小,大於這個值,將從upstream服務器傳
proxy_temp_file_write_size 64k;
}
#本地動靜分離反向代理配置
#所有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的常規操作&一些疑惑解答
下面以ubuntu直接apt-get install 安裝的nginx爲例。
配置文件的位置在/usr/local/nginx/conf, /etc/nginx, 或 /usr/local/etc/nginx
ubuntu16.04: /etc/nginx/nginx.conf
ubuntu安裝的nginx 在/etc/nginx/sites-available 下的default文件中有默認的配置。指向 /var/www/html 可以改這個文件。
改完了 nginx -s reload 然後再訪問就可以了、
1.fastCGI 代理。 快速通用網關接口 common gateway interface
PHP有這個服務器。(php-fpm) 其他程序也可以裝。 php-fpm fastCGI process manager進程管理器。
FastCGI也是語言無關的。其主要行爲是將CGI解釋器進程保持在內存中並因此獲得高效的性能。下面來個配置例子。
server {
location \.php(.*)$ {
fastcgi_pass localhost:9000; # 如果是PHP一般php-fpm默認是9000端口。按照路由規則將請求路由到PHP服務器
fastcgi_index index.php;
include fastcgi.conf; #這個是關鍵。使用fastcgi.conf文件中的參數,而不是fastcgi_param
}
}
兩者有區別。 變量$fastcgi_script_name的值是請求的uri
#fastcgi.conf的 SCRIPT_FILENAME是 $document_root$fastcgi_script_name; 表示腳本執行前面有根目錄。
#fastcgi_param 中的那個參數是沒有document_root的。會導致404 也可以用fastcgi_param 並在location中重寫。建議用conf
nginx是多進程的反向代理服務器。 包括一個master分支和多個worker分支。 master負責管理worker分支和讀取nginx.conf配置文件。 改完worker會保持原有的配置。直到reload後worker進程纔會加載新的配置文件。
2.windows windows的nginx使用有一些小問題。
使用 start nginx 後臺啓動nginx 默認使用 conf/nginx.conf配置文件。
關掉nginx 使用 taskkill /F /IM nginx.exe 全乾掉。 因爲別的 quit什麼的命令不知道什麼原因有時候沒作用。
nginx -s reload 也可以重新加載配置文件。 但是nginx在windows需要非常注意這個命令執行的位置 保證在nginx.exe這個文件夾裏執行。
配置環境變量也不行。應該是nginx.conf 配置文件中有一些相對路徑的原因導致的。
對於阿里雲服務器。 有一個坑。 配置nginx的域名 訪問需要在阿里雲進行備案
3.有關master進程的強殺和優雅殺掉的區別。
kill -9 (sigkill) 和普通 kill (默認 sigteam) 傳給進程的信號量不一樣產生的結果。
kill sigteam 是默認不加數字參數傳遞的信號量。 進程接到信號量執行類似 nginx -s quit(或stop)的命令 會將worker和master都殺掉、
kill sigkill sigkill 信號不能被捕獲。 所以進程不知道自己咋死的。因此捕獲不了master就沒法控制worker進程.從而導致worker進程仍是運行狀態,還可以接受請求。
nginx -s quit 會等現有的連接請求處理完再關閉。 nginx -s stop 就直接關閉了。 nginx -s reload 是重新加載配置文件。 不會殺master會殺worker
4.nginx 進程間通信的方式
信號量、socket套接字、共享內存
1.其中信號量是我們執行nginx -s quit等這種命令是通過信號量進行通信給master進程的,然後master進程在作爲對應的相應。
2.socket套接字是在master與worker進程之間,通過發送socket進行通信。
3.共享內存,master和worker是父子進程,正常是不會有共享內存的。共享內存我們知道一般是存在在多線程的環境下。而nginx中的master進程會開闢一塊內存空間作爲共享內存來進行與worker進行一些數據的同步,例如http的連接數信息等。worker與worker進程之間的通信也是通過共享內存來實現的。
nginx有一個現象較驚羣現象,就是來了一個請求,正常交給一個worker進程來處理就好了。但是如果共享變量沒有加互斥鎖的話會導致大量worker進程監聽到這個請求,但是真正能拿走這個請求的worker進程只能有一個。這就會導致一個問題。就是其餘的worker被喚醒從而增加了CPU開銷和資源的消耗。因此共享內存中變量加個互斥鎖就會解決這個問題。
5.爲什麼worker與master採用socketpair這種套接字進行通信?
nginx會將這個socketpair加入到epoll中,通過事件模塊獲取該套接字。
6.一些重要指令的用法
location ~ \.php{
set $var_test "index.php"; #定義變量名爲 var_test 值爲 index.php 在使用時 $var_test 這麼用。 只有字符串類型。
#配置URL重寫和重定向 這個語法是 rewrite src desc command; 將src的請求重定向到 desc 注意這個是在當前location的基礎上搞得。
#這個重定向操作是很有價值的。 需要注意 src的位置必須是 regex正則表達式。
rewrite .*.a.php /found/ redirect;
return 404 http://www.hello.com; #這個是可選的。可以僅返回狀態碼,也可以還返回重定向的uri
}
rewrite 後面的那個指令有四個 last break permanent redirect
last 和break 出現在location外差不多。都是rewrite這行命令之後直接跳轉到 desc指定的location了。
如果在location裏面寫rewrite是last表示跳出當前location,重新一個請求重走server路、 break就是停止了。
try_files 在上下文的root目錄下進行處理。指令可用於檢查指定的文件或目錄是否存在並進行內部重定向,如果沒有指定的文件或目錄,則返回特定的狀態代碼如下這個try_files 可以應對yii框架 將路由寫在index.php?controller/action 這種。如果不進行內部uri重寫,訪問不到的。
location / {
try_files $uri/ /index.php?$args @backend ; #比如請求admin-zy.com 然後沒找到。就會重寫爲 /index.php?admin-zy.com 然後走yii的邏輯。還可以重定向到location
}
location @backend {
proxy_pass http://www.s.com;
sendfile on; #默認情況下,nginx會自動處理文件傳輸,並在發送文件之前就將其複製到緩衝區中。sendfile將直接從一個fd複製到另一個fd
sendfile_max_chunk 1m; #設置調用單個sendfile()傳輸的數據量、
tcp_nopush on; #與sendfile一起用。使nginx通過sendfile獲取數據塊之後,在一個數據包中發送http響應頭。
tcp_nodelay on; #默認就是on 禁用nagle算法。這個算法發包是有大概200ms延遲的並將小包組成大包一起發。禁用了就直接發了。省去延時。
}
location / {
proxy_pass http://backend; #這個是一個負載均衡的 upstream配置,配置名爲 backend 其中有三個ip
proxy_bind 192.168.172.38; #這個就是綁定到這個ip這樣每次訪問代理不會發生負載均衡操作。
}
關於location的匹配。 先查前綴表達式,再查正則表達式。 前綴表達式的結果作爲備胎使用, 正則表達式也匹配則使用正則表達式的location。只有正則表達式不匹配時才用之前的前綴location
location值匹配URI部分,參數是啥跟匹配沒關。除非你定義一個 / 的location 然後定義try_files重定向。
如果過程中發生的重定向,將重新匹配location。例如訪問 / 然後重定向到 /index.php 會找匹配 /index.php的location 去匹配。
請求匹配要處理的server是通過Host請求頭信息
多個server,當訪問的域名映射的ip是你的nginx時,會先查找listen的端口,找完端口會尋找server_name 如果有對應就會返回,沒有對應的就返回這個listen監聽的端口的默認server
這個默認server可以在listen 80 default_server; 聲明這個default_server就可以了。 如果沒聲明就把相同listen的第一個server作爲默認server
如果不允許一個沒有host頭的請求,可以server_name "";
server {
listen 80;
server_name "";
return 444; #444是一個nginx走向。
}
六.https相關
https 是在 http 和 TCP 中間加上一層加密層 SSL
瀏覽器向服務端發送消息時:本質上是瀏覽器(客戶端)使用服務端的公鑰來加密信息,服務端使用自己的私鑰解密,
瀏覽器從服務端獲取消息是:服務端使用自己私鑰加密,瀏覽器(客戶端)使用服務端的公鑰來解密信息
在這個過程中,需要保證服務端給瀏覽器的公鑰不是假冒的。證明服務端公鑰信息的機構是 CA(數字認證中心)
https默認的端口是443端口。http默認端口是80 所以如果是https的網址不寫端口號默認是443
https相對於http消耗的資源要多很多。http是tcp三次握手建立連接。 而https除了這三次握手還需要ssl握手的9個包。
openssl生成證書server.key server.crt 生成這個證書是需要域名的。本地可以測試的。隨便生成一個域名。做HTTPS的測試
Key是私用祕鑰,通常是RSA算法
Csr是證書請求文件,用於申請證書。在製作csr文件時,必須使用自己的私鑰來簽署申,還可以設定一個密鑰。
crt是CA認證後的證書文,簽署人用自己的key給你簽署憑證。
key的生成(第一步)
openssl genrsa -out server.key 2048
這樣是生成RSA密鑰,openssl格式,2048位強度。server.key是密鑰文件名。
csr的生成 (第二步)(基於剛剛生成的server.key)
openssl req -new -key server.key -out server.csr,需要依次輸入國家,地區,組織,email。最重要的是有一個common name,可以寫你的名字或者域名。如果爲了https申請,這個必須和域名吻合,否則會引發瀏覽器警報。生成的csr文件講給CA簽名後形成服務端自己的證書。
crt的生成 (第三步)(基於上兩步生成的csr key)
openssl x509 -req -days 365 -in server.csr -signkey server.key -out server.crt
注意: 生成的這個目錄nginx一定要有訪問權限 不然403
如果想將http的請求重定向到https,則還需配置一個server 監聽80端口然後跳到https
server {
listen 443 ssl;
server_name hello-zy.cn;
ssl_certificate /etc/nginx/ssl/server.crt;
ssl_certificate_key /etc/nginx/ssl/server.key;
ssl on;
root /etc/nginx/html;
index index.html;
location / {
}
}
server {
listen 80;
server_name hello-zy.cn;
root /etc/nginx/html;
index 80index.html;
location / {
#return 301 https://$server_name$request_uri;
#rewrite ^(.*)$ https://$host$1 permanent; #跟上面這種都行。就是重定向。 permanent就是301的永久重定向。
}
}
linux curl 301 的問題
需要使用-L參數 如果訪問的是https 還需要加 --insecure參數
curl --insecure -L hello-zy.cn
curl --insecure https://hello-zy.cn