1. 程式人生 > >Nginx原理和配置總結

Nginx原理和配置總結

some serve delay 找到 部署 正則表達式 emp cnblogs process

一:前言

  Nginx是一款優秀的HTTP服務器和反向代理服務器,除卻網上說的效率高之類的優點,個人的切身體會是Nginx配置確實簡單而且還好理解,和redis差不多,比rabbitmq好理解太多了;

這裏Nginx可以作為Http服務器在我們安裝部署啟動後,訪問http://localhost/就能看到這一特性;這裏主要來說說反向代理:

1.正向代理

  舉個最簡單的例子,FQ;我們正常情況下是不能訪問google等外國網站的,這時候可以通過代理服務器來實現,即我們主動配置一個proxy地址並啟動成功,然後我們在瀏覽器上輸入的所有訪問請求

如http://188.155.88.3/testb,這時候瀏覽器不會去訪問這個ip,而是去連接我們配置的代理服務,成功後將數據發送給代理服務,代理服務通過判斷header中的host等值從而知道我們真正要訪問的是

哪個host,然後代理服務器內部創建一個socket以tcp協議去連接我們想訪問的host將我們原本的數據發送過去(一般會在header裏額外加點東西)。。。扯遠了,正向代理最大的特點是客戶端主動配置

代理服務器,由代理服務器完成客戶端和客戶端本身想訪問的服務之間的數據傳輸;

2.反向代理

  反向代理特點則是:客戶端不知道自己真正要溝通的是誰,只是別人提供了一個代理服務器的ip和port,然後客戶端就只需要訪問這個地址即可;這裏我們暫認為反向代理服務器就是nginx;然而nginx

在配置了proxy_pass後成為反向代理,它會主動將客戶端的數據通過ip+port數據轉接的方式發送給在nginx裏配置好的服務,這一步客戶端是不清楚的,他以為反向代理服務器就是真正處理自己請求的服務

,而不像正向代理一樣客戶端事先知道自己只是通過這個正向代理服務實現FQ而以(或者說正向代理是客戶端可以指定要訪問的服務由代理服務實現轉接,而反向代理客戶端無法指定轉接規則);

3.流量轉發原理

  無論是正向代理還是反向代理,都需要通過流量轉發來實現代理功能;它的原理是:1)正/反代理服務器先bind一個ip和端口;2)客戶端對此地址發起連接並發送數據;

3)代理服務器收到數據後根據規則(常用規則有1.根據host將client的數據轉發到host:80裏;2.根據代理服務器內部事先規定好的規則如queryPath/host/固定端口-ip:端口[tcp nat]等)找出要轉發的ip:port;

4)代理服務器創建一個如socket對象並連接3步驟中找到的地址,成功後將client發給代理服務的數據(可以進行一定修飾)通過創建的socket對象[代理服務主機的另一個port,這也是為什麽有可同時接收連接數量配置的存在理由之一,太多了端口沒那麽多]將

其轉發給3中匹配到的真正的服務器[但是這個真正的服務器指不定還是個代理服務器,會只需去找,有點像鏈表的感覺];

5)處理服務器對轉發過來的數據進行處理(一般http請求的轉發是會在header裏添加origin的,故處理服務器能依次判斷要不要對此請求進行處理,否則處理服務器只知道代理服務器向自己發起連接並發送了請求而不知道真正的源),將處理結果返回給

代理服務器;

6)代理服務器的socket[不一定是socket只是以此舉例]收到數據後(此socket不是bind的socket它們端口也不一樣),將數據提取出來(可能有一定的修飾)並讓另一個socket(這個socket是客戶端連接代理服務器,代理服務器接收請求後產生的port和serversocket一致

的那個)將此數據send給客戶端;

至此,一條完整的代理流程就弄完了,這裏原理其實不難,難在各種特殊情況的控制,比如如果Client->Proxy發送數據後會發送協定的結束標識或事先雙方有格式規約,且發送完後會先等待Proxy返回數據然後才發第二個消息,那麽其實非常好實現(http協議的代理

比較容易,因為可以通過content-length來判斷數據是否發送完畢而且一般也是發送一次數據後會等結果才發第二次數據,如果是短連接更好辦了),最難的是stream的代理,它可能存在Client發送數據後Proxy將數據轉發給server,還沒處理client又來了數據,這裏

就需要有比較好的設計才能支撐這種較為復雜的業務;目前我的理解是proxy將client發來的數據都串行化放入隊列,然後由一個單線程按自己的能力去從隊列裏取數據並轉發;

二:Nginx配置整理

  上面講了很多啰嗦的話,這裏正式通過配置文件來說下自己對Nginx配置的理解:

user nginx nginx;  # 這個配置不是很重要,可以不配置,不過一般都會為後臺進程創建一個nologin的賬號,如mysql,我這裏為nginx創建的是nginx賬號,group也是一樣[用www貌似較多],這裏第一個是user,第二個是group
worker_processes  1;  # 允許生成的進程數,默認為1,按原作者的話一個足夠只需要把連接數設置到足夠大即可,但是如果存在同時對多個文件的占用,使用gzip等可以增加(似乎是因為os會限制進程可同時占用的資源數),一般不超過cpu個數的2倍

# 這裏用的是相對的是nginx的安裝目錄,即logs在/usr/local/nginx下,可以配置絕對路徑將日誌寫到其它地方 # 級別:debug
|info|notice|warn|error|crit|alert|emerg error_log logs/error.log crit; # 日誌級別,不要配太小,畢竟這是高並發的服務,如果什麽都要記錄日誌肯定影響性能; # 可要可不要,就是方便kill時能獲取其pid,原理是nginx啟動後會找到自己的pid然後將其寫入此文件裏,但是還是通過./nginx -s quit|stop就可以了;註意nginx是daemon進程 #pid logs/nginx.pid; worker_rlimit_nofile 50000; # nginx可以同時打開的文件個數 events { multi_accept on; # 設置一個進程是否同時接受多個網絡連接,默認off # 事件驅動模型,select/poll/kqueue/epoll/resig/dev-poll/eventport use epoll; worker_connections 60000; # 同時連接數,即代理時可同時創建多少個中間socket; }
# 註意,這裏寫了http表示內部的都是根http協議相關的,後面還會加個stream的,它表示普通的tcp數據 http { # 文件擴展名與文件類型映射表(可以去看conf目錄,裏面有個mime.types文件,裏面的內容為:
    # types {
  #  text/html html htm shtml;
    #  text/css                  css;
    # .....等等 } include mime.types;
  # 默認的類型,即流數據 default_type application
/octet-stream; # 這個應該是記錄日誌時的pattern,名為main,下面的 access_log logs/access.log main;就用到了
  
 # 1.$remote_addr記錄的是直接連接nginx的ip,它可能是個代理服務; 而$http_x_forwarded_for的記錄格式是:clientip,proxy1,proxy2...故能獲取origin和中間節點信息; 2.$remote_user:用來記錄客戶端用戶名稱;
  # 3.$time_local: 用來記錄訪問時間與時區;4.$request: 用來記錄請求的url與http協議; 5.$status: 用來記錄請求狀態;成功是200;
  # 6.$body_bytes_sent:記錄發送給客戶端文件主體內容大小;7.$http_referer: 用來記錄從那個頁面鏈接訪問過來的(這個由瀏覽器實現,瀏覽器能知道當前頁的地址); 8.$http_user_agent: 記錄客戶端瀏覽器的相關信息(還能記錄手機類型); 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;
    server_names_hash_bucket_size 128; # 據說是根保存服務器名字的hash表有關,還有另一個協同的配置項server_names_hash_max_size;貌似是如果添加了很多的域名後nginx如果報錯可以增大此值(以32的倍數增大)
# 配置關於客戶端數據限制的一些參數
client_header_buffer_size 32k; # 指http請求header的緩存大小,默認是1k large_client_header_buffers 4 32k; # 當上面配置的緩存不夠大時這個時新的緩存大小 client_max_body_size 8m; # 這個可以考慮再加大,畢竟body是存儲數據的主要地方(如果是多文件則考慮multipart)
  # nodelay是指服務器處理好後立刻就將結果數據發送給客戶端而不等待數據到達一定量(tcp是有這方面優化的,比如我返回數據指有5b,那麽tcp默認會等待達到1k時才一次性發送,這裏就是為了禁用這種選項),畢竟處理結果數據少是正常的
  tcp_nodelay on; sendfile on; # 允許sendfile方式傳輸文件,默認off tcp_nopush on; # 和nodelay有些類似,也是阻止立刻發送的
keepalive_timeout 65; # 空閑狀態長連接保持的時間,並不是說header裏設置了keepalive就一直保持長連接,還要看是否長時間空閑
    # 經過看了conf下的多個fastcgi相關的文件,都有寫PHP only,故如果我們不用php應該可以不配置; # cgi 是common gateway interface通用網關接口的意思 #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;
    # 註意,個人不建議在nginx裏開啟gzip,因為gzip功能完全可以由真正的處理服務器去做,nginx只需要進行數據傳輸和流量轉發即可,這樣可以保證nginx的高效性 # gzip 最好不要在nginx裏配置,畢竟nginx最好只是做流量轉發不要有 # 任何業務操作或其它耗資源的操作   #gzip on; #gzip_min_length 1k; #gzip_buffers
4 16k; #gzip_http_version 1.0; # 註意只能是1.0不能1.1,因為CDN抓取目前只能1.0 #gzip_comp_level 2; # 壓縮等級 #gzip_types text/plain application/x-javascript text/css application/xml; #gzip_vary on; # 這裏是nginx實現負載均衡的關鍵,這個是定義一個服務器名,但它可以對應多個服務,這裏可以配置1.熱備[下面的就是];2.輪詢[將backup去掉就是]即內部的server權重一樣會循環的分別轉發給server;3.加權輪詢,ip後加上weight=n即可,n越大權重越大
     # 4.ip_hash,最下面加個ip_hash;即可,nginx會讓相同的客戶端都由一個server處理(或說ip具有共性的客戶端由一個server處理,這個共性就包括了ip一樣)
upstream myhost1 { server 127.0.0.1:8080; server 127.0.0.1:8081 backup; # 熱備,當127.0.0.1:8080無法訪問時啟用 } # 註意這個server是可以配置多個的,但則是一個虛擬主機,即可以有多個server它的監聽端口都是80,但是前提是server_name不一樣(host) # 順便HTTPS和HTTP的端口不一樣的前者默認是443,後者默認是80 server { keepalive_requests 1024; # 此服務同時保持keepalive的客戶端的數量; listen 80; # 此虛擬主機監聽的端口 # 註意,很重要的參數,如果nginx轉發多個80端口的數據到不同tomcat就靠此區分 server_name localhost; # 域名,雖然連接是靠ip,但header裏還是有域名的 #charset koi8-r; #access_log logs/host.access.log main; # 註意,nginx配置裏location有多種模式,優先級是:(location =) > (location 完整路徑) > (location ^~ 路徑) > (location ~,~* 正則順序) > (location 部分起始路徑) > (/)
    # 這個有點像tomcat的url-pattern;其中/的優先級最小但是可以匹配任何情況;而=的優先級最大但是只能絕對匹配;而location /aaa可以匹配如http:../aaab但是如果不是完全匹配則其優先級比後面的正則表達式的要小(~匹配大小寫,~*不匹配大小寫)
    # 均不匹配queryString部分,即?xx=bb&nn之類的不作為匹配(但據說可以自己升級此部分的處理模塊來支持更多的匹配);詳情可以看:https://www.cnblogs.com/cheyunhua/p/7927674.html
location / { #root html; # 可以改到srv的www目錄內,這兩個配置是不轉發時的配置 #index index.html index.htm; # 設置默認頁 proxy_pass http://myhost1; # 用於流量轉發,註意這個myhost1和upstream的對應 #deny 192.168.0.88 # 拒絕的ip #allow 192.168.0.14 # 允許的ip
        # 還可以配置proxy_connect_timeout和read/write的超時時間,即nginx創建一個socket和處理服務建立連接將客戶端的數據發送給處理服務,但是可以配置此socket和處理服務之間的超時關系; } # 正則表達式的匹配,開頭
~表示區分大小寫,而~*則不區分 # 這是個perl類型正則表達式,可以將靜態資源由一個服務統一處理,也可以由nginx之間轉發,或者根據後綴規則轉發各個系統共用的靜態資源(其它的資源可以通過url映射實現無後綴訪問) location ~^.*\.(gif|jpg|jpeg|png|bmp|swf|ico|js|css)$ { root html; # 這個則可以轉發給一個專門處理靜態資源的處理器處理,或則nginx直接處理 #proxy_pass http://127.0.0.1:8080; expires 30d; # 設置靜態資源在緩存裏的過期時間,如果不經常更新可以將值弄大一點; # access_log off; }

        access_log off; # 不記錄訪問日誌 #error_page 404 /404.html;
    # 配置error_page 中間的是具體的error,後面的則是表示轉發的地址(有點像java的requestDispatcher.forward(..),然後後面的location就是為了和此forward匹配從而從html目錄裏找到此文件並返回給客戶端
#error_page 500 502 503 504 /50x.html; #location = /50x.html { # root html; #} # deny access to .htaccess files, if Apache‘s document root # concurs with nginx‘s one # #location ~ /\.ht { # deny all; #} } # another virtual host using mix of IP-, name-, and port-based configuration # #server { # listen 8000; # listen somename:8080; # server_name somename alias another.alias; # location / { # root html; # index index.html index.htm; # } #} # HTTPS server # #server { # listen 443 ssl; # server_name localhost; # ssl_certificate cert.pem; # ssl_certificate_key cert.key; # ssl_session_cache shared:SSL:1m; # ssl_session_timeout 5m; # ssl_ciphers HIGH:!aNULL:!MD5; # ssl_prefer_server_ciphers on; # location / { # root html; # index index.html index.htm; # } #} }

Nginx原理和配置總結