了解和测量HTTP时间有助于我们发现客户端到服务器或服务器到服务器通信中的性能瓶颈。本文描述了HTTP请求中的计时开销,并展示了如何在Node.js中对其进行测量。在开始了解HTTP时间开销之前,让我们先了解一些基本概念:IP(InternetProtocol):IP是处理网络寻址和路由的网络层协议。IP负责根据一个或多个IP网络上的数据包报头将数据包从源主机传送到目标主机。它还定义了封装要传递的数据的数据包结构。DNS(域名服务器):DNS是一种分层的分散式命名系统,用于将人类可读的主机名(例如risingstack.com)解析为机器可读的IP地址。TCP(传输控制协议):TCP标准定义了如何在应用程序之间建立和维护网络对话以交换数据。TCP在通过IP网络通信的主机上运行的应用程序之间提供可靠、有序和错误检查的八位字节流。HTTP客户端通过建立TCP连接来发起请求。SSL/TLS(传输层安全性):TLS是一种加密协议,可通过计算机网络提供通信安全性。SSL(安全套接字层)是TLS已弃用的前身。TLS和SSL都使用证书来建立安全连接。SSL证书不依赖于加密协议(如TLS),证书中包含一对密钥:公钥和私钥。这些密钥协同工作以建立加密连接。现在让我们看一下典型HTTP请求的时间线:DNS查找:执行DNS查找所花费的时间。DNS查找将域名解析为IP地址。每个新域都需要一个完整的往返行程来进行DNS查找。当目的地已经是一个IP地址时,就不会进行DNS查找。TCP连接:在源主机和目的主机之间建立TCP连接所需的时间。在多步握手期间必须正确建立连接。TCP连接由操作系统管理,如果无法建立底层TCP连接,则操作系统范围的TCP连接超时将输入到我们应用程序的超时配置中。TLS握手:完成TLS握手的时间。在握手期间,端点交换身??份验证和密钥以建立或恢复安全会话。HTTPS请求不需要TLS握手。TimetoFirstByte(TTFB):等待初始响应的时间。除了等待服务器处理请求和传递响应所花费的时间之外,此时间还捕获进出服务器的延迟。内容传输:接收响应数据所花费的时间。响应数据的大小和可用的网络带宽决定了它的持续时间。HTTP时间开销如何帮助发现性能瓶颈?例如,如果您的DNS查询花费的时间比预期的要长,则问题可能出在您的DNS提供商或DNS缓存设置上。缓慢的内容交付可能是由低效的响应机制引起的,例如发回过多数据(未使用的JSON属性等)或连接速度慢。在Node.js中测量HTTP时间开销为了在Node.js中测量HTTP时间开销,我们需要订阅特定的请求、响应和套接字事件。这是一个简短的代码片段,展示了如何在Node.js中执行此操作,此示例仅关注计时:consttimings={//使用process.hrtime()因为它不是时钟漂移的主题startAt:process。hrtime(),dnsLookupAt:undefined,tcpConnectionAt:undefined,tlsHandshakeAt:undefined,firstByteAt:undefined,endAt:undefined}constreq=http.request({...},(res)=>{res.once('可读',()=>{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查找只会发生在有域名的情况下:/ThereisnoDNSlookupwithIPaddressconstdnsLookup=dnsLookupAt!==un定义?getDuration(startAt,dnsLookupAt):undefinedTCPconnectionhappensimmediatelyafterhostresolve:consttcpConnection=getDuration((dnsLookupAt||startAt),tcpConnectionAt)TLS握手(SSL)只能使用https协议//没有httpsconst就没有TLS握手tlsHandshake=tlsHandshakeAt!==未定义?getDuration(tcpConnectionAt,tlsHandshakeAt):undefined我们等待服务器开始发送第一个字节:constfirstByte=getDuration((tlsHandshakeAt||tcpConnectionAt),firstByteAt)从开始和结束日期计算的总持续时间:consttotal=getDuration(startAt,endAt)要查看整个示例,请查看我们的https://github.com/RisingStac...要求。请求模块众所周知的请求模块具有用于测量HTTP计时的内置方法。您可以使用时间属性启用它。constrequest=require('request')request({uri:'https://risingstack.com',方法:'GET',time:true},(err,resp)=>{console.log(err||resp.timings)})DistributedTracing可以使用DistributedTracing工具来收集HTTP时间并在时间线上可视化。这样,您就可以全面了解幕后发生的事情,以及构建分布式系统的实际成本是多少。RisingStack的opentracing-auto库有一个内置标志,可以通过OpenTracing收集所有HTTP时间。在Jaeger中使用opentracing-auto的HTTP请求计时。总结使用Node.js测量HTTP时间可以帮助您发现性能瓶颈。Node生态系统提供了很好的工具来从应用程序中提取这些指标。关注我的公众号,更多优质文章会定期推送翻译自Understanding&MeasuringHTTPTimingswithNode.js
