免费视频淫片aa毛片_日韩高清在线亚洲专区vr_日韩大片免费观看视频播放_亚洲欧美国产精品完整版

打開(kāi)APP
userphoto
未登錄

開(kāi)通VIP,暢享免費(fèi)電子書(shū)等14項(xiàng)超值服

開(kāi)通VIP
Nginx 引入線程池,提升 9 倍性能

介紹

眾所周知,NGINX 采用異步、事件驅(qū)動(dòng)的方式處理連接。意味著無(wú)需對(duì)每個(gè)請(qǐng)求創(chuàng)建專門(mén)的進(jìn)程或線程,它用一個(gè)工作進(jìn)程(worker process)處理多個(gè)連接和請(qǐng)求。為了達(dá)到這個(gè)目的,NGINX采用非阻塞模式的 socket,并利用諸如 epoll 和 kqueue 的高效方法。


全量進(jìn)程(full-weight process)數(shù)很少(通常是一個(gè) CPU 核只有一個(gè))而且恒定、內(nèi)存開(kāi)銷少、CPU 周期不會(huì)浪費(fèi)在任務(wù)切換上。此方法的優(yōu)勢(shì)因?yàn)镹GINX而廣為人知。它能同時(shí)處理成千上萬(wàn)請(qǐng)求,而且容易擴(kuò)展。

每個(gè)進(jìn)程消耗額外的內(nèi)存,進(jìn)程之間的每次切換都會(huì)消耗 CPU 周期和丟棄 CPU 緩存


不過(guò)異步、事件驅(qū)動(dòng)方式依然存在一個(gè)問(wèn)題,或者可以說(shuō)是敵人。其名字就是:阻塞。不幸的是,許多第三方模塊采用阻塞方式調(diào)用,用戶(有時(shí)甚至這些模塊的開(kāi)發(fā)者)都沒(méi)有意識(shí)到這個(gè)缺陷。阻塞操作會(huì)毀掉 NGINX 性能,必須采取一切手段避免這樣的問(wèn)題。


甚至在當(dāng)前 NGINX 官方代碼中,也無(wú)法在每個(gè)例子中避免阻塞操作,為了解決這個(gè)問(wèn)題,NGINX 1.7.11 版實(shí)現(xiàn)了新的線程池機(jī)制。它是什么,如何使用?我會(huì)在后面說(shuō)明。我們先看看我們的敵人。


問(wèn)題

首先,為了更好的理解問(wèn)題,我們先簡(jiǎn)單看看NGINX是如何工作的。


總體來(lái)說(shuō),NGINX 是一個(gè)事件處理器,一個(gè)從內(nèi)核接收所有發(fā)生在連接上的事件信息的控制器,然后給操作系統(tǒng)發(fā)布命令。實(shí)際上,NGINX 通過(guò)編排操作系統(tǒng)做了全部的辛苦工作,操作系統(tǒng)則做了讀字節(jié)和發(fā)送字節(jié)等日常工作??梢?jiàn) NGINX 快速及時(shí)響應(yīng)是如此重要。

工作進(jìn)程監(jiān)聽(tīng)、處理來(lái)自內(nèi)核中的事件。


事件可能是某個(gè)超時(shí),或者socket準(zhǔn)備讀取或者寫(xiě)入的通知,或者錯(cuò)誤發(fā)生的通知。NGINX 接收一串事件,接著挨個(gè)處理,做一些必要的動(dòng)作。這些處理都在線程隊(duì)列的簡(jiǎn)單循環(huán)中完成。NGINX 從隊(duì)列中放出一個(gè)事件,接著做出反應(yīng),例如寫(xiě)或者讀一個(gè) socket。在許多案例中,這非??欤ㄒ苍S只需要很少的CPU 周期就可以將數(shù)據(jù)復(fù)制到內(nèi)存中),并且 NGINX  會(huì)立即處理隊(duì)列中所有的事件。

所有處理是在一個(gè)簡(jiǎn)單的循環(huán)中由某個(gè)線程完成的


但是如果遇到某些又長(zhǎng)又重操作,又會(huì)怎樣呢?整個(gè)事件處理周期可能會(huì)卡在那里等待此操作結(jié)束。


我們說(shuō)的“阻塞操作”是指會(huì)讓處理循環(huán)明顯停止一段時(shí)間的操作。阻塞的原因多種多樣。比如,NGINX忙于漫長(zhǎng)的 CPU 密集型處理,或者不得不等待獲取某個(gè)資源,比如硬件驅(qū)動(dòng)、某個(gè)互斥鎖、庫(kù)函數(shù)以同步方式調(diào)用數(shù)據(jù)庫(kù)響應(yīng)。最關(guān)鍵的是處理諸如此類的操作,工作進(jìn)程就沒(méi)有辦法做其他的事情,處理其他的事件,即使系統(tǒng)有更多可用資源可供隊(duì)列中某些事件使用。


試想商店里售貨員,面前排著一個(gè)很長(zhǎng)的隊(duì)列。排第一的顧客需要的貨物在倉(cāng)庫(kù),不是在店里,售貨員去倉(cāng)庫(kù)搬運(yùn)貨物。為此整個(gè)隊(duì)列需要等待幾個(gè)小時(shí),等待的人都會(huì)不高興的。你能想象人們的反應(yīng)么?隊(duì)列中每個(gè)人等待時(shí)間因?yàn)檫@幾個(gè)小時(shí)而增加,但他們想買的貨物或許就在商店里。

隊(duì)列中的每一個(gè)人不得不等待第一個(gè)人的訂單


幾乎同樣的場(chǎng)景發(fā)生在 NGINX 中,需要讀取一個(gè)文件,但它沒(méi)有緩存在內(nèi)存,不得不從硬盤(pán)中讀取。硬盤(pán)很慢(特別是旋轉(zhuǎn)的機(jī)械硬盤(pán)),然而隊(duì)列中其他等待的請(qǐng)求即使無(wú)需讀取硬盤(pán),也被迫等待。結(jié)果增加了延遲,系統(tǒng)資源沒(méi)有被充分利用。

僅僅一個(gè)阻塞操作就能長(zhǎng)時(shí)間地延遲接下來(lái)所有的操作


某些操作系統(tǒng)(比如 FreeBSD)提供了一個(gè)讀文件和發(fā)送文件的異步接口,NGINX可以調(diào)用這個(gè)接口(見(jiàn) aio 指令)。不幸的是,Linux 并非都如此。盡管 Linux系統(tǒng)也提供了讀取文件的異步接口,但它有兩個(gè)重大缺陷。其一是文件讀取和緩存時(shí)需要對(duì)齊,不過(guò) NGINX 能處理地很好。第二個(gè)問(wèn)題更糟,異步接口需要在文件描述符上作 O_DIRECT 標(biāo)記,這樣任何獲取文件的操作越過(guò)內(nèi)存級(jí)的緩存,增加了硬盤(pán)負(fù)載。在很多例子中,這真不是一個(gè)好的選擇。


為解決這個(gè)問(wèn)題,NGINX 1.7.11 引入了線程池。NGINX Plus 默認(rèn)狀態(tài)下沒(méi)有線程池,如果你想給 NGINX Plus R6 構(gòu)建一個(gè)線程池,請(qǐng)聯(lián)系銷售。


讓我們深入探究什么是線程池、它是如何工作的。


線程池

讓我們回到剛才那個(gè)可憐的銷售助理,從很遠(yuǎn)的倉(cāng)庫(kù)取貨物。但是他變聰明了,也或許因?yàn)閼嵟仡櫩捅梢曌兊寐斆髁???gòu)買了一套配送服務(wù)?,F(xiàn)在有人想購(gòu)買遠(yuǎn)距離倉(cāng)庫(kù)中的貨物,銷售助理無(wú)需前往,只需要將訂單轉(zhuǎn)給配送服務(wù),后者會(huì)處理這個(gè)訂單,銷售助理可以繼續(xù)為其他顧客服務(wù)。由此只有貨物不再商鋪的顧客需要等待貨物提取,其他顧客能夠快速得到服務(wù)。

把訂單轉(zhuǎn)給配送服務(wù),這樣就不會(huì)阻塞隊(duì)列了


對(duì) NGINX 而言,線程池就是充當(dāng)配送服務(wù)的角色,它由一個(gè)任務(wù)隊(duì)列和一組處理隊(duì)列的線程組成。一旦工作進(jìn)程需要處理某個(gè)可能的長(zhǎng)操作,不用自己操作,將其作為一個(gè)任務(wù)放出線程池的隊(duì)列,接著會(huì)被某個(gè)空閑線程提取處理。

工作進(jìn)程把阻塞操作轉(zhuǎn)給線程池


像是擁有了一個(gè)新的隊(duì)列,不過(guò)本例中的隊(duì)列局限于某個(gè)特定的資源。從硬盤(pán)中讀取數(shù)據(jù)的速度不會(huì)超過(guò)硬盤(pán)生成數(shù)據(jù)的速度。硬盤(pán)沒(méi)有延遲處理其他事件,僅僅需要獲取文件的請(qǐng)求在等待。


硬盤(pán)讀取操作通常就是阻塞操作,不過(guò)NGINX中的線程池可以用來(lái)處理任何在主工作周期不適合處理的任務(wù)。


此刻分派給線程池的任務(wù)主要有兩個(gè):許多操作系統(tǒng)上 read() 方法的系統(tǒng)調(diào)用,以及 Linux 系統(tǒng)的 sendfile()方法。我們會(huì)繼續(xù)測(cè)試(test)和基準(zhǔn)測(cè)試(benchmark),未來(lái)發(fā)布的版本或許將其他的操作分派給線程池。

 

基準(zhǔn)測(cè)試

I到了從理論到實(shí)踐的時(shí)候了,為了展示利用線程池的效果,我們打算設(shè)置一個(gè)合成基準(zhǔn)模擬最糟糕的阻塞或者非阻塞操作。


數(shù)據(jù)集不能超出內(nèi)存,在一個(gè) 48GB 內(nèi)存機(jī)器上,生成 256GB 隨機(jī)數(shù)據(jù),每個(gè)文件大小 4MB ,接著配置 NGINX 1.9.0 為其提供服務(wù)。


配置及其簡(jiǎn)單:


worker_processes 16;

 

events {

    accept_mutex off;

}

 

http {

    include mime.types;

    default_type application/octet-stream;

 

    access_log off;

    sendfile on;

    sendfile_max_chunk 512k;

 

    server {

        listen 8000;

 

        location / {

            root /storage;

        }

    }

}


正如你所看到的,為了獲得更好的性能,我們做了一些調(diào)優(yōu):關(guān)閉了 loggin 和 accept_mutex,同時(shí)開(kāi)啟了 sendfile(),設(shè)置 sendfile_max_chunk 大小為512K。最后面的指令可以減少阻塞方法 sendfile() 調(diào)用的所花費(fèi)的最大時(shí)間,即 NGINX 每次無(wú)需發(fā)送整個(gè)文件,只發(fā)送 512KB 的塊數(shù)據(jù)。


計(jì)算機(jī)含有兩個(gè)英特爾至強(qiáng) E5645 處理器(Intel Xeon E5645),以及 10Gbps 網(wǎng)絡(luò)接口。硬盤(pán)子系統(tǒng)由四個(gè)西部數(shù)據(jù) WD1003FBYX 硬盤(pán)按放在一個(gè) RAID10 陣列中。所有硬件由Ubuntu Server 14.04.1 LTS進(jìn)行管理。

為基準(zhǔn)測(cè)試,配置 NGINX 和負(fù)載生成器


客戶端由兩個(gè)配置相同的計(jì)算機(jī)組成,其中一臺(tái),wrk 通過(guò)用 Lua 腳本創(chuàng)建負(fù)載。腳本通過(guò)  200 個(gè)并行連接,隨機(jī)向服務(wù)器請(qǐng)求文件。每一個(gè)請(qǐng)求可能導(dǎo)致緩存失效、產(chǎn)生一個(gè)硬盤(pán)阻塞讀操作。姑且稱這種負(fù)載叫隨機(jī)負(fù)載。


在第二臺(tái)客戶端計(jì)算機(jī)上,我們運(yùn)行另一個(gè) wrk 拷貝,用 50 個(gè)并行連接多次訪問(wèn)同一個(gè)文件。因?yàn)槲募哳l訪問(wèn),它會(huì)一直留在內(nèi)存中。通常,NGINX可以非??斓靥幚磉@些請(qǐng)求,不過(guò)工作進(jìn)程一旦阻塞被其他請(qǐng)求阻塞,性能就會(huì)下滑。姑且稱這種負(fù)載為恒定負(fù)載。


利用 ifstat 命令獲取第二臺(tái)客戶端的 wrk 結(jié)果,來(lái)監(jiān)控服務(wù)器吞吐量,并以此測(cè)定服務(wù)器性能。


第一次沒(méi)有線程池參與的運(yùn)行,并沒(méi)有帶給我們什么驚喜的結(jié)果:


% ifstat -bi eth2

 

eth2

Kbps in  Kbps out

5531.24  1.03e 06

4855.23  812922.7

5994.66  1.07e 06

5476.27  981529.3

6353.62  1.12e 06

5166.17  892770.3

5522.81  978540.8

6208.10  985466.7

6370.79  1.12e 06

6123.33  1.07e 06


正如你所看到的,如此配置的服務(wù)器產(chǎn)生流量總計(jì)大約為 1 Gbps。從 top 的輸出信息,我們可以看出所有工作進(jìn)程在阻塞輸入輸出上花費(fèi)的時(shí)間:


top - 10:40:47 up 11 days,  1:32,  1 user,  load average: 49.61, 45.77 62.89

Tasks: 375 total,  2 running, 373 sleeping,  0 stopped,  0 zombie

%Cpu(s):  0.0 us,  0.3 sy,  0.0 ni, 67.7 id, 31.9 wa,  0.0 hi,  0.0 si,  0.0 st

 

KiB Mem:  49453440 total, 49149308 used,   304132 free,    98780 buffers

KiB Swap: 10474236 total,    20124 used, 10454112 free, 46903412 cached Mem

 

  PID USER     PR  NI    VIRT    RES     SHR S  %CPU %MEM    TIME COMMAND

 4639 vbart    20   0   47180  28152     496 D   0.7  0.1  0:00.17 nginx

 4632 vbart    20   0   47180  28196     536 D   0.3  0.1  0:00.11 nginx

 4633 vbart    20   0   47180  28324     540 D   0.3  0.1  0:00.11 nginx

 4635 vbart    20   0   47180  28136     480 D   0.3  0.1  0:00.12 nginx

 4636 vbart    20   0   47180  28208     536 D   0.3  0.1  0:00.14 nginx

 4637 vbart    20   0   47180  28208     536 D   0.3  0.1  0:00.10 nginx

 4638 vbart    20   0   47180  28204     536 D   0.3  0.1  0:00.12 nginx

 4640 vbart    20   0   47180  28324     540 D   0.3  0.1  0:00.13 nginx

 4641 vbart    20   0   47180  28324     540 D   0.3  0.1  0:00.13 nginx

 4642 vbart    20   0   47180  28208     536 D   0.3  0.1  0:00.11 nginx

 4643 vbart    20   0   47180  28276     536 D   0.3  0.1  0:00.29 nginx

 4644 vbart    20   0   47180  28204     536 D   0.3  0.1  0:00.11 nginx

 4645 vbart    20   0   47180  28204     536 D   0.3  0.1  0:00.17 nginx

 4646 vbart    20   0   47180  28204     536 D   0.3  0.1  0:00.12 nginx

 4647 vbart    20   0   47180  28208     532 D   0.3  0.1  0:00.17 nginx

 4631 vbart    20   0   47180    756     252 S   0.0  0.1  0:00.00 nginx

 4634 vbart    20   0   47180  28208     536 D   0.0  0.1  0:00.11 nginx

 4648 vbart    20   0   25232   1956    1160 R   0.0  0.0  0:00.08 top

25921 vbart    20   0  121956   2232    1056 S   0.0  0.0  0:01.97 sshd

25923 vbart    20   0   40304   4160    2208 S   0.0  0.0  0:00.53 zsh


I本例中,吞吐量的短板為硬盤(pán)子系統(tǒng),CPU大多數(shù)時(shí)間都在空閑。wrk 輸出結(jié)果看吞吐量很低:


Running 1m test @ http://192.0.2.1:8000/1/1/1

  12 threads and 50 connections

  Thread Stats   Avg    Stdev     Max   /- Stdev

    Latency     7.42s  5.31s   24.41s   74.73%

    Req/Sec     0.15    0.36     1.00    84.62%

  488 requests in 1.01m, 2.01GB read

Requests/sec:      8.08

Transfer/sec:     34.07MB


記住,應(yīng)該從內(nèi)存送達(dá)文件。巨大的延遲是因?yàn)樗械墓ぷ鬟M(jìn)程忙于從硬盤(pán)讀取文件,響應(yīng)第一個(gè)客戶端的 200 個(gè)連接創(chuàng)建的隨機(jī)負(fù)載,無(wú)法處理我們的請(qǐng)求。


是時(shí)候讓線程登場(chǎng)了,為此我們給 location 模塊添加了 aio threads 指令:


location / {

    root /storage;

    aio threads;

}


請(qǐng)求NGINX重載其配置


重新測(cè)試結(jié)果:


% ifstat -bi eth2

 

eth2

Kbps in  Kbps out

60915.19  9.51e 06

59978.89  9.51e 06

60122.38  9.51e 06

61179.06  9.51e 06

61798.40  9.51e 06

57072.97  9.50e 06

56072.61  9.51e 06

61279.63  9.51e 06

61243.54  9.51e 06

59632.50  9.50e 06


此時(shí)服務(wù)器產(chǎn)生 9.5 Gbps 流量,而沒(méi)有線程池參與時(shí)只產(chǎn)生大約 1 Gbps 的流量。


甚至可以產(chǎn)生更多流量,不過(guò)這已經(jīng)達(dá)到實(shí)際網(wǎng)絡(luò)最大容量。由此可見(jiàn)本測(cè)試中,制約NGINX因素為網(wǎng)絡(luò)接口。工作進(jìn)程大部分時(shí)間在休眠和等待新事件,參見(jiàn)top輸出S state


top - 10:43:17 up 11 days,  1:35,  1 user,  load average: 172.71, 93.84, 77.90

Tasks: 376 total,  1 running, 375 sleeping,  0 stopped,  0 zombie

%Cpu(s):  0.2 us,  1.2 sy,  0.0 ni, 34.8 id, 61.5 wa,  0.0 hi,  2.3 si,  0.0 st

 

KiB Mem:  49453440 total, 49096836 used,   356604 free,    97236 buffers

KiB Swap: 10474236 total,    22860 used, 10451376 free, 46836580 cached Mem

 

  PID USER     PR  NI    VIRT    RES     SHR S  %CPU %MEM    TIME COMMAND

 4654 vbart    20   0  309708  28844     596 S   9.0  0.1  0:08.65 nginx

 4660 vbart    20   0  309748  28920     596 S   6.6  0.1  0:14.82 nginx

 4658 vbart    20   0  309452  28424     520 S   4.3  0.1  0:01.40 nginx

 4663 vbart    20   0  309452  28476     572 S   4.3  0.1  0:01.32 nginx

 4667 vbart    20   0  309584  28712     588 S   3.7  0.1  0:05.19 nginx

 4656 vbart    20   0  309452  28476     572 S   3.3  0.1  0:01.84 nginx

 4664 vbart    20   0  309452  28428     524 S   3.3  0.1  0:01.29 nginx

 4652 vbart    20   0  309452  28476     572 S   3.0  0.1  0:01.46 nginx

 4662 vbart    20   0  309552  28700     596 S   2.7  0.1  0:05.92 nginx

 4661 vbart    20   0  309464  28636     596 S   2.3  0.1  0:01.59 nginx

 4653 vbart    20   0  309452  28476     572 S   1.7  0.1  0:01.70 nginx

 4666 vbart    20   0  309452  28428     524 S   1.3  0.1  0:01.63 nginx

 4657 vbart    20   0  309584  28696     592 S   1.0  0.1  0:00.64 nginx

 4655 vbart    20   0  30958   28476     572 S   0.7  0.1  0:02.81 nginx

 4659 vbart    20   0  309452  28468     564 S   0.3  0.1  0:01.20 nginx

 4665 vbart    20   0  309452  28476     572 S   0.3  0.1  0:00.71 nginx

 5180 vbart    20   0   25232   1952    1156 R   0.0  0.0  0:00.45 top

 4651 vbart    20   0   20032    752     252 S   0.0  0.0  0:00.00 nginx

25921 vbart    20   0  121956   2176    1000 S   0.0  0.0  0:01.98 sshd

25923 vbart    20   0   40304   3840    2208 S   0.0  0.0  0:00.54 zsh


仍有充裕的CPU資源。


wrk執(zhí)行結(jié)果:


Running 1m test @ http://192.0.2.1:8000/1/1/1

  12 threads and 50 connections

  Thread Stats   Avg      Stdev     Max   /- Stdev

    Latency   226.32ms  392.76ms   1.72s   93.48%

    Req/Sec    20.02     10.84    59.00    65.91%

  15045 requests in 1.00m, 58.86GB read

Requests/sec:    250.57

Transfer/sec:      0.98GB


處理一個(gè) 4 MB文件的平均時(shí)間由 7.42 秒降到 226.32 毫秒,降低至少33倍。同時(shí),每秒請(qǐng)求數(shù)提高31倍。


這是因?yàn)槲覀兊恼?qǐng)求無(wú)需在事件隊(duì)列中等待處理,即使工作進(jìn)程阻塞在讀操作上,請(qǐng)求可以由空閑的線程來(lái)完成處理。只要硬盤(pán)子系統(tǒng)表現(xiàn)出色,NGINX很好地為來(lái)自第一個(gè)客戶端的隨機(jī)負(fù)載服務(wù),它就可以利用剩余的CPU資源和網(wǎng)絡(luò)容量,從內(nèi)存讀取,為第二個(gè)客戶端的請(qǐng)求服務(wù)。


這并非是銀彈


當(dāng)我們經(jīng)歷了阻塞操作的帶來(lái)的恐懼以及線程池帶來(lái)的興奮感之后,或許我們中的多數(shù)人已經(jīng)打算在服務(wù)器中配置線程池。別急!


幸運(yùn)的是,多數(shù)讀寫(xiě)文件操作無(wú)需處理緩慢的硬盤(pán),如果你有足夠的內(nèi)存,操作系統(tǒng)會(huì)足夠聰明把那些高頻次訪問(wèn)的文件緩存到一個(gè)稱之為“頁(yè)面緩存”(page cache)中。


頁(yè)面緩存表現(xiàn)優(yōu)異,使得 NGINX 幾乎在通常的用例中性能表現(xiàn)突出。從頁(yè)面緩存中讀取速度非??欤瑳](méi)有人認(rèn)為類操作是“阻塞”的。換言之,分派負(fù)載給線程池會(huì)帶來(lái)一些開(kāi)銷。


所以,如果有合適的內(nèi)存,并且數(shù)據(jù)集不大,那么無(wú)需線程池,NGINX 就可以在最佳性能下工作。


分派讀操作給線程池是一種對(duì)針對(duì)特定任務(wù)的技術(shù)。頻次非常高的請(qǐng)求內(nèi)容不適合放入操作系統(tǒng)虛擬緩存中,這時(shí)候線程池就很有了?;蛟S就是如此,例如,重量級(jí)基于NGINX負(fù)載流媒體服務(wù)器。我們的基準(zhǔn)測(cè)試已模仿這個(gè)場(chǎng)景。


如果能將讀操作分派給線程池是極好的,我們所要做的是需要的文件數(shù)據(jù)是否在內(nèi)存中,如果不在內(nèi)存中,那么我們就應(yīng)該將讀操作分派給某個(gè)線程。


回到銷售的例子,當(dāng)下銷售員面臨的情況是,不知道請(qǐng)求物品是否在店鋪,要么將所有的訂單傳給提取貨物服務(wù),要么他自己處理這些訂單。


要命的是,操作系統(tǒng)可能永遠(yuǎn)沒(méi)有這個(gè)功能。第一次嘗試是 2010 年 linux 中引入 fincore() 系統(tǒng)調(diào)用方法,沒(méi)有成功。接著做了一系列嘗試,例如引入新的帶有 RWF_NONBLOCK 標(biāo)記的 preadv2() 系統(tǒng)調(diào)用方法。所有的這些補(bǔ)丁前景依舊不明朗。比較悲劇的是,因?yàn)槌掷m(xù)的口水戰(zhàn),導(dǎo)致這些補(bǔ)丁一直沒(méi)有被內(nèi)核接受。


另一個(gè)原因是,F(xiàn)reeBSD用戶根本不會(huì)關(guān)心這個(gè)。因?yàn)?FreeBSD 已經(jīng)有一個(gè)非常高效的異步文件讀取接口,完全可以不用線程池。


配置線程池


如果確信你的用例采用線程池可以獲利,那么是時(shí)候深入其配置了。


線程池配置非常容易而且靈活。首先你需要 NGINX 1.7.11 版,或者更新的版本,采用配置文件中的參數(shù) –with-threads 進(jìn)行編譯。最簡(jiǎn)單的例子,配置看起來(lái)相當(dāng)?shù)娜菀?,所有你需要做的的事情就是給http、server或者location上下文中添加 aio threads 指令。


aio threads;


這可能是最簡(jiǎn)短的線程池配置了,實(shí)際上,下面這個(gè)配置是一個(gè)簡(jiǎn)化版的:


thread_pool default threads=32 max_queue=65536;

aio threads=default;


它定義一個(gè)名為 default 的線程池,擁有 32 個(gè)工作線程,任務(wù)隊(duì)列容納的最大請(qǐng)求數(shù)為 65536。一旦任務(wù)隊(duì)列過(guò)載,NGINX日志會(huì)報(bào)錯(cuò)并拒絕這一請(qǐng)求:


thread pool 'NAME' queue overflow: N tasks waiting


報(bào)錯(cuò)意味著線程可能處理工作的速度跟不上任務(wù)添加進(jìn)隊(duì)列的速度,你可以試著增加隊(duì)列的到最大容量。如果還是不起作用,可能是系統(tǒng)服務(wù)請(qǐng)求的數(shù)量已達(dá)到了上線。


正如你所看到的,可以用thread_pool指令設(shè)置線程數(shù)量、隊(duì)列最大容量、為某個(gè)線程池命名。為某個(gè)線程池命名意味著你可以設(shè)置多個(gè)獨(dú)立的線程池,在不同的配置文件用于不同目的。


http {

    thread_pool one threads=128 max_queue=0;

    thread_pool two threads=32;

 

    server {

        location /one {

            aio threads=one;

        }

 

        location /two {

            aio threads=two;

        }

    }

}


如果沒(méi)有指定max_queue參數(shù),它的默認(rèn)值為65536。如上面所展示的,可以將max_queue設(shè)置為0。這意味這,如在本例,線程池只能處理分派給線程那些任務(wù);因?yàn)殛?duì)列中沒(méi)有存儲(chǔ)任何等待的任務(wù)。


試想你的服務(wù)器有三個(gè)硬盤(pán),你希望服務(wù)器能像緩存代理一樣作用,緩存所有來(lái)自后端的響應(yīng),預(yù)期緩存的數(shù)據(jù)量遠(yuǎn)遠(yuǎn)超過(guò)了現(xiàn)有的內(nèi)存。這個(gè)緩存節(jié)點(diǎn)為私人內(nèi)容分發(fā)網(wǎng)絡(luò)(CDN)服務(wù),當(dāng)然本例中最重要的事情就是從硬盤(pán)那里獲取最大性能。


一種選擇是設(shè)置一個(gè)磁盤(pán)陣列,這種方式有其優(yōu)點(diǎn)和缺點(diǎn)。NGINX采用另外一種方式:


# 假定每個(gè)硬盤(pán)驅(qū)動(dòng)掛載一個(gè)文件目錄上

# We assume that each of the hard drives is mounted on one of the directories:

# /mnt/disk1, /mnt/disk2, or /mnt/disk3 accordingly

proxy_cache_path /mnt/disk1 levels=1:2 keys_zone=cache_1:256m max_size=1024G 

                 use_temp_path=off;

proxy_cache_path /mnt/disk2 levels=1:2 keys_zone=cache_2:256m max_size=1024G 

                 use_temp_path=off;

proxy_cache_path /mnt/disk3 levels=1:2 keys_zone=cache_3:256m max_size=1024G 

                 use_temp_path=off;

 

thread_pool pool_1 threads=16;

thread_pool pool_2 threads=16;

thread_pool pool_3 threads=16;

 

split_clients $request_uri $disk {

    33.3%     1;

    33.3%     2;

    *         3;

}

 

location / {

    proxy_pass http://backend;

    proxy_cache_key $request_uri;

    proxy_cache cache_$disk;

    aio threads=pool_$disk;

    sendfile on;

}


在這個(gè)設(shè)置中,用到了三個(gè)獨(dú)立的緩存,對(duì)應(yīng)一個(gè)硬盤(pán)。同樣也有三個(gè)獨(dú)立的線程池對(duì)應(yīng)某個(gè)硬盤(pán)。


split_clients 模塊用于緩存之間的負(fù)載平衡,很好地滿足這個(gè)任務(wù)。


proxy_cache_path 指令中的參數(shù) use_temp_path=off 指示 NGINX 存儲(chǔ)臨時(shí)文件到緩存數(shù)據(jù)對(duì)應(yīng)的相同目錄中;在緩存更新時(shí),避免磁盤(pán)之間拷貝響應(yīng)數(shù)據(jù)。


做的所有這一切,都是為了使當(dāng)前硬盤(pán)子系統(tǒng)性能達(dá)到最大,因?yàn)镹GINX中每個(gè)線程池與磁盤(pán)的交互都是獨(dú)立并行的。每個(gè)磁盤(pán)由 16 個(gè)獨(dú)立的線程為其服務(wù),即處理某個(gè)特定任務(wù)隊(duì)列中文件的讀取和發(fā)送。


我猜測(cè)你的客戶端采用類似客戶定制的方式,那么同樣確保你的硬盤(pán)驅(qū)動(dòng)也采用類似的方式。


本例很好的展示了NGINX如何靈活地針對(duì)特定硬盤(pán)做出調(diào)優(yōu),就像你給出指令,告訴NGINX與計(jì)算機(jī)以及數(shù)據(jù)集的最佳交互方式。通過(guò)細(xì)粒度的NGINX調(diào)優(yōu),可以確保軟件、操作系統(tǒng)、硬件處在一種最佳的工作狀態(tài),即盡可能有效地利用系統(tǒng)資源。


結(jié)論

總之,線程池是一個(gè)非常棒的特性,它能促使NGINX性能上一個(gè)新臺(tái)階,移除了眾所周知的頑疾——阻塞,特別是涉及海量數(shù)據(jù)的時(shí)候。


當(dāng)然遠(yuǎn)非這些,正如前面所提到的,新的接口可能會(huì)允許我們分派任何長(zhǎng)的阻塞操作,而且不會(huì)有性能損失。NGINX開(kāi)辟了新天地,擁有一批新的模塊和功能。而許多流行的庫(kù)依舊沒(méi)有提供某種異步非阻塞接口,這樣很難和NGINX兼容?;蛟S我們需要花費(fèi)很多時(shí)間和資源,開(kāi)發(fā)一些我們自己的非阻塞原生庫(kù),但這樣做值得么?隨著線程池特性的上線,這些庫(kù)在不影響模塊性能的前提下會(huì)更加相對(duì)簡(jiǎn)單易用。


文章來(lái)源:伯樂(lè)在線

本站僅提供存儲(chǔ)服務(wù),所有內(nèi)容均由用戶發(fā)布,如發(fā)現(xiàn)有害或侵權(quán)內(nèi)容,請(qǐng)點(diǎn)擊舉報(bào)
打開(kāi)APP,閱讀全文并永久保存 查看更多類似文章
猜你喜歡
類似文章
NGINX引入線程池 性能提升9倍
NGINX 架構(gòu)
多線程并發(fā)基礎(chǔ)通過(guò)Object的方法實(shí)現(xiàn)阻阻塞隊(duì)列
java-從java線程池來(lái)看java的阻塞隊(duì)列
nodejs多線程,真正的非阻塞
深入解讀 Elasticsearch 熱點(diǎn)線程 hot_threads
更多類似文章 >>
生活服務(wù)
分享 收藏 導(dǎo)長(zhǎng)圖 關(guān)注 下載文章
綁定賬號(hào)成功
后續(xù)可登錄賬號(hào)暢享VIP特權(quán)!
如果VIP功能使用有故障,
可點(diǎn)擊這里聯(lián)系客服!

聯(lián)系客服