Understanding and measuring HTTP timings helps us to discover performance bottlenecks in client to server or server to server communication. This article explains timings in an HTTP request and shows how to measure them in Node.jsNode.js is an asynchronous event-driven JavaScript runtime and is the most effective when building scalable network applications. Node.js is free of locks, so there's no chance to dead-lock any process..
Before we jump into HTTP timings, let’s take a look at some basic concepts:
Timings explained:
For example, if your DNS Lookup takes longer time than you expected, the issue might be with your DNS provider or with your DNS caching settings.
When you see longer Time to First Byte durations, you should check out the latency between the endpoints, but you should also check out the current load of the server.
Slow Content Transfer can be caused by inefficient response body like sending back too much data (unused JSON properties, etc.) or by a slow connection as well.
Measuring HTTP timings in Node.jsTo measure HTTP timings in Node.js, we need to subscribe to a specific request, response and socket events. Here is a short code snippet how to do this in Node.js, this example focuses only to the timings:
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 Lookup only happens with domain names:
// There is no DNS lookup with IP address
const dnsLookup = dnsLookupAt !== undefined ?
getDuration(startAt, dnsLookupAt) : undefined
TCP Connection happens immediately after the host is resolved:
const tcpConnection = getDuration((dnsLookupAt || startAt), tcpConnectionAt)
TLS handshake (SSL) happens only with https protocol:
// There is no TLS handshake without https
const tlsHandshake = tlsHandshakeAt !== undefined ?
getDuration(tcpConnectionAt, tlsHandshakeAt) : undefined
We wait for server to start sending First Byte:
const firstByte = getDuration((tlsHandshakeAt || tcpConnectionAt), firstByteAt)
Content Transfer starts with the first byte:
const contentTransfer = getDuration(firstByteAt, endAt)
Total Duration is calculated from start and end dates:
const total = getDuration(startAt, endAt)
Too see the whole example together check out our https://github.com/RisingStack/example-http-timings repository.
Tools to measure timingsNow that we know how to measure HTTP timings with Node, let’s talk about existing tools that you can use to understand your HTTP requests.
request
module
The popular request module has a built-in method to measure HTTP timings. You can enable it with the time
property.
const request = require('request')
request({
uri: 'https://risingstack.com',
method: 'GET',
time: true
}, (err, resp) => {
console.log(err || resp.timings)
})
Distributed tracing
It’s possible to collect HTTP timings with distributed tracing tools and visualize them on a timeline. This way, you can have a full picture of what’s happening in the background and how much is the real cost of building distributed systems.
RisingStack’s opentracing-auto library has a built-in flag to collect all the HTTP timings with OpenTracing.
HTTP Request timing with opentracing-auto in Jaeger.
SummaryMeasuring HTTP Timings with Node.js can help to discover performance bottlenecks. The Node ecosystem provides great tools to extract these metrics from your application.
RetroSearch is an open source project built by @garambo | Open a GitHub Issue
Search and Browse the WWW like it's 1997 | Search results from DuckDuckGo
HTML:
3.2
| Encoding:
UTF-8
| Version:
0.7.4