死磕nginx系列--nginx入門

nginx 功能介紹

Nginx由於它的穩定性、豐富的模塊庫、靈活的配置和低系統資源的消耗而聞名.業界一致認爲它是Apache2.2+mod_proxy_balancer的輕量級代替者,不只是由於響應靜態頁面的速度很是快,並且它的模塊數量達到Apache的近2/3。對proxy和rewrite模塊的支持很完全,還支持mod_fcgi、ssl、vhosts ,適合用來作mongrel clusters的前端HTTP響應。
nginx和Apache同樣使用模塊化設計,nginx模塊包括內置模塊和第三方模塊,其中內置模塊中包含主模塊和事件模塊。php

nginx處理請求邏輯圖
Nginx模塊的HTTP請求和響應過程css

nginx能夠提供的服務

  1. web 服務.
  2. 負載均衡 (反向代理)
  3. web cache(web 緩存)

nginx 的優勢

  1. 高併發。靜態小文件
  2. 佔用資源少。2萬併發、10個線程,內存消耗幾百M。
  3. 功能種類比較多。web,cache,proxy。每個功能都不是特別強。
  4. 支持epoll模型,使得nginx能夠支持高併發。
  5. nginx 配合動態服務和Apache有區別。(FASTCGI 接口)
  6. 利用nginx能夠對IP限速,能夠限制鏈接數。
  7. 配置簡單,更靈活。

nginx應用場合

  1. 靜態服務器。(圖片,視頻服務)另外一個lighttpd。併發幾萬,html,js,css,flv,jpg,gif等。
  2. 動態服務,nginx——fastcgi 的方式運行PHP,jsp。(PHP併發在500-1500,MySQL 併發在300-1500)。
  3. 反向代理,負載均衡。日pv2000W如下,均可以直接用nginx作代理。
  4. 緩存服務。相似 SQUID,VARNISH。

主流web服務產品對比說明

Apache-特性

  1. 2.2版本自己穩定強大,據官方說:其2.4版本性能更強。
  2. prefork模式取消了進程建立開銷,性能很高。
  3. 處理動態業務數據時,因關聯到後端的引擎和數據庫,瓶頸不在與Apache自己。
  4. 高併發時消耗系統資源相對多一些。
  5. 基於傳統的select模型。
  6. 擴展庫,DSO方法。

nginx-特性

  1. 基於異步IO模型,(epoll,kqueue),性能強,可以支持上萬併發。
  2. 對小文件支持很好,性能很高(限靜態小文件1M)。
  3. 代碼優美,擴展庫必須編譯進主程序。
  4. 消耗代碼資源比較低。
  5. lighttpd(百度貼吧,豆瓣)
  6. 基於異步IO模式,性能和nginx相近。
  7. 擴展庫是SO模式,比nginx要靈活。
    8.經過差距(mod_secdownload)可實現文件URL地址加密。

web服務產品性能對比測試

靜態數據性能對比
  1. 處理靜態文件Apache性能比nginx和lighttpd要差。
  2. nginx在處理小文件優點明顯。
  3. 處理靜態小文件(小於1M),nginx和lighttpd比Apache更有優點,lighttpd最強。html

    動態數據性能對比
  4. 處理動態內容三者相差不大,主要取決於PHP和數據庫的壓力。
  5. 當處理動態數據時,三者差距不大,從測試結果看,Apache更有優點一點。這是由於處理動態數據能力取決於PHP和後端數據的提供服務能力。也就是說瓶頸不在web服務器上。
  6. 通常PHP引擎支持的併發參考值300-1000,JAVA引擎併發300-1000,數據庫的併發300-1000.前端

爲何nginx的整體性能比Apache高。
  1. nginx使用最新的epoll和kqueue網絡IO模型,而Apache使用牀頭的select模式。
  2. 目前Linux下可以承受高併發訪問的squid、Memcached 都採用的是epoll網絡IO模型。

如何選擇WEB服務器:

靜態業務:高併發、採用nginx,lighttpd,根據本身的掌握程度或公司的要求。
動態業務:採用nginx和Apache都可。
既有靜態業務又有動態業務:nginx或Apache,不要多選要單選。
動態業務能夠由前端代理(haproxy),根據頁面元素的類型,向後轉發相應的服務器進行處理。
思想:咱們工做都不要追求一步到位,知足需求的前提下,先用,而後逐步完善。
提示:nginx作web(Apache,lighttpd)、反向代理(haproxy,lvs,nat)及緩存服務器(squid)也是不錯的。
最終建議:對外的業務nginx,對內的業務Apache(yum httpd mysql-server php)。python

nginx實戰過程

安裝依賴包

  • nginx安裝依賴GCC、openssl-devel、pcre-devel和zlib-devel軟件庫。
  • Pcre全稱(Perl Compatible Regular Expressions),中文perl兼容正則表達式,pcre官方站點
yum install  pcre pcre-devel -y 
yum install openssl openssl-devel -y

開始編譯

使用./configure --help查看各個模塊的使用狀況,使用--without-http_ssi_module的方式關閉不須要的模塊。可使用--with-http_perl_modules方式安裝須要的模塊。mysql

編譯命令linux

tar -zxf nginx-1.10.1.tar.gz 
cd nginx-1.10.1/
./configure --prefix=/data/app/nginx-1.10.1 --user=nginx --group=nginx  --with-http_ssl_module  --with-http_stub_status_module

useradd nginx -M -s /sbin/nologin 
make && make install 
ln -s /data/app/nginx-1.10.1 /data/app/nginx

測試nginx配置文件是否正常nginx

/data/app/nginx/sbin/nginx -t 
nginx: the configuration file /data/app/nginx-1.10.1/conf/nginx.conf syntax is ok
nginx: configuration file /data/app/nginx-1.10.1/conf/nginx.conf test is successful

啓動nginx服務器web

/data/app/nginx/sbin/nginx  -t  ##檢查配置文件
/data/app/nginx/sbin/nginx      ##肯定nginx服務
netstat -lntup |grep nginx        ## 檢查進程是否正常
curl 192.168.56.12                ## 確認結果

nginx其餘命令正則表達式

nginx -s signal
signal:
stop — fast shutdown
quit — graceful shutdown
reload — reloading the configuration file
reopen — reopening the log files
用來打開日誌文件,這樣nginx會把新日誌信息寫入這個新的文件中

/data/app/nginx/sbin/nginx -V 查看已經編譯的參數。

使用kill命令操做nginx。格式:kill -信號 PID

信號名稱

  • TERM,INT 快速關閉
  • QUIT 優雅的關閉,保持吸納有的客戶端鏈接
  • HUP 重啓應用新的配置文件
  • USR1 從新打開日誌文件
  • USR2 升級程序
  • WINCH 優雅的關閉工做進程

例子

kill -QUIT  `cat /data/app/nginx/nginx.pid`
kill -HUP `cat /data/app/nginx/nginx.pid`

nginx配置文件

配置基礎配置文件

worker_processes  1;
events {
    worker_connections  1024;
}
http {
    include       mime.types;
    default_type  application/octet-stream;
    sendfile        on;
    keepalive_timeout  65;
    server {
        listen       80;
        server_name  localhost;
        location / {
            root   html;
            index  index.html index.htm;
        }
        error_page   500 502 503 504  /50x.html;
        location = /50x.html {
            root   html;
        }
    }
}
### 測試配置文件是否正常
shell> /data/app/nginx/sbin/nginx -t 
nginx: the configuration file /data/app/nginx-1.10.3/conf/nginx.conf syntax is ok
nginx: configuration file /data/app/nginx-1.10.3/conf/nginx.conf test is successful
shell> curl -I http://192.168.56.12
HTTP/1.1 200 OK

nginx監控

開啓nginx的監控服務

開啓狀態頁

#設定查看Nginx狀態的地址   
       location /NginxStatus {  
        stub_status on;   
        access_log off;   
        # auth_basic "NginxStatus";   
        # auth_basic_user_file conf/htpasswd;   
       }
  • stub_status on; 表示開啓stubStatus的工做狀態統計功能。
  • access_log off; 關閉access_log 日誌記錄功能。
  • auth_basic "NginxStatus"; auth_basic 是nginx的一種認證機制。
  • auth_basic_user_file conf/htpasswd; 用來指定密碼文件的位置。

    配置登陸密碼

yum install -y httpd-tools
/usr/local/apache/bin/htpasswd -c /data/app/nginx/conf/htpasswd biglittleant 
New password:

完成後會在/data/app/nginx/conf/目錄下生成htpasswd文件。

訪問URL

# curl http://127.0.0.1/NginxStatus
Active connections: 11921 
server accepts handled requests
 11989 11989 11991 
Reading: 0 Writing: 7 Waiting: 42
  • active connections – 活躍的鏈接數量
  • server accepts handled requests — 總共處理了11989個鏈接 , 成功建立11989次握手, 總共處理了11991個請求
  • Reading — 讀取客戶端的鏈接數.
  • Writing — 響應數據到客戶端的數量
  • Waiting — 開啓 keep-alive 的狀況下,這個值等於 active – (reading+writing), 意思就是 Nginx 已經處理完正在等候下一次請求指令的駐留鏈接.

    編寫zabbix監控腳本

nginx_status_fun(){
    NGINX_PORT=$1
    NGINX_COMMAND=$2
    nginx_active(){
        /usr/bin/curl "http://127.0.0.1:"$NGINX_PORT"/NginxStatus/" 2>/dev/null| grep 'Active' | awk '{print $NF}'
        }
    nginx_reading(){
        /usr/bin/curl "http://127.0.0.1:"$NGINX_PORT"/NginxStatus/" 2>/dev/null| grep 'Reading' | awk '{print $2}'
       }
    nginx_writing(){
        /usr/bin/curl "http://127.0.0.1:"$NGINX_PORT"/NginxStatus/" 2>/dev/null| grep 'Writing' | awk '{print $4}'
       }
    nginx_waiting(){
        /usr/bin/curl "http://127.0.0.1:"$NGINX_PORT"/NginxStatus/" 2>/dev/null| grep 'Waiting' | awk '{print $6}'
       }
    nginx_accepts(){
        /usr/bin/curl "http://127.0.0.1:"$NGINX_PORT"/NginxStatus/" 2>/dev/null| awk NR==3 | awk '{print $1}'
       }
    nginx_handled(){
        /usr/bin/curl "http://127.0.0.1:"$NGINX_PORT"/NginxStatus/" 2>/dev/null| awk NR==3 | awk '{print $2}'
       }
    nginx_requests(){
        /usr/bin/curl "http://127.0.0.1:"$NGINX_PORT"/NginxStatus/" 2>/dev/null| awk NR==3 | awk '{print $3}'
       }
    case $NGINX_COMMAND in
        active)
            nginx_active;
            ;;
        reading)
            nginx_reading;
            ;;
        writing)
            nginx_writing;
            ;;
        waiting)
            nginx_waiting;
            ;;
        accepts)
            nginx_accepts;
            ;;
        handled)
            nginx_handled;
            ;;
        requests)
            nginx_requests;
        esac 
}

nginx優化

nginx內核優化

net.ipv4.tcp_fin_timeout = 2
net.ipv4.tcp_tw_reuse = 1
net.ipv4.tcp_tw_recycle = 1
net.ipv4.tcp_syncookies = 1
net.ipv4.tcp_keepalive_time = 600
net.ipv4.ip_local_port_range = 4000    65000
net.ipv4.tcp_max_syn_backlog = 16384
net.ipv4.tcp_max_tw_buckets = 36000
net.ipv4.route.gc_timeout = 100
net.ipv4.tcp_syn_retries = 1
net.ipv4.tcp_synack_retries = 1
net.core.somaxconn = 16384
net.core.netdev_max_backlog = 16384
net.ipv4.tcp_max_orphans = 16384
#如下參數是對iptables防火牆的優化,防火牆不開會提示,能夠忽略不理。
net.ipv4.ip_conntrack_max = 25000000
net.ipv4.netfilter.ip_conntrack_max=25000000
net.ipv4.netfilter.ip_conntrack_tcp_timeout_established=180
net.ipv4.netfilter.ip_conntrack_tcp_timeout_time_wait=120
net.ipv4.netfilter.ip_conntrack_tcp_timeout_close_wait=60
net.ipv4.netfilter.ip_conntrack_tcp_timeout_fin_wait=120

報錯彙總

問題1:編譯報錯

./configure: error: the HTTP rewrite module requires the PCRE library.
You can either disable the module by using —without-http_rewrite_module(僞靜態)
option, or install the PCRE library into the system, or build the PCRE library
statically from the source with nginx by using --with-pcre=<path> option
yum install  pcre pcre-devel -y

問題2: 提示找不到libpcre.so.1

解決:

  1. find / -name libpcre.so*
  2. 將找到的路徑 追加到 /etc/ld.so.conf
  3. ldconfig 生效。
  4. ln -s /ser/local/lib/libpcre.so.l /lib64
  5. 或編譯時指定源碼的安裝路徑:--with-pcre=/data/tools/pcre-8.33
  6. 最終解決方案 yum install pcre-devel -y 不會出現上述報錯。

問題3:啓動nginx報錯

[root@centos6 tools]# /application/nginx/sbin/nginx 
nginx: [emerg] bind() to 0.0.0.0:80 failed (98: Address already in use)
nginx: [emerg] bind() to 0.0.0.0:80 failed (98: Address already in use)
nginx: [emerg] bind() to 0.0.0.0:80 failed (98: Address already in use)
nginx: [emerg] bind() to 0.0.0.0:80 failed (98: Address already in use)
nginx: [emerg] bind() to 0.0.0.0:80 failed (98: Address already in use)
nginx: [emerg] still could not bind()

解決辦法:(由於開啓了Apache服務)

[root@nfs-client application]# lsof -i :80 
COMMAND   PID USER   FD   TYPE DEVICE SIZE/OFF NODE NAME
httpd   35833  www    4u  IPv6 129886      0t0  TCP *:http (LISTEN)
httpd   35834  www    4u  IPv6 129886      0t0  TCP *:http (LISTEN)
httpd   98511 root    4u  IPv6 129886      0t0  TCP *:http (LISTEN)
[root@nfs-client application]# /application/apache/bin/apachectl stop 
[root@nfs-client application]# /application/nginx/sbin/nginx ##從新啓動nginx。

擴展閱讀:

nginx全局變量

  • $args:這個變量等於請求行中的參數,同$query_string。
  • $is_args: 若是已經設置$args,則該變量的值爲"?",不然爲""。
  • $content_length: 請求頭中的Content-length字段。
  • $content_type: 請求頭中的Content-Type字段。
  • $document_uri: 與$uri相同。
  • $document_root: 當前請求在root指令中指定的值。
  • $host: 請求主機頭字段,不然爲服務器名稱。
  • $http_user_agent: 客戶端agent信息。
  • $http_cookie: 客戶端cookie信息。
  • $limit_rate: 這個變量能夠限制鏈接速率。
  • $request_method: 客戶端請求的動做,一般爲GET或POST。
  • $remote_addr: 客戶端的IP地址。
  • $remote_port: 客戶端的端口。
  • $remote_user: 已經通過Auth Basic Module驗證的用戶名。
  • $request_body_file`: 客戶端請求主體的臨時文件名。
  • $request_uri: 請求的URI,帶參數
  • $request_filename: 當前請求的文件路徑,由root或alias指令與URI請求生成。
  • $scheme: 所用的協議,好比http或者是https,好比rewrite ^(.+)$ $scheme://example.com$1 redirect;
  • $server_protocol: 請求使用的協議,一般是HTTP/1.0或HTTP/1.1。
  • $server_addr: 服務器地址,在完成一次系統調用後能夠肯定這個值。
  • $server_name: 服務器名稱。
  • $server_port: 請求到達服務器的端口號。
  • $request_uri: 包含請求參數的原始URI,不包含主機名,如:/foo/bar.php?arg=baz
  • $uri: 不帶請求參數的當前URI,$uri不包含主機名,如/foo/bar.html可能和最初的值有不一樣,好比通過重定向之類的。

例子:

訪問連接是:http://localhost:88/test1/test2/test.php 
網站路徑是:/var/www/html

$host:localhost
$server_port:88
$request_uri:http://localhost:88/test1/test2/test.php
$document_uri:/test1/test2/test.php
$document_root:/var/www/html
$request_filename:/var/www/html/test1/test2/test.php

nginx plus -- ngx_http_status_module

商業版的 nginx plus 經過他的 ngx_http_status_module 提供了比 nginx 更多的監控指標,能夠參看 http://demo.nginx.com/status.html

nginx access log 分析

nginx 的 access log 中能夠記錄不少有價值的信息,經過分析 access log,能夠收集到不少指標。
python 編寫的 linux 工具 ngxtop 就實現了對 access log 的分析功能。

web服務器事件處理模型

select

select最先於1983年出如今4.2BSD中,它經過一個select()系統調用來監視多個文件描述符的數組,當select()返回後,該數組中就緒的文件描述符便會被內核修改標誌位,使得進程能夠得到這些文件描述符從而進行後續的讀寫操做。
select目前幾乎在全部的平臺上支持,其良好跨平臺支持也是它的一個優勢,事實上從如今看來,這也是它所剩很少的優勢之一。
select的一個缺點在於單個進程可以監視的文件描述符的數量存在最大限制,在Linux上通常爲1024,不過能夠經過修改宏定義甚至從新編譯內核的方式提高這一限制。
另外,select()所維護的存儲大量文件描述符的數據結構,隨着文件描述符數量的增大,其複製的開銷也線性增加。同時,因爲網絡響應時間的延遲使得大量TCP鏈接處於非活躍狀態,但調用select()會對全部socket進行一次線性掃描,因此這也浪費了必定的開銷。

poll

poll在1986年誕生於System V Release 3,它和select在本質上沒有多大差異,可是poll沒有最大文件描述符數量的限制。
poll和select一樣存在一個缺點就是,包含大量文件描述符的數組被總體複製於用戶態和內核的地址空間之間,而不論這些文件描述符是否就緒,它的開銷隨着文件描述符數量的增長而線性增大。
另外,select()和poll()將就緒的文件描述符告訴進程後,若是進程沒有對其進行IO操做,那麼下次調用select()和poll()的時候將再次報告這些文件描述符,因此它們通常不會丟失就緒的消息,這種方式稱爲水平觸發(Level Triggered)。

epoll

直到Linux2.6纔出現了由內核直接支持的實現方法,那就是epoll,它幾乎具有了以前所說的一切優勢,被公認爲Linux2.6下性能最好的多路I/O就緒通知方法。
epoll能夠同時支持水平觸發和邊緣觸發(Edge Triggered,只告訴進程哪些文件描述符剛剛變爲就緒狀態,它只說一遍,若是咱們沒有采起行動,那麼它將不會再次告知,這種方式稱爲邊緣觸發),理論上邊緣觸發的性能要更高一些,可是代碼實現至關複雜。
epoll一樣只告知那些就緒的文件描述符,並且當咱們調用epoll_wait()得到就緒文件描述符時,返回的不是實際的描述符,而是一個表明就緒描述符數量的值,你只須要去epoll指定的一個數組中依次取得相應數量的文件描述符便可,這裏也使用了內存映射(mmap)技術,這樣便完全省掉了這些文件描述符在系統調用時複製的開銷。
另外一個本質的改進在於epoll採用基於事件的就緒通知方式。在select/poll中,進程只有在調用必定的方法後,內核纔對全部監視的文件描述符進行掃描,而epoll事先經過epoll_ctl()來註冊一個文件描述符,一旦基於某個文件描述符就緒時,內核會採用相似callback的回調機制,迅速激活這個文件描述符,當進程調用epoll_wait()時便獲得通知。

nginx -s reload 過程

nginx主進程讀取配置文件,若是發現配置文件變動,會建立一個新的主進程,而後同時舊的進程,及舊的子進程關閉,舊進程會拒絕新的鏈接,服務到本身的鏈接結束,而後關閉。

Apache select模型和 nginx epoll 模型對比講解

Nginx的高併發得益於其採用了epoll模型,與傳統的服務器程序架構不一樣,epoll是linux內核2.6之後纔出現的。下面經過比較Apache和Nginx工做原理來比較。

傳統Apache都是多進程或者多線程來工做,假設是多進程工做(prefork),apache會先生成幾個進程,相似進程池的工做原理,只不過這裏的進程池會隨着請求數目的增長而增長。對於每個鏈接,apache都是在一個進程內處理完畢。具體是 recv(),以及根據 URI 去進行磁盤I/O來尋找文件,還有 send()都是阻塞的。其實說白了都是 apche 對於套接字的I/O,讀或者寫,可是讀或者寫都是阻塞的,阻塞意味着進程就得掛起進入sleep狀態,那麼一旦鏈接數不少,Apache必然要生成更多的進程來響應請求,一旦進程多了,CPU對於進程的切換就頻繁了,很耗資源和時間,因此就致使apache性能降低了,說白了就是處理不過來這麼多進程了。其實仔細想一想,若是對於進程每一個請求都沒有阻塞,那麼效率確定會提升不少。

Nginx採用epoll模型,異步非阻塞。對於Nginx來講,把一個完整的鏈接請求處理都劃分紅了事件,一個一個的事件。好比accept(), recv(),磁盤I/O,send()等,每部分都有相應的模塊去處理,一個完整的請求多是由幾百個模塊去處理。真正核心的就是事件收集和分發模塊,這就是管理全部模塊的核心。只有核心模塊的調度才能讓對應的模塊佔用CPU資源,從而處理請求。拿一個HTTP請求來講,首先在事件收集分發模塊註冊感興趣的監聽事件,註冊好以後不阻塞直接返回,接下來就不須要再管了,等待有鏈接來了內核會通知你(epoll的輪詢會告訴進程),cpu就能夠處理其餘事情去了。一旦有請求來,那麼對整個請求分配相應的上下文(其實已經預先分配好),這時候再註冊新的感興趣的事件(read函數),一樣客戶端數據來了內核會自動通知進程能夠去讀數據了,讀了數據以後就是解析,解析完後去磁盤找資源(I/O),一旦I/O完成會通知進程,進程開始給客戶端發回數據send(),這時候也不是阻塞的,調用後就等內核發回通知發送的結果就行。整個下來把一個請求分紅了不少個階段,每一個階段都到不少模塊去註冊,而後處理,都是異步非阻塞。異步這裏指的就是作一個事情,不須要等返回結果,作好了會自動通知你。

select/epoll的特色

select的特色:select 選擇句柄的時候,是遍歷全部句柄,也就是說句柄有事件響應時,select須要遍歷全部句柄才能獲取到哪些句柄有事件通知,所以效率是很是低。可是若是鏈接不多的狀況下, select和epoll的LT觸發模式相比, 性能上差異不大。
這裏要多說一句,select支持的句柄數是有限制的, 同時只支持1024個,這個是句柄集合限制的,若是超過這個限制,極可能致使溢出,並且很是不容易發現問題, 固然能夠經過修改linux的socket內核調整這個參數。
epoll的特色:epoll對於句柄事件的選擇不是遍歷的,是事件響應的,就是句柄上事件來就立刻選擇出來,不須要遍歷整個句柄鏈表,所以效率很是高,內核將句柄用紅黑樹保存的。
對於epoll而言還有ET和LT的區別,LT表示水平觸發,ET表示邊緣觸發,二者在性能以及代碼實現上差異也是很是大的。

能夠舉一個簡單的例子來講明Apache的工做流程,咱們平時去餐廳吃飯。餐廳的工做模式是一個服務員全程服務客戶,流程是這樣,服務員在門口等候客人(listen),客人到了就接待安排的餐桌上(accept),等着客戶點菜(request uri),去廚房叫師傅下單作菜(磁盤I/O),等待廚房作好(read),而後給客人上菜(send),整個下來服務員(進程)不少地方是阻塞的。這樣客人一多(HTTP請求一多),餐廳只能經過叫更多的服務員來服務(fork進程),可是因爲餐廳資源是有限的(CPU),一旦服務員太多管理成本很高(CPU上下文切換),這樣就進入一個瓶頸。

再來看看Nginx得怎麼處理?餐廳門口掛個門鈴(註冊epoll模型的listen),一旦有客人(HTTP請求)到達,派一個服務員去接待(accept),以後服務員就去忙其餘事情了(好比再去接待客人),等這位客人點好餐就叫服務員(數據到了read()),服務員過來拿走菜單到廚房(磁盤I/O),服務員又作其餘事情去了,等廚房作好了菜也喊服務員(磁盤I/O結束),服務員再給客人上菜(send()),廚房作好一個菜就給客人上一個,中間服務員能夠去幹其餘事情。整個過程被切分紅不少個階段,每一個階段都有相應的服務模塊。咱們想一想,這樣一旦客人多了,餐廳也能招待更多的人。

無論是Nginx仍是Squid這種反向代理,其網絡模式都是事件驅動。事件驅動實際上是很老的技術,早期的select、poll都是如此。後來基於內核通知的更高級事件機制出現,如libevent裏的epoll,使事件驅動性能得以提升。事件驅動的本質仍是IO事件,應用程序在多個IO句柄間快速切換,實現所謂的異步IO。事件驅動服務器,最適合作的就是這種IO密集型工做,如反向代理,它在客戶端與WEB服務器之間起一個數據中轉做用,純粹是IO操做,自身並不涉及到複雜計算。反向代理用事件驅動來作,顯然更好,一個工做進程就能夠run了,沒有進程、線程管理的開銷,CPU、內存消耗都小。

因此Nginx、Squid都是這樣作的。固然,Nginx也能夠是多進程 + 事件驅動的模式,幾個進程跑libevent,不須要Apache那樣動輒數百的進程數。Nginx處理靜態文件效果也很好,那是由於靜態文件自己也是磁盤IO操做,處理過程同樣。至於說多少萬的併發鏈接,這個毫無心義。隨手寫個網絡程序都能處理幾萬的併發,但若是大部分客戶端阻塞在那裏,就沒什麼價值。

再看看Apache或者Resin這類應用服務器,之因此稱他們爲應用服務器,是由於他們真的要跑具體的業務應用,如科學計算、圖形圖像、數據庫讀寫等。它們極可能是CPU密集型的服務,事件驅動並不合適。例如一個計算耗時2秒,那麼這2秒就是徹底阻塞的,什麼event都沒用。想一想MySQL若是改爲事件驅動會怎麼樣,一個大型的join或sort就會阻塞住全部客戶端。這個時候多進程或線程就體現出優點,每一個進程各幹各的事,互不阻塞和干擾。固然,現代CPU愈來愈快,單個計算阻塞的時間可能很小,但只要有阻塞,事件編程就毫無優點。因此進程、線程這類技術,並不會消失,而是與事件機制相輔相成,長期存在。

總言之,事件驅動適合於IO密集型服務,多進程或線程適合於CPU密集型服務,它們各有各的優點,並不存在誰取代誰的傾向。

相關參考

nginx-日誌高級技巧
nginx-官方文檔
nginx優化
查看網站排名
nginx-status-demo

相關文章
相關標籤/搜索