摘要:將訂單傳遞給運送服務從而解除阻塞隊列在方面,線程池正在執行運送服務的功能。我們將繼續測試和評估,如果有明顯的好處,我們可能會在未來的版本中將其他操作也提交到線程池。
在nginx的官網看到一篇介紹nginx原理的文章,這篇文章比較老了是15年發布的,國內有人翻譯過但是有些小瑕疵,這里更正出來發布在我個人的文章里供大家參考,這篇文章詳細的介紹了nginx線程池的原理以及設計思路,在最后通過詳細的實驗數據來告訴我們通過線程池提升的性能以及分析了應該使用線程池的場景。在日后的其他領域依然很有借鑒意義。
點我看源文
大家都知道NGINX使用異步以及事件驅動的方式來處理請求,這意味著,我們不會為每個請求創建另一個專用的進程或線程(比如像那些使用了傳統架構的服務器)。而是選擇一個工作進程來處理多個連接請求。為了實現這樣的特性,NGINX使用非阻塞模式下的socket以及選擇了更有效率的系統調用比如epoll和kqueue。
滿負載的進程數量很少(通常是每個cpu核心只占一個)而且是恒定的,這樣消耗了更少的內存以及cpu時間片沒有被浪費在任務切換上。這個方法的優點可以通過nginx這個例子來反映出來。它可以非常好的并發處理上百萬的請求規模并且處理的效果還不錯。
每個進程消耗額外的內存,每次進程之間的切換會消耗CPU周期以及產生cpu緩存垃圾
但是異步,事件驅動這類模型同樣存在問題。或者我更喜歡把這樣的問題稱作敵人。敵人的名字叫做:阻塞。不幸的是,許多第三方模塊都使用了阻塞式的調用,而且用戶(有時候甚至模塊的開發者)沒有意識到這么做的弊端。阻塞式的操作會毀掉NGINX的性能所以無論如何一定要被阻止。
但是在現在的官方版本的NGINX源代碼中也不可能在任何情況下避免阻塞,為了解決這個問題新的“線程池”特性被引入到NGINX version 1.7.11以及NGINX PLUS Release 7當中來.它是什么以及它如何使用這個我們稍后討論,現在我們來面對我們的敵人了。
編輯注-想對NGINX PLUS R7有個大概了解可以在我們的博客看到更多
想看NGINX PLUS R7其他特性的具體分析,可以看下邊列出來的博客:
HTTP/2 Now Fully Supported in NGINX Plus
Socket Sharding in NGINX
The New NGINX Plus Dashboard in Release 7
TCP Load Balancing in NGINX Plus R7
問題首先,為了更好的了解NGINX我們會用幾句話解釋一下它是如何工作的。
大體來說,NGINX是一個事件處理器,一個從內核接收目前的連接信息然后發送接下來做的什么命令給操作系統的控制器。實際上NGINX做的臟活累活是通過協調操作系統來做的,本質上是操作系統在做周期性的讀或者寫。所以對NGINX來說反應的快速及時是很重要的。
工作進程監聽以及處理從內核傳過來的事件
這些事件可能會超時,通知socket讀就緒或者寫就緒,或者通知一個錯誤的產生。NGINX接收到一串事件接著一個一個的處理它們。所以所有的操作可以在一個線程的一個隊列的一次簡單循環當中完成。NGINX從隊列當中彈出一個事件然后通過比如讀寫socket來做后續處理。在大多數情況下,這個操作會很快(也許這個操作只需要很少的cpu時間片去從內存當中copy一些數據)并且NGINX可以用很短的時間在這個隊列當中處理完所有的事件。
所有的操作都在一個線程的簡單循環當中做完了。
但是如果一個長時間并且重量級的操作到來會發生啥呢?答案顯而易見,整個事件處理的循環都會被這個操作所阻塞直到這個操作完成。
因此,所謂“阻塞操作”是指任何導致事件處理循環顯著停止一段時間的操作。操作會因為各種各樣的原因而被阻塞。比如說,NGINX可能忙于處理冗長的CPU密集型處理,或者可能需要等待訪問資源(例如硬盤驅動器,或一個庫函數以同步方式從數據庫獲取響應,等等等等)。關鍵的問題在于,處理這樣的事情,工作線程不能做其他別的事情,即使其他的系統資源可以獲取到而且隊列當中的其他一些事件會用到這些資源。
想象一下商店銷售員面前有長長的一長隊人。 隊列中的第一個人需要一個不在商店但是在倉庫里的東西。 銷售人員跑到倉庫去提貨。 現在,整個隊列必須等待幾個小時才能進行交付,排隊當中的每個人都不滿意。 想想如果是你你會如何反應? 隊員中的每個人的等待時間都增加了這幾個小時,但他們打算買的東西有可能就在店里。
隊列里的每個人都必須因為第一個的訂單而等待。
相同的情況發生在NGINX當中,想想當它想要讀一個沒有緩存在內存中的文件而不得不去訪問硬盤的時候。硬盤驅動器很慢(特別是機械硬盤),而等待隊列中的其他請求可能不需要訪問驅動器,所以它們也是被迫等待的。 因此,延遲增加,系統資源未得到充分利用。
只有一個阻塞會大幅延遲所有的接下來所有的操作
一些操作系統提供用于讀取和發送文件的異步接口,NGINX可以使用此接口(請參閱aio指令)。 這里有個好例子就是FreeBSD。坑爹的是,Linux可能不如左邊這位那么友好。 雖然Linux提供了一種用于讀取文件的異步接口,但它有一些顯著的缺點。 其中一個是文件訪問和緩沖區的對齊要求,當然NGINX可以把這個問題處理得很好。 但第二個問題更糟糕,異步接口需要在文件描述符上設置O_DIRECT標志,這意味著對文件的任何訪問將繞過內存中的緩存并增加硬盤上的負載。這無形中干掉了很多原本可以使用這個調用的場景。
為了特別解決這個問題,NGINX 1.7.11和NGINX Plus Release 7中引入了線程池。
現在我們來看看什么線程池是關于它們以及它們的工作原理。
線程池讓我們回到上個問題,倒霉的銷售助理從遙遠的倉庫配貨這個用例。 這次他變得更聰明(也許是被憤怒的客戶群毆后變得更聰明了),他雇傭了送貨服務。 現在,當有人需要遙遠的倉庫里的一些東西的時候,他不會親自去倉庫而只不過下了一個訂單到送貨服務,他們會處理訂單,而我們的銷售助理會繼續為其他客戶服務。 因此,只有那些貨物不在商店的客戶正在等待交貨,而售貨員可以馬上繼續為其他客戶提供服務。
將訂單傳遞給運送服務從而解除阻塞隊列
在NGINX方面,線程池正在執行運送服務的功能。 它由一個任務隊列和多個處理隊列的線程組成。 當一個工作進程需要做一個潛在的長時間操作時,它不會自己處理這個操作,而是將一個任務放在線程池的隊列中,任何空閑的線程都可以從中進行處理。
工作進程將阻塞操作裝載到線程池
看來我們還有一個隊列。是的,但是在這種情況下,隊列受到特定資源的限制。我們從磁盤讀取資源速度永遠比磁盤生成數據要慢。但是現在至少磁盤操作不會延遲其他事件的處理,只有需要訪問文件的請求正在等待。
通常將“從磁盤讀取”操作用作阻塞操作的最常見示例,但實際上NGINX中的線程池實現適用于任何不適合在主工作循環中處理的任務。
目前,提交到線程池僅用于三個基本操作:大多數操作系統上的read()系統調用,Linux上的sendfile()和Linux上的在編寫一些臨時文件比如緩存時使用到的aio_write()。我們將繼續測試和評估,如果有明顯的好處,我們可能會在未來的版本中將其他操作也提交到線程池。
編輯注: 在NGINX 1.9.13和NGINX Plus R9中添加了對aio_write()系統調用的支持。
評估基準現在到了理論通往實踐的時候了。 為了演示使用線程池的效果,我們將執行一個合成基準,模擬阻塞和非阻塞操作的最糟糕組合。
它需要一個確保不適合內存貯存的數據集。 在具有48 GB內存的機器上,我們已經生成了256 GB的隨機4M分割數據,然后配置了NGINX version 1.9.0來為其提供服務。
配置非常簡單:
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; } } }
可以看到的是,為了獲得更好的性能,一些調優已經提前做完:logging和accept_mutex被禁用,sendfile被啟用,并且sendfile_max_chunk被設置。 最后一個指令可以減少阻止sendfile()調用所花費的最大時間,因為NGINX不會一次嘗試發送整個文件,而是分割成512 KB的數據塊來執行相應操作。
該機器有兩塊Intel Xeon E5645(12核24線程)處理器和10 Gbps網絡接口。 磁盤子系統由安裝在RAID10陣列中的四個西數WD1003FBYX硬盤驅動器表示。 操作系統是Ubuntu Server 14.04.1 LTS。
相應基準下負載生成和NGINX的配置。
客戶由兩臺相同的規格的機器組成。其中一個機器上,wrk使用Lua腳本創建負載。腳本以200的并發連接從服務器以隨機順序請求文件,和每個請求都可能會導致緩存缺失從而導致從磁盤讀取產生的阻塞。我們就叫它“加載隨機載荷”。
第二客戶端機器我們將運行另一個副本的wrk,但是這個腳本我們使用50的并發連接來請求相同的文件。因為這個文件被經常訪問的,它將保持在內存中。在正常情況下,NGINX很快的處理這些請求,但是工作線程如果被其他的請求阻塞性能將會下降。所以我們暫且叫它“加載恒定負載”。
性能將由服務器上ifstat監測的吞吐率(throughput)和從第二臺客戶端獲取的wrk結果來度量。
現在,第一次沒有線程池給了我們不是那么讓人賽艇的結果:
% 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
如你所見,上述的配置可以產生一共1G的流量,從top命令上我們可以看到所有的工作線程在阻塞io上花費了大量的時間(下圖D狀態):
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
在這種情況下,吞吐率受限于磁盤子系統,而CPU在大部分時間里是空轉狀態的。從wrk獲得的結果來看也非常低:
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
請記住,文件是從內存送達的!第一個客戶端的200個連接創建的隨機負載,使服務器端的全部的工作進程忙于從磁盤讀取文件,因此產生了過大的延遲,并且無法在合適的時間內處理我們的請求。
然后亮出線程池了。為此,我們只需在location塊中添加aio threads指令:
location / { root /storage; aio threads; }
接著,執行NGINX reload重新加載配置。
然后,我們重復上述的測試:
% 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
現在我們的服務器產生9.5 Gbps的流量,對比之前沒有線程池時的1 Gbps高下立判!
理論上還可以產生更多的流量,但是這已經達到了機器的最大網絡吞吐能力,所以在這次NGINX的測試中,NGINX受限于網絡接口。工作進程的大部分時間只是休眠和等待新的事件(它們在下圖處于top的S狀態):
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的結果:
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.42秒降到226.32毫秒(減少了33倍),每秒請求處理數提升了31倍(250 vs 8)!
對此,我們的解釋是請求不再因為工作進程被阻塞在讀文件而滯留在事件隊列中等待處理,它們可以被空閑的線程(線程池當中的)處理掉。只要磁盤子系統能撐住第一個客戶端上的隨機負載,NGINX可以使用剩余的CPU資源和網絡容量,從內存中讀取,以服務于上述的第二個客戶端的請求。
沒有什么靈丹妙藥在拋出我們對阻塞操作的擔憂并給出一些令人振奮的結果后,可能大部分人已經打算在你的服務器上配置線程池了。但是先別著急。
實際上很幸運大多數的讀或者寫文件操作都不會和硬盤打交道。如果我們有足夠的內存來存儲數據集,那么操作系統會聰明地在被稱作“頁面緩存”的地方緩存那些頻繁使用的文件。
“頁面緩存”的效果很好,可以讓NGINX在幾乎所有常見的用例中展示優異的性能。從頁面緩存中讀取比較快,沒有人會說這種操作是“阻塞”。另一方面,裝載任務到線程池是有一定開銷的。
因此,如果你的機器有合理的大小的內存并且待處理的數據集不是很大的話,那么無需使用線程池,NGINX已經工作在最優化的方式下。
裝載讀操作到線程池是一種適用于非常特殊任務的技巧。只有當經常請求的內容的大小不適合操作系統的虛擬機緩存時,這種技術才是最有用的。至于可能適用的場景,比如,基于NGINX的高負載流媒體服務器。這正是我們已經上文模擬的基準測試的場景。
我們如果可以改進裝載讀操作到線程池,將會非常有意義。我們只需要知道所需的文件數據是否在內存中,只有不在內存中的時候讀操作才應該裝載到線程池的某個多帶帶的線程中。
再回到售貨員的場景中,這回售貨員不知道要買的商品是否在店里,他必須要么總是將所有的訂單提交給運貨服務,要么總是親自處理它們。
是的,問題的本質就是操作系統沒有這樣的特性。2010年人們第一次試圖把這個功能作為fincore()系統調用加入到Linux當中,但是沒有成功。后來還有一些是使用RWF_NONBLOCK標記作為preadv2()系統調用來實現這一功能的嘗試(詳情見LWN.net上的非阻塞緩沖文件讀取操作和異步緩沖讀操作)。但所有這些補丁的命運目前還不明朗。悲催的是,這些補丁尚沒有被內核接受的主要原因你可以看這里:(bikeshedding)。
譯者著:我覺得沒加入內核完全就是開發組里面一派人有類似“要啥自行車”這樣的想法.....
另一方面,FreeBSD的用戶完全不必擔心。FreeBSD已經具備足夠好的異步讀取文件接口,我們應該用它而不是線程池。
配置線程池所以如果你確信在你的用例中使用線程池會帶來好處,那么現在就是時候深入了解線程池的配置了。
線程池的配置非常簡單、靈活。首先,獲取NGINX 1.7.11或更高版本的源代碼,使用--with-threads配置參數編譯。在最簡單的場景中,配置也看起來很簡單。所有你需要的所有事就是在合適的情況下把aio線程的指令include進來:
# in the "http", "server", or "location" context aio threads;
這是線程池的最簡配置。實際上邊的配置是下邊的精簡版:
# in the "main" context thread_pool default threads=32 max_queue=65536; # in the "http", "server", or "location" context aio threads=default;
這里定義了一個名為“default”,包含32個線程,任務隊列最多支持65536個請求的線程池。如果任務隊列過載,NGINX將拒絕請求并輸出如下錯誤日志:
thread pool "NAME" queue overflow: N tasks waiting
錯誤輸出意味著線程處理作業的速度有可能低于任務入隊的速度了。你可以嘗試增加隊列的最大值,但是如果這無濟于事,那這意味著你的系統沒有能力處理這么多的請求了。
正如你已經注意到的,你可以使用thread_pool指令,配置線程的數量、隊列的最大長度,以及特定線程池的名稱。最后要說明的是,可以配置多個相互獨立的線程池,并在配置文件的不同位置使用它們來滿足不同的用途:
# in the "main" context thread_pool one threads=128 max_queue=0; thread_pool two threads=32; http { server { location /one { aio threads=one; } location /two { aio threads=two; } } #... }
如果沒有指定max_queue參數的值,默認使用的值是65536。如上所示,可以設置max_queue為0。在這種情況下,線程池將使用配置中全部數量的線程來盡可能地同時處理多個任務;隊列中不會有等待的任務。
現在,假設我們有一臺服務器,掛了3塊硬盤,我們希望把該服務器用作“緩存代理”,緩存后端服務器的全部響應。預期的緩存數據量遠大于可用的內存。它實際上是我們個人CDN的一個緩存節點。毫無疑問,在這種情況下,最重要的事情是發揮硬盤的最大性能。
我們的選擇之一是配置一個RAID陣列。這種方法毀譽參半,現在,有了NGINX,我們可以有另外的選擇:
# We assume that each of the hard drives is mounted on one of these directories: # /mnt/disk1, /mnt/disk2, or /mnt/disk3 # in the "main" context thread_pool pool_1 threads=16; thread_pool pool_2 threads=16; thread_pool pool_3 threads=16; http { 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; split_clients $request_uri $disk { 33.3% 1; 33.3% 2; * 3; } server { #... location / { proxy_pass http://backend; proxy_cache_key $request_uri; proxy_cache cache_$disk; aio threads=pool_$disk; sendfile on; } } }
在這份配置中,使用了3個獨立的緩存,每個緩存專用一塊硬盤,另外,3個獨立的線程池也各自專用一塊硬盤,proxy_cache_path指令在每個磁盤定義了一個專用、獨立的緩存
split_clients模塊用于高速緩存之間的負載平衡(以及磁盤之間的結果),它完全適合這類任務。
在 proxy_cache_path指令中設置use_temp_path=off,表示NGINX會將臨時文件保存在緩存數據的同一目錄中。這是為了避免在更新緩存時,磁盤之間互相復制響應數據。
這些調優將發揮磁盤子系統的最優性能,因為NGINX通過多帶帶的線程池并行且獨立地與每塊磁盤交互。每個磁盤由16個獨立線程提供支持,并且線程具有用于讀取和發送文件的專用任務隊列。
我們相信你的客戶會喜歡這種量身定制的方法。請確保你的磁盤撐得住。
這個示例很好地證明了NGINX可以為硬件專門調優的靈活性。這就像你給NGINX下了一道命令,要求機器和數據最優配合。而且,通過NGINX在用戶空間中細粒度的調優,我們可以確保軟件、操作系統和硬件工作在最優模式下并且盡可能有效地利用系統資源。
總結綜上所述,線程池是個好功能,它將NGINX的性能提高到新的高度并且干掉了一個眾所周知的長期隱患:阻塞,尤其是當我們真正面對大量吞吐的情況下這種優勢更加明顯。
但是還有更多的驚喜。正如前面所述,這種全新的接口可能允許裝載任何耗時和阻塞的操作而不會造成任何性能的損失。 NGINX在大量新模塊和功能方面開辟了新的天地。 許多受歡迎的庫仍然沒有提供異步非阻塞接口,以前這使得它們與NGINX不兼容。 我們可能花費大量的時間和精力來開發自己的非阻塞原型庫,但是這么做可能并不值得。 現在,使用線程池,我們可以相對容易地使用這些庫,并且這些模塊不會對性能產生影響。
敬請期待下篇文章。
文章版權歸作者所有,未經允許請勿轉載,若此文章存在違規行為,您可以聯系管理員刪除。
轉載請注明本文地址:http://m.specialneedsforspecialkids.com/yun/39589.html
摘要:文件系統請求和相關請求都會放進這個線程池處理其他的請求,如網絡平臺特性相關的請求會分發給相應的系統處理單元參見設計概覽。 譯者按:在 Medium 上看到這篇文章,行文脈絡清晰,闡述簡明利落,果斷點下翻譯按鈕。第一小節背景鋪陳略啰嗦,可以略過。剛開始我給這部分留了個 blah blah blah 直接翻后面的,翻完之后回頭看,考慮完整性才把第一節給補上。接下來的內容干貨滿滿,相信對 N...
摘要:當一個進行需要處理阻塞操作時,它會將這個任務交給線程池來完成。線程池配置如果你確信引入線程池對性能提升有效,那么咱們可以繼續了解一些調優參數。這個錯誤表示這個線程池消費小于生產,所以可以增加隊列長度,如果調整無效,說明系統達到了瓶頸。 五年級英語水平,端午家庭作業。 前言 Nginx以異步、事件驅動的方式處理連接。傳統的方式是每個請求新起一個進程或線程,Nginx沒這樣做,它通過非...
摘要:用線程池執行異步任務為了減少阻塞時間,加快響應速度,把無需返回結果的操作變成異步任務,用線程池來執行,這是提高性能的一種手段。疲于奔命的模式,做不好大型服務端開發,也難以做好各種領域的開發。 1. 用線程池執行異步任務 為了減少阻塞時間,加快響應速度,把無需返回結果的操作變成異步任務,用線程池來執行,這是提高性能的一種手段。 你可能要驚訝了,這么做不對嗎? 首先,我們把異步任務分...
摘要:用線程池執行異步任務為了減少阻塞時間,加快響應速度,把無需返回結果的操作變成異步任務,用線程池來執行,這是提高性能的一種手段。疲于奔命的模式,做不好大型服務端開發,也難以做好各種領域的開發。 1. 用線程池執行異步任務 為了減少阻塞時間,加快響應速度,把無需返回結果的操作變成異步任務,用線程池來執行,這是提高性能的一種手段。 你可能要驚訝了,這么做不對嗎? 首先,我們把異步任務分...
閱讀 1830·2021-10-20 13:49
閱讀 1371·2019-08-30 15:52
閱讀 2876·2019-08-29 16:37
閱讀 1046·2019-08-29 10:55
閱讀 3079·2019-08-26 12:14
閱讀 1659·2019-08-23 17:06
閱讀 3243·2019-08-23 16:59
閱讀 2553·2019-08-23 15:42