摘要:當(dāng)一個進(jìn)行需要處理阻塞操作時,它會將這個任務(wù)交給線程池來完成。線程池配置如果你確信引入線程池對性能提升有效,那么咱們可以繼續(xù)了解一些調(diào)優(yōu)參數(shù)。這個錯誤表示這個線程池消費小于生產(chǎn),所以可以增加隊列長度,如果調(diào)整無效,說明系統(tǒng)達(dá)到了瓶頸。
五年級英語水平,端午家庭作業(yè)。
前言Nginx以異步、事件驅(qū)動的方式處理連接。傳統(tǒng)的方式是每個請求新起一個進(jìn)程或線程,Nginx沒這樣做,它通過非阻塞sockets、epoll、kqueue等高效手段,實現(xiàn)一個worker進(jìn)程處理多個連接和請求。
一般情況下下是一個CPU內(nèi)核對應(yīng)一個worker進(jìn)程,所以worker進(jìn)程數(shù)量固定,并且不多,所以在任務(wù)切換上消耗的內(nèi)存和CPU減少了。這種方式很不錯,在高并發(fā)和擴(kuò)展能力等方面都能體現(xiàn)。
看圖說話,任務(wù)切換不見了。
但是異步事件模式很不喜歡阻塞(blocking)。很多第三方模塊使用了阻塞模式的調(diào)用,有時候,用戶乃至模塊作者都不知道到阻塞調(diào)用會大大降低Nginx的性能。
Nginx自己的代碼都有一些場景需要使用到阻塞,所以在1.7.11版本中,引入了新的“線程池”機(jī)制,在了解這個機(jī)制前,我們先瞅瞅阻塞。
問題了解阻塞前,先講兩句
Nginx其實就是一個事件處理器,接收內(nèi)核發(fā)出的所有與connections相關(guān)的事件信息,然后告訴操作系統(tǒng)該做什么。操作系統(tǒng)如此復(fù)雜和底層,所以Nginx的指揮必須叼。
從上圖看,有超時、sockets準(zhǔn)備好讀寫、錯誤通知等事件。這些事件都放在一個隊列中,Nginx對事件隊列進(jìn)行處理。
如果一個事件對于到的操作非常耗時,那么整個隊列的處理就會延遲。
“阻塞操作”就是這樣一個導(dǎo)致隊列處理延遲的什么鬼。舉個例子,CPU密集型計算,資源訪問(硬盤、mutex、同步訪問數(shù)據(jù)庫等等)。發(fā)生阻塞時,worker進(jìn)程只能等待。
就跟過安檢時一樣,如果你的隊伍里面有個小朋友帶了一大瓶AD鈣奶,那你只有等他喝完。
有些系統(tǒng)提供的異步文件接口,例如FreeBSD。Linux也提供了類似機(jī)制,但是不太好用。首先它要求文件或緩存是扇區(qū)對齊的,好吧,Nginx能做到。其次更苛刻的一點是,它要求文件設(shè)置O_DIRECT標(biāo)志位,這就是說,所有訪問這個文件的操作都是直接讀取,不走任何緩存,這樣反而會增加磁盤IO負(fù)擔(dān)。
問了解決這些問題,1.7.11版本中引入了線程池。
線程池你家樓下的順豐快遞就是一個線程池,不用每次寄快遞都要去順豐總部,狗屎一樣的比喻。。
對Nginx來說,線程池的作用跟快遞點一樣。它包括一個任務(wù)隊列以及配套線程。當(dāng)一個worker進(jìn)行需要處理阻塞操作時,它會將這個任務(wù)交給線程池來完成。
這里引入了一個新的隊列,在例子中,這個隊列因為讀取資源導(dǎo)致緩慢,讀取硬盤雖然慢,至少它不會影響事件隊列的繼續(xù)處理。
任何阻塞操作都可以放到線程池中。目前,我們只嘗試了兩個核心操作:主流操作系統(tǒng)的read()系統(tǒng)調(diào)用和Linux上的sendfile()。后續(xù)經(jīng)過性能測試會考慮納入更多的操作。
性能測試為了證實上述理論,進(jìn)行了如下測試,測試場景包括各種阻塞操作和非阻塞操作。
我們在一臺48G內(nèi)存的機(jī)器上生成了總共256的隨機(jī)文件,每個文件大小為4MB。這樣做的目的是保證數(shù)據(jù)不受內(nèi)存緩存影響。
簡單的配置如下:
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; } } }
配置中進(jìn)行了一些調(diào)優(yōu):禁用logging和accpet_mutex,啟用sendfile并設(shè)置sendfile_max_chunk,有利于減少阻塞調(diào)用sendfile時帶來的總時間。
測試機(jī)器配置為雙Intel至強(qiáng)E5645(共12核-24線程),10G網(wǎng)卡,四塊西數(shù)1003FBYX組成的RAID10,系統(tǒng)為Ubuntu Server 14.04.1 LTS。
兩臺配置一樣的客戶端,一臺機(jī)器通過Lua和wrk隨機(jī)產(chǎn)生200個并發(fā)請求,每個請求都不會命中緩存,所以Nginx處理時會產(chǎn)生讀盤阻塞操作。另一臺機(jī)器則是產(chǎn)生50個并發(fā)請求,每個請求讀取固定文件,頻繁的文件讀取會命中緩存,所以一般情況下此類請求處理速度較快,當(dāng)worker進(jìn)程阻塞時請求速度會受影響。
通過ifstat和在第二臺機(jī)器上wrk來監(jiān)控系統(tǒng)吞吐性能。
無線程池結(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
吞吐量大約是1Gbps,從top看,所有的worker進(jìn)程主要消耗在阻塞I/O上(top中的D狀態(tài))
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
IO受磁盤限制,CPU多數(shù)處于空閑狀態(tài)。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)該命中緩存非常快速的,但是因為worker進(jìn)程受第一臺服務(wù)器的200并發(fā)影響,所以最終比較慢。
接下來對照線程池實驗,在location配置中添加一個aio線程指令
location / { root /storage; aio threads; }
重新加載Nginx配置后,重復(fù)上述測試
% 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
哇,產(chǎn)生了9.5Gbps的吞吐性能。
性能沒準(zhǔn)還能更改,因為已經(jīng)達(dá)到了網(wǎng)卡瓶頸。這次,worker進(jìn)程主要消耗在sleeping和時間等待上(top中的S狀態(tài))。
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的結(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
4MB文件的請求時間從7.41秒提升至了226.32毫秒(約33倍),QPS提升了大約31倍(250比8)。
提升的原因不再贅述,大約就是事件隊列沒有受阻罷了。
不是萬靈丹看到這里,是不是立馬就想去修改你的生產(chǎn)環(huán)境了,且慢。
事實上,絕大多數(shù)的read和sendfile都是在緩存頁中進(jìn)行的,操作系統(tǒng)會把頻繁使用的文件放在緩存頁中。
當(dāng)你的數(shù)據(jù)量較小,并且內(nèi)存足夠大時,Nginx已經(jīng)是處于最佳狀態(tài)了,開線程池反倒會引入開銷。線程池能夠良好應(yīng)對的一個場景,是數(shù)據(jù)無法被完全緩存,例如流媒體服務(wù)器,我們上面的測試環(huán)境,就是模擬的流媒體服務(wù)。
能否用線程池來提升讀操作的性能呢?唯一需要做的,就是能有效區(qū)分哪些文件已經(jīng)被緩存,哪些文件未緩存。
咱們的系統(tǒng)沒有提供這樣的信息。早在2010年Linux嘗試通過fincore()來實現(xiàn)未果。接下來是preadv2()和RWF_NONBLOCK標(biāo)志位方式,可惜也不好用,具體可以參考內(nèi)核bikeshedding一文。
哈哈,至少FreeBSD用戶可以先喝咖啡了,無需在線程池問題上傷腦筋。
線程池配置如果你確信引入線程池對性能提升有效,那么咱們可以繼續(xù)了解一些調(diào)優(yōu)參數(shù)。
這些調(diào)優(yōu)都是基于1.7.11+ 版本,編譯選項為--with-threads參數(shù)。最簡單的場景下,僅需在http、server或location區(qū)塊配置aio thread參數(shù)即可
aio threads;
它對應(yīng)的完整配置是
thread_pool default threads=32 max_queue=65536; aio threads=default;
默認(rèn)情況下包括一個32個線程的線程池,長度為65536的請求隊列。如果隊列溢出,Nginx會輸出如下錯誤并拒絕請求。
thread pool "NAME" queue overflow: N tasks waiting
這個錯誤表示這個線程池消費小于生產(chǎn),所以可以增加隊列長度,如果調(diào)整無效,說明系統(tǒng)達(dá)到了瓶頸。
另外,我們可以調(diào)整線程相關(guān)的參數(shù),例如對不同場景,可以提供獨立的線程池。
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; } } … }
在未定義max_queue時默認(rèn)為65536,當(dāng)設(shè)置成0時,服務(wù)能力等同線程數(shù)量。
假如你的緩存代理服務(wù)器有3塊磁盤,內(nèi)存不能放下預(yù)期需要緩存的文件,所以我們首先需要讓磁盤工作最大化。
一個方式是RAID,好壞兼并。另一個方式是Nginx
# 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; }
使用了3個獨立的緩存,每個緩存指定到一塊磁盤,然后有3個獨立的線程池。
split_clients模塊用于緩存間的負(fù)載均衡。
use_temp_path=off參數(shù)讓Nginx將緩存文件保存至文件同級目錄,可以避免緩存更新時磁盤間的文件數(shù)據(jù)交換。
結(jié)論明天他媽又要上課了
原文地址:http://nginx.com/blog/thread-pools-boost-performance-9x/
文章版權(quán)歸作者所有,未經(jīng)允許請勿轉(zhuǎn)載,若此文章存在違規(guī)行為,您可以聯(lián)系管理員刪除。
轉(zhuǎn)載請注明本文地址:http://specialneedsforspecialkids.com/yun/39170.html
摘要:將訂單傳遞給運送服務(wù)從而解除阻塞隊列在方面,線程池正在執(zhí)行運送服務(wù)的功能。我們將繼續(xù)測試和評估,如果有明顯的好處,我們可能會在未來的版本中將其他操作也提交到線程池。 在nginx的官網(wǎng)看到一篇介紹nginx原理的文章,這篇文章比較老了是15年發(fā)布的,國內(nèi)有人翻譯過但是有些小瑕疵,這里更正出來發(fā)布在我個人的文章里供大家參考,這篇文章詳細(xì)的介紹了nginx線程池的原理以及設(shè)計思路,在最后通...
摘要:為每個依賴提供一個小的線程池或信號,如果線程池已滿調(diào)用將被立即拒絕,默認(rèn)不采用排隊加速失敗判定時間。 最近小主看到很多公眾號都在發(fā)布Hystrix停更的文章,spring cloud體系的使用者和擁護(hù)者一片哀嚎,實際上,spring作為Java最大的家族,根本不需要擔(dān)心其中一兩個零件的廢棄,Hystrix的停更,只會催生更多或者更好的零件來替代它,因此,我們需要做的是:**知道Hyst...
摘要:快杰云主機(jī)最新一代快杰云主機(jī),整體計算性能提升內(nèi)網(wǎng)包量最高可達(dá)萬單個支持最大外網(wǎng)帶寬存儲性能最高可達(dá)萬,延遲低至。憑借強(qiáng)大的性能,快杰云主機(jī)為海量數(shù)據(jù)運算高性能數(shù)據(jù)庫高并發(fā)網(wǎng)絡(luò)集群等場景帶來新一輪的創(chuàng)新性體驗。 隨著5G網(wǎng)絡(luò)、大數(shù)據(jù)、人工智能、物聯(lián)網(wǎng)等技術(shù)的快速發(fā)展,數(shù)據(jù)增長進(jìn)入了空前的規(guī)模。如何實現(xiàn)海量數(shù)據(jù)的存儲、分析、交互,真正發(fā)揮數(shù)據(jù)的價值,已經(jīng)成為企業(yè)新的挑戰(zhàn),而算力就是其中最先需...
摘要:關(guān)于過程中如何細(xì)節(jié)控制一致性,穩(wěn)定性,信號控制,控制等等,敬請期待小拽的進(jìn)一步探索處理流程和模塊啟動進(jìn)程后,請求在內(nèi)部是如何流轉(zhuǎn)的,內(nèi)部包括哪些模塊處理過程請求到達(dá)后首先讀取,中初始時間便從此開始。 由于性能問題,需要將 apache + php5.2 升級到 nginx + php7,對于nginx的性能和熱加載早有耳聞,why nginx so diao。小拽進(jìn)行了初探,有任何疑問...
摘要:第一階段基礎(chǔ)階段基礎(chǔ)程序員重點把搞熟練核心是安裝配置基本操作目標(biāo)能夠完成基本的系統(tǒng)安裝,簡單配置維護(hù)能夠做基本的簡單系統(tǒng)的開發(fā)能夠在中型系統(tǒng)中支持某個功能模塊的開發(fā)。本項不做重點學(xué)習(xí),除非對前端有興趣。 第一階段:基礎(chǔ)階段(基礎(chǔ)PHP程序員) 重點:把LNMP搞熟練(核心是安裝配置基本操作) 目標(biāo):能夠完成基本的LNMP系統(tǒng)安裝,簡單配置維護(hù);能夠做基本的簡單系統(tǒng)的PHP開發(fā);能夠在P...
閱讀 1778·2023-04-26 01:41
閱讀 3077·2021-11-23 09:51
閱讀 2740·2021-10-09 09:43
閱讀 9040·2021-09-22 15:13
閱讀 2457·2021-09-07 09:59
閱讀 2629·2019-08-30 15:44
閱讀 1137·2019-08-30 12:45
閱讀 2621·2019-08-30 12:43