Nginx相關&理解

nginx是一個非常好的技術點,javaWeb可以用到。php更是與nginx有lnmp的組合說法。網站開發可以說nginx是炙手可熱的一個技術點了。本篇博客把我對nginx的瞭解記載下來。後續對nginx的瞭解也會補充到這篇文章。文章會從如下幾方面進行記載。

一.nginx是幹什麼用的?

二.nginx的優勢是什麼?

三.nginx的優勢是怎麼做到的?

四.配置文件相關。

五.nginx的常規操作&一些疑惑解答

六.https相關


 

一.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

 

 

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章