SRE 排障利器,接口请求超时试试 httpstat

介绍如何用 httpstat 排查 HTTP 接口超时,按 DNS、TCP、TLS、服务端处理和内容传输拆解耗时,辅助判断问题在网络侧还是服务端。

作者 巴辉特

HTTP 接口超时排查时,最怕只知道“慢”,却不知道慢在哪一段。httpstat 的价值就在这里:它像 curl 一样发起请求,同时把 DNS 解析、TCP 连接、TLS 握手、服务端处理和内容传输等阶段的耗时拆开展示,帮助 SRE 快速判断问题更像网络侧、连接侧还是后端服务侧。

夜莺资深用户群有人推荐了这个工具,看了一下确实实用,推荐给大家。

适用场景

A 服务调用 B 服务的 HTTP 接口,发现 B 服务返回超时,但不确定原因在哪里。常见可能性包括:

  • DNS 解析慢或失败。
  • TCP 建连耗时高。
  • TLS 握手耗时高。
  • 服务端处理慢。
  • 响应体传输慢。
  • 代理、跨地域网络或出口链路带来额外延迟。

这时直接看应用日志可能只能看到总耗时,使用 httpstat 可以把总耗时拆成更细的阶段。

工具简介

httpstat 的使用方式和 curl 类似,也可以请求某个后端接口。不同之处在于,它会把一次 HTTP 请求拆成多个阶段,并把每个阶段的耗时展示出来:

阶段 含义 排查价值
DNS Lookup 域名解析耗时 判断 DNS 服务、域名解析链路是否异常。
TCP Connection TCP 建连耗时 判断网络连通性、跨地域链路或服务端端口响应问题。
TLS Handshake TLS 握手耗时 判断证书、加密协商、HTTPS 链路是否拖慢请求。
Server Processing 服务端处理并等待响应耗时 判断后端应用、数据库或下游依赖是否慢。
Content Transfer 响应体传输耗时 判断响应体大小、带宽或客户端读取是否异常。

效果如下:

httpstat

这个工具是 Go 写的,作者没有提供二进制包,所以需要自己编译安装。

安装 Go 环境

自己编译就需要有 Go 环境。下面以 Mac M1 为例,先下载 Go 安装包(https://go.dev/dl/):https://go.dev/dl/go1.22.2.darwin-arm64.tar.gz。一般使用 tar.gz 文件即可,不一定要用 pkg。

cd /Users/ulric/works/tgz
wget https://go.dev/dl/go1.22.2.darwin-arm64.tar.gz
tar -zxf go1.22.2.darwin-arm64.tar.gz

操作如上,/Users/ulric/works/tgz/go 这个目录就是 go 的安装目录,然后配置环境变量:

export GOROOT=/Users/ulric/works/tgz/go
export GOPATH=/Users/ulric/works/gopath
export PATH=$PATH:$GOROOT/bin:$GOPATH/bin

GOROOT 是 go 的安装目录,GOPATH 是 go 的工作目录,PATH 是环境变量,这样配置之后,就可以使用 go 命令了。上面的几行命令可以保存在 ~/.bash_profile 或者 ~/.zshrc 里,这样每次打开终端都会自动加载。

验证 Go 环境是否正常安装:

% go version
go version go1.22.2 darwin/arm64

安装 httpstat

有了 Go 环境后,安装 httpstat 就很简单:

ulric@ulric-flashcat ~ % go install github.com/davecheney/httpstat@latest
go: downloading github.com/davecheney/httpstat v1.1.0
go: downloading golang.org/x/sys v0.0.0-20201223074533-0d417f636930

测试 httpstat

安装完成之后,先看看 httpstat 有哪些参数可用:

ulric@ulric-flashcat ~ % httpstat --help
Usage: httpstat [OPTIONS] URL

OPTIONS:
  -4	resolve IPv4 addresses only
  -6	resolve IPv6 addresses only
  -E string
    	client cert file for tls config
  -H value
    	set HTTP header; repeatable: -H 'Accept: ...' -H 'Range: ...'
  -I	don't read body of request
  -L	follow 30x redirects
  -O	save body as remote filename
  -X string
    	HTTP method to use (default "GET")
  -d string
    	the body of a POST or PUT request; from file use @filename
  -k	allow insecure SSL connections
  -o string
    	output file for body
  -v	print version number

ENVIRONMENT:
  HTTP_PROXY    proxy for HTTP requests; complete URL or HOST[:PORT]
                used for HTTPS requests if HTTPS_PROXY undefined
  HTTPS_PROXY   proxy for HTTPS requests; complete URL or HOST[:PORT]
  NO_PROXY      comma-separated list of hosts to exclude from proxy

很多参数和 curl 都很像。比如先用 curl 测试一个 POST 请求:

ulric@ulric-flashcat ~ % curl -X POST -H "Content-Type: application/json" -d '{"service": "tomcat"}' 'https://httpbin.org/post?name=ulric&city=beijing'
{
  "args": {
    "city": "beijing",
    "name": "ulric"
  },
  "data": "{\"service\": \"tomcat\"}",
  "files": {},
  "form": {},
  "headers": {
    "Accept": "*/*",
    "Content-Length": "21",
    "Content-Type": "application/json",
    "Host": "httpbin.org",
    "User-Agent": "curl/8.4.0",
    "X-Amzn-Trace-Id": "Root=1-6655a6c4-4522374c5b8d68143d638049"
  },
  "json": {
    "service": "tomcat"
  },
  "origin": "123.113.255.104",
  "url": "https://httpbin.org/post?name=ulric&city=beijing"
}

curl 换成 httpstat,请求效果如下:

ulric@ulric-flashcat ~ % httpstat -X POST -H "Content-Type: application/json" -d '{"service": "tomcat"}' 'https://httpbin.org/post?name=ulric&city=beijing'

Connected to 34.198.16.126:443

HTTP/2.0 200 OK
Server: gunicorn/19.9.0
Access-Control-Allow-Credentials: true
Access-Control-Allow-Origin: *
Content-Length: 529
Content-Type: application/json
Date: Tue, 28 May 2024 09:41:44 GMT

Body discarded

  DNS Lookup   TCP Connection   TLS Handshake   Server Processing   Content Transfer
[     11ms  |         217ms  |        446ms  |            570ms  |             0ms  ]
            |                |               |                   |                  |
   namelookup:11ms           |               |                   |                  |
                       connect:229ms         |                   |                  |
                                   pretransfer:678ms             |                  |
                                                     starttransfer:1248ms           |
                                                                                total:1248ms

可以看到,httpstat 把请求的各个阶段耗时都展示出来了。

如何解读输出

上面的输出里,总耗时是 1248ms,其中:

  • namelookup:11ms:DNS 解析很快,不像是主要瓶颈。
  • connect:229ms:TCP 连接完成时间约为 229ms。
  • pretransfer:678ms:TLS 握手完成后进入可发送请求的状态。
  • starttransfer:1248ms:收到首字节时已经达到 1248ms,主要时间消耗在连接完成后的等待阶段。
  • total:1248ms:整体请求完成时间。

排查时可以先看哪个阶段明显异常:

现象 优先怀疑方向
DNS Lookup 很高 DNS 服务、解析链路、域名配置。
TCP Connection 很高 网络链路、服务端端口、跨地域访问、代理。
TLS Handshake 很高 HTTPS 握手、证书协商、客户端与服务端加密性能。
Server Processing 很高 后端应用、数据库、缓存、下游服务或线程池。
Content Transfer 很高 响应体过大、带宽不足、客户端读取慢。

使用注意事项

httpstat 适合做单次请求的快速定位,但它不能替代长期监控。生产排障时,建议和服务端日志、APM Trace、指标大盘、网关日志一起看。

如果一个接口偶发超时,可以多执行几次,观察慢的阶段是否稳定。如果每次慢的位置不同,问题可能不是单点瓶颈,而是网络抖动、代理链路、下游依赖或服务端资源竞争。

FAQ

Q1:已经有 curl 了,还需要 httpstat 吗? 需要看场景。curl 很适合验证请求是否能通,httpstat 更适合把一次请求的阶段耗时拆开看。

Q2:httpstat 能判断根因吗? 它不能直接给出根因,但能缩小排查范围。例如 Server Processing 高,说明应该优先看服务端和下游依赖;DNS Lookup 高,则先看解析链路。

Q3:它适合放到监控系统里长期跑吗? 这篇文章主要介绍临时排障用法。长期探测建议使用专门的黑盒探测、合成监控或拨测方案。

联系我们交流

延伸路径

继续看解决方案和产品对比

如果你正在做监控、可观测性或故障定位相关选型,建议从解决方案和产品对比继续往下看。

标签 httpstat
快猫星云 联系方式 快猫星云 联系方式
快猫星云 联系方式
快猫星云 联系方式
快猫星云 联系方式
快猫星云