使用Node.js瞭解和測量HTTP花費的時間

瞭解和測量HTTP時間有助於咱們發現客戶端到服務器服務器到服務器之間的通訊性能瓶頸。 本文介紹了HTTP請求中的時間開銷,並展現瞭如何在Node.js中進行測量。node

在咱們開始瞭解HTTP時間開銷以前,讓咱們來看一些基本的概念:git

  • IP(互聯網協議):IP是網絡層協議,涉及網絡尋址和路由。 IP負責根據一個或多個IP網絡上的數據包頭將數據包從源主機傳送到目標主機。 它還定義了封裝要傳遞的數據的數據包結構。
  • DNS(域名服務器):DNS是一種分層分散式命名系統,用於將諸如risingstack.com的人類可讀主機名解析爲機器可讀的IP地址。
  • TCP(傳輸控制協議):TCP標準定義瞭如何在應用程序之間創建和維護網絡對話以交換數據。 TCP在經過IP網絡通訊的主機上運行的應用程序之間提供可靠,有序和錯誤檢查的八位字節流。 HTTP客戶端經過創建TCP鏈接來發起請求。
  • SSL / TLS(傳輸層安全性):TLS是一種經過計算機網絡提供通訊安全性的加密協議。 SSL(安全套接字層)是TLS的不推薦使用的前身。 TLS和SSL都使用證書創建安全鏈接。 SSL證書不依賴於加密協議(如TLS),證書包含密鑰對:公鑰和私鑰。 這些密鑰一塊兒工做,創建一個加密的鏈接。

如今咱們來看一下一般HTTP請求的時間表:

clipboard.png

  • DNS查找:執行DNS查找所花費的時間。 DNS查找將域名解析爲IP地址。 每一個新的域須要一個完整的往返行程來進行DNS查找。 當目的地已是IP地址時,沒有DNS查找。
  • TCP鏈接:在源主機和目標主機之間創建TCP鏈接所需的時間。 必須在多步握手過程當中正確創建鏈接。 TCP鏈接由操做系統管理,若是基礎TCP鏈接沒法創建,則OS範圍的TCP鏈接超時將會進入咱們應用程序中的超時配置。
  • TLS握手:完成TLS握手的時間。 在握手過程當中,端點交換認證和密鑰以創建或恢復安全會話。 沒有HTTPS請求的不須要TLS握手。
  • 第一個字節的時間(TTFB):等待初始響應的時間。 此時間除了等待服務器處理請求和傳遞響應所花費的時間以外,還能夠捕獲往返服務器的延遲。
  • 內容傳輸:接收響應數據所花費的時間。 響應數據的大小和可用的網絡帶寬決定其持續時間。

如何經過HTTP時間開銷幫助發現性能瓶頸?

例如,若是您的DNS查詢所花費的時間比預期的要長,那麼問題多是您的DNS提供商或DNS緩存設置。github

緩慢的內容傳輸多是由效率低下的反應機構引發的,例如發回太多的數據(未使用的JSON屬性等)或緩慢的鏈接。緩存

測量Node.js中的HTTP時間開銷

爲了測量Node.js中的HTTP時間開銷,咱們須要訂閱特定的請求,響應和套接字事件。 這是一個簡短的代碼片斷,展現瞭如何在Node.js中執行此操做,此示例僅關注時序:安全

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查找只會發生在有域名的時候:服務器

/ There is no DNS lookup with IP address
const dnsLookup = dnsLookupAt !== undefined ?  
  getDuration(startAt, dnsLookupAt) : undefined

TCP鏈接在主機解析後當即發生:網絡

const tcpConnection = getDuration((dnsLookupAt || startAt), tcpConnectionAt)

TLS握手(SSL)只能使用https協議:socket

// There is no TLS handshake without https    
const tlsHandshake = tlsHandshakeAt !== undefined ?  
      getDuration(tcpConnectionAt, tlsHandshakeAt) : undefined

咱們等待服務器開始發送第一個字節tcp

const firstByte = getDuration((tlsHandshakeAt || tcpConnectionAt), firstByteAt)

總持續時間從開始和結束日期計算:分佈式

const total = getDuration(startAt, endAt)

看到整個例子,看看咱們的https://github.com/RisingStac...倉庫。

測量時間的工具

如今咱們知道如何使用Node測量HTTP時間,咱們來討論可用於瞭解HTTP請求的現有工具。

request module

著名的request module具備測量HTTP定時的內置方法。 您可使用time屬性啓用它。

const request = require('request')

request({  
  uri: 'https://risingstack.com',
  method: 'GET',
  time: true
}, (err, resp) => {
  console.log(err || resp.timings)
})

分佈式跟蹤

可使用分佈式跟蹤工具收集HTTP定時,並在時間軸上可視化它們。 這樣,您能夠全面瞭解後臺發生的狀況,以及構建分佈式系統的實際成本是多少。

RisingStack的opentracing-auto庫具備內置的標誌,可經過OpenTracing收集全部HTTP時間。

clipboard.png

在Jaeger中使用opentracing-auto的HTTP請求時序。

總結

使用Node.js測量HTTP時間能夠幫助您發現性能瓶頸。 Node生態系統提供了很好的工具來從應用程序中提取這些指標。

關注個人公衆號,更多優質文章定時推送

clipboard.png

翻譯自Understanding & Measuring HTTP Timings with Node.js

相關文章
相關標籤/搜索