文/岳晉 溫宇 黃旻亮
Nginx是高性能的Http和反向代理服務器,在Linux環(huán)境下,其可以采用epoll作為網(wǎng)絡I/O模型。在高并發(fā)連接的情況下,其是Apache服務器不錯的替代品。Nginx具有高并發(fā)連接、內(nèi)存占用低、成本低等特點。
Nginx運行時,會存在一個主進程和多個工作進程。工作進程的數(shù)目可以在配置文件中進行指定,通常設置為CPU的核數(shù)。主進程用于管理工作進程的運行,并處置工作進程的異常情況。借助于主進程和工作進程的模式,Nginx可以實現(xiàn)平滑升級、配置即時生效等功能。而工作進程的任務相對單一,主要用于處理業(yè)務請求,它們彼此獨立,互不影響。此外,借助于異步非阻塞的工作機制,Nginx可以處理上萬的并發(fā)請求。
反向代理是Nginx的主要應用場景之一。反向代理是相對于正向代理來說,一般情況下,內(nèi)網(wǎng)的客戶機通過代理服務器訪問公網(wǎng)上服務的這種模式是正向代理。與此相反,當代理服務器的作用是將后臺服務器隱藏起來,并根據(jù)客戶機的請求,分發(fā)給后臺服務器的這種方式是反向代理。Nginx反向代理的原理如圖1所示。
圖1中,Nginx代理服務器接收到來自客戶端的請求,根據(jù)自己的配置,決定將該請求轉(zhuǎn)發(fā)給哪個業(yè)務服務器。當業(yè)務服務器處理完該請求后,將響應結(jié)果交給Nginx代理服務器,Nginx代理服務器再將響應內(nèi)容返回給客戶機。
反向代理可以保護后端服務器,此外,還可以用作負載均衡,來平衡后端服務器的性能壓力。Nginx通過proxy_pass命令和upstream模塊,就可以實現(xiàn)反向代理。如果后臺服務和Nginx在同一機器上,但運行在不同的端口上,Nginx可以將請求轉(zhuǎn)發(fā)到后臺服務運行的端口上。通常情況下,后臺服務和Nginx不在一臺服務器上,這時候Nginx可以將請求發(fā)送給upstream模塊,再通過upstream模塊轉(zhuǎn)發(fā)給后臺服務器。而且在upstream模塊中,也可以進行負載均衡相關(guān)的配置。
Nginx的另一主要應用場景是負載均衡。負載均衡是在各服務器之間均衡業(yè)務壓力,Nginx的負載均衡策略包括輪詢、指定權(quán)重、fair、ip_hash和url_hash等。
Windows版本的Nginx默認開啟了stub_status模塊來查看Nginx的一些狀態(tài)信息。此外,還需要在nginx.conf(Nginx的主要配置文件)中增加如下配置。
location/nginx_status{
stub_status;
allow 127.0.0.1;
}
這樣,通過訪問對應的url就可以打開監(jiān)控頁面。監(jiān)控頁面上的監(jiān)控數(shù)據(jù)如下所示:
Active connections: 6
Server accepts handled requests:
12053 12053 17528
Reading: 0 Writing: 2 Waiting: 4
其中,active connection 6; 對上游服務發(fā)起的連接數(shù),需要注意的是,如果reading或者writing的值很高,說明正在處理的數(shù)據(jù)量較大,可能是因為后臺服務處理慢,這個時候需要對后臺進行優(yōu)化。
在使用長連接的情況下,waiting的值代表有多少個連接在等待新的請求。waiting表明Nginx已經(jīng)將請求處理完畢,并且把數(shù)據(jù)返回給了客戶端,該連接已經(jīng)閑置,正在等待下一次請求。因此,這個值比較高說明請求處理得很快。一般應是writing和reading越小越好,而waiting越高越高。
為獲取較高的并發(fā)性能,需要對Nginx的主要配置參數(shù)進行調(diào)優(yōu)。主要的配置參數(shù)及調(diào)優(yōu)如下。
2.2.1 multi_accept on
如果multi_accept被禁止了,Nginx的一個工作進程只能同時接受一個新的連接,否則,一個工作進程可以接受所有的新連接。這個時候在監(jiān)控頁面上看到的active connections通常是很低的,因此,需要開啟該參數(shù),該配置對于提高Nginx的并發(fā)至為關(guān)鍵。
2.2.2 worker_processes
worker_processes后面的數(shù)值一般設置為CPU的核數(shù),代表Nginx開啟的工作進程的數(shù)目。例如,worker_processes 8代表開啟8個工作進程。
2.2.3 worker_connections
配置一個工作進程能夠處理的并發(fā)連接請求的數(shù)目??紤]高并發(fā)場景,將其設置為一個比較大的值。例如,worker_connections 40960,在Windows服務器下,該參數(shù)一般不超過65535。
2.2.4 worker_rlimit_nofile
配置一個工作進程能夠打開的文件句柄數(shù)上限。在高并發(fā)場景下,也需要設置為比較大的值,例如,worker_limit_nofile 40960。
2.2.5 sendfile
將該參數(shù)打開可以提高發(fā)送文件的效率,采用如下配置打開此參數(shù),sendfile on。
圖1:Nginx反向代理處理流程
2.2.6 tcp_nopush
打開tcp_nopush后,將會在發(fā)送響應時,把整個響應頭放在一個tcp包中發(fā)送,能夠達到優(yōu)化吞吐的效果,建議打開。
2.2.7 tcp_nodelay
該參數(shù)打開后,會關(guān)閉Nagle算法,保證高頻發(fā)送小數(shù)據(jù)報文的實時性,建議打開。
2.2.8 access_log
設置為on時,會保存Nginx代理的訪問請求。將這個設置關(guān)閉,會降低磁盤IO而提升速度。在生產(chǎn)環(huán)境,當確保Nginx不會出現(xiàn)問題后,可以將該參數(shù)設置為off。
2.2.9 gzip
該參數(shù)設置是否壓縮發(fā)送數(shù)據(jù),建議打開。gzip_comp_level 數(shù)據(jù)壓縮的等級,可以是1~9的任意一個值,9表示最慢但最高比例的壓縮。gzip_types 設置gzip的類型。
2.2.10 open_file_cache
open_file_cache 緩存最大數(shù)目及超時時間。open_file_cache_vaild 用于設置檢測緩存源文件是否超時的時間間隔。open_file_cache_min_uses設置緩存文件最小訪問次數(shù)。open_file_cache_errors設置是否保存緩存文件的錯誤信息。
2.2.11 proxy_buffering
proxy_buffering該參數(shù)用于設置是否開啟響應內(nèi)容的緩沖。如果關(guān)閉該參數(shù),那么proxy_buffers和proxy_busy_buffers_size的配置將無效。但是,proxy_buffer_size是否生效與proxy_buffering參數(shù)的設置無關(guān)。如果開啟proxy_buffering下,響應內(nèi)容會被Nginx先存入緩沖區(qū)中,之后再傳遞給客戶端。緩存區(qū)的臨時文件由proxy_max_temp_file_size
和proxy_temp_file_write_size決定。當內(nèi)存中的無非存儲響應內(nèi)容時,會在磁盤中存儲部分響應內(nèi)容。
當關(guān)閉proxy_buffering后,Nginx不再緩存后端返回的響應內(nèi)容,而是直接傳遞給客戶端。proxy_buffers配置接收一次響應的buffer個數(shù)和每個buffer的大小。proxy_busy_buffers_size 如果系統(tǒng)很忙的時候,可以申請更大的proxy_buffers,官方推薦乘2。proxy_temp_path path配置臨時文件目錄,proxy_temp_file_write_size緩存臨時文件的大小,proxy_max_temp_file_size 配置所有臨時文件的總大小。配置實例如下,
proxy_buffering on;
proxy_buffer_size 64k; proxy_buffers 4 32k;
proxy_busy_buffers_size 64k; proxy_temp_file_write_size 64k; proxy_max_temp_file_size 1024m;
2.2.12 keepalive
為提高并發(fā)能力,需要對長連接進行優(yōu)化。主要包括keepalive_timeout和keepalive_requests,keepalive_timeout表 示keepAlive的超時時間,也就是在超時時間內(nèi),如果客戶端沒有后續(xù)請求過來,Nginx就會斷掉這個Tcp連接。如果設置為0,表示禁用keepAlive。keepalive_timeout表示一個長連接,Nginx處理的請求上限,keepalive_timeout可以根據(jù)實際情況設置為一個較大的值。
圖2:10秒思考時間下,LoadRunner模擬5000用戶并發(fā)壓測某業(yè)務結(jié)果
在實際壓測并發(fā)能力的過程中,發(fā)現(xiàn)當并發(fā)超過1023后,Nginx會拒絕連接,并打印錯誤日志“maximum number of descriptors supported by select() is 1024 while waiting for request”。主要原因是在Windows環(huán)境下,盡管修改了worker_connections,但無法生效。為解決此問題,可以在網(wǎng)站http://nginx.org/en/download.html上獲取修改了最大文件描述符限制的Nginx版本,該版本的Nginx盡管無非使用epoll機制,但該專用版本已經(jīng)提供了盡可能多的功能,并針對Windows環(huán)境做了優(yōu)化,其可以支持每秒幾千到幾萬的并發(fā)請求。并且,其商業(yè)版本也可以提供付費的技術(shù)支持服務。因此,在Windows環(huán)境下,為提高并發(fā)能力,需使用Windows專用版本的Nginx。
在每秒創(chuàng)建的新連接比較多且持續(xù)創(chuàng)建的情況下,運行一段時間后,Nginx會拒絕連接,并打印錯誤日志。“An operation on a socket could not be performed because the system lacked sufficient buffer space or because a queue is full while connecting to upstream”,該 報錯的原因主要有兩種情況,第一種就是TCP連接端口耗盡,第二種是超過了socket隊列能夠處理的最大連接。其中,第二種情況可以通過配置backlog解決,如,listen 8080 backlog=40960。
第一種TCP連接端口耗盡的情況,在Windows環(huán)境下比較難處理。Windows server 2008在默認情況下,給TCP連接提供的端口只有16384個,可以通過在命令行輸入“netsh int ipv4 show dynamicport tcp”查看。對于每個新的客戶端連接,Nginx除了和客戶端建立連接外,和后端服務器也建立了一個臨時的TCP連接。這個臨時的TCP連接就是端口耗盡的根源
根據(jù)TCP/IP原理,TCP連接在進行“四次揮手”斷開連接時,首先斷開連接的一方會進入“timewait”狀態(tài),在timewait狀態(tài)內(nèi),由(源ip,源端口,目的ip,目的端口)組成的四元組是不允許被重用的。
針對TCP連接端口耗盡問題,在Windows服務器上,可以通過多種方式改善該問題,第一種是通過“netsh int ipv4 set dynamicport tcp start=5000 num=60000”,增加TCP連接的可用端口數(shù)。第二種是通過在注冊表的HKEY_LOCAL_MACHINESYSTEMCurrentControlSetserviceTcpipParameters增加TcpTimedWaitDelay的REG_DWORD參數(shù),并將其設置為30。這種方法是將TCP連接timewait的時間(范圍為30秒到240秒)降低為30秒,修改完成后,重啟機器生效。
此外,還可以對客戶端請求進行限速,對單個ip短時間內(nèi)多個TCP連接排隊處理。
另外,可以在upstream中配置keepalive xxx,其中xxx可以設置為1000。原因是nginx和后端服務器之間的連接為短連接,且無連接復用,這樣在高并發(fā)場景下,會造成端口的耗盡。通過以上配置,并配合proxy_http_version 1.1和proxy_set_header Connection "",就可以較好地解決端口耗盡問題。
通過對配置的調(diào)優(yōu),在Windows環(huán)境下,也達到了上萬的活躍連接數(shù),如下監(jiān)控數(shù)據(jù)所示。
Active connections: 10003
Server accepts handled requests:
559064 559064 7196725
Reading: 0 Writing: 6678 Waiting: 3324
使用Nginx反向代理某一Web服務,并使用LoadRunner進行壓力測試,模擬5000用戶并發(fā)訪問該服務,其測試結(jié)果如圖2所示。
圖2中,第一行的圖代表用戶的并發(fā)數(shù),其是從0逐漸增加到5000,然后再下降到0。第二行的圖是HPS(hits per second)的結(jié)果圖,圖中瞬時HPS可以達到2500以上,說明該方案在Windows環(huán)境下可以提供較高的并發(fā)能力。
Windows環(huán)境下,Nginx的并發(fā)性能會存在一定的瓶頸。本文通過對Nginx的主要配置進行調(diào)優(yōu),并采用Windows專用版本的Nginx,較好地解決了高并發(fā)情形下TCP連接端口耗盡等性能瓶頸,并實現(xiàn)了Windows生產(chǎn)環(huán)境下的Nginx高并發(fā)處理。