lnmmp

爲什麼選擇Nginx?因爲它具有以下特點:

(1)更快

這表現在兩個方面:一方面,在正常情況下,單次請求會得到更快的響應;另一方面, 在高峯期(如有數以萬計的併發請求),Nginx可以比其他Web服務器更快地響應請求。

實際上,本書第三部分中大量的篇幅都是在說明Nginx是如何做到這兩點的。

(2)高擴展性

Nginx的設計極具擴展性,它完全是由多個不同功能、不同層次、不同類型且耦合度極低的模塊組成。因此,當對某一個模塊修復Bug或進行升級時,可以專注於模塊自身,無須 在意其他。而且在HTTP模塊中,還設計了 HTTP過濾器模塊:一個正常的HTTP模塊在處 理完請求後,會有一串HTTP過濾器模塊對請求的結果進行再處理。這樣,當我們開發一個 新的HTTP模塊時,不但可以使用諸如HTTP核心模塊、events模塊、log模塊等不同層次 或者不同類型的模塊,還可以原封不動地複用大量已有的HTTP過濾器模塊。這種低耦合度 的優秀設計,造就了 Ngimc龐大的第三方模塊,當然,公開的第三方模塊也如官方發佈的模 塊一樣容易使用。

Nginx的模塊都是嵌入到二進制文件中執行的,無論官方發佈的模塊還是第三方模塊都 是如此。這使得第三方模塊一樣具備極其優秀的性能,充分利用Nginx的高併發特性,因 此,許多高流量的網站都傾向於開發符合自己業務特性的定製模塊。

(3)髙可靠性

高可靠性是我們選擇Nginx的最基本條件,因爲Nginx的可靠性是大家有目共睹的,很 多家高流量網站都在覈心服務器上大規模使用Nginx。Nginx的高可靠性來自於其核心框架 代碼的優秀設計、模塊設計的簡單性;另外,官方提供的常用模塊都非常穩定,每個worker 進程相對獨立,master進程在1個worker進程出錯時可以快速“拉起”新的worker子進程


(4)低內存消耗

一般情況下,10 000個非活躍的HTTP Keep-Alive連接在Nginx中僅消耗2.5MB的內 存,這是Nginx支持髙併發連接的基礎。

從第3章開始,我們會接觸到Nginx在內存中爲了維護一個HTTP連接所分配的對象, 屆時將會看到,實際上Nginx—直在爲用戶考慮(尤其是在髙併發時)如何使得內存的消耗

更少。

(5)單機支持10萬以上的併發連接

這是一個非常重要的特性!隨着互聯網的迅猛發展和互聯網用戶數量的成倍增長,各大 公司、網站都需要應付海量併發請求,一個能夠在峯值期頂住10萬以上併發請求的Server, 無疑會得到大家的青睞。理論上,Nginx支持的併發連接上限取決於內存,10萬遠未封頂。 當然,能夠及時地處理更多的併發請求,是與業務特點緊密相關的,本書第811章將會 詳細說明如何實現這個特點。


(6)熱部署

master管理進程與worker工作進程的分離設計,使得Nginx能夠提供熱部署功能,即 可以在7X24小時不間斷服務的前提下,升級Nginx的可執行文件。當然,它也支持不停止 服務就更新配置項、更換日誌文件等功能。

(7)最自由的BSD許可協議

這是Nginx可以快速發展的強大動力。BSD許可協議不只是允許用戶免費使用Nginx,它還允許用戶在自己的項目中直接使用或修改Nginx源碼,然後發佈。這吸引了無數開發者 繼續爲Nginx貢獻自己的智慧。


以上7個特點當然不是Nginx的全部,擁有無數個官方功能模塊、第三方功能模塊使得 Nginx能夠滿足絕大部分應用場景,這些功能模塊間可以疊加以實現更加強大、複雜的功能, 有些模塊還支持Nginx與Perl、Lua等腳本語言集成工作,大大提高了開發效率。這些特點 促使用戶在尋找一個Web服務器時更多考慮Nginx。

當然,選擇Nginx的核心理由還是它能在支持髙併發請求的同時保持髙效的服務。

如果Web服務器的業務訪問量巨大,就需要保證在數以百萬計的請求同時訪問服務時, 用戶可以獲得良好的體驗,不會出現併發訪問量達到一個數字後,新的用戶無法獲取服務, 或者雖然成功地建立起了 TCP連接,但大部分請求卻得不到響應的情況。

通常,高峯期服務器的訪問量可能是正常情況下的許多倍,若有熱點事件的發生,可能 會導致正常情況下非常順暢的服務器直接“掛死”。然而,如果在部署服務器時,就預先針 對這種情況進行擴容,又會使得正常情況下所有服務器的負載過低,這會造成大量的資源浪 費。因此,我們會希望在這之間取得平衡,也就是說,在低併發壓力下,用戶可以獲得高速 體驗,而在髙併發壓力下,更多的用戶都能接入,可能訪問速度會下降,但這隻應受制於帶 寬和處理器的速度,而不應該是服務器設計導致的軟件瓶頸。事實上,由於中國互聯網用戶羣體的數量巨大,致使對Web服務器的設計往往要比歐美 公司更加困難。例如,對於全球性的一些網站而言,歐美用戶分佈在兩個半球,歐洲用戶活 躍時,美洲用戶通常在休息,反之亦然。而國內巨大的用戶羣體則對業界的程序員提出更高 的挑戰,早上9點和晚上20點到24點這些時間段的併發請求壓力是非常巨大的。尤其節假 日、寒暑假到來之時,更會對服務器提出極髙的要求。

另外,國內業務上的特性,也會引導用戶在同一時間大併發地訪問服務器。例如,許多 SNS網頁遊戲會在固定的時間點刷新遊戲資源或者允許“偷菜”等好友互動操作。這些會導 致服務器處理髙併發請求的壓力增大.

上述情形都對我們的互聯網服務在大併發壓力下是否還能夠給予用戶良好的體驗提出了 更髙的要求。若要提供更好的服務,那麼可以從多方面入手,例如,修改業務特性、引導用 戶從高峯期分流或者把服務分層分級、對於不同併發壓力給用戶提供不同級別的服務等。但 最根本的是,Web服務器要能支持大併發壓力下的正常服務,這纔是關鍵。
快速增長的互聯網用戶羣以及業內所有互聯網服務提供商越來越好的用戶體驗,都促使 我們在大流量服務中用Nginx取代其他Web服務器^ Nginx先天的事件驅動型設計、全異步

的網絡I/O處理機制、極少的進程間切換以及許多優化設計,都使得Nginx天生善於處理 髙併發壓力下的互聯網請求,同時Nginx降低了資源消耗,可以把服務器硬件資源“壓榨” 到極致。




一、安裝Nginx:

1、解決依賴關係

# yum groupinstall "Development Tools" "Server Platform Deveopment"
# yum install openssl-devel pcre-devel

2、安裝

首先添加用戶nginx,實現以之運行nginx服務進程:

# groupadd -r nginx
# useradd -r -g nginx nginx
接着開始編譯和安裝:
# ./configure \
  --prefix=/usr \
  --sbin-path=/usr/sbin/nginx \
  --conf-path=/etc/nginx/nginx.conf \
  --error-log-path=/var/log/nginx/error.log \
  --http-log-path=/var/log/nginx/access.log \
  --pid-path=/var/run/nginx/nginx.pid  \
  --lock-path=/var/lock/nginx.lock \
  --user=nginx \
  --group=nginx \
  --with-http_ssl_module \
  --with-http_flv_module \
  --with-http_stub_status_module \
  --with-http_gzip_static_module \
  --http-client-body-temp-path=/var/tmp/nginx/client/ \
  --http-proxy-temp-path=/var/tmp/nginx/proxy/ \
  --http-fastcgi-temp-path=/var/tmp/nginx/fcgi/ \
  --http-uwsgi-temp-path=/var/tmp/nginx/uwsgi \
  --http-scgi-temp-path=/var/tmp/nginx/scgi \
  --with-pcre
# make && make install

說明:
1、Nginx可以使用Tmalloc(快速、多線程的malloc庫及優秀性能分析工具)來加速內存分配,使用此功能需要事先安裝gperftools,而後在編譯nginx添加--with-google_perftools_module選項即可。
2、如果想使用nginx的perl模塊,可以通過爲configure腳本添加--with-http_perl_module選項來實現,但目前此模塊仍處於實驗性使用階段,可能會在運行中出現意外,因此,其實現方式這裏不再介紹。如果想使用基於nginx的cgi功能,也可以基於FCGI來實現,具體實現方法請參照網上的文檔。

3、爲nginx提供SysV init腳本:

新建文件/etc/rc.d/init.d/nginx,內容如下:

#!/bin/sh
#
# nginx - this script starts and stops the nginx daemon
#
# chkconfig:   - 85 15
# description:  Nginx is an HTTP(S) server, HTTP(S) reverse \
#               proxy and IMAP/POP3 proxy server
# processname: nginx
# config:      /etc/nginx/nginx.conf
# config:      /etc/sysconfig/nginx
# pidfile:     /var/run/nginx.pid
# Source function library.
. /etc/rc.d/init.d/functions
# Source networking configuration.
. /etc/sysconfig/network
# Check that networking is up.
[ "$NETWORKING" = "no" ] && exit 0
nginx="/usr/sbin/nginx"
prog=$(basename $nginx)
NGINX_CONF_FILE="/etc/nginx/nginx.conf"
[ -f /etc/sysconfig/nginx ] && . /etc/sysconfig/nginx
lockfile=/var/lock/subsys/nginx
make_dirs() {
   # make required directories
   user=`nginx -V 2>&1 | grep "configure arguments:" | sed 's/[^*]*--user=\([^ ]*\).*/\1/g' -`
   options=`$nginx -V 2>&1 | grep 'configure arguments:'`
   for opt in $options; do
       if [ `echo $opt | grep '.*-temp-path'` ]; then
           value=`echo $opt | cut -d "=" -f 2`
           if [ ! -d "$value" ]; then
               # echo "creating" $value
               mkdir -p $value && chown -R $user $value
           fi
       fi
   done
}
start() {
    [ -x $nginx ] || exit 5
    [ -f $NGINX_CONF_FILE ] || exit 6
    make_dirs
    echo -n $"Starting $prog: "
    daemon $nginx -c $NGINX_CONF_FILE
    retval=$?
    echo
    [ $retval -eq 0 ] && touch $lockfile
    return $retval
}
stop() {
    echo -n $"Stopping $prog: "
    killproc $prog -QUIT
    retval=$?
    echo
    [ $retval -eq 0 ] && rm -f $lockfile
    return $retval
}
restart() {
    configtest || return $?
    stop
    sleep 1
    start
}
reload() {
    configtest || return $?
    echo -n $"Reloading $prog: "
    killproc $nginx -HUP
    RETVAL=$?
    echo
}
force_reload() {
    restart
}
configtest() {
  $nginx -t -c $NGINX_CONF_FILE
}
rh_status() {
    status $prog
}
rh_status_q() {
    rh_status >/dev/null 2>&1
}
case "$1" in
    start)
        rh_status_q && exit 0
        $1
        ;;
    stop)
        rh_status_q || exit 0
        $1
        ;;
    restart|configtest)
        $1
        ;;
    reload)
        rh_status_q || exit 7
        $1
        ;;
    force-reload)
        force_reload
        ;;
    status)
        rh_status
        ;;
    condrestart|try-restart)
        rh_status_q || exit 0
            ;;
    *)
        echo $"Usage: $0 {start|stop|status|restart|condrestart|try-restart|reload|force-reload|configtest}"
        exit 2
esac

而後爲此腳本賦予執行權限:
# chmod +x /etc/rc.d/init.d/nginx

添加至服務管理列表,並讓其開機自動啓動:
# chkconfig --add nginx
# chkconfig nginx on

而後就可以啓動服務並測試了:
# service nginx start

Nginx的代碼是由一個核心和一系列的模塊組成, 核心主要用於提供Web Server的基本功能,以及Web和Mail反向代理的功能;還用於啓用網絡協議,創建必要的運行時環境以及確保不同的模塊之間平滑地進行交互。不過,大多跟協議相關的功能和某應用特有的功能都是由nginx的模塊實現的。這些功能模塊大致可以分爲事件模塊、階段性處理器、輸出過濾器、變量處理器、協議、upstream和負載均衡幾個類別,這些共同組成了nginx的http功能。事件模塊主要用於提供OS獨立的(不同操作系統的事件機制有所不同)事件通知機制如kqueue或epoll等。協議模塊則負責實現nginx通過http、tls/ssl、smtp、pop3以及imap與對應的客戶端建立會話。

Nginx的核心模塊爲Main和Events,此外還包括標準HTTP模塊、可選HTTP模塊和郵件模塊,其還可以支持諸多第三方模塊。Main用於配置錯誤日誌、進程及權限等相關的參數,Events用於配置IO模型,如epoll、kqueue、select或poll等,它們是必備模塊。

Nginx的主配置文件由幾個段組成,這個段通常也被稱爲nginx的上下文,每個段的定義格式如下所示。需要注意的是,其每一個指令都必須使用分號(;)結束,否則爲語法錯誤。

<section> {
   <directive> <parameters>;
}

2.1 配置main模塊

下面說明main模塊中的幾個關鍵參數。

2.1.1 error_log

用於配置錯誤日誌,可用於main、http、server及location上下文中;語法格式爲:

error_log file | stderr [ debug | info | notice | warn | error | crit | alert | emerg ]

如果在編譯nginx時使用了--with-debug選項,還可以使用如下格式打開調試功能。

error_log LOGFILE [debug_core | debug_alloc | debug_mutex | debug_event | debug_http | debug_imap];

要禁用錯誤日誌,不能使用“error_log off;”,而要使用類似如下選項:

error_log /dev/null crit;

2.1.2 timer_resolution

用於降低gettimeofday()系統調用的次數。默認情況下,每次從kevent()、epoll、/dev/poll、select()或poll()返回時都會執行此係統調用。語法格式爲:

timer_resolution interval

例如:

timer_resolution  100ms;

2.1.3 worker_cpu_affinity

通過sched_setaffinity()將worker綁定至CPU上,只能用於main上下文。語法格式爲:

worker_cpu_affinity cpumask ...

例如:
worker_processes     4;
worker_cpu_affinity 0001 0010 0100 1000;

2.1.4 worker_priority

爲worker進程設定優先級(指定nice值),此參數只能用於main上下文中,默認爲0;語法格式爲:

worker_priority number

2.1.5 worker_processes

worker進程是單線程進程。如果Nginx用於CPU密集型的場景中,如SSL或gzip,且主機上的CPU個數至少有2個,那麼應該將此參數值設定爲與CPU核心數相同;如果Nginx用於大量靜態文件訪問的場景中,且所有文件的總大小大於可用內存時,應該將此參數的值設定得足夠大以充分利用磁盤帶寬。

此參數與Events上下文中的work_connections變量一起決定了maxclient的值:
maxclients = work_processes * work_connections

2.1.6 worker_rlimit_nofile

設定worker進程所能夠打開的文件描述符個數的最大值。語法格式:

worker_rlimit_nofile number

2.2 配置Events模塊

2.2.1 worker_connections

設定每個worker所處理的最大連接數,它與來自main上下文的worker_processes一起決定了maxclients的值。

max clients = worker_processes * worker_connections

而在反向代理場景中,其計算方法與上述公式不同,因爲默認情況下瀏覽器將打開2個連接,而nginx會爲每一個連接打開2個文件描述符,因此,其maxclients的計算方法爲:

max clients = worker_processes * worker_connections/4

2.2.2 use

在有着多於一個的事件模型IO的應用場景中,可以使用此指令設定nginx所使用的IO機制,默認爲./configure腳本選定的各機制中最適用當前OS的版本。語法格式:

use [ kqueue | rtsig | epoll | /dev/poll | select | poll | eventport ]

2.3 一個配置示例

user nginx;
# the load is CPU-bound and we have 16 cores
worker_processes 16;
error_log /var/log/nginx/error.log;
pid /var/run/nginx.pid;
events {
    use epoll;
    worker_connections 2048;
}


2.4 HTTP服務的相關配置

http上下文專用於配置用於http的各模塊,此類指令非常的多,每個模塊都有其專用指定,具體請參數nginx官方wiki關於模塊部分的說明。大體上來講,這些模塊所提供的配置指令還可以分爲如下幾個類別。

客戶端類指令:如client_body_buffer_size、client_header_buffer_size、client_header_timeout和keepalive_timeout等;
文件IO類指令:如aio、directio、open_file_cache、open_file_cache_min_uses、open_file_cache_valid和sendfile等;
hash類指令:用於定義Nginx爲某特定的變量分配多大的內存空間,如types_hash_bucket_size、server_names_hash_bucket_size和variables_hash_bucket_size等;
套接字類指令:用於定義Nginx如何處理tcp套接字相關的功能,如tcp_nodelay(用於keepalive功能啓用時)和tcp_nopush(用於sendfile啓用時)等;

2.5 虛擬服務器相關配置

server {
   <directive> <parameters>;
}

用於定義虛擬服務器相關的屬性,常見的指令有backlog、rcvbuf、bind及sndbuf等。

2.6 location相關的配置

location [modifier] uri {...} 或 location @name {…}

通常用於server上下文中,用於設定某URI的訪問屬性。location可以嵌套。

The prefix "@" specifies a named location. Such locations are not used during normal processing of requests, they are intended only to process internally redirected requests (see error_page, try_files). 如下面關於memcached的相關配置。

server {
  location / {
    set $memcached_key $uri;
    memcached_pass     name:11211;
    default_type       text/html;
    error_page         404 @fallback;
  }
  location @fallback {
    proxy_pass http://backend;
  }
}

三、Nginx反向代理

Nginx通過proxy模塊實現反向代理功能。在作爲web反向代理服務器時,nginx負責接收客戶請求,並能夠根據URI、客戶端參數或其它的處理邏輯將用戶請求調度至上游服務器上(upstream server)。nginx在實現反向代理功能時的最重要指令爲proxy_pass,它能夠將location定義的某URI代理至指定的上游服務器(組)上。如下面的示例中,location的/uri將被替換爲上游服務器上的/newuri。

location /uri {
    proxy_pass http://www.magedu.com:8080/newuri;
}

不過,這種處理機制中有兩個例外。一個是如果location的URI是通過模式匹配定義的,其URI將直接被傳遞至上游服務器,而不能爲其指定轉換的另一個URI。例如下面示例中的/forum將被代理爲http://www.magedu.com/forum。

   location ~ ^/bbs {
       proxy_pass http://www.magedu.com;
   }

第二個例外是,如果在loation中使用的URL重定向,那麼nginx將使用重定向後的URI處理請求,而不再考慮上游服務器上定義的URI。如下面所示的例子中,傳送給上游服務器的URI爲/index.php?page=<match>,而不是/index。

   location / {
       rewrite /(.*)$ /index.php?page=$1 break;
       proxy_pass http://localhost:8080/index;
   }

3.1 proxy模塊的指令

proxy模塊的可用配置指令非常多,它們分別用於定義proxy模塊工作時的諸多屬性,如連接超時時長、代理時使用http協議版本等。下面對常用的指令做一個簡單說明

proxy_connect_timeout:nginx將一個請求發送至upstream server之前等待的最大時長;
proxy_cookie_domain:將upstream server通過Set-Cookie首部設定的domain屬性修改爲指定的值,其值可以爲一個字符串、正則表達式的模式或一個引用的變量;
proxy_cookie_path: 將upstream server通過Set-Cookie首部設定的path屬性修改爲指定的值,其值可以爲一個字符串、正則表達式的模式或一個引用的變量;
proxy_hide_header:設定發送給客戶端的報文中需要隱藏的首部;
proxy_pass:指定將請求代理至upstream server的URL路徑;
proxy_set_header:將發送至upsream server的報文的某首部進行重寫;
proxy_redirect:重寫location並刷新從upstream server收到的報文的首部;
proxy_send_timeout:在連接斷開之前兩次發送至upstream server的寫操作的最大間隔時長;
proxy_read_timeout:在連接斷開之前兩次從接收upstream server接收讀操作的最大間隔時長;

如下面的一個示例:

proxy_redirect off;
proxy_set_header Host $host;
proxy_set_header X-Real-IP $remote_addr;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
client_max_body_size 10m;
client_body_buffer_size 128k;
proxy_connect_timeout 30;
proxy_send_timeout 15;
proxy_read_timeout 15;

3.2 upstream模塊

與proxy模塊結合使用的模塊中,最常用的當屬upstream模塊。upstream模塊可定義一個新的上下文,它包含了一組寶島upstream服務器,這些服務器可能被賦予了不同的權重、不同的類型甚至可以基於維護等原因被標記爲down。

upstream模塊常用的指令有:
ip_hash:基於客戶端IP地址完成請求的分發,它可以保證來自於同一個客戶端的請求始終被轉發至同一個upstream服務器;
keepalive:每個worker進程爲發送到upstream服務器的連接所緩存的個數;
least_conn:最少連接調度算法;
server:定義一個upstream服務器的地址,還可包括一系列可選參數,如:
weight:權重;
max_fails:最大失敗連接次數,失敗連接的超時時長由fail_timeout指定;
fail_timeout:等待請求的目標服務器發送響應的時長;
backup:用於fallback的目的,所有服務均故障時才啓動此服務器;
down:手動標記其不再處理任何請求;

例如:

    upstream backend {
      server www.magedu.com weight=5;
      server www2.magedu.com:8080       max_fails=3  fail_timeout=30s;
    }
upstream模塊的負載均衡算法主要有三種,輪調(round-robin)、ip哈希(ip_hash)和最少連接(least_conn)三種。
此外,upstream模塊也能爲非http類的應用實現負載均衡,如下面的示例定義了nginx爲memcached服務實現負載均衡之目的。
    upstream memcachesrvs {
        server 172.16.100.6:11211;
        server 172.16.100.7:11211;
    }
    server {
        location / {
        set $memcached_key "$uri?$args";
        memcached_pass memcachesrvs;
        error_page 404 = @fallback;
        }
        location @fallback {
                proxy_pass http://127.0.0.1:8080;
        }
    }

3.3 if判斷語句

在location中使用if語句可以實現條件判斷,其通常有一個return語句,且一般與有着last或break標記的rewrite規則一同使用。但其也可以按需要使用在多種場景下,需要注意的是,不當的使用可能會導致不可預料的後果。

location / {
    if ($request_method == “PUT”) {
        proxy_pass http://upload.magedu.com:8080;
    }
    if ($request_uri ~ "\.(jpg|gif|jpeg|png)$") {
        proxy_pass http://imageservers;
        break;
    }
}
upstream imageservers {
    server 172.16.100.8:80 weight 2;
    server 172.16.100.9:80 weight 3;
}

3.3.1 if語句中的判斷條件

正則表達式匹配:
   ~:與指定正則表達式模式匹配時返回“真”,判斷匹配與否時區分字符大小寫;
   ~*:與指定正則表達式模式匹配時返回“真”,判斷匹配與否時不區分字符大小寫;
   !~:與指定正則表達式模式不匹配時返回“真”,判斷匹配與否時區分字符大小寫;
   !~*:與指定正則表達式模式不匹配時返回“真”,判斷匹配與否時不區分字符大小寫;

文件及目錄匹配判斷:
   -f, !-f:判斷指定的路徑是否爲存在且爲文件;
   -d, !-d:判斷指定的路徑是否爲存在且爲目錄;
   -e, !-e:判斷指定的路徑是否存在,文件或目錄均可;
   -x, !-x:判斷指定路徑的文件是否存在且可執行;

3.3.2 nginx常用的全局變量

下面是nginx常用的全局變量中的一部分,它們經常用於if語句中實現條件判斷。

$args
$content_length
$content_type
$document_root
$document_uri
$host
$http_user_agent
$http_cookie
$limit_rate
$request_body_file
$request_method
$remote_addr
$remote_port
$remote_user
$request_filename
$request_uri
$query_string
$scheme
$server_protocol
$server_addr
$server_name
$server_port
$uri

四、反向代理性能優化

在反向代理場景中,nginx有一系列指令可用於定義其工作特性,如緩衝區大小等,給這些指令設定一個合理的值,可以有效提升其性能。

4.1 緩衝區設定

nginx在默認情況下在將其響應給客戶端之前會儘可能地接收來upstream服務器的響應報文,它會將這些響應報文存暫存於本地並儘量一次性地響應給客戶端。然而,在來自於客戶端的請求或來自upsteam服務器的響應過多時,nginx會試圖將之存儲於本地磁盤中,這將大大降低nginx的性能。因此,在有着更多可用內存的場景中,應該將用於暫存這些報文的緩衝區調大至一個合理的值。

proxy_buffer_size size:設定用於暫存來自於upsteam服務器的第一個響應報文的緩衝區大小;
proxy_buffering on|off:啓用緩衝upstream服務器的響應報文,否則,如果proxy_max_temp_file_size指令的值爲0,來自upstream服務器的響應報文在接收到的那一刻將同步發送至客戶端;一般情況下,啓用proxy_buffering並將proxy_max_temp_file_size設定爲0能夠啓用緩存響應報文的功能,並能夠避免將其緩存至磁盤中;
proxy_buffers 8 4k|8k:用於緩衝來自upstream服務器的響應報文的緩衝區大小;



4.2 緩存
nginx做爲反向代理時,能夠將來自upstream的響應緩存至本地,並在後續的客戶端請求同樣內容時直接從本地構造響應報文。

proxy_cache zone|off:定義一個用於緩存的共享內存區域,其可被多個地方調用;緩存將遵從upstream服務器的響應報文首部中關於緩存的設定,如 "Expires""Cache-Control: no-cache""Cache-Control: max-age=XXX""private""no-store"等,但nginx在緩存時不會考慮響應報文的"Vary"首部。爲了確保私有信息不被緩存,所有關於用戶的私有信息可以upstream上通過"no-cache"or "max-age=0"來實現,也可在nginx設定proxy_cache_key必須包含用戶特有數據如$cookie_xxx的方式實現,但最後這種方式在公共緩存上使用可能會有風險。因此,在響應報文中含有以下首部或指定標誌的報文將不會被緩存。
Set-Cookie
Cache-Control containing "no-cache", "no-store", "private", or a "max-age"with a non-numeric or 0 value
Expires with a timeinthe past
X-Accel-Expires: 0
proxy_cache_key:設定在存儲及檢索緩存時用於“鍵”的字符串,可以使用變量爲其值,但使用不當時有可能會爲同一個內容緩存多次;另外,將用戶私有信息用於鍵可以避免將用戶的私有信息返回給其它用戶;
proxy_cache_lock:啓用此項,可在緩存未命令中阻止多個相同的請求同時發往upstream,其生效範圍爲worker級別;
proxy_cache_lock_timeout:proxy_cache_lock功能的鎖定時長;
proxy_cache_min_uses:某響應報文被緩存之前至少應該被請求的次數;
proxy_cache_path:定義一個用記保存緩存響應報文的目錄,及一個保存緩存對象的鍵及響應元數據的共享內存區域(keys_zone=name:size),其可選參數有:
levels:每級子目錄名稱的長度,有效值爲1或2,每級之間使用冒號分隔,最多爲3級;
inactive:非活動緩存項從緩存中剔除之前的最大緩存時長;
max_size:緩存空間大小的上限,當需要緩存的對象超出此空間限定時,緩存管理器將基於LRU算法對其進行清理;
loader_files:緩存加載器(cache_loader)的每次工作過程最多爲多少個文件加載元數據;
loader_sleep:緩存加載器的每次迭代工作之後的睡眠時長;
loader_threashold:緩存加載器的最大睡眠時長;
例如:  proxy_cache_path  /data/nginx/cache/onelevels=1      keys_zone=one:10m;
proxy_cache_path  /data/nginx/cache/twolevels=2:2    keys_zone=two:100m;
proxy_cache_path  /data/nginx/cache/threelevels=1:1:2  keys_zone=three:1000m;
proxy_cache_use_stale:在無法聯繫到upstream服務器時的哪種情形下(如error、timeout或http_500等)讓nginx使用本地緩存的過期的緩存對象直接響應客戶端請求;其格式爲:
proxy_cache_use_stale error | timeout | invalid_header | updating | http_500 | http_502 | http_503 | http_504 | http_404 | off
proxy_cache_valid [ code ...] time:用於爲不同的響應設定不同時長的有效緩存時長,例如:proxy_cache_valid  200 302  10m;
proxy_cache_methods [GET HEAD POST]:爲哪些請求方法啓用緩存功能;
proxy_cache_bypass string:設定在哪種情形下,nginx將不從緩存中取數據;例如:
proxy_cache_bypass $cookie_nocache $arg_nocache $arg_comment;
proxy_cache_bypass $http_pragma $http_authorization;

4.2.1 使用示例

http {
    proxy_cache_path  /data/nginx/cache  levels=1:2    keys_zone=STATIC:10m
                                         inactive=24h  max_size=1g;
    server {
        location / {
            proxy_pass             http://www.magedu.com;
            proxy_set_header       Host $host;
            proxy_cache            STATIC;
            proxy_cache_valid      200  1d;
            proxy_cache_valid       301 302 10m;
            proxy_cache_vaild        any 1m;
            proxy_cache_use_stale  error timeout invalid_header updating
                                   http_500 http_502 http_503 http_504;
        }
    }
}


4.3 壓縮

nginx將響應報文發送至客戶端之前可以啓用壓縮功能,這能夠有效地節約帶寬,並提高響應至客戶端的速度。通常編譯nginx默認會附帶gzip壓縮的功能,因此,可以直接啓用之。

http {
    gzip on;
    gzip_http_version 1.0;
    gzip_comp_level 2;
    gzip_types text/plain text/css application/x-javascript text/xml application/xml application/xml+rss text/javascript application/javascript application/json;
    gzip_disable msie6;
}

gzip_proxied指令可以定義對客戶端請求哪類對象啓用壓縮功能,如“expired”表示對由於使用了expire首部定義而無法緩存的對象啓用壓縮功能,其它可接受的值還有“no-cache”、“no-store”、“private”、“no_last_modified”、“no_etag”和“auth”等,而“off”則表示關閉壓縮功能。





五、配置示例

5.1 反向代理

server {
        listen       80;
        server_name  www.magedu.com;
        add_header X-Via $server_addr;
        location / {
            root   html;
            index  index.html index.htm;
            if ($request_method ~* "PUT") {
                proxy_pass http://172.16.100.12;
                break;
            }
        }
        location /bbs {
            proxy_pass http://172.16.100.11/;
        }
}

此例中,對http://www.magedu.com/bbs/的請求將被轉發至http://172.16.100.11/這個URL,切記最後的/不應該省去;而/匹配的URL中請求方法爲“PUT”時,將被轉發至http://172.16.100.12/這個URL。

另外,add_header用於讓nginx在響應給用戶的報文中構造自定義首部,其使用格式爲“add_header NAME VALUE”。

可以使用curl命令對配置好的服務進行請求,以驗正其效果。如:

# curl -I http://www.magedu.com/bbs/
HTTP/1.1 200 OK
Server: nginx/1.4.1
Date: Tue, 14 May 2013 10:19:10 GMT
Content-Type: text/html; charset=UTF-8
Content-Length: 15
Connection: keep-alive
Last-Modified: Tue, 30 Apr 2013 09:34:09 GMT
ETag: "186e9f-f-b4076640"
X-Via: 172.16.100.107
Accept-Ranges: bytes


在後端服務器172.16.100.12上裝載dav模塊,並開放其dav功能,而後驗正文件上傳效果。開放dav功能的方法如下:

首先啓用如下兩個模塊:
LoadModule dav_module modules/mod_dav.so
LoadModule dav_fs_module modules/mod_dav_fs.so

而後配置相應主機的目錄如下所示,關鍵是其中的dav一行。
<Directory "/var/www/html">
   dav on
   Options Indexes FollowSymLinks
   Order allow,deny
   Allow from all
</Directory>
接着嘗試訪問代理服務器:

# curl -I -T /etc/inittab http://www.magedu.com/
HTTP/1.1 100 Continue
HTTP/1.1 201 Created
Server: nginx/1.4.1
Date: Tue, 14 May 2013 10:20:15 GMT
Content-Type: text/html; charset=UTF-8
Content-Length: 261
Location: http://172.16.100.107/inittab
Connection: keep-alive
X-Via: 172.16.100.107
<!DOCTYPE HTML PUBLIC "-//IETF//DTD HTML 2.0//EN">
<html><head>
<title>201 Created</title>
</head><body>
<h1>Created</h1>
<p>Resource /inittab has been created.</p>
<hr />
<address>Apache/2.2.3 (Red Hat) Server at 172.16.100.12 Port 80</address>
</body></html>




5.2 啓用緩存

http {
    include       mime.types;
    default_type  application/octet-stream;
    sendfile        on;
    keepalive_timeout  65;
    proxy_cache_path /nginx/cache/first  levels=1:2   keys_zone=first:10m max_size=512m;
    server {
        listen       80;
        server_name  www.magedu.com;
        location / {
            root   html;
            index  index.html index.htm;
            if ($request_method ~* "PUT") {
                proxy_pass http://172.16.100.12;
                break;
            }
        }
        location /bbs {
            proxy_pass http://172.16.100.11/;
            proxy_cache first;
            proxy_cache_valid 200 1d;
            proxy_cache_valid 301 302 10m;
            proxy_cache_valid any 1m;
        }
    }
}

5.3 使用upstream

5.3.1 不啓用緩存

http {
    include       mime.types;
    default_type  application/octet-stream;
    sendfile        on;
    keepalive_timeout  65;
    upstream websrv {
        server 172.16.100.11 weight=1;
        server 172.16.100.12 weight=1;
        server 127.0.0.1:8080 backup;
    }
    server {
        listen       80;
        server_name  www.magedu.com;
        add_header X-Via $server_addr;
        location / {
            proxy_pass http://websrv;
            index  index.html index.htm;
            if ($request_method ~* "PUT") {
                proxy_pass http://172.16.100.12;
                break;
            }
        }
        error_page   500 502 503 504  /50x.html;
        location = /50x.html {
            root   html;
        }
    }
    server {
        listen 8080;
        server_name localhost;
        root /nginx/htdocs;
        index index.html;
    }
}

測試效果:默認情況下,nginx對定義了權重的upstream服務器使用加權輪調的方法調度訪問,因此,其多次訪問應該由不同的服務器進行響應。如下所示。

# curl  http://172.16.100.107/
RS2.magedu.com

# curl  http://172.16.100.107/
RS1.magedu.com

根據上面的配置,如果172.16.100.11和172.16.100.12兩個upstream服務器均宕機時,將由本地監聽在8080端口的虛擬主機進行響應。
# curl  http://172.16.100.107/
Sorry...


5.3.2 爲upstream啓用緩存

http {
    include       mime.types;
    default_type  application/octet-stream;
    sendfile        on;
    keepalive_timeout  65;
    proxy_cache_path /nginx/cache/first  levels=1:2   keys_zone=first:10m max_size=512m;
    upstream websrv {
        server 172.16.100.11 weight=1;
        server 172.16.100.12 weight=1;
        server 127.0.0.1:8080 backup;
    }
    server {
        listen       80;
        server_name  www.magedu.com;
        add_header X-Via $server_addr;
        add_header X-Cache-Status $upstream_cache_status;
        location / {
            proxy_pass http://websrv;
            proxy_cache first;
            proxy_cache_valid 200 1d;
            proxy_cache_valid 301 302 10m;
            proxy_cache_valid any 1m;
            index  index.html index.htm;
            if ($request_method ~* "PUT") {
                proxy_pass http://172.16.100.12;
                break;
            }
        }
        error_page   500 502 503 504  /50x.html;
        location = /50x.html {
            root   html;
        }
    }
    server {
        listen 8080;
        server_name localhost;
        root /nginx/htdocs;
        index index.html;
    }
}

第一次訪問某可緩存資源時,在本地緩存中尚未有其對應的緩存對象,因此,其一定爲未命中狀態。而第二次請求時,則可以直接從本地緩存構建響應報文。

# curl -I http://www.magedu.com/
HTTP/1.1 200 OK
Server: nginx/1.4.1
Date: Tue, 14 May 2013 10:53:07 GMT
Content-Type: text/html; charset=UTF-8
Content-Length: 15
Connection: keep-alive
Last-Modified: Tue, 30 Apr 2013 09:34:09 GMT
ETag: "186e9f-f-b4076640"
Accept-Ranges: bytes
X-Via: 172.16.100.107
X-Cache-Status: MISS
# curl -I http://www.magedu.com/
HTTP/1.1 200 OK
Server: nginx/1.4.1
Date: Tue, 14 May 2013 10:53:09 GMT
Content-Type: text/html; charset=UTF-8
Content-Length: 15
Connection: keep-alive
Last-Modified: Tue, 30 Apr 2013 09:34:09 GMT
ETag: "186e9f-f-b4076640"
X-Via: 172.16.100.107
X-Cache-Status: HIT
Accept-Ranges: bytes

六、nginx限速配置

nginx的限速功能通過limit_zone、limit_conn和limit_rate指令進行配置。首先需要在http上下文配置一個limit_zone,然後在需要的地方使用limit_conn和limit_rate 進行限速設置。下面是一個簡單的例子。

http {
  limit_zone  first  $binary_remote_addr  10m;
  server {
    location /downloads/ {
      limit_conn   first  1;
      limit_rate 50k;
    }
  }
}

說明:
limit_zone:語法格式“limit_req_zone $variable zone=name:size rate=rate;”,實現針對每個IP定義一個存儲session狀態的容器。這個示例中定義了一個名叫first的10m大小的容器,這個名字會在後面的limit_conn中使用。
limit_conn first 1; 限制在first中記錄狀態的每個IP只能發起一個併發連接。
limit_rate 50k; 對每個連接限速50k. 注意,這裏是對連接限速,而不是對IP限速。如果一個IP允許三個併發連接,那麼這個IP就是限速爲limit_rate×3,在設置的時候要根據自己的需要做設置調整,要不然會達不到自己希望的目的。



限制連接數的配置如下所示。

limit_conn_zone $binary_remote_addr zone=perip:10m;
limit_conn_zone $server_name zone=perserver:10m;
server {
    ...
    limit_conn perip 10;
    limit_conn perserver 100;
}

七、一個完整配置例(生產環境中使用)

user                              nobody nobody;
worker_processes                  4;
worker_rlimit_nofile              51200;
error_log                         logs/error.log  notice;
pid                               /var/run/nginx.pid;
events {
  use                             epoll;
  worker_connections              51200;
}
http {
  server_tokens                   off;
  include                         mime.types;
  proxy_redirect                off;
  proxy_set_header              Host $host;
  proxy_set_header              X-Real-IP $remote_addr;
  proxy_set_header              X-Forwarded-For $proxy_add_x_forwarded_for;
  client_max_body_size          20m;
  client_body_buffer_size       256k;
  proxy_connect_timeout         90;
  proxy_send_timeout            90;
  proxy_read_timeout            90;
  proxy_buffer_size             128k;
  proxy_buffers                 4 64k;
  proxy_busy_buffers_size       128k;
  proxy_temp_file_write_size    128k;
  default_type                    application/octet-stream;
  charset                         utf-8;
  client_body_temp_path           /var/tmp/client_body_temp 1 2;
  proxy_temp_path                 /var/tmp/proxy_temp 1 2;
  fastcgi_temp_path               /var/tmp/fastcgi_temp 1 2;
  uwsgi_temp_path                 /var/tmp/uwsgi_temp 1 2;
  scgi_temp_path                  /var/tmp/scgi_temp 1 2;
  ignore_invalid_headers          on;
  server_names_hash_max_size      256;
  server_names_hash_bucket_size   64;
  client_header_buffer_size       8k;
  large_client_header_buffers     4 32k;
  connection_pool_size            256;
  request_pool_size               64k;
  output_buffers                  2 128k;
  postpone_output                 1460;
  client_header_timeout           1m;
  client_body_timeout             3m;
  send_timeout                    3m;
  log_format main                 '$server_addr $remote_addr [$time_local] $msec+$connection '
                                  '"$request" $status $connection $request_time $body_bytes_sent "$http_referer" '
                                  '"$http_user_agent" "$http_x_forwarded_for"';
  open_log_file_cache               max=1000 inactive=20s min_uses=1 valid=1m;
  access_log                      logs/access.log      main;
  log_not_found                   on;
  sendfile                        on;
  tcp_nodelay                     on;
  tcp_nopush                      off;
  reset_timedout_connection       on;
  keepalive_timeout               10 5;
  keepalive_requests              100;
  gzip                            on;
  gzip_http_version               1.1;
  gzip_vary                       on;
  gzip_proxied                    any;
  gzip_min_length                 1024;
  gzip_comp_level                 6;
  gzip_buffers                    16 8k;
  gzip_proxied                    expired no-cache no-store private auth no_last_modified no_etag;
  gzip_types                      text/plain application/x-javascript text/css application/xml application/json;
  gzip_disable                    "MSIE [1-6]\.(?!.*SV1)";
  upstream tomcat8080 {
    ip_hash;
    server                        172.16.100.103:8080 weight=1 max_fails=2;
    server                        172.16.100.104:8080 weight=1 max_fails=2;
    server                        172.16.100.105:8080 weight=1 max_fails=2;
  }
  server {
    listen                        80;
    server_name                   www.magedu.com;
    # config_apps_begin
    root                          /data/webapps/htdocs;
    access_log                    /var/logs/webapp.access.log     main;
    error_log                     /var/logs/webapp.error.log      notice;
    location / {
      location ~* ^.*/favicon.ico$ {
        root                      /data/webapps;
        expires                   180d;
        break;
      }
      if ( !-f $request_filename ) {
        proxy_pass                http://tomcat8080;
        break;
      }
    }
    error_page                    500 502 503 504  /50x.html;
      location = /50x.html {
      root                        html;
    }
  }
  server {
    listen                        8088;
    server_name                   nginx_status;
      location / {
          access_log                  off;
          deny                        all;
          return                      503;
      }
      location /status {
          stub_status                 on;
          access_log                  off;
          allow                       127.0.0.1;
          allow                       172.16.100.71;
          deny                        all;
      }
  }
}

          4、timer_resolution t;
               每次內核事件調用返回時,都會使用gettimeofday()來更新nginx緩存時鐘;timer_resolution用於定義每隔多久纔會由gettimeofday()更新一次緩存時鐘;x86-64系統上,gettimeofday()代價已經很小,可以忽略此配置;

           5、worker_priority nice;
               -20,19之間的值;

       事件相關的配置
           1、accept_mutex [on|off]
               是否打開Ningx的負載均衡鎖;此鎖能夠讓多個worker進輪流地、序列化地與新的客戶端建立連接;而通常當一個worker進程的負載達到其上限的7/8,master就儘可能不再將請求調度此worker;

           2、lock_file /path/to/lock_file;
               lock文件

           3、accept_mutex_delay #ms;
               accept鎖模式中,一個worker進程爲取得accept鎖的等待時長;如果某worker進程在某次試圖取得鎖時失敗了,至少要等待#ms才能再一次請求鎖;

           4、multi_accept on|off;
               是否允許一次性地響應多個用戶請求;默認爲Off;

           5、use [epoll|rtsig|select|poll];
               定義使用的事件模型,建議讓nginx自動選擇;

           6、worker_connections #;
               每個worker能夠併發響應最大請求數;

       用於調試、定位問題: 只調試nginx時使用
           1、daemon on|off;
               是否讓ningx運行後臺;默認爲on,調試時可以設置爲off,使得所有信息去接輸出控制檯;

           2、master_process on|off
               是否以master/worker模式運行nginx;默認爲on;調試時可設置off以方便追蹤;

           3、error_log /path/to/error_log level;
               錯誤日誌文件及其級別;默認爲error級別;調試時可以使用debug級別,但要求在編譯時必須使用--with-debug啓用debug功能;

       網絡連接相關的設置:
           1、keepalive_timeout time;
               保持連接的超時時長;默認爲75秒;

           2、keepalive_requests n;
               在一次長連接上允許承載的最大請求數;

           3、keepalive_disable [msie6 | safari | none ]
               對指定的瀏覽器禁止使用長連接;

           4、tcp_nodelay on|off
               對keepalive連接是否使用TCP_NODELAY選項;

           5、client_header_timeout time;
               讀取http請求首部的超時時長;

           6、client_body_timeout time;
               讀取http請求包體的超時時長;

           7、send_timeout time;
               發送響應的超時時長;

       對客戶端請求的限制:
           1、limit_except method ... { ... }
               指定對範圍之外的其它方法的訪問控制;

               limit_except GET {
                   allow 172.16.0.0/16;
                   deny all;
               }

           2、client_max_body_size SIZE;
               http請求包體的最大值;常用於限定客戶所能夠請求的最大包體;根據請求首部中的Content-Length來檢測,以避免無用的傳輸;

           3、limit_rate speed;
               限制客戶端每秒鐘傳輸的字節數;默認爲0,表示沒有限制;

           4、limit_rate_after time;
               nginx向客戶發送響應報文時,如果時長超出了此處指定的時長,則後續的發送過程開始限速;

       文件操作的優化:
           1、sendfile on|off
               是否啓用sendfile功能;

           2、aio on|off
               是否啓用aio功能;

           3、open_file_cache max=N [inactive=time]|off
               是否打開文件緩存功能;
                   max: 緩存條目的最大值;當滿了以後將根據LRU算法進行置換;
                   inactive: 某緩存條目在指定時長時沒有被訪問過時,將自動被刪除;默認爲60s;

               緩存的信息包括:
                   文件句柄、文件大小和上次修改時間;
                   已經打開的目錄結構;
                   沒有找到或沒有訪問權限的信息;

           4、open_file_cache_errors on|off
               是否緩存文件找不到或沒有權限訪問等相關信息;

           5、open_file_cache_valid time;
               多長時間檢查一次緩存中的條目是否超出非活動時長,默認爲60s;

           6、open_file_cache_min_use #;
               在inactive指定的時長內被訪問超此處指定的次數地,纔不會被刪除;

       對客戶端請求的特殊處理:
           1、ignore_invalid_headers on|off
               是否忽略不合法的http首部;默認爲on; off意味着請求首部中出現不合規的首部將拒絕響應;只能用於server和http;

           2、log_not_found on|off
               是否將文件找不到的信息也記錄進錯誤日誌中;

           3、resolver address;
               指定nginx使用的dns服務器地址;

           4、resover_timeout time;
               指定DNS解析超時時長,默認爲30s;

           5、server_tokens on|off;
               是否在錯誤頁面中顯示nginx的版本號;

       內存及磁盤資源分配:
           1、client_body_in_file_only on|clean|off
               HTTP的包體是否存儲在磁盤文件中;非off表示存儲,即使包體大小爲0也會創建一個磁盤文件;on表示請求結束後包體文件不會被刪除,clean表示會被刪除;

           2、client_body_in_single_buffer on|off;
               HTTP的包體是否存儲在內存buffer當中;默認爲off;

           3、cleint_body_buffer_size size;
               nginx接收HTTP包體的內存緩衝區大小;

           4、client_body_temp_path dir-path [level1 [level2 [level3]]];
               HTTP包體存放的臨時目錄;
               client_body_temp_path /var/tmp/client/  1 2

           5、client_header_buffer_size size;
               正常情況下接收用戶請求的http報文header部分時分配的buffer大小;默認爲1k;

           6、large_client_header_buffers number size;
               存儲超大Http請求首部的內存buffer大小及個數;

           7、connection_pool_size size;
               nginx對於每個建立成功的tcp連接都會預先分配一個內存池,此處即用於設定此內存池的初始大小;默認爲256;

           8、request_pool_size size;
               nginx在處理每個http請求時會預先分配一個內存池,此處即用於設定此內存池的初始大小;默認爲4k;



http核心模塊的內置變量:
           $uri: 當前請求的uri,不帶參數;
           $request_uri: 請求的uri,帶完整參數;
           $host: http請求報文中host首部;如果請求中沒有host首部,則以處理此請求的虛擬主機的主機名代替;
           $hostname: nginx服務運行在的主機的主機名;
           $remote_addr: 客戶端IP
           $remote_port: 客戶端Port
           $remote_user: 使用用戶認證時客戶端用戶輸入的用戶名;
           $request_filename: 用戶請求中的URI經過本地root或alias轉換後映射的本地的文件路徑;
           $request_method: 請求方法
           $server_addr: 服務器地址
           $server_name: 服務器名稱
           $server_port: 服務器端口
           $server_protocol: 服務器向客戶端發送響應時的協議,如http/1.1, http/1.0
           $scheme: 在請求中使用scheme, 如https://www.magedu.com/中的https;
           $http_HEADER: 匹配請求報文中指定的HEADER,$http_host匹配請求報文中的host首部
           $sent_http_HEADER: 匹配響應報文中指定的HEADER,例如$http_content_type匹配響應報文中的content-type首部;
           $document_root:當前請求映射到的root配置;



傳統上基於進程或線程模型架構的web服務通過每進程或每線程處理併發連接請求,這勢必會在網絡和I/O操作時產生阻塞,其另一個必然結果則是對內存或CPU的利用率低下。生成一個新的進程/線程需要事先備好其運行時環境,這包括爲其分配堆內存和棧內存,以及爲其創建新的執行上下文等。這些操作都需要佔用CPU,而且過多的進程/線程還會帶來線程抖動或頻繁的上下文切換,系統性能也會由此進一步下降。

在設計的最初階段,nginx的主要着眼點就是其高性能以及對物理計算資源的高密度利用,因此其採用了不同的架構模型。受啓發於多種操作系統設計中基於“事件”的高級處理機制,nginx採用了模塊化、事件驅動、異步、單線程及非阻塞的架構,並大量採用了多路複用及事件通知機制。在nginx中,連接請求由爲數不多的幾個僅包含一個線程的進程worker以高效的迴環(run-loop)機制進行處理,而每個worker可以並行處理數千個的併發連接及請求。

如果負載以CPU密集型應用爲主,如SSL或壓縮應用,則worker數應與CPU數相同;如果負載以IO密集型爲主,如響應大量內容給客戶端,則worker數應該爲CPU個數的1.5或2倍。

nginx會按需同時運行多個進程:一個主進程(master)和幾個工作進程(worker),配置了緩存時還會有緩存加載器進程(cache loader)和緩存管理器進程(cache manager)等。所有進程均是僅含有一個線程,並主要通過“共享內存”的機制實現進程間通信。主進程以root用戶身份運行,而worker、cache loader和cache manager均應以非特權用戶身份運行。

主進程主要完成如下工作:
1. 讀取並驗正配置信息;
2. 創建、綁定及關閉套接字;
3. 啓動、終止及維護worker進程的個數;
4. 無須中止服務而重新配置工作特性;
5. 控制非中斷式程序升級,啓用新的二進制程序並在需要時回滾至老版本;
6. 重新打開日誌文件,實現日誌滾動;
7. 編譯嵌入式perl腳本;

worker進程主要完成的任務包括:
1. 接收、傳入並處理來自客戶端的連接;
2. 提供反向代理及過濾功能;
3. nginx任何能完成的其它任務;

cache loader進程主要完成的任務包括:
1. 檢查緩存存儲中的緩存對象;
2. 使用緩存元數據建立內存數據庫;

cache manager進程的主要任務:
1. 緩存的失效及過期檢驗;

nginx的配置有着幾個不同的上下文:main、http、server、upstream和location(還有實現郵件服務反向代理的mail)。配置語法的格式和定義方式遵循所謂的C風格,因此支持嵌套,還有着邏輯清晰並易於創建、閱讀和維護等優勢。


nginx的代碼是由一個核心和一系列的模塊組成, 核心主要用於提供Web Server的基本功能,以及Web和Mail反向代理的功能;還用於啓用網絡協議,創建必要的運行時環境以及確保不同的模塊之間平滑地進行交互。不過,大多跟協議相關的功能和某應用特有的功能都是由nginx的模塊實現的。這些功能模塊大致可以分爲事件模塊、階段性處理器、輸出過濾器、變量處理器、協議、upstream和負載均衡幾個類別,這些共同組成了nginx的http功能。事件模塊主要用於提供OS獨立的(不同操作系統的事件機制有所不同)事件通知機制如kqueue或epoll等。協議模塊則負責實現nginx通過http、tls/ssl、smtp、pop3以及imap與對應的客戶端建立會話。

在nginx內部,進程間的通信是通過模塊的pipeline或chain實現的;換句話說,每一個功能或操作都由一個模塊來實現。例如,壓縮、通過FastCGI或uwsgi協議與upstream服務器通信,以及與memcached建立會話等。




應用實例: 搭建Lnmmp
一、安裝nginx:

1、解決依賴關係

編譯安裝nginx需要事先需要安裝開發包組"Development Tools"和 "Development Libraries"。同時,還需要專門安裝pcre-devel包:

# yum -y install pcre-devel

2、安裝

首先添加用戶nginx,實現以之運行nginx服務進程:

# groupadd -r nginx
# useradd -r -g nginx nginx


接着開始編譯和安裝:

# ./configure \
  --prefix=/usr/local/nginx \
  --sbin-path=/usr/local/nginx/sbin/nginx \
  --conf-path=/etc/nginx/nginx.conf \
  --error-log-path=/var/log/nginx/error.log \
  --http-log-path=/var/log/nginx/access.log \
  --pid-path=/var/run/nginx/nginx.pid  \
  --lock-path=/var/lock/nginx.lock \
  --user=nginx \
  --group=nginx \
  --with-http_ssl_module \
  --with-http_flv_module \
  --with-http_stub_status_module \
  --with-http_gzip_static_module \
  --http-client-body-temp-path=/var/tmp/nginx/client/ \
  --http-proxy-temp-path=/var/tmp/nginx/proxy/ \
  --http-fastcgi-temp-path=/var/tmp/nginx/fcgi/ \
  --http-uwsgi-temp-path=/var/tmp/nginx/uwsgi \
  --http-scgi-temp-path=/var/tmp/nginx/scgi \
  --with-pcre
# make && make install


3、爲nginx提供SysV init腳本:

新建文件/etc/rc.d/init.d/nginx,內容如下:

#!/bin/sh
#
# nginx - this script starts and stops the nginx daemon
#
# chkconfig:   - 85 15
# description:  nginx is an HTTP(S) server, HTTP(S) reverse \
#               proxy and IMAP/POP3 proxy server
# processname: nginx
# config:      /etc/nginx/nginx.conf
# config:      /etc/sysconfig/nginx
# pidfile:     /var/run/nginx.pid
# Source function library.
. /etc/rc.d/init.d/functions
# Source networking configuration.
. /etc/sysconfig/network
# Check that networking is up.
[ "$NETWORKING" = "no" ] && exit 0
nginx="/usr/sbin/nginx"
prog=$(basename $nginx)
nginx_CONF_FILE="/etc/nginx/nginx.conf"
[ -f /etc/sysconfig/nginx ] && . /etc/sysconfig/nginx
lockfile=/var/lock/subsys/nginx
make_dirs() {
   # make required directories
   user=`nginx -V 2>&1 | grep "configure arguments:" | sed 's/[^*]*--user=\([^ ]*\).*/\1/g' -`
   options=`$nginx -V 2>&1 | grep 'configure arguments:'`
   for opt in $options; do
       if [ `echo $opt | grep '.*-temp-path'` ]; then
           value=`echo $opt | cut -d "=" -f 2`
           if [ ! -d "$value" ]; then
               # echo "creating" $value
               mkdir -p $value && chown -R $user $value
           fi
       fi
   done
}
start() {
    [ -x $nginx ] || exit 5
    [ -f $nginx_CONF_FILE ] || exit 6
    make_dirs
    echo -n $"Starting $prog: "
    daemon $nginx -c $nginx_CONF_FILE
    retval=$?
    echo
    [ $retval -eq 0 ] && touch $lockfile
    return $retval
}
stop() {
    echo -n $"Stopping $prog: "
    killproc $prog -QUIT
    retval=$?
    echo
    [ $retval -eq 0 ] && rm -f $lockfile
    return $retval
}
restart() {
    configtest || return $?
    stop
    sleep 1
    start
}
reload() {
    configtest || return $?
    echo -n $"Reloading $prog: "
    killproc $nginx -HUP
    RETVAL=$?
    echo
}
force_reload() {
    restart
}
configtest() {
  $nginx -t -c $nginx_CONF_FILE
}
rh_status() {
    status $prog
}
rh_status_q() {
    rh_status >/dev/null 2>&1
}
case "$1" in
    start)
        rh_status_q && exit 0
        $1
        ;;
    stop)
        rh_status_q || exit 0
        $1
        ;;
    restart|configtest)
        $1
        ;;
    reload)
        rh_status_q || exit 7
        $1
        ;;
    force-reload)
        force_reload
        ;;
    status)
        rh_status
        ;;
    condrestart|try-restart)
        rh_status_q || exit 0
            ;;
    *)
        echo $"Usage: $0 {start|stop|status|restart|condrestart|try-restart|reload|force-reload|configtest}"
        exit 2
esac



而後爲此腳本賦予執行權限:

# chmod +x /etc/rc.d/init.d/nginx

添加至服務管理列表,並讓其開機自動啓動:

# chkconfig --add nginx
# chkconfig nginx on

而後就可以啓動服務並測試了:

# service nginx start


nginx的http web功能:

       虛擬主機相關的配置:    
           1、server {}
               定義一個虛擬主機;nginx支持使用基於主機名或IP的虛擬主機;



           2、listen
               listen address[:port];
               listen port

               default_server:定義此server爲http中默認的server;如果所有的server中沒有任何一個listen使用此參數,那麼第一個server即爲默認server;
               rcvbuf=SIZE: 接收緩衝大小;
               sndbuf=SIZE: 發送緩衝大小;
               ssl: https server;

           3、server_name [...];
               server_name可以跟多個主機名,名稱中可以使用通配符和正則表達式(通常以~開頭);當nginx收到一個請求時,會取出其首部的server的值,而後跟衆server_name進行比較;比較方式:
                   (1) 先做精確匹配;www.magedu.com
                   (2) 左側通配符匹配;*.magedu.com
                   (3) 右側通配符匹配;www.abc.com, www.*
                   (4) 正則表達式匹配: ~^.*\.magedu\.com$

           4、server_name_hash_bucket_size 32|64|128;
               爲了實現快速主機查找,nginx使用hash表來保存主機名;

           5、location [ = | ~ | ~* | ^~ ] uri { ... }
              location @name { ... }
              功能:允許根據用戶請求的URI來匹配指定的各location以進行訪問配置;匹配到時,將被location塊中的配置所處理;比如:http://www.magedu.com/images/logo.gif

              =:精確匹配;
              ~:正則表達式模式匹配,匹配時區分字符大小寫
              ~*:正則表達式模式匹配,匹配時忽略字符大小寫
              ^~: URI前半部分匹配,不檢查正則表達式

                  http://www.magedu.com/index.html
                  http://www.magedu.com/
                  http://www.magedu.com/documents/index.html
                  http://www.magedu.com/images/index.html
                  http://www.magedu.com/images/a.png

                匹配優先級:
                    字符字面量最精確匹配、正則表達式檢索(由第一個匹配到所處理)、按字符字面量

       文件路徑定義:
           1、root path
               設置web資源路徑;用於指定請求的根文檔目錄;
               location / {
                   root /www/htdocs;
               }

               location ^~ /images/ {
                   root /web;
               }

               root: root/URI/

                   http://www.magedu.com/images/b.html



2、alias path
只能用於location中,用於路徑別名;路徑別名;如下圖所示;將訪問/firefox/*能夠訪問物理路徑下的/Mozilla/*

    location ^~ /firefox {
        alias /moziila;
}

wKiom1NaYWTDXioqAABxPbbrvUw787.jpg

[root@node5 moziila]# pwd
/moziila
[root@node5 moziila]# ls
b.html  firefox


3、index file ...;
定義默認頁面,可參跟多個值;

index  index.html index.htm;


4、error_page code ... [=[response]] uri;
當對於某個請求返回錯誤時,如果匹配上了error_page指令中設定的code,則重定向到新的URI中。錯誤頁面重定向;如果響應碼爲404則將頁面轉到/www/htdoc/404.htm   至於等於200;是爲了不讓它寫入錯誤日誌當中;

server {
        listen       80;
        server_name  localhost;
        error_page 404 =200 /404.html; ########################
        #charset koi8-r;
        #access_log  logs/host.access.log  main;
        location / {
            root   /www/htdoc;
            index  index.html index.htm;
        }
        location ^~ /firefox {
        alias /moziila;
}
[root@node5 nginx]# cd /www/htdoc/
[root@node5 htdoc]# pwd
/www/htdoc
[root@node5 htdoc]# ls
404.html  index.html
[root@node5 htdoc]# cat 404.html
<h1>This page not found<h1>

wKiom1NaZErydVauAACTlOYL0BA209.jpg

172.16.250.248 - - [25/Apr/2014:21:30:17 +0800] "GET /asdasdasd HTTP/1.1" 200 28 "-" "Mozilla/5.0 (Windows NT 6.1; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/33.0.1750.149 Safari/537.36"
172.16.250.248 - - [25/Apr/2014:21:30:18 +0800] "GET /favicon.ico HTTP/1.1" 200 0 "-" "Mozilla/5.0 (Windows NT 6.1; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/33.0.1750.149 Safari/537.36"
[root@node5 www]# cat /var/log/nginx/access.log



5、防盜鏈
(1) 定義合規的引用
valid_referers none | blocked | server_names | string ...;
(2) 拒絕不合規的引用
if  ($invalid_referer) {
rewrite ^/.*$ http://www.b.org/403.html
}

server {
        listen       80;
        server_name  www.baidu.org;
        #charset koi8-r;
        #access_log  logs/host.access.log  main;
        location / {
            root   /www/baidu.org/;
            index  index.html index.htm;
        }
        location /download/ {
        root /www/baidu.org/;
        autoindex on;
        rewrite ^/download/(.*\.(jpg|gif|jpeg|png))$ /images/$1 last;
        rewrite_log on;
}
############################################################### 如下:防盜鏈
        location ~* \.(jpg|png|gif|jpeg)$ {
            root /www/baidu.org;
            valid_referers none blocked www.baidu.org *.baidu.org;
            if ($invalid_referer) {
                rewrite ^/ http://www.baidu.org/403.html;
            }
        }
[root@node5 nginx]# cd /www/baidu.org/
[root@node5 baidu.org]# pwd
/www/baidu.org
[root@node5 baidu.org]# cat index.html
www.baidu.org
<img src="http://172.16.249.27/images/1.jpg">
#####################自己域內中的服務器使用####################
[root@node5 baidu.org]# cd /www/firefox.com/
[root@node5 firefox.com]# cat index.html
<h1>www.firefox.com<h1>
<img src="http://172.16.249.27/images/1.jpg">
####################不是屬於本區域內的服務器###################

wKioL1NadaDiis4zAAdJYOzFm44188.jpg

wKiom1NaddvQdNQOAACy1ekAAh4222.jpg

6、URL rewrite
       rewrite regex replacement [flag];

   location / {
            root   /www/baidu.org/;
            index  index.html index.htm;
        }
        location /download/ {
        root /www/baidu.org/;
        autoindex on;
        rewrite ^/download/(.*\.(jpg|gif|jpeg|png))$ /images/$1 last;
        rewrite_log on;
}

  URL rewrite  註釋:只要url路徑開頭指的是/download/.*jpg..... 都將它重寫到/www/baidu.org/images/*.jpg

[root@node5 baidu.org]# pwd
/www/baidu.org
[root@node5 baidu.org]# ls
download  images  index.html
[root@node5 baidu.org]# ls download/
[root@node5 baidu.org]# ls images/
1.jpg  200832621323760509.jpg  2.jpg  3.jpeg  firefox.html

wKiom1Naa_nDYKopAAbDYMgzUn0619.jpg
last: 一旦被當前規則匹配並重寫後立即停止檢查後續的其它rewrite的規則,而後通過重寫後的規則重新發起請求;
break: 一旦被當前規則匹配並重寫後立即停止後續的其它rewrite的規則,而後繼續由TenGine進行後續操作;
redirect: 返回302臨時重定向;
permanent: 返回301永久重定向;

nginx最多循環10次,超出之後會返回500錯誤;
注意:一般將rewrite寫在location中時都使用break標誌,或者將rewrite寫在if上下文中;
rewrite_log on|off
是否把重寫過程記錄在錯誤日誌中;默認爲notice級別;默認爲off;

172.16.250.248 - - [25/Apr/2014:21:55:47 +0800] "GET /download/1.jpg HTTP/1.1" 200 104372 "-" "Mozilla/5.0 (Windows NT 6.1; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/33.0.1750.149 Safari/537.36"

return code:
用於結束rewrite規則,並且爲客戶返回狀態碼;可以使用的狀態碼有204, 400, 402-406, 500-504等;
if (condition) {
}

7、 啓用壓縮功能;

gzip on;
gzip_http_version 1.0;
gzip_comp_level 2;
gzip_types text/plain text/css images/jpeg application/x-javascript text/xml application/xml application/xml+rss text/javascript application/javascript application/json;
gzip_disable msie6;


8、upstream使用注意:
1、只能用於http上下文;
2、各server只能直接使用IP或主機名,不要加協議;
server address [parameters];
weight=#: 設定權重
max_fails=#: 最大失敗嘗試次數,默認爲1;
fail_timeout=time: 失敗嘗試超時時長;默認爲10秒;

upstream webservers {
       server 172.16.249.109 weight=3 max_fails=2 fail_timeout=3;
       server 172.16.249.72 weight=1 max_fails=2 fail_timeout=3;
       server 127.0.0.1:8080 backup;
       #ip_hash;
       least_conn;
   }

 其中proxy_set_header作用是;後端服務器;顯示真實客戶端的IP地址;(least_conn)最少連接(least connected, lc), 加權最少連接(weighted least connection, wlc)——新的連接請求將被分配至當前連接數最少的RealServer;最小連接調度是一種動態調度算法,它通過服務器當前所活躍的連接數來估計服務器的負載情況。調度器需要記錄各個服務器已建立連接的數目,當一個請求被調度到某臺服務器,其連接數加1;當連接中止或超時,其連接數減一。

server {
        listen 80;
        server_name www.henhenlu.net;
        location / {
            proxy_pass http://webservers;
            proxy_set_header X-Real-IP $remote_addr;
        }
    }
    server {
        listen 8080; ###################################################
        server_name 127.0.0.1;
        root /www/backup;
    }
}

   後端webserver需要將日誌的格式修改

LogFormat "%{X-Real-IP}i %l %u %t \"%r\" %>s %b \"%{Referer}i\" \"%{User-Agent}i\"" combined

   修改之前;

172.16.249.27 - - [28/Mar/2014:17:06:52 +0800] "GET / HTTP/1.0" 304 - "-" "Mozilla/5.0 (Windows NT 6.1; WOW64; rv:28.0) Gecko/20100101 Firefox/28.0"

   修改之後;  

172.16.250.248 - - [28/Mar/2014:17:30:25 +0800] "GET / HTTP/1.0" 304 - "-" "Mozilla/5.0 (Windows NT 6.1; WOW64; rv:28.0) Gecko/20100101 Firefox/28.0"

wKiom1NbCazTQqPNAABYvWjEjjY250.jpg

wKiom1NbCeHCRZTnAABT9yEoaKI028.jpg


使用add_header添加自定義的http首部信息;

server {
      listen 80;
      server_name www.henhenlu.net;
      add_header X-Via $server_addr;
      location / {
          proxy_pass http://webservers;
          proxy_set_header X-Real-IP $remote_addr;
      }
  }
Accept-Ranges:bytes
Connection:keep-alive
Content-Length:14
Content-Type:text/html; charset=UTF-8
Date:Fri, 25 Apr 2014 16:39:00 GMT
ETag:"e0569-e-4f718c607dcc2"
Last-Modified:Tue, 15 Apr 2014 18:14:40 GMT
Server:nginx/1.4.7
X-Via:172.16.249.27


9、使用nginx反向代理並緩存;

1、proxy指令:
proxy_pass URL;
2、proxy_set_header
3、proxy_hide_header
4、proxy_pass_header
5、proxy_pass_request_body: 是否將http請求報文的包體部分發往上游服務器;
6、proxy_pass_request_header: 是否將Http首部發往上游服務器;
7、proxy_redirect [default|off|redirect|replacement]
當上遊服務器返回的響應是重定向或刷新請求時,proxy_redirect會重新設定http首部的location或refresh;
http://www.magedu.com/images/some/path, http://localhost:8080/imgs/some/path,
proxy_redirect http://localhost:8080/imgs
http://www.magedu.com/images

proxy_cache_path /cache/webserver levels=1:2 keys_zone=web:100m max_size=1g inactive=12h;
  server {
        listen 80;
        server_name www.henhenlu.net;
        add_header X-Via $server_addr;
        add_header X-Cache $upstream_cache_status;
        location / {
            proxy_pass http://webservers;
            proxy_cache web;
            proxy_cache_valid 200 2h;
            proxy_cache_valid 301 302 10m;
            proxy_cache_valid any 1m;
            #health_check uri=/.health.html match=webcheck;
            #health_check;
            proxy_set_header X-Real-IP $remote_addr;
        }
    }

x-Cache是我們自定義的字段;查看服務器的緩存是否命中;HIT表示命中了;miss....表示沒有命中

Connection:keep-alive
Date:Fri, 25 Apr 2014 17:06:48 GMT
ETag:"c0100-f-4f4796c66319a"
Last-Modified:Thu, 13 Mar 2014 09:17:33 GMT
Server:nginx/1.4.7
X-Cache:HIT
X-Via:172.16.249.27


10、使用Nginx反向代理;使網頁文本;與圖片分離;

server {
      listen 80;
      server_name www.henhenlu.net;
      add_header X-Via $server_addr;
      add_header X-Cache $upstream_cache_status;
      location / {
          proxy_pass http://172.16.249.72;
          proxy_cache web;
          proxy_cache_valid 200 2h;
          proxy_cache_valid 301 302 10m;
          proxy_cache_valid any 1m;
          #health_check uri=/.health.html match=webcheck;
          #health_check;
          proxy_set_header X-Real-IP $remote_addr;
      }
       location ~*\.(jpg|jpeg|png|gif)$ {
          proxy_pass http://172.16.249.168;
          proxy_cache web;
          proxy_cache_valid 200 2h;
          proxy_cache_valid 301 302 10m;
          proxy_cache_valid any 1m;
  }
      }

   後端server IP:172.16.249.72

[root@station145 html]# cat index.html
172.16.249.72
[root@station145 html]# ls
index.html

   後端server IP :172.16.248.168

[root@station20 html]# pwd
/var/www/html
[root@station20 html]# ls
1.jpg  2.jpg  3.jpeg  linux.jpg


11、使用Nginx反向代理;php-fpm;並緩存;

fastcgi模塊的常用指令:
fastcgi_pass: 指定fastcgi服務監聽端口、地址;也支持使用Unix sock;
fastcgi_bind: 指定聯繫fpm服務時使用的地址;
fastcgi_param: 定義傳遞給fpm服務器的參數;
fastcgi_index: php的主頁面文件;
結果可以緩存,緩存空間使用fastcgi_cache_path定義,使用fastcgi_cache來調用;
fastcgi_cache_path 定義在全局配置文件當中;
fastcgi_cache : 使用fastcgi_cache來調用;
fastcgi_cache_valid 定義合法的時間;
fastcgi_connect_timeout: 連接fastcgi服務器的超時時長;

fastcgi_send_timeout: 向fastcgi服務傳輸數據的超時時長

1、編輯/etc/nginx/nginx.conf,啓用如下選項:
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;
        }
2、編輯/etc/nginx/fastcgi_params,將其內容更改爲如下內容:
fastcgi_param  GATEWAY_INTERFACE  CGI/1.1;
fastcgi_param  SERVER_SOFTWARE    nginx;
fastcgi_param  QUERY_STRING       $query_string;
fastcgi_param  REQUEST_METHOD     $request_method;
fastcgi_param  CONTENT_TYPE       $content_type;
fastcgi_param  CONTENT_LENGTH     $content_length;
fastcgi_param  SCRIPT_FILENAME    $document_root$fastcgi_script_name;
fastcgi_param  SCRIPT_NAME        $fastcgi_script_name;
fastcgi_param  REQUEST_URI        $request_uri;
fastcgi_param  DOCUMENT_URI       $document_uri;
fastcgi_param  DOCUMENT_ROOT      $document_root;
fastcgi_param  SERVER_PROTOCOL    $server_protocol;
fastcgi_param  REMOTE_ADDR        $remote_addr;
fastcgi_param  REMOTE_PORT        $remote_port;
fastcgi_param  SERVER_ADDR        $server_addr;
fastcgi_param  SERVER_PORT        $server_port;
fastcgi_param  SERVER_NAME        $server_name;


fastcgi_cache_path /cache/fastcgi  levels=1:2 keys_zone=fcgi:50m max_size=1g inactive=12h;
    server {
    listen 80;
    server_name www.henhenlu.net;
    add_header X-Via $server_addr;
    add_header X-Cache $upstream_cache_status;
    location / {
        root          /www/baidu.org  ;
        index          index.php index.html index.htm;
        fastcgi_pass   127.0.0.1:9000;
        fastcgi_index  index.php;
        fastcgi_param  SCRIPT_FILENAME  /scripts$fastcgi_script_name;
        include        fastcgi_params;
            fastcgi_cache fcgi;
            fastcgi_cache_valid 200 1h;
            fastcgi_cache_valid 301 302 5m;
            fastcgi_cache_valid any 1m;
    }
}
[root@node5 ~]# ab -n 1000 -c 100 http://172.16.249.27/index.php
This is ApacheBench, Version 2.3 <$Revision: 655654 $>
Copyright 1996 Adam Twiss, Zeus Technology Ltd, http://www.zeustech.net/
Licensed to The Apache Software Foundation, http://www.apache.org/
Benchmarking 172.16.249.27 (be patient)
Completed 100 requests
Completed 200 requests
Completed 300 requests
Completed 400 requests
Completed 500 requests
Completed 600 requests
Completed 700 requests
Completed 800 requests
Completed 900 requests
Completed 1000 requests
Finished 1000 requests
Server Software:        nginx/1.4.7
Server Hostname:        172.16.249.27
Server Port:            80
Document Path:          /index.php
Document Length:        62358 bytes
Concurrency Level:      100
Time taken for tests:   0.565 seconds
Complete requests:      1000
Failed requests:        0
Write errors:           0
Total transferred:      62541000 bytes
HTML transferred:       62358000 bytes
Requests per second:    1769.37 [#/sec] (mean)
Time per request:       56.517 [ms] (mean)
Time per request:       0.565 [ms] (mean, across all concurrent requests)
Transfer rate:          108064.60 [Kbytes/sec] received
Connection Times (ms)
              min  mean[+/-sd] median   max
Connect:        0    3   5.0      0      66
Processing:    10   51  23.7     50     130
Waiting:        0   49  22.0     50     125
Total:         24   54  21.1     51     130
Percentage of the requests served within a certain time (ms)
  50%     51
  66%     54
  75%     57
  80%     61
  90%     89
  95%    107
  98%    125
  99%    128
 100%    130 (longest request)


二、安裝 mariadb-10.0.10-linux-x86_64

# mkdir  /mydata/data -pv
# useradd  -r mysql
# chown  -R mysql.mysql /mydata/data/
# tar xf  mariadb-10.0.10-linux-x86_64.tar.gz  -C /usr/local
# cd /usr/local
# ln -sv mariadb-10.0.10-linux-x86_64/ mysql
# cd mysql/
# chown  -R root.mysql ./*
# scripts/mysql_install_db  --user=mysql --datadir=/mydata/data/
[root@localhost mysql]# mkdir  /etc/mysql
[root@localhost mysql]# cp support-files/my-large.cnf  /etc/mysql/my.cnf
[root@localhost mysql]# cp support-files/mysql.server  /etc/rc.d/init.d/mysqld
[root@localhost mysql]# chmod  +x  /etc/rc.d/init.d/mysqld
[root@localhost mysql]# chkconfig  --add mysqld
[root@localhost mysql]# chkconfig  mysqld on
# vim /etc/mysql/my.cnf
datadir= /mydata/data
innodb_file_per_table=ON

三、編譯安裝php-5.4.4
1、解決依賴關係

# yum -y groupinstall "Desktop Platform Development"
# yum -y install bzip2-devel libmcrypt-devel
# tar xf php-5.4.26.tar.bz2
# cd php-5.4.26
# ./configure --prefix=/usr/local/php  --with-openssl --enable-fpm --enable-sockets --enable-sysvshm  --with-mysql=mysqlnd --with-pdo-mysql=mysqlnd --with-mysqli=mysqlnd   --enable-mbstring --with-freetype-dir --with-jpeg-dir --with-png-dir --with-zlib-dir --with-libxml-dir=/usr --enable-xml  --with-mhash --with-mcrypt  --with-config-file-path=/etc --with-config-file-scan-dir=/etc/php.d --with-bz2 --with-curl
# make && make install

註釋: 缺什麼包;就安裝那個包名或庫名後面加上--devel就行啦;;!

爲php提供配置文件:
# cp php.ini-production /etc/php.ini
爲php-fpm提供Sysv init腳本,並將其添加至服務列表:
# cp sapi/fpm/init.d.php-fpm  /etc/rc.d/init.d/php-fpm
# chmod +x /etc/rc.d/init.d/php-fpm
# chkconfig --add php-fpm
# chkconfig php-fpm on
爲php-fpm提供配置文件:
# cp /usr/local/php/etc/php-fpm.conf.default /usr/local/php/etc/php-fpm.conf
編輯php-fpm的配置文件:
# vim /usr/local/php/etc/php-fpm.conf
配置fpm的相關選項爲你所需要的值,並啓用pid文件(如下最後一行):
pm.max_children = 150
pm.start_servers = 8
pm.min_spare_servers = 5
pm.max_spare_servers = 10
pid = /usr/local/php/var/run/php-fpm.pid
接下來就可以啓動php-fpm了:
# service php-fpm start
使用如下命令來驗正(如果此命令輸出有中幾個php-fpm進程就說明啓動成功了):
# ps aux | grep php-fpm




四、整合nginx和php5

1、編輯/etc/nginx/nginx.conf,啓用如下選項:

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;
        }
2、編輯/etc/nginx/fastcgi_params,將其內容更改爲如下內容:
fastcgi_param  GATEWAY_INTERFACE  CGI/1.1;
fastcgi_param  SERVER_SOFTWARE    nginx;
fastcgi_param  QUERY_STRING       $query_string;
fastcgi_param  REQUEST_METHOD     $request_method;
fastcgi_param  CONTENT_TYPE       $content_type;
fastcgi_param  CONTENT_LENGTH     $content_length;
fastcgi_param  SCRIPT_FILENAME    $document_root$fastcgi_script_name;
fastcgi_param  SCRIPT_NAME        $fastcgi_script_name;
fastcgi_param  REQUEST_URI        $request_uri;
fastcgi_param  DOCUMENT_URI       $document_uri;
fastcgi_param  DOCUMENT_ROOT      $document_root;
fastcgi_param  SERVER_PROTOCOL    $server_protocol;
fastcgi_param  REMOTE_ADDR        $remote_addr;
fastcgi_param  REMOTE_PORT        $remote_port;
fastcgi_param  SERVER_ADDR        $server_addr;
fastcgi_param  SERVER_PORT        $server_port;
fastcgi_param  SERVER_NAME        $server_name;

並在所支持的主頁面格式中添加php格式的主頁,類似如下:

location / {
            root   html;
            index  index.php index.html index.htm;
        }

而後重新載入nginx的配置文件:
# service nginx reload

3、在/usr/html新建index.php的測試頁面,測試php是否能正常工作:
# cat > /usr/html/index.php << EOF
<?php
phpinfo();
?>

接着就可以通過瀏覽器訪問此測試頁面了。

wKioL1NbVPbjwnunAAEV-9UVwFM723.jpg




五、安裝xcache,爲php加速:

1、安裝

# tar xf xcache-2.0.0.tar.gz
# cd xcache-2.0.0
# /usr/local/php/bin/phpize
# ./configure --enable-xcache --with-php-config=/usr/local/php/bin/php-config
# make && make install

安裝結束時,會出現類似如下行:
Installing shared extensions:     /usr/local/php/lib/php/extensions/no-debug-zts-20100525/

2、編輯php.ini,整合php和xcache:

首先將xcache提供的樣例配置導入php.ini
# mkdir /etc/php.d
# cp xcache.ini /etc/php.d

說明:xcache.ini文件在xcache的源碼目錄中。

接下來編輯/etc/php.d/xcache.ini,找到zend_extension開頭的行,修改爲如下行:
extension =  /usr/local/php/lib/php/extensions/no-debug-non-zts-20100525/xcache.so

注意:如果xcache.ini文件中有多條extension指令行,要確保此新增的行排在第一位。
3、重新啓動php-fpm
# service php-fpm restart
wKiom1NbVQ2z84QJAABKn1tDDb4753.jpg


六、補充說明

如果要在SSL中使用php,需要在php的location中添加此選項:

fastcgi_param HTTPS on;


Memcached是一款開源、高性能、分佈式內存對象緩存系統,可應用各種需要緩存的場景,其主要目的是通過降低對Database的訪問來加速web應用程序。它是一個基於內存的“鍵值對”存儲,用於存儲數據庫調用、API調用或頁面引用結果的直接數據,如字符串、對象等。

memcached是以LiveJournal旗下Danga Interactive 公司的Brad Fitzpatric 爲首開發的一款軟件。現在
已成爲mixi、hatena、Facebook、Vox、LiveJournal等衆多服務中提高Web應用擴展性的重要因素。

Memcached是一款開發工具,它既不是一個代碼加速器,也不是數據庫中間件。其設計哲學思想主要反映在如下方面:

1. 簡單key/value存儲:服務器不關心數據本身的意義及結構,只要是可序列化數據即可。存儲項由“鍵、過期時間、可選的標誌及數據”四個部分組成;
2. 功能的實現一半依賴於客戶端,一半基於服務器端:客戶負責發送存儲項至服務器端、從服務端獲取數據以及無法連接至服務器時採用相應的動作;服務端負責接收、存儲數據,並負責數據項的超時過期;
3. 各服務器間彼此無視:不在服務器間進行數據同步;
4. O(1)的執行效率
5. 清理超期數據:默認情況下,Memcached是一個LRU緩存,同時,它按事先預訂的時長清理超期數據;但事實上,memcached不會刪除任何已緩存數據,只是在其過期之後不再爲客戶所見;而且,memcached也不會真正按期限清理緩存,而僅是當get命令到達時檢查其時長;

Memcached提供了爲數不多的幾個命令來完成與服務器端的交互,這些命令基於memcached的協議實現。

存儲類命令:set, add, replace, append, prepend
獲取數據類命令:get, delete, incr/decr
統計類命令:stats, stats items, stats slabs, stats sizes
清理命令: flush_all

一、安裝libevent

memcached依賴於libevent API,因此要事先安裝之,項目主頁:http://libevent.org/,讀者可自行選擇需要的版本下載。本文采用的是目前最新版本的源碼包libevent-2.0.21-stable.tar.gz。安裝過程:

# tar xf libevent-2.0.21-stable.tar.gz
# cd libevent-2.0.21
# ./configure --prefix=/usr/local/libevent
# make && make install
# echo "/usr/local/libevent/lib" > /etc/ld.so.conf.d/libevent.conf
# ldconfig

二、安裝配置memcached

1、安裝memcached
# tar xf memcached-1.4.15.tar.gz
# cd memcached-1.4.15
# ./configure --prefix=/usr/local/memcached --with-libevent=/usr/local/libevent
# make && make install


2、memcached SysV的startup腳本代碼如下所示,將其建立爲/etc/init.d/memcached文件:

#!/bin/bash
#
# Init file for memcached
#
# chkconfig: - 86 14
# description: Distributed memory caching daemon
#
# processname: memcached
# config: /etc/sysconfig/memcached
. /etc/rc.d/init.d/functions
## Default variables
PORT="11211"
USER="nobody"
MAXCONN="1024"
CACHESIZE="64"
OPTIONS=""
RETVAL=0
prog="/usr/local/memcached/bin/memcached"
desc="Distributed memory caching"
lockfile="/var/lock/subsys/memcached"
start() {
        echo -n $"Starting $desc (memcached): "
        daemon $prog -d -p $PORT -u $USER -c $MAXCONN -m $CACHESIZE -o "$OPTIONS"
        RETVAL=$?
        [ $RETVAL -eq 0 ] && success && touch $lockfile || failure
        echo
        return $RETVAL
}
stop() {
        echo -n $"Shutting down $desc (memcached): "
        killproc $prog
        RETVAL=$?
        [ $RETVAL -eq 0 ] && success && rm -f $lockfile || failure
        echo
        return $RETVAL
}
restart() {
        stop
        start
}
reload() {
        echo -n $"Reloading $desc ($prog): "
        killproc $prog -HUP
        RETVAL=$?
        [ $RETVAL -eq 0 ] && success || failure
        echo
        return $RETVAL
}
case "$1" in
  start)
        start
        ;;
  stop)
        stop
        ;;
  restart)
        restart
        ;;
  condrestart)
        [ -e $lockfile ] && restart
        RETVAL=$?
        ;;   
  reload)
        reload
        ;;
  status)
        status $prog
        RETVAL=$?
        ;;
   *)
        echo $"Usage: $0 {start|stop|restart|condrestart|status}"
        RETVAL=1
esac
exit $RETVAL


使用如下命令配置memcached成爲系統服務:

# chmod +x /etc/init.d/memcached
# chkconfig --add memcached
# service memcached start

3、使用telnet命令測試memcached的使用

Memcached提供一組基本命令用於基於命令行調用其服務或查看服務器狀態等。

# telnet 127.0.0.1 11211
add命令:
add keyname flag  timeout  datasize
如:
add mykey 0 10 12
Hello world!
get命令:
get keyname
如:get mykey
VALUE mykey 0 12
Hello world!
END

4、memcached的常用選項說

-l <ip_addr>:指定進程監聽的地址;
-d: 以服務模式運行;
-u <username>:以指定的用戶身份運行memcached進程;
-m <num>:用於緩存數據的最大內存空間,單位爲MB,默認爲64MB;
-c <num>:最大支持的併發連接數,默認爲1024;
-p <num>: 指定監聽的TCP端口,默認爲11211;
-U <num>:指定監聽的UDP端口,默認爲11211,0表示關閉UDP端口;
-t <threads>:用於處理入站請求的最大線程數,僅在memcached編譯時開啓了支持線程纔有效;
-f <num>:設定Slab Allocator定義預先分配內存空間大小固定的塊時使用的增長因子;
-M:當內存空間不夠使用時返回錯誤信息,而不是按LRU算法利用空間;
-n: 指定最小的slab chunk大小;單位是字節;
-S: 啓用sasl進行用戶認證;


三、安裝Memcache的PHP擴展

①安裝PHP的memcache擴展
# tar xf memcache-2.2.5.tgz
# cd memcache-2.2.5
/usr/local/php/bin/phpize
# ./configure --with-php-config=/usr/local/php/bin/php-config --enable-memcache
# make && make install

上述安裝完後會有類似以下的提示信息如下:

Installing shared extensions:     /usr/local/php/lib/php/extensions/no-debug-non-zts-20090626/
②編輯/etc/php.ini,在“動態模塊”相關的位置添加如下一行來載入memcache擴展:
extension=/usr/local/php/lib/php/extensions/no-debug-non-zts-20090626/memcache.so

wKioL1NbX-byFl8VAACCa0_Vj7Y110.jpg

# pwd
/www/baidu.org
[root@node5 baidu.org]# cat test.php
<?php
$mem = new Memcache;
$mem->connect("172.16.249.72", 11211)  or die("Could not connect");
$version = $mem->getVersion();
echo "Server's version: ".$version."<br/>\n";
$mem->set('hellokey', 'Hello World', 0, 600) or die("Failed to save data at the memcached server");
echo "Store data in the cache (data will expire in 600 seconds)<br/>\n";
$get_result = $mem->get('hellokey');
echo "$get_result is from memcached server.";     
?>

wKiom1NbYYeDLLRqAADdmD1eEXA174.jpg

如果有輸出“Hello World is from memcached.”等信息,則表明memcache已經能夠正常工作。



四、使用libmemcached的客戶端工具:
訪問memcached的傳統方法是使用基於perl語言開發的Cache::memcached模塊,這個模塊在大多數perl代碼中都能良好的工作,但也有着衆所周知的性能方面的問題。libMemcached則是基於C語言開發的開源的C/C++代碼訪問memcached的庫文件,同時,它還提供了數個可以遠程使用的memcached管理工具,如memcat, memping,memstat,memslap等

1) 編譯安裝libmemcached
# tar xf libmemcached-1.0.2.tar.gz
# cd libmemcached-1.0.2
# ./configure
# make && make install
# ldconfig
2) 客戶端工具
# memcat --servers=127.0.0.1:11211 mykey
# memping
# memslap
# memstat




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