天天看點

第十四章 nginx詳解

14.1 nginx簡介

  Nginx(發音同engine x)是一款輕量級的Web伺服器/反向代理伺服器及電子郵件(IMAP/POP3)代理伺服器,并在一個BSD-like協定下發行。

  Nginx由俄羅斯的程式設計師Igor Sysoev所開發,最初供俄國大型的入口網站及搜尋引擎Rambler使用。

  第一個公開版本0.1.0釋出于2004年10月4日。其将源代碼以類BSD許可證的形式釋出,因它的穩定性、豐富的功能集、示例配置檔案和低系統資源的消耗而聞名。2011年6月1日,nginx 1.0.4釋出。

  nginx的特點是占有記憶體少,并發能力強,事實上nginx的并發能力确實在同類型的網頁伺服器中表現較好,中國大陸使用nginx網站使用者有:百度、京東、新浪、網易、騰訊、淘寶等。

14.2 nginx的特性與優點

14.2.1 nginx的特性

  Nginx是一個很牛的高性能Web和反向代理伺服器,它具有很多非常優越的特性:

    在高連接配接并發的情況下,Nginx是Apache伺服器不錯的替代品,能夠支援高達50000個并發連接配接數的響應

    使用epoll and kqueue作為開發模型

    Nginx作為負載均衡伺服器:Nginx既可在内部直接支援和PHP程式對外進行服務,也可支援作為HTTP代理伺服器對外進行服務

    Nginx采用C進行編寫,不論系統資源開銷還是CPU使用效率都比Perlbal要好很多

14.2.2 nginx的優點

  Nginx的優點:

    高并發連接配接:官方測試能夠支撐5萬并發連接配接,在實際生産環境中跑到2-3萬并發連接配接數

    記憶體消耗少:在3萬并發連接配接下,開啟的10個Nginx程序才消耗150M記憶體(15M*10=150M)

    配置檔案非常簡單:風格跟程式一樣通俗易懂

    成本低廉:Nginx為開源軟體,可以免費使用。而購買F5 BIG-IP、NetScaler等硬體負載均衡交換機則需要十多萬至幾十萬人民币

    支援Rewrite重寫規則:能夠根據域名、URL的不同,将HTTP請求分到不同的後端伺服器群組

    内置的健康檢查功能:如果Nginx Proxy後端的某台Web伺服器當機了,不會影響前端通路

    節省帶寬:支援GZIP壓縮,可以添加浏覽器本地緩存的Header頭

    穩定性高:用于反向代理,當機的機率微乎其微

    子產品化設計:子產品可以動态編譯

    外圍支援好:文檔全,二次開發和子產品較多

    支援熱部署:可以不停機重載配置檔案

    支援事件驅動、AIO(AsyncIO,異步IO)、mmap(Memory Map,記憶體映射)等性能優化

14.3 nginx的功能及應用類别

14.3.1 nginx的基本功能

  Nginx基本功能:

    靜态資源的web伺服器,能緩存打開的檔案描述符

    http、smtp、pop3協定的反向代理伺服器

    緩存加速、負載均衡

    支援FastCGI(fpm,LNMP),uWSGI(Python)等

    子產品化(非DSO機制),過濾器zip、SSI及圖像的大小調整

    支援SSL

14.3.2 nginx的擴充功能

  Nginx擴充功能:

    基于名稱和IP的虛拟主機

    支援keepalive

    支援平滑更新

    定制通路日志、支援使用日志緩沖區提高日志存儲性能

    支援URL重寫

    支援路徑别名

    支援基于IP及使用者的通路控制

    支援速率限制,支援并發數限制

14.3.3 nginx的應用類别

  Nginx的主要應用類别:

    使用Nginx結合FastCGI運作PHP、JSP、Perl等程式

    使用Nginx作反向代理、負載均衡、規則過濾

    使用Nginx運作靜态HTML網頁、圖檔

    Nginx與其他新技術的結合應用

14.4 nginx的子產品與工作原理

  Nginx由核心和子產品組成。其中,核心的設計非常微小和簡潔,完成的工作 也非常簡單,僅僅通過查找配置檔案将用戶端請求映射到一個location block(location是Nginx配置中的一個指令,用于URL比對),而在這個location中所配置的每個指令将會啟動不同的子產品去完成相應的工作。

14.4.1 nginx的子產品分類

  Nginx的子產品從結構上分為核心子產品、基礎子產品和第三方子產品

    HTTP子產品、EVENT子產品和MAIL子產品等屬于核心子產品

    HTTP Access子產品、HTTP FastCGI子產品、HTTP Proxy子產品和HTTP Rewrite子產品屬于基本子產品

    HTTP Upstream子產品、Request Hash子產品、Notice子產品和HTTP Access Key子產品屬于第三方子產品

  使用者根據自己的需要開發的子產品都屬于第三方子產品。正是有了如此多子產品的支撐,Nginx的功能才會如此強大

  Nginx子產品從功能上分為三類,分别是:

    Handlers(處理器子產品)。此類子產品直接處理請求,并進行輸出内容和修改headers資訊等操作。handlers處理器子產品一般隻能有一個

    Filters(過濾器子產品)。此類子產品主要對其他處理器子產品輸出的内容進行修改操作,最後由Nginx輸出

    Proxies(代理器子產品)。就是Nginx的HTTP Upstream之類的子產品,這些子產品主要與後端一些服務比如fastcgi等操作互動,實作服務代理和負載均衡等功能

  Nginx子產品分為:核心子產品、事件子產品、标準Http子產品、可選Http子產品、郵件子產品、第三方子產品和更新檔等

    Nginx基本子產品:所謂基本子產品,指的是Nginx預設的功能子產品,它們提供的指令,允許你使用定義Nginx基本功能的變量,在編譯時不能被禁用,包括:

      核心子產品:基本功能和指令,如程序管理和安全。常見的核心子產品指令,大部分是放置在配置檔案的頂部

      事件子產品:在Nginx内配置網絡使用的能力。常見的events(事件)子產品指令,大部分是放置在配置檔案的頂部

      配置子產品:提供包含機制

    具體的指令,請參考nginx的官方文檔,詳見http://nginx.org/en/docs/ngx_core_module.html

14.4.2 nginx的工作原理

  Nginx的子產品直接被編譯進Nginx,是以屬于靜态編譯方式。

  啟動Nginx後,Nginx的子產品被自動加載,不像在Apache一樣,首先将子產品編譯為一個so檔案,然後在配置檔案中指定是否進行加載。

  在解析配置檔案時,Nginx的每個子產品都有可能去處理某個請求,但是同一個處理請求隻能由一個子產品來完成。

  Nginx的基本架構:

    一個master程序,生成一個或多個worker程序

    事件驅動:epoll(邊緣觸發)、kqueue,/dev/poll

      複用器:select,poll,rt signal

    支援sendfile,sendfile64

    支援AIO

    支援mmap

  Nginx的程序結構:

    啟動Nginx時,會啟動一個Master程序,這個程序不處理任何用戶端的請求,主要用來産生worker線程,一個worker線程用來處理n個request

第十四章 nginx詳解
  下圖展示了Nginx子產品下一次正常的HTTP請求和響應的過程:
第十四章 nginx詳解
  下圖展示了HTTP基于套接字通信:
第十四章 nginx詳解
   下圖展示了基本的WEB服務請求步驟:
第十四章 nginx詳解

14.5 nginx的安裝與配置

14.5.1 nginx的安裝

useradd nginx -M -s /sbin/nologin

yum -y install pcre-devel openssl openssl-devel gd-devel
yum -y groupinstall "Development Tools" 

mkdir -pv /data/logs/nginx
cd /usr/src
wget http://nginx.org/download/nginx-1.12.0.tar.gz
 
tar xf nginx-1.12.0.tar.gz
cd nginx-1.12.0

./configure \
--prefix=/usr/local/nginx \
--user=nginx \
--group=nginx \
--with-debug \
--with-http_ssl_module \
--with-http_realip_module \
--with-http_p_w_picpath_filter_module \
--with-http_gunzip_module \
--with-http_gzip_static_module \
--with-http_stub_status_module \
--http-log-path=/data/logs/nginx/access.log \
--error-log-path=/data/logs/nginx/error.log

make && make install      

14.5.2 nginx的配置檔案

  配置檔案:/usr/local/nginx/conf/nginx.conf

    預設啟動Nginx時,使用的配置檔案是:安裝路徑/conf/nginx.conf檔案

    可以在啟動nginx時通過-c選項來指定要讀取的配置檔案

  nginx常見的配置檔案有如下幾個:

    nginx.conf應用程式的基本配置檔案

    mime.typesMIME類型關聯的擴充檔案

    fastcgi.conf         與fastcgi相關的配置

    proxy.conf與proxy相關的配置

    sites.conf配置Nginx提供的網站,包括虛拟主機

  nginx.conf配置詳解:

    nginx.conf的内容分為以下幾段:

      main配置段:全局配置段。其中main配置段中可能包含event配置段

      event {}:定義event模型工作特性

      http {}:定義http協定相關的配置

    配置指令:要以分号結尾,文法格式如下:

derective value1 [value2 ...]      

    支援使用變量:

      内置變量:子產品會提供内建變量定義

      自定義變量:

set var_name value      

14.5.3 nginx.conf常用配置詳解

  nginx.conf配置段的指令有以下幾類:

    用于調試、定位問題:

daemon {on|off};    #是否以守護程序方式運作nginx,調試時應設定為off
master_process {on|off};    #是否以master/worker模型來運作nginx,調試時可以設定為off
error_log 位置 級别;    #配置錯誤日志      

      位置有以下幾種:

        file

        stderr

        syslog:server=address[,parameter=value]

        memory:size

      級别可選值有:

        debug:若要使用debug級别,需要在編譯nginx時使用--with-debug選項

        info

        notice

        warn

        error

        crit

        alert

        emerg

    正常運作必備的配置:

user USERNAME [GROUPNAME];    #指定運作worker程序的使用者群組
pid /path/to/pid_file;    #指定nginx守護程序的pid檔案
worker_rlimit_nofile number;    #設定所有worker程序最大可以打開的檔案數,預設為1024
worker_rlimit_core size;    #指明所有worker程序所能夠使用的總體的最大核心檔案大小,保持預設即可      

    優化性能的配置:

worker_processes n;    #啟動n個worker程序,這裡的n為了避免上下文切換,通常設定為cpu總核心數-1或等于總核心數
worker_cpu_affinity cpumask ...;    #将程序綁定到某cpu中,避免頻繁重新整理緩存
#  cpumask:使用8位二進制表示cpu核心,如:
#  0000 0001:第一顆cpu核心
#  0000 0010:第二顆cpu核心
#  0000 0100:第三顆cpu核心
#  0000 1000:第四顆cpu核心
timer_resolution interval;    #計時器解析度。降低此值,可減少gettimeofday()系統調用的次數
worker_priority number;    #指明worker程序的nice值      

    事件相關的配置:event{}段中的配置

accept_mutex {off|on};    #master排程使用者請求至各worker程序時使用的負載均衡鎖;on表示能讓多個worker輪流地、序列化地去響應新請求
lock_file file;    #accept_mutex用到的互斥鎖鎖檔案路徑
use [epoll | rtsig | select | poll];    #指明使用的事件模型,建議讓Nginx自行選擇
worker_connections #;    #每個程序能夠接受的最大連接配接數      

    網絡連接配接相關的配置:

keepalive_timeout number;    #長連接配接的逾時時長,預設為75s
keepalive_requests number;    #在一個長連接配接上所能夠允許請求的最大資源數
keepalive_disable [msie6|safari|none];    #為指定類型的UserAgeng禁用長連接配接
tcp_nodelay on|off;    #是否對長連接配接使用TCP_NODELAY選項,為了提升使用者體驗,通常設為on
client_header_timeout number;    #讀取http請求封包首部的逾時時長
client_body_timeout number;    #讀取http請求封包body部分的逾時時長
send_timeout number;    #發送響應封包的逾時時長      

    fastcgi的相關配置:

      LNMP:php要啟用fpm模型

      配置示例:

location ~ \.php$ {
  root html;
  fastcgi_pass 127.0.0.1:9000;定義反向代理
  fastcgi_index index.php;
  fastcgi_param SCRIPT_FILENAME /scripts$fastcgi_script_name;
  include fastcgi_params;
}      

    常需要進行調整的參數:

worker_processes
worker_connections
worker_cpu_affinity
worker_priority      

    nginx作為web伺服器時使用的配置:

      http{...}:配置http相關,由ngx_http_core_module子產品引入。Nginx的HTTP配置主要包括四個區塊,結構如下:

http {//協定級别
  include mime.types;
  default_type application/octet-stream;
  keepalive_timeout 65;
  gzipon;
  upstream {//負載均衡配置
    ...
  }
  server {//伺服器級别,每個server類似于httpd中的一個<VirtualHost>
    listen80;
    server_name localhost;
    location / {//請求級别,類似于httpd中的<Location>,用于定義URL與本地檔案系統的映射關系
      root html;
      index index.html index.htm;
    }
  }
}      

      配置指令:

        server {}:定義一個虛拟主機,示例如下:

server {
  listen 80;
  server_name www.idfsoft.com;
  root "/vhosts/web";
}      

        listen:指定監聽的位址和端口

listen address[:port];
listen port;      

        server_name NAME [...];  後面可跟多個主機,名稱可使用正規表達式或通配符

          當有多個server時,比對順序如下:

        (1)先做精确比對檢查

        (2)左側通配符比對檢查,如*.idfsoft.com

        (3)右側通配符比對檢查,如mail.*

        (4)正規表達式比對檢查,如~^.*\.idfsoft\.com$

        (5)default_server

        root path;  設定資源路徑映射,用于指明請求的URL所對應的資源所在的檔案系統上的起始路徑

        alias path;  用于location配置段,定義路徑别名

        index file;預設首頁面

index index.php index.html;      

        error_page code [...] [=code] URI | @name    根據http響應狀态碼來指明特用的錯誤頁面,例如 error_page 404 /404_customed.html

          [=code]:以指定的響應碼進行響應,而不是預設的原來的響應,預設表示以新資源的響應碼為其響應碼,例如 error_page 404 =200 /404_customed.html

        log_format:定義日志格式

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;

注意:此處可用變量為nginx各子產品内建變量      

        location區段,通過指定模式來與用戶端請求的URI相比對

          功能:允許根據使用者請求的URI來比對定義的各location,比對到時,此請求将被相應的location配置塊中的配置所處理,例如做通路控制等功能

          文法:

location [ 修飾符 ] pattern {......}      

         修飾符:

            =:精确比對

            ~:正規表達式模式比對,區分大小寫

            ~*:正規表達式模式比對,不區分大小寫

            ^~:字首比對,類似于無修飾符的行為,也是以指定子產品開始,不同的是,如果模式比對,那麼就停止搜尋其他模式了,不支援正規表達式

            @:定義命名location區段,這些區段用戶端不能通路,隻可以由内部産生的請求來通路,如try_files或error_page等

          沒有修飾符表示必須以指定模式開始,如:

server {
  server_name www.idfsoft.com;
  location /abc {
    ......
  }
}      

          那麼如下内容就可正确比對:

            http://www.idfsoft.com/abc

            http://www.idfsoft.com/abc?p1=11&p2=22

            http://www.idfsoft.com/abc/

          =:表示必須與指定的模式精确比對,如:

server {
  server_name www.idfsoft.com;
  location = /abc {
    ......
  }
}      

          那麼如下内容就可正确比對:

          如下内容則無法比對:

            http://www.idfsoft.com/abc/abcde

          ~:表示指定的正規表達式要區分大小寫,如:

server {
  server_name www.idfsoft.com;
  location ~ ^/abc$ {
  ......
  }
}      

            http://www.idfsoft.com/ABC

            http://www.idfsoft.com/abcde

          ~*:表示指定的正規表達式不區分大小寫,如:

server {
  server_name www.idfsoft.com;
  location ~* ^/abc$ {
    ......
  }
}      

          ^~:類似于無修飾符的行為,也是以指定模式開始,不同的是,如果模式比對,則停止搜尋其他模式

          查找順序和優先級:由高到底依次為

            帶有“=”的精确比對優先

            正規表達式按照他們在配置檔案中定義的順序

            帶有“^~”修飾符的,開頭比對

            帶有“~”或“~*”修飾符的,如果正規表達式與URI比對

            沒有修飾符的精确比對

          優先級次序如下:

            ( location = 路徑 ) > ( location ^~ 路徑 ) > ( location ~ 正則 ) > ( location ~* 正則 ) > ( location 路徑 )

    通路控制:

      allow:設定允許哪台或哪些主機通路,多個參數間用空格隔開

      deny:設定禁止哪台或哪些主機通路,多個參數間用空格隔開

      示例:

allow 192.168.1.1/32 172.16.0.0/16;
deny all;      

    基于使用者認證:

auth_basic "歡迎資訊";
auth_basic_user_file "/path/to/user_auth_file"      

      user_auth_file内容格式為:

username:password      

      這裡的密碼為加密後的密碼串,建議用htpasswd來建立此檔案:

htpasswd -c -m /path/to/.user_auth_file USERNAME      

    https服務:

      生成私鑰,生成證書簽署請求并獲得證書,然後在nginx.conf中配置如下内容:

server {
  listen       443 ssl;
  server_name  www.idfsoft.com;
  ssl_certificate      /etc/nginx/ssl/nginx.crt;
  ssl_certificate_key  /etc/nginx/ssl/nginx.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;
  }
}      

    狀态頁面:

      開啟status:

location /status {
  stub_status {on | off};
  allow 172.16.0.0/16;
  deny all;
}      

      通路狀态頁面的方式:

        http://server_ip/status

      狀态頁面資訊詳解:

        狀态頁面示例如下圖:

第十四章 nginx詳解

        Active connections 2:目前所有處于打開狀态的連接配接數

        accepts:總共處理了多少個連接配接

        handled:成功建立多少握手

        requests:總共處理了多少個請求

        Reading:Nginx讀取到用戶端的Header資訊數,表示正處于接收請求狀态的連接配接數

        Writing:Nginx傳回給用戶端的Header資訊數,表示請求已經接收完成,正處于處理請求或發送響應的過程中的連接配接數

        Waiting:開啟keep-alive的情況下,這個值等于active - (reading + writing),意思就是Nginx已處理完正在等候下一次請求指令的駐留連接配接

    ReWrite:

      文法:

rewrite regex replacement flag;      

      如:

rewrite ^/p_w_picpaths/(.*\.jpg)$ /imgs/$1 break;      

      $1用于引用(.*\.jpg)比對到的内容

      又如:

rewrite ^/bbs/(.*)$ http://www.idfsoft.com/index.html redirect      

      如上例所示,replacement可以是某個路徑,也可以是某個URL

      常見的flag:

        last:基本上都用這個flag,表示目前的比對結束,繼續下一個比對,最多比對10個到20個

          一旦此rewrite規則重寫完成後,就不再被後面其它的rewrite規則進行處理

          而是由UserAgent重新對重寫後的URL再一次發起請求,并從頭開始執行類似的過程

        break:中止Rewrite,不再繼續比對

          一旦此rewrite規則重寫完成後,由UserAgent對新的URL重新發起請求,且不再會被目前location内的任何rewrite規則所檢查

        redirect:以臨時重定向的HTTP狀态302傳回新的URL

        permanent:以永久重定向的HTTP狀态301傳回新的URL

      Rewrite子產品:用來執行URL重定向。這個機制有利于去掉惡意通路的url,也有利于搜尋引擎優化(SEO)

      Nginx使用的文法源于Perl相容正規表達式(PCRE)庫,基本文法如下:

        ^:必須以^後的實體開頭

        $:必須以$前的實體結尾

        .:比對任意字元

        [ ]:比對指定字元集内的任意字元

        [^ ]:比對任何不包括在指定字元集内的任意字元串

        |:比對 | 之前或之後的實體

        ():分組,組成一組用于比對的實體,通常會有 | 來協助

      捕獲子表達式,可以捕獲放在()之間的任何文本,比如:

        ^(hello|sir)$字元串為“hi sir”捕獲的結果:$1=hi$2=sir

        這些被捕獲的資料,在後面就可以當變量一樣使用了

    if:

if (condition) {...}      

      應用環境:

        server

        location

      常見的condition:

      a) 變量名(變量值為空串,或者以“0”開始,則為false,其它的均為true)

      b) 以變量為操作數構成的比較表達式(可使用=,!=類似的比較操作符進行測試)

      c) 正規表達式的模式比對操作

        ~:區分大小寫的模式比對檢查

        ~*:不區分大小寫的模式比對檢查

        !~和!~*:對上面兩種測試取反

      d) 測試指定路徑為檔案的可能性(-f,!-f)

      e) 測試指定路徑為目錄的可能性(-d,!-d)

      f) 測試檔案的存在性(-e,!-e)

      g) 檢查檔案是否有執行權限(-x,!-x)

      基于浏覽器實作分離案例:

if ($http_user_agent ~ Firefox) {
  rewrite ^(.*)$ /firefox/$1 break;
}

if ($http_user_agent ~ MSIE) {
  rewrite ^(.*)$ /msie/$1 break;
}

if ($http_user_agent ~ Chrome) {
  rewrite ^(.*)$ /chrome/$1 break;
}      

      防盜鍊:

location ~* \.(jpg|gif|jpeg|png)$ {
  valid_referer none clocked www.idfsoft.com;
  if ($invalid_referer) {
    rewrite ^/ http://www.idfsoft.com/403.html;
  }
}      

14.5.4 nginx反向代理

  Nginx通常被用作後端伺服器的反向代理,這樣就可以很友善的實作動靜分離以及負載均衡,進而大大提高伺服器的處理能力。

  Nginx實作動靜分離,其實就是在反向代理的時候,如果是靜态資源,就直接從Nginx釋出的路徑去讀取,而不需要從背景伺服器擷取了。

  但是要注意,這種情況下需要保證後端跟前端的程式保持一緻,可以使用Rsync做服務端自動同步或者使用NFS、MFS分布式共享存儲。

  Http Proxy子產品,功能很多,最常用的是proxy_pass和proxy_cache

  如果要使用proxy_cache,需要內建第三方的ngx_cache_purge子產品,用來清除指定的URL緩存。這個內建需要在安裝nginx的時候去做,如:

./configure --add-module=../ngx_cache_purge-1.0 ......      

14.5.5 nginx負載均衡

  Nginx通過upstream子產品來實作簡單的負載均衡,upstream需要定義在http段内

  在upstream段内,定義一個伺服器清單,預設的方式是輪詢,如果要确定同一個通路者發出的請求總是由同一個後端伺服器來處理,可以設定ip_hash,如:

upstream idfsoft.com {
  ip_hash;
  server 127.0.0.1:9080 weight=5;
  server 127.0.0.1:8080 weight=5;
  server 127.0.0.1:1111;
}      
server {
  location / {
    proxy_pass http://idfsoft.com;
  }
}      

繼續閱讀