ARTICLE DETAIL

建站实战干货

来自一线的建站与推广经验沉淀,每一条都经过真实交付验证。

k6 v0.31.1 补丁解读:修复 Cloud 输出中 `http_req_failed` 指标恒为 1 的问题

2026/9/10 18:23:21 拓冰建站 浏览量
k6 v0.31.1 补丁解读:修复 Cloud 输出中 `http_req_failed` 指标恒为 1 的问题 k6 v0.31.1 补丁解读修复 Cloud 输出中http_req_failed指标恒为 1 的问题【免费下载链接】k6A modern load testing tool, using Go and JavaScript项目地址: https://gitcode.com/GitHub_Trending/k6/k6k6 v0.31.1 是一个仅包含单一缺陷修复bugfix的补丁版本其核心任务是为 v0.31.0 新引入的http_req_failed指标在 k6 Cloud 输出链路中的异常行为打上补丁。本文将以这份发布说明为骨架先交代 v0.31.0 引入该指标的功能背景再剖析 v0.31.1 所修复问题的现象、根因与影响边界最后结合当前仓库源码说明http_req_failed指标在 k6 内部的真实生成机制帮助你理解这条指标的正确语义以及如何在测试中规避同类问题。版本背景v0.31.0 引入http_req_failed指标要理解 v0.31.1 修复了什么必须先回到上一个版本 release notes/v0.31.0.md。在 v0.31.0 中k6 引入了将请求标记为失败Marking requests as failed的能力用户可以为整个测试或单个 HTTP 请求声明期望的 HTTP 响应状态码k6 会据此发出一个新的http_req_failed指标同时为所有 HTTP 指标打上expected_response: bool标签默认情况下HTTP 4xx/5xx 响应会被视为失败请求。默认的期望状态码为{min: 200, max: 399}若希望恢复旧版本不发出该指标的行为可以通过http.setResponseCallback(null)显式关闭。在脚本中使用http_req_failedv0.31.0 发布说明给出了一个可直接运行的示例来源release notes/v0.31.0.mdimport http from k6/http; // 为所有请求全局设置期望状态码。 http.setResponseCallback(http.expectedStatuses({min: 200, max: 399}, 418)); export default function () { // 该请求将因返回 400 被标记为失败。 http.get(https://httpbin.test.k6.io/status/400); // 该请求因 responseCallback 覆盖而被视为通过。 http.get(https://httpbin.test.k6.io/status/400, { responseCallback: http.expectedStatuses(400) }); }对应地测试结束摘要中会新增一行http_req_failed并出现http_req_duration的expected_response: true子项http_req_duration..............: avg204.57ms min203.31ms med204.57ms max205.82ms p(90)205.57ms p(95)205.7ms { expected_response:true }...: avg203.31ms min203.31ms med203.31ms max203.31ms p(90)203.31ms p(95)203.31ms http_req_failed................: 50.00% ✓ 1 ✗ 1与阈值thresholds的组合用法http_req_failed是一条Rate类型指标见后文源码佐证最典型的应用是配合阈值判断测试是否通过http_req_failed: [rate0.1]当请求失败率超过 10% 时使测试失败http_req_duration{expected_response:true}: [p(95)300, p(99.9)500]对期望成功的请求单独施加延迟分位数门槛——这一点很关键因为失败的请求往往比正常请求返回得更快若不按expected_response:true过滤会拉低整体耗时从而虚假地满足阈值。当前仓库的模板文件 internal/cmd/templates/protocol.js 也保留了类似的阈值写法http_req_failed: [rate0.01]说明这一用法已成为 k6 项目的标配实践。v0.31.1 修复了什么根据 release notes/v0.31.1.md 的官方描述该补丁只处理一个问题即cloud output 与http_req_failed指标的组合缺陷对应 issue #1908。问题现象由于两个原因叠加导致http_req_failed的取值恒为1为向 k6 Cloud 传输该指标而引入了额外的状态additional state这条指标的数据在传输链路上被额外包装了一层状态信息对某个库依赖library dependency中一个函数调用的语义存在误解导致读取到的值不是指标的真实采样值。影响范围仅限 cloud output发布说明明确给出了两个重要的边界结论其他输出不受影响http_req_failed的生成与正常写入发生在 k6 引擎内部问题只出在传输到 k6 Cloud这一段因此 CSV、JSON、InfluxDB 等本地输出以及任何自定义输出均不受影响测试结束摘要不受影响端末摘要end of test summary由引擎侧的汇总逻辑计算同样保持正确。换言之这是一个只影响 k6 Cloud 结果可视化的传输层缺陷并未破坏指标本身的采集正确性。这一点对判断问题严重程度很重要如果你只在本机查看摘要或使用本地输出v0.31.0 的行为就是正确的只有在使用k6 cloud/ cloud output 时http_req_failed系列数据才会被污染。为什么恒为 1很严重http_req_failed是一条Rate类型指标其采样值是 0 或 10 表示期望中的成功1 表示失败。如果传输层把值固定成 1那么在云端的图表上每一次请求都会被渲染为失败失败率曲线恒为 100%阈值相关的统计如rate0.1也会完全失真。这正是补丁需要立即修复的原因——它不是视觉效果问题而是直接颠覆了该指标的业务语义。源码级佐证http_req_failed的正确生成机制虽然当前仓库代码已经历多次版本演进cloud output 已重写为expv2但http_req_failed指标在引擎侧的生成逻辑依然可以印证值应为 0 或 1这一正确语义也解释了修复后的预期行为。1. 指标注册一条 Rate 类型的内置指标在 metrics/builtin.go 中指标名被定义为常量HTTPReqFailedName http_req_failed并在RegisterBuiltinMetrics中以Rate类型注册HTTPReqs: registry.MustNewMetric(HTTPReqsName, Counter), HTTPReqFailed: registry.MustNewMetric(HTTPReqFailedName, Rate), HTTPReqDuration: registry.MustNewMetric(HTTPReqDurationName, Trend, Time),Rate类型的语义是布尔值比例每条采样记录要么是 0 要么是 1聚合后得到的是百分比。2. 采样值生成failed 0 或 1真正决定http_req_failed取值的代码位于 lib/netext/httpext/transport.go。其中核心逻辑为var failed float64 if t.responseCallback ! nil { var statusCode int if unfReq.err nil { statusCode unfReq.response.StatusCode } expected : t.responseCallback(statusCode) if !expected { failed 1 } tagsAndMeta.SetSystemTagOrMetaIfEnabled(enabledTags, metrics.TagExpectedResponse, strconv.FormatBool(expected)) }也就是说只有当响应状态码不满足response callback 的期望时failed才会被置为 1随后该值被写入HTTPReqFailed指标对应的样本中Value: failed。这里可以清楚地看到指标值天然依赖每个请求的状态码判定结果不存在恒为 1的任何合理路径——v0.31.1 修复的正是 cloud 传输段丢失了这种动态值的行为。同时这段代码还把expected_response系统标签metrics.TagExpectedResponse一并写入这就是摘要中{ expected_response:true }子项的数据来源。3. 期望状态码的判定规则response callback 的匹配实现在 js/modules/k6/http/response_callback.go。默认值即 v0.31.0 所述的范围var defaultExpectedStatuses expectedStatuses{ minmax: [][2]int{{200, 399}}, }匹配逻辑支持两种形态的参数整数精确匹配单个状态码如400与{min, max}区间func (e expectedStatuses) match(status int) bool { if slices.Contains(e.exact, status) { return true } for _, v : range e.minmax { if v[0] status status v[1] { return true } } return false }而SetResponseCallback只接受http.expectedStatuses(...)或nullnull表示回到 v0.31.0 之前不发出http_req_failed的行为其他值会直接抛出运行时错误。4. 样本结构Value 字段承载 0/1在 metrics/sample.go 中Sample结构以Value float64承载指标测量值TimeSeries则唯一标识指标 标签集。cloud output 需要从这个结构中读取正确的Value——v0.31.1 的缺陷说明中提到为传输引入的额外状态与对库依赖函数调用的误解指向的正是这段读取/序列化路径而引擎端通过metrics.PushIfNotDone推入样本通道的机制metrics/sample.go保证了摘要统计始终基于真实采样值。5. 测试用例印证lib/netext/httpext/request_test.go 中保留了针对expected_response标签与HTTPReqFailedName样本的断言如ResponseCallback: func(i int) bool { return i 0 }配合expected_response: true的用例证明 k6 内部对指标值随状态码动态变化这一行为是有明确测试约束的。如何确认修复与规避同类问题升级与验证将 k6 升级到 v0.31.1 或更高版本后用上述示例脚本分别执行本地运行与 cloud 运行比对http_req_failed的百分比是否一致本地验证可观察摘要输出中的http_req_failed行与{ expected_response:true }子项是否随请求成功/失败变化云端验证则确认 k6 Cloud 图表中的失败率不再恒为 100%。使用建议不要通过http.setResponseCallback(null)关闭该指标来回避问题——这会同时失去expected_response标签的过滤能力如需自定义失败语义优先使用http.expectedStatuses(...)组合精确状态码与区间参数必须是整数或{min, max}对象而不是在脚本里手工统计结合阈值使用时务必给http_req_duration加上expected_response:true标签过滤避免快速失败的请求拉低延迟统计、掩盖真实的性能问题。小结k6 v0.31.1 以极小体量单一 bugfix解决了 v0.31.0 引入的http_req_failed指标在 cloud output 传输链路上恒为 1 的缺陷。其本质是传输层的状态处理问题而非指标采集逻辑错误因此本地输出与测试结束摘要始终正确。从当前仓库源码看http_req_failed作为一条Rate指标其 0/1 采样值由 response callback 对每个请求状态码的动态判定产生lib/netext/httpext/transport.go配合expected_response标签可构成强大的阈值与可视化能力。对于使用 k6 Cloud 的用户将版本升级至包含该修复的版本是恢复http_req_failed云端正确性的最低成本操作。【免费下载链接】k6A modern load testing tool, using Go and JavaScript项目地址: https://gitcode.com/GitHub_Trending/k6/k6创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考