利用Node.js了解與測量HTTP所花費(fèi)的時(shí)間詳解
前言
了解和測量HTTP時(shí)間有助于我們發(fā)現(xiàn)客戶端到服務(wù)器或服務(wù)器到服務(wù)器之間的通信性能瓶頸。 本文介紹了HTTP請求中的時(shí)間開銷,并展示了如何在Node.js中進(jìn)行測量。
在我們開始了解HTTP時(shí)間開銷之前,讓我們來看一些基本的概念:
- IP(互聯(lián)網(wǎng)協(xié)議):IP是網(wǎng)絡(luò)層協(xié)議,涉及網(wǎng)絡(luò)尋址和路由。 IP負(fù)責(zé)根據(jù)一個(gè)或多個(gè)IP網(wǎng)絡(luò)上的數(shù)據(jù)包頭將數(shù)據(jù)包從源主機(jī)傳送到目標(biāo)主機(jī)。 它還定義了封裝要傳遞的數(shù)據(jù)的數(shù)據(jù)包結(jié)構(gòu)。
- DNS(域名服務(wù)器):DNS是一種分層分散式命名系統(tǒng),用于將諸如risingstack.com的人類可讀主機(jī)名解析為機(jī)器可讀的IP地址。
- TCP(傳輸控制協(xié)議):TCP標(biāo)準(zhǔn)定義了如何在應(yīng)用程序之間建立和維護(hù)網(wǎng)絡(luò)對話以交換數(shù)據(jù)。 TCP在通過IP網(wǎng)絡(luò)通信的主機(jī)上運(yùn)行的應(yīng)用程序之間提供可靠,有序和錯(cuò)誤檢查的八位字節(jié)流。 HTTP客戶端通過建立TCP連接來發(fā)起請求。
- SSL / TLS(傳輸層安全性):TLS是一種通過計(jì)算機(jī)網(wǎng)絡(luò)提供通信安全性的加密協(xié)議。 SSL(安全套接字層)是TLS的不推薦使用的前身。 TLS和SSL都使用證書建立安全連接。 SSL證書不依賴于加密協(xié)議(如TLS),證書包含密鑰對:公鑰和私鑰。 這些密鑰一起工作,建立一個(gè)加密的連接。
現(xiàn)在我們來看一下通常HTTP請求的時(shí)間表:

- DNS查找:執(zhí)行DNS查找所花費(fèi)的時(shí)間。 DNS查找將域名解析為IP地址。 每個(gè)新的域需要一個(gè)完整的往返行程來進(jìn)行DNS查找。 當(dāng)目的地已經(jīng)是IP地址時(shí),沒有DNS查找。
- TCP連接:在源主機(jī)和目標(biāo)主機(jī)之間建立TCP連接所需的時(shí)間。 必須在多步握手過程中正確建立連接。 TCP連接由操作系統(tǒng)管理,如果基礎(chǔ)TCP連接無法建立,則OS范圍的TCP連接超時(shí)將會進(jìn)入我們應(yīng)用程序中的超時(shí)配置。
- TLS握手:完成TLS握手的時(shí)間。 在握手過程中,端點(diǎn)交換認(rèn)證和密鑰以建立或恢復(fù)安全會話。 沒有HTTPS請求的不需要TLS握手。
- 第一個(gè)字節(jié)的時(shí)間(TTFB):等待初始響應(yīng)的時(shí)間。 此時(shí)間除了等待服務(wù)器處理請求和傳遞響應(yīng)所花費(fèi)的時(shí)間之外,還可以捕獲往返服務(wù)器的延遲。
- 內(nèi)容傳輸:接收響應(yīng)數(shù)據(jù)所花費(fèi)的時(shí)間。 響應(yīng)數(shù)據(jù)的大小和可用的網(wǎng)絡(luò)帶寬決定其持續(xù)時(shí)間。
如何通過HTTP時(shí)間開銷幫助發(fā)現(xiàn)性能瓶頸?
例如,如果您的DNS查詢所花費(fèi)的時(shí)間比預(yù)期的要長,那么問題可能是您的DNS提供商或DNS緩存設(shè)置。
緩慢的內(nèi)容傳輸可能是由效率低下的反應(yīng)機(jī)構(gòu)引起的,例如發(fā)回太多的數(shù)據(jù)(未使用的JSON屬性等)或緩慢的連接。
測量Node.js中的HTTP時(shí)間開銷
為了測量Node.js中的HTTP時(shí)間開銷,我們需要訂閱特定的請求,響應(yīng)和套接字事件。 這是一個(gè)簡短的代碼片段,展示了如何在Node.js中執(zhí)行此操作,此示例僅關(guān)注時(shí)序:
const timings = {
// use process.hrtime() as it's not a subject of clock drift
startAt: process.hrtime(),
dnsLookupAt: undefined,
tcpConnectionAt: undefined,
tlsHandshakeAt: undefined,
firstByteAt: undefined,
endAt: undefined
}
const req = http.request({ ... }, (res) => {
res.once('readable', () => {
timings.firstByteAt = process.hrtime()
})
res.on('data', (chunk) => { responseBody += chunk })
res.on('end', () => {
timings.endAt = process.hrtime()
})
})
req.on('socket', (socket) => {
socket.on('lookup', () => {
timings.dnsLookupAt = process.hrtime()
})
socket.on('connect', () => {
timings.tcpConnectionAt = process.hrtime()
})
socket.on('secureConnect', () => {
timings.tlsHandshakeAt = process.hrtime()
})
})
DNS查找只會發(fā)生在有域名的時(shí)候:
/ There is no DNS lookup with IP address const dnsLookup = dnsLookupAt !== undefined ? getDuration(startAt, dnsLookupAt) : undefined
TCP連接在主機(jī)解析后立即發(fā)生:
const tcpConnection = getDuration((dnsLookupAt || startAt), tcpConnectionAt)
TLS握手(SSL)只能使用https協(xié)議:
// There is no TLS handshake without https const tlsHandshake = tlsHandshakeAt !== undefined ? getDuration(tcpConnectionAt, tlsHandshakeAt) : undefined
我們等待服務(wù)器開始發(fā)送第一個(gè)字節(jié):
const firstByte = getDuration((tlsHandshakeAt || tcpConnectionAt), firstByteAt)
總持續(xù)時(shí)間從開始和結(jié)束日期計(jì)算:
const total = getDuration(startAt, endAt)
看到整個(gè)例子,看看我們的https://github.com/RisingStac...倉庫。
測量時(shí)間的工具
現(xiàn)在我們知道如何使用Node測量HTTP時(shí)間,我們來討論可用于了解HTTP請求的現(xiàn)有工具。
request module
著名的request module具有測量HTTP定時(shí)的內(nèi)置方法。 您可以使用time屬性啟用它。
const request = require('request')
request({
uri: 'https://risingstack.com',
method: 'GET',
time: true
}, (err, resp) => {
console.log(err || resp.timings)
})
分布式跟蹤
可以使用分布式跟蹤工具收集HTTP定時(shí),并在時(shí)間軸上可視化它們。 這樣,您可以全面了解后臺發(fā)生的情況,以及構(gòu)建分布式系統(tǒng)的實(shí)際成本是多少。
RisingStack的opentracing-auto庫具有內(nèi)置的標(biāo)志,可通過OpenTracing收集所有HTTP時(shí)間。

在Jaeger中使用opentracing-auto的HTTP請求時(shí)序。
總結(jié)
使用Node.js測量HTTP時(shí)間可以幫助您發(fā)現(xiàn)性能瓶頸。 Node生態(tài)系統(tǒng)提供了很好的工具來從應(yīng)用程序中提取這些指標(biāo)。
好了,以上就是這篇文章的全部內(nèi)容了,希望本文的內(nèi)容對大家的學(xué)習(xí)或者工作能帶來一定的幫助,如果有疑問大家可以留言交流,謝謝大家對腳本之家的支持。
翻譯自Understanding & Measuring HTTP Timings with Node.js
相關(guān)文章
Node.js中MongoDB更新數(shù)據(jù)的兩種方法
本文主要介紹了Node.js中MongoDB更新數(shù)據(jù)的兩種方法,主要包括使用原生的 MongoDB 驅(qū)動程序或者使用 Mongoose 來更新 MongoDB 數(shù)據(jù),2023-12-12
node.js中的buffer.Buffer.byteLength方法使用說明
這篇文章主要介紹了node.js中的buffer.Buffer.byteLength方法使用說明,本文介紹了buffer.Buffer.byteLength的方法說明、語法、接收參數(shù)、使用實(shí)例和實(shí)現(xiàn)源碼,需要的朋友可以參考下2014-12-12
Node.js中的文件系統(tǒng)(file system)模塊詳解
Node.js文件系統(tǒng)模塊提供了豐富的方法,用于讀取、寫入、操作文件和目錄,文件系統(tǒng)模塊是Node.js強(qiáng)大而靈活的一部分,為文件操作提供了方便的API,本文給大家介紹Node.js中的文件系統(tǒng)(file system)模塊,感興趣的朋友一起看看吧2023-11-11
jwt在node中的應(yīng)用實(shí)踐(安裝配置封裝)
這篇文章主要為大家介紹了jwt在node中的應(yīng)用實(shí)踐包括安裝配置封裝,有需要的朋友可以借鑒參考下,希望能夠有所幫助,祝大家多多進(jìn)步,早日升職加薪2023-09-09
nodejs制作一個(gè)文檔同步工具自動同步到gitee中的實(shí)現(xiàn)代碼
這篇文章主要介紹了nodejs制作一個(gè)文檔同步工具自動同步到gitee中,本文通過實(shí)例代碼給大家介紹的非常詳細(xì),對大家的學(xué)習(xí)或工作具有一定的參考借鑒價(jià)值,需要的朋友可以參考下2021-12-12
Nodejs封裝類似express框架的路由實(shí)例詳解
在本篇文章里小編給大家整理的是關(guān)于Nodejs封裝類似express框架的路由實(shí)例內(nèi)容,有需要的朋友們學(xué)習(xí)下。2020-01-01
基于 Docker 開發(fā) NodeJS 應(yīng)用
這是兩篇文章的第一篇。本文涵蓋了有關(guān)在使用 Express 框架開發(fā)一個(gè)Node應(yīng)用時(shí),用Docker 替代 Vagrant 的比較詳細(xì)的教程, 應(yīng)用將使用 connect-redis 中間件將會話信息持久化到Redis中. 第二篇文章將介紹到將這個(gè)開發(fā)的設(shè)置產(chǎn)品化.2014-07-07
node連接MongoDB數(shù)據(jù)庫錯(cuò)誤:MongoServerSelectionError:?connect?ECON
使用node連接MongoDB數(shù)據(jù)庫時(shí)發(fā)生報(bào)錯(cuò),MongoServerSelectionError:?connect?ECONNREFUSED?::1:27017,本文給大家分享原因分析及解決方案,感興趣的朋友跟隨小編一起看看吧2023-04-04

