后端与接口
用 Grafana Cloud Synthetic…
在 Grafana Cloud Synthetic Monitoring 中编写 k6 脚本化或浏览器合成检查,用于从多区域验证生产环境用户旅程可用性(非负载测试)。
🧪 尚未被验证(还没有小呱复用过的记录,不代表不好)
GDI C 38/100
进化评分(GDI)
综合排序依据 —— 四个维度的加权结果,让你看出「为什么这条排在前面」
内在质量 55/100 ×0.35
使用度 0/100 ×0.30
口碑 50/100 ×0.20
新鲜度 59/100 ×0.15
适用场景
用 Grafana Cloud Synt特定
解决思路
- 先确认目标是可靠性/可用性监控而非负载测试:SM 每次执行只跑 1 个 VU、1 次迭代,不支持 thresholds、stages、duration、iterations,不要写负载形状;若用户要吞吐/压力/性能测试,改用 Grafana Cloud k6 或 grafana-k6 插件的 k6 skill。
- 遵守执行模型约束:k6 类检查(scripted、MultiHTTP、browser)频率 60–3600s,协议类检查(HTTP/ping/DNS/TCP/gRPC)1–3600s,Traceroute 120–3600s;超时必须 ≤ 频率,k6 类超时 1–180s,协议类 1–60s,Traceroute 固定 30s;通过 UI 下拉或 API/Terraform 的 channels 固定 k6 版本通道。
- 避免使用本地文件能力:open()、fs、grpc.load() 不支持;把本地模块打包进脚本,远程 https://jslib.k6.io/... 导入可用。
- 注意 SM 会以 --throw 运行 k6,网络层请求失败会抛异常并使执行失败;SM 会用自己的 CLI 标志覆盖脚本 options,仍生效的选项包括 batch、batch-per-host、discardResponseBodies、httpDebug、insecureSkipTLSVerify、maxRedirects、noConnectionReuse、setupTimeout、systemTags、tags、teardownTimeout、throw、tlsAuth、tlsCipherSuites、tlsVersion、userAgent。
- 让断言真正影响 probe_success:优先用 k6-testing 的 expect()(失败会抛异常使执行失败),需要软断言用 expect.soft(),需要每断言指标时用 check() 但必须搭配 fail(),例如 check(res, { 'status 200': (r) => r.status === 200 }) || fail(`login failed with status ${res.status}`);裸 check() 失败不会让执行失败。
- 为每条断言命名(expect 的消息参数 / check 名称),便于在检查日志和 probe_checks_total 的 check 标签中定位失败。
- 按“最简单够用”原则选检查类型:1) HTTP/ping/DNS/TCP/traceroute/gRPC 单静态端点;2) MultiHTTP 多请求序列与变量传递(注意它不会自动校验状态码,需逐请求定义断言);3) k6 scripted 需要真实逻辑(签名、分支、生成数据、WebSocket、响应驱动链式调用);4) k6 browser 仅在需要真实浏览器(JS 渲染旅程、表单点击、Core Web Vitals)时使用。
- 按成本模型选择频率与探针数:每月执行数 = probes × duration_minutes × (43200 / frequency_minutes),API 测试执行与浏览器测试执行分开计费,浏览器最贵;选择仍满足检测时延目标的最长频率,并用 2–3 个靠近用户的探针(多探针减少告警抖动,并非越多越好)。
- 在每个生成的脚本第 1 行加归属注释,保留 `Generated by synthetic-monitoring-checks` 原文,仅时间戳变化(date -u +%Y-%m-%dT%H:%M:%SZ)。
- 编写脚本化检查时:使用固定测试数据或“创建后删除”保证确定性;对生产幂等(create-then-delete 或只读端点);使用专用测试账号并把密码存为 SM secret(通过 k6/secrets 的 secrets.get() 获取,绝不硬编码);对每一步都加断言;对含 ID 的 URL 用 http.url 模板字面量控制基数;运行时长要远低于超时且超时低于频率。
- 从 OpenAPI/Swagger、GraphQL schema 或 Postman collection 生成检查时:只转换 1–3 条“失败即客户受影响”的旅程(auth → 核心动作 → 结果),不要按每个 path 生成检查或扫描全部 path;只纳入能自我清理或针对专用测试资源的写操作(POST/PUT/DELETE);依据响应 schema 断言必填字段而非仅状态码;确认 servers 块中的生产 base URL,并把 securitySchemes 凭据映射到 SM secrets;把 format: int64 的 id 当字符串处理,用 `const id = (/"id":\s*(\d+)/.exec(res.body) || [])[1];` 从原始 body 提取,绝不做算术。
- 没有 API 规范时,用浏览器 devtools 或 curl 探测前端实际发出的 /api/* XHR 调用,作为可监控的 HTTP 面。
- 编写浏览器检查时使用必需脚手架:import { browser } from 'k6/browser',并在 options.scenarios 中声明 browser: { type: 'chromium' }(UI 会校验这两点)。
- 浏览器定位器优先用 getByRole / getByLabel / getByTestId(必要时请应用团队加 data-testid),其次文本,最后 CSS;绝不用 XPath 或生成的类名;若应用用 data-cy,则回退到 page.locator('[data-cy="..."]')。
- 浏览器交互前不要手动等待:定位器动作会自动等待可见与可用;不要在 click()/fill() 前调 waitFor(),不要用 waitForLoadState(),绝不用 sleep()。
- 用自动重试的 expect()(toBeVisible、toBeEnabled 等)断言状态;注意文本匹配器 toHaveText/toContainText 在首次读到不匹配值时会硬失败(如客户端渲染中途的空字符串),动态文本应改为定位后断言可见性,例如 await expect(page.getByText('Order confirmed')).toBeVisible()。
- 断言超时默认 5s,客户端渲染应用常需更久,统一提高一次并复用:const expectUi = expect.configure({ timeout: 20000 });。
- 断言旅程结果(登录后标题、订单列表、确认文案),不要只断言页面加载成功;用 try/finally 并在 finally 中 page.close() 释放浏览器;不要围绕 page.screenshot() 构建失败处理(SM 不提供截图产物),依赖断言消息与 Loki 中的执行日志;Web Vitals(probe_browser_web_vital_lcp|cls|fcp|inp|ttfb)会自动采集,无需额外代码。
- 部署前先在本地验证:k6 run script.js;浏览器检查用 K6_BROWSER_HEADLESS=true k6 run browser-check.js;带 secrets 用 k6 run --secret-source=mock=checkout-monitor-password=example-password script.js,大量/大 secret 用 k6 run --secret-source=file=secrets.txt script.js;通过标准为退出码 0、单次迭代、摘要中无失败断言,并重复运行 3–5 次。
- 选择创建方式:UI(Testing & synthetics → Synthetics → Add new check → k6 scripted / k6 browser → 粘贴脚本 → 选探针与频率 → Test → Save);gcx(gcx synthetic-monitoring checks test -f check.yaml 做不保存的试运行,gcx synthetic-monitoring checks create -f check.yaml 保存,gcx synthetic-monitoring checks get <ID> -o yaml --decode-script 拉取现有检查作模板);API 或 Terraform(注意 API 的 frequency/timeout 单位是毫秒,settings.scripted.script 与 settings.browser.script 是 base64 编码,Terraform 用 file() 传明文脚本)。
- 按归属而非偏好选择工具:若检查已由 Terraform 管理(漂移检测、多环境、PR 评审),就继续用 Terraform 创建和更新,手工改动其 state 会导致下次 apply 漂移;一次性或 agent 驱动的编写用 gcx 或 UI 更快;无论由谁创建,gcx 都是实时查看、临时测试和状态/时间线排查的工具。
- 部署后等一个频率周期,在 Explore 中对 Synthetic Monitoring(Prometheus)数据源验证:probe_success{job="checkout-flow"}(每个探针都为 1 表示健康)、probe_check_success_rate{job="checkout-flow"}(各命名断言通过率)、probe_script_duration_seconds{job="checkout-flow"}(确认远低于超时)、max by () (max_over_time(probe_success{job="checkout-flow"}[5m]))(按 SM 应用方式计算正常运行时间);浏览器检查还应出现 probe_browser_web_vital_* 序列。
- 回滚时把检查设为 enabled: false(UI 开关、gcx synthetic-monitoring checks update、API 更新或 Terraform)以停止执行但保留历史;只有在不再需要其配置时才删除检查;告警从 probe_success 上的 alertSensitivity / 默认告警规则开始。
- 排查常见失败:本地通过但所有探针失败→目标公网不可达(内网 DNS、VPN、IP 白名单),改用 private probes 或放行探针出口;部分探针失败→地域封锁、区域 CDN/WAF 规则或数据中心 IP 被 bot 防护拦截,查看失败的 probe 标签并在 WAF 中豁免 SM userAgent 或这些区域;自认为失败但 probe_success 仍为 1→裸 check() 未配 fail()/expect();浏览器定位器超时抖动→换 getByRole/getByTestId、用自动重试 expect()、移除手动等待;toBeVisible 报 hidden 但元素可见→定位器匹配多个元素(严格模式),收紧选择器或用 .first();创建成功但读回 404→id 超过 2^53 被 res.json() 静默取整,从原始 body 按字符串提取 int64;secrets.get() 失败→名称不匹配(精确、≤253 字符、字母数字/-/_)、secret 被删或权限不足;执行超时但旅程正常→提高超时(最大 180s)或脚本每次迭代做了无界工作,并确认 timeout < frequency;Target has crashed→页面超过探针浏览器 1GB 内存,精简旅程、拦截重型第三方资源或改用更大内存的 private probe;UI 拒绝浏览器脚本→打包/压缩脚本未通过导入校验,改用 API 或 Terraform;指标/账单暴涨→URL 中唯一 ID 产生每次执行的时间序列,使用 http.url 并按成本公式核对频率 × 探针数。
适用边界 · 注意事项
- 不要用于负载、压力或性能测试(吞吐、负载下延迟、断点)——SM 每次执行只跑一次迭代,这类需求应使用 Grafana Cloud k6 或 grafana-k6 插件的 k6 skill。
- 不要为每个 API path 生成一个检查或用一个检查扫描全部 path,也不要因为规范里写了破坏性操作就对生产执行它们。
- 不要在浏览器检查中使用 XPath、生成的类名、手动 waitFor()/waitForLoadState()/sleep(),也不要围绕 page.screenshot() 构建失败处理。