中文字幕在线观看,亚洲а∨天堂久久精品9966,亚洲成a人片在线观看你懂的,亚洲av成人片无码网站,亚洲国产精品无码久久久五月天

關(guān)于真正理解Node.js事件循環(huán)你需要了解的一切

2018-07-20    來源:編程學(xué)習(xí)網(wǎng)

容器云強(qiáng)勢(shì)上線!快速搭建集群,上萬Linux鏡像隨意使用

Node.js是一個(gè)基于事件的平臺(tái)。這意味著Node中發(fā)生的任何事情都是對(duì)于事件的響應(yīng)。傳入Node的數(shù)據(jù)處理要經(jīng)歷一層層嵌套的回調(diào)。這一流程相對(duì)于開發(fā)者被抽象出來,由一個(gè)叫做libuv的庫處理,就是libuv為我們提供了事件循環(huán)機(jī)制。

事件循環(huán)也許是Node中最容易被誤解的概念。

我為Dynatrace工作,這是一家性能監(jiān)控服務(wù)商。在我們解決事件循環(huán)監(jiān)控這一問題時(shí),我們付出了很多努力去正確理解我們正在監(jiān)測(cè)的部分。

這篇文章將包含我們所學(xué)到的,事件循環(huán)是如何工作,以及如何去正確的監(jiān)控它。

常見錯(cuò)誤觀念

libuv是為Node.js提供事件循環(huán)的庫。libuv背后的關(guān)鍵人物之一,Bert Belder,在他令人驚嘆的 Node Interactive的主題演講的一開始,他以一個(gè)Google圖片搜索的結(jié)果展示了人們用來描繪事件循環(huán)的不同方法,并且他說其中大部分是錯(cuò)誤的。

關(guān)于真正理解Node.js事件循環(huán)你需要了解的一切 - 眾成翻譯

我來概括一下(在我看來)最普遍的錯(cuò)誤觀念。

錯(cuò)誤觀念 1: 事件循環(huán)在用戶代碼中運(yùn)行于一個(gè)獨(dú)立的線程。

錯(cuò)誤觀念

一個(gè)主線程來執(zhí)行用戶的JavaScript代碼(用戶代碼 userland code),另一個(gè)線程來執(zhí)行事件循環(huán)。每當(dāng)有異步操作發(fā)生,主線程將會(huì)把異步操作移交給事件循環(huán)線程,當(dāng)異步操作完成,事件循環(huán)線程將會(huì)通知主線程去執(zhí)行回調(diào)。

事實(shí)

只有一個(gè)線程來執(zhí)行JavaScript代碼而且事件循環(huán)也運(yùn)行在這個(gè)線程之中;卣{(diào)(一個(gè)運(yùn)行中的Node.js應(yīng)用中的任何用戶代碼都是回調(diào))的執(zhí)行通過事件循環(huán)來完成。后面我們將深入了解這些。

錯(cuò)誤觀念 2: 所有異步操作通過一個(gè)線程池來處理

錯(cuò)誤觀念

異步操作,比如操作文件系統(tǒng),發(fā)起對(duì)外的HTTP請(qǐng)求或者數(shù)據(jù)庫交互總是需要加載一個(gè)由libuv提供的線程池。

事實(shí)

libuv默認(rèn)創(chuàng)建一個(gè)由四個(gè)線程組成的線程池來加載異步操作。如今的操作系統(tǒng)已經(jīng)對(duì)很多I/O任務(wù)提供了異步接口 (如Linux中的AIO)。只要有可能,libuv都會(huì)使用這些異步接口而避免使用線程池。這同樣適用于第三方的子系統(tǒng)比如數(shù)據(jù)庫。這些驅(qū)動(dòng)的作者將更傾向于使用異步接口而不是使用線程池。簡(jiǎn)而言之: 只有不存在其他方式的時(shí)候,異步I/O才會(huì)使用線程池。

錯(cuò)誤觀念 3: 事件循環(huán)類似于;蜿(duì)列

錯(cuò)誤觀念

事件循環(huán)輪詢一個(gè)由異步任務(wù)組成的先進(jìn)先出隊(duì)列,當(dāng)任務(wù)完成時(shí)執(zhí)行回調(diào)。

事實(shí)

雖然需要類似于隊(duì)列的結(jié)構(gòu),但是事件循環(huán)并沒有使用棧。事件循環(huán)就像是一系列的階段以循環(huán)的方式處理各自具體任務(wù)的過程。

理解事件循環(huán)中的不同階段

為了真正了解事件循環(huán)我們必須去了解它在每個(gè)階段做了哪些工作。希望可以得到Bert Belder的認(rèn)同,以我的方式來展示事件循環(huán)是如何工作的將會(huì)是下面這樣:

關(guān)于真正理解Node.js事件循環(huán)你需要了解的一切 - 眾成翻譯

讓我們來聊一聊這些階段。全面的解釋可以在Node.js 網(wǎng)站上看到。

Timers

各種通過setTimeout()或者setInterval()設(shè)置的定時(shí)任務(wù)都將在這一階段被處理。

IO Callbacks

這一階段大多數(shù)回調(diào)會(huì)被處理。這里指的是用戶代碼,因?yàn)樗性贜ode.js中的用戶代碼本質(zhì)上來說都在回調(diào)中(例如一個(gè)剛收到的http請(qǐng)求會(huì)觸發(fā)一連串嵌套的回調(diào))。

IO Polling

輪詢將在下一輪事件循環(huán)中被處理的新事件。

Set Immediate

執(zhí)行所有通過setImmediate()注冊(cè)的回調(diào)。

Close

所有偵聽close事件的回調(diào)將在這一階段被處理。

監(jiān)控事件循環(huán)

我們可以看出事實(shí)上一個(gè)Node應(yīng)用里發(fā)生的任何事情都是通過事件循環(huán)來運(yùn)行的。這意味著如果我們可以從事件循環(huán)中得到各種指標(biāo),這些指標(biāo)可以在應(yīng)用大體上的健康情況和性能方面,為我們提供有價(jià)值的信息。由于沒有可以從事件循環(huán)中獲取到運(yùn)行時(shí)指標(biāo)的API,各種監(jiān)控工具提供了各自的指標(biāo)。來看一下我們所提供的指標(biāo)。

Tick Frequency

每段時(shí)間內(nèi)完成的周期數(shù)量。

Tick Duration

一個(gè)周期需要花費(fèi)的時(shí)間。

由于我們的代理可以像原生模塊那樣運(yùn)行,通過添加探針來為我們提供這些信息是相對(duì)容易的。

Tick frequency 和 tick duration 指標(biāo)在實(shí)際中的應(yīng)用

當(dāng)我們第一次在不同的負(fù)載在進(jìn)行測(cè)試的時(shí)候,結(jié)果是令人意想不到的----讓我展示一個(gè)示例:

在下面的場(chǎng)景中,我將調(diào)用一個(gè)express.js應(yīng)用來向另外一臺(tái)http服務(wù)器發(fā)送請(qǐng)求。

這里有四個(gè)場(chǎng)景:

  1. Idle 沒有收到任何請(qǐng)求。

  2. ab -c 5 利用apache bench一次創(chuàng)建5個(gè)并發(fā)請(qǐng)求

  3. ab -c 10 10個(gè)并發(fā)請(qǐng)求

  4. ab -c 10 (slow backend) http服務(wù)器1s后再返回?cái)?shù)據(jù)來模擬緩慢的后端。這會(huì)產(chǎn)生回調(diào)的壓力因?yàn)檎?qǐng)求在等待的后端返回在Node內(nèi)部堆積。

關(guān)于真正理解Node.js事件循環(huán)你需要了解的一切 - 眾成翻譯

如果我們觀察結(jié)果圖表,我們可以得出一個(gè)有趣的結(jié)論:

事件循環(huán)的持續(xù)時(shí)間和頻率是動(dòng)態(tài)的,以適應(yīng)負(fù)載的變化。

如果應(yīng)用是空閑的,意味著沒有待處理的任務(wù)(計(jì)時(shí)器任務(wù)或是回調(diào)等等),因?yàn)闆]有理由去全速完成事件循環(huán)中的各個(gè)階段,因此事件循環(huán)會(huì)調(diào)整以適應(yīng)這一情況,并且會(huì)在輪詢階段阻塞一會(huì)兒來等待新的外部事件進(jìn)來。

這也意味著,沒有負(fù)載下的指標(biāo)(低頻率高耗時(shí))與在高負(fù)載下緩慢的后端的情況下的指標(biāo)是相似的。

我們也看到這個(gè)示例應(yīng)用在5個(gè)并發(fā)請(qǐng)求的場(chǎng)景下運(yùn)行的狀態(tài)最好。

因此周期頻率和周期時(shí)間應(yīng)以當(dāng)前的每秒請(qǐng)求數(shù)為基準(zhǔn)。

盡管這些數(shù)據(jù)已經(jīng)為我們提供了一些有價(jià)值的信息,但我們依舊不知道時(shí)間花在哪一個(gè)階段,因此我們做了更加深入的研究,又提出了兩個(gè)新指標(biāo)。

Work processed latency

這個(gè)指標(biāo)用了度量一個(gè)異步任務(wù)被線程池處理所花費(fèi)的時(shí)間。

高的工作處理時(shí)延表明了這是一個(gè)忙碌/被耗盡的線程池。

為了測(cè)試這個(gè)指標(biāo),我創(chuàng)建了一個(gè)express路由,利用一個(gè)名叫Sharp的圖片來處理圖片。因?yàn)閳D片處理是昂貴的,Sharp利用線程池來完成對(duì)圖片的處理。

關(guān)于真正理解Node.js事件循環(huán)你需要了解的一切 - 眾成翻譯

運(yùn)行Apache bench以5個(gè)并發(fā)連接請(qǐng)求有圖片處理功能的路由的結(jié)果直接的反映在這個(gè)圖表上,并且能夠很明顯的與中等負(fù)載而無圖片處理的場(chǎng)景區(qū)分開。

Event Loop Latency

事件循環(huán)時(shí)延用來度量一個(gè)通過setTimeout(X)設(shè)置的定時(shí)任務(wù)被處理所花費(fèi)的時(shí)間。

高的時(shí)間循環(huán)時(shí)延意味著時(shí)間循環(huán)忙于處理回調(diào)。

為了這次這個(gè)指標(biāo),我創(chuàng)建了一個(gè)express路由,通過一個(gè)很低效的算法來計(jì)算斐波那契數(shù)列。

關(guān)于真正理解Node.js事件循環(huán)你需要了解的一切 - 眾成翻譯

運(yùn)行Apache bench,以5個(gè)并發(fā)連接調(diào)用有斐波那契數(shù)列計(jì)算功能的路由,結(jié)果展示了當(dāng)前回調(diào)隊(duì)列是忙碌的。

我們清楚地看到上面四個(gè)指標(biāo)可以為我們提供有價(jià)值的信息來幫助我們更好的理解Node.js的內(nèi)部是如何工作。

所有這些指標(biāo)都需要從一個(gè)更大的圖景來觀察以理解它。因此我們當(dāng)前正在收集信息并將這些數(shù)據(jù)作為參考因素。

調(diào)整事件循環(huán)

事實(shí)上,僅有指標(biāo)而不知道如何采取行動(dòng)去修正這些問題對(duì)我們幫助不大。這里有一些關(guān)于事件循環(huán)看起來繁忙時(shí)應(yīng)該如何去做的建議。

關(guān)于真正理解Node.js事件循環(huán)你需要了解的一切 - 眾成翻譯

利用所有的CPU

一個(gè)Node.js應(yīng)用運(yùn)行在一個(gè)單一的線程中。這意味著在多核設(shè)備中,負(fù)載并沒有被分發(fā)到所有的核心上。使用 cluster模塊,它使得Node.js可以輕松的在每個(gè)CPU上創(chuàng)建子進(jìn)程。每個(gè)子進(jìn)程維護(hù)著一個(gè)獨(dú)立的事件循環(huán),并且主進(jìn)程將負(fù)載分發(fā)到所有的子進(jìn)程中。

調(diào)整線程池

就像上面提到的,libuv將創(chuàng)建一個(gè)四個(gè)線程的線程池。這個(gè)線程池的默認(rèn)大小可以通過設(shè)置環(huán)境變量UV_THREADPOOL_SIZE來重寫。雖然這樣可以解決I/O密集型應(yīng)用的負(fù)載問題,但是過高的負(fù)載測(cè)試?yán)邕^大的線程池依舊會(huì)耗盡內(nèi)存或CPU的資源。

移除服務(wù)中的計(jì)算密集型工作

如果Node.js花費(fèi)太多時(shí)間在計(jì)算密集型操作上,為服務(wù)移除這些工作或是使用另一種更適合這個(gè)任務(wù)的語言將會(huì)是一個(gè)切實(shí)可行的選擇。

總結(jié)

讓我們總結(jié)一下在這篇文章中我們學(xué)到的:

  • 事件循環(huán)維持著一個(gè)Node.js應(yīng)用的運(yùn)行

  • 它的功能經(jīng)常被錯(cuò)誤的理解----它是需要經(jīng)歷一系列的階段,每個(gè)階段處理不同的任務(wù)

  • 事件循環(huán)沒有提供開箱可用的指標(biāo),因此不同的APM服務(wù)商收集的指標(biāo)是不同的。

  • 雖然這些指標(biāo)提供了關(guān)于性能瓶頸有價(jià)值的信息,但是深入理解事件循環(huán)機(jī)制和正在執(zhí)行的代碼才是關(guān)鍵。

  • 在未來,Dynatrace將增加一個(gè)事件循環(huán)遠(yuǎn)程監(jiān)控技術(shù)到根本原因檢測(cè)中以將事件循環(huán)的異常與問題相關(guān)聯(lián)。

對(duì)我來說,毫無疑問的我們剛剛創(chuàng)建了當(dāng)今市場(chǎng)上最全面的事件循環(huán)監(jiān)控解決方案,并且我很開心這些令人激動(dòng)的新特性將在接下來的幾周內(nèi)推向我們的用戶。

感謝

Dynatrace中杰出的Node.js代理團(tuán)隊(duì)在事件循環(huán)監(jiān)控上付出了很多努力。這篇博客文章中呈現(xiàn)的大部分發(fā)現(xiàn)是基于他們?cè)贜ode.js內(nèi)部工作機(jī)制方面深入的知識(shí)。我想感謝Bernhard Liedl、Dominik Gruber、Gerhard St?bich和Gernot Reisinger,感謝他們付出的努力以及對(duì)我的支持。

我希望這篇文章在這個(gè)主題上對(duì)讀者確實(shí)有所啟發(fā)。請(qǐng)關(guān)注我的twitter@dkhan,在很高興在那里或是在下面的評(píng)論區(qū)里解答你們的提問。

如果你想繼續(xù)了解更多事件循環(huán)的內(nèi)部工作機(jī)制或是作為開發(fā)者如何使用事件循環(huán),我推薦我朋友發(fā)表在RisingStack上的這篇文章 。

如果你想嘗試一下我們的Node.js監(jiān)控,下載我們的免費(fèi)試用版并在任何時(shí)間分享你的反饋給我——這是我們了解用戶的方式。

來自:

 

標(biāo)簽: Google http服務(wù)器 linux 代碼 服務(wù)器 服務(wù)商 開發(fā)者 數(shù)據(jù)庫 搜索

版權(quán)申明:本站文章部分自網(wǎng)絡(luò),如有侵權(quán),請(qǐng)聯(lián)系:west999com@outlook.com
特別注意:本站所有轉(zhuǎn)載文章言論不代表本站觀點(diǎn)!
本站所提供的圖片等素材,版權(quán)歸原作者所有,如需使用,請(qǐng)與原作者聯(lián)系。

上一篇:2018 年初值得關(guān)注的 25 個(gè)新 Android 庫和項(xiàng)目

下一篇:Go 1.10中值得關(guān)注的幾個(gè)變化