[{"data":1,"prerenderedAt":-1},["ShallowReactive",2],{"blog-strapi-article:zh:region-error-rate-rollback":3,"blog-article:\u002Fblog\u002Fregion-error-rate-rollback":632,"blog-related:\u002Fblog\u002Fregion-error-rate-rollback":633,"blog-translations:\u002Fblog\u002Fregion-error-rate-rollback":634},{"available":4,"article":5,"relatedArticles":154,"translations":535},true,{"source":6,"id":7,"documentId":8,"translationKey":8,"locale":9,"slug":10,"path":11,"_path":11,"title":12,"description":13,"excerpt":13,"image":14,"publishedAt":15,"updatedAt":16,"author":17,"tags":18,"featured":19,"sortOrder":20,"readingTime":21,"bodyType":22,"bodyBlocks":23,"bodyHtml":153},"strapi",3732,"zoq7ywrk09kqq6smss7lhhbb","zh","region-error-rate-rollback","\u002Fblog\u002Fregion-error-rate-rollback","国际站按地区灰度发布时，如何观察错误率并判断是否回滚？ | 全球代理","按发布单元归并地区，先定错误率口径、最小样本与观察窗口，再把阈值写成能执行的回滚条件，并给出一次演练可复用的记录字段与判定标准。","https:\u002F\u002Fcms.quanqiudaili.com\u002Fuploads\u002Flarge_cover_2fc0fcf55b.webp","2026-10-27T06:01:18.340Z","2026-10-27T06:01:18.320Z","Global Proxies Team",[],false,0,3,"blocks",[24,30,36,40,44,48,52,56,60,64,68,72,76,80,84,88,92,96,100,104,108,113,117,121,125,129,133,137,141,145,149],{"type":25,"children":26},"paragraph",[27],{"text":28,"type":29},"国际站的错误率不该按国家逐个设。先把共享同一套代码、机制和依赖的地区合成一个发布单元，每个单元给一条错误率基线和观察窗口，再把“连续 N 分钟超过基线几倍”写成熔断条件；核心路径完全不可用时直接回滚，不必等窗口跑完。测试和灰度时，用代理IP 把出口固定到目标地区，不同地区的错误率才有可比性。下面整理一套能照做的分组口径、阈值写法和演练记录表。","text",{"type":31,"level":32,"children":33},"heading",2,[34],{"text":35,"type":29},"先按发布单元分组，不按国家分别看",{"type":25,"children":37},[38],{"text":39,"type":29},"错误率应以发布单元为单位观察，而不是把每个国家单独当成一条结论。先把使用同一版本、配置和依赖的地区归为一个单元，再为每个单元设定基线。同一版本、同一套地区配置、同一批依赖的一组地区，才能合成一个单元。确定分组后，可对照[代理 IP 产品页](https:\u002F\u002Fwww.quanqiudaili.com\u002Fproduct\u002Fdynamic-residential)整理目标地区清单，避免监控分组与实际测试范围不一致。原因是单个小市场的样本量太小，错误率的波动大部分是噪声；而把配置不同的地区混在一起，配置问题会被平均掉，看起来反而像“偶发”。",{"type":25,"children":41},[42],{"text":43,"type":29},"分组时给每个单元标注三件事：包含哪些地区、各占多少流量、当前配置版本。配置或依赖明显不同的地区单独拆出来，配置差异明显时应拆分单元，避免不同表现被汇总后掩盖。发布前先按风险缩减测试组合，把监控和人力留给高风险单元。出口类型也会影响基线：住宅 IP 走真实用户网络，机房 IP 延迟稳定，两类混在一张图里，波动会被误读成故障。",{"type":31,"level":32,"children":45},[46],{"text":47,"type":29},"统一错误率口径并设置最小样本量",{"type":25,"children":49},[50],{"text":51,"type":29},"没有口径的错误率，涨了也不知道该不该动。分子默认算服务端错误和超时；4xx 先按业务定义分类——用户输入错误、未登录、权限不足单独统计，不混进可用性，影响核心路径的 4xx（如地区策略拦截、回调地址错误）单列告警或并入对应服务指标。分母用有效请求总数，不用 UV：请求级错误率 = 错误请求数 ÷ 有效请求总数，同一个用户重试只会增加请求数，不会让分母变大十倍。若要观察“受影响用户比例”，分子分母都要换成用户口径（受影响用户数 ÷ 活跃用户数），不能拿错误请求数去除以 UV。重试、超时、4xx 的纳入规则要在统计前写进口径文档，否则同一张图换个算法就能得出不同结论。",{"type":25,"children":53},[54],{"text":55,"type":29},"小市场应设最小样本量。若指标涉及代理出口的连通性或延迟，可另参考[代理 IP 可用率、延迟和稳定性测试](https:\u002F\u002Fwww.quanqiudaili.com\u002Fblog\u002Fproxy-ip-availability-latency-stability-test)，不要把网络指标与应用错误率混为一谈。例如，团队可以设定单窗口最低请求量；样本不足时，将该地区标记为数据不足，结合发布单元整体指标和核心路径监控判断。具体样本量需按流量和历史波动确定。文中的百分比和倍数只是阈值写法示例，实际回滚标准应根据业务影响、历史基线和团队响应能力确定。",{"type":31,"level":32,"children":57},[58],{"text":59,"type":29},"用双窗口识别突发故障和持续恶化",{"type":25,"children":61},[62],{"text":63,"type":29},"一个窗口不够用，急跌和慢漂是两种完全不同的故障。两个窗口共用同一条基线，但判断逻辑分开。",{"type":31,"level":21,"children":65},[66],{"text":67,"type":29},"5 分钟窗口触发时，先暂停放量还是回滚",{"type":25,"children":69},[70],{"text":71,"type":29},"五分钟窗看的是“还能不能用”，用绝对阈值判断，例如核心路径成功率低于 A%。A% 由团队按业务基线定，并同时设单窗口最小请求量；样本不足时先标“数据不足”，不按超阈值处理。它胜在快、输在噪声大，所以触发后的动作不是立刻全量回滚，而是按下一节的统一模板走：达到最小样本且持续满足短窗阈值 → 暂停放量或摘除受影响流量 → 按业务预案确认后回滚；核心路径完全不可用时不必等窗口，直接走紧急回滚。",{"type":31,"level":21,"children":73},[74],{"text":75,"type":29},"1 小时窗口持续偏高时，怎样判断趋势",{"type":25,"children":77},[78],{"text":79,"type":29},"一小时窗看的是“是不是在变坏”，也可参考相对基线变化，例如 5xx 率达到基线 B 倍；A、B 两个值按历史波动和业务影响设定。慢速劣化靠趋势判断：可将连续多个窗口不收敛设为升级条件，单次越线先结合样本量与核心路径表现复核。",{"type":25,"children":81},[82],{"text":83,"type":29},"只用一个小时窗，整页挂掉要等一小时才动手；只用五分钟窗，慢速劣化永远触发不了。",{"type":31,"level":32,"children":85},[86],{"text":87,"type":29},"把阈值写成值班人员能执行的回滚条件",{"type":25,"children":89},[90],{"text":91,"type":29},"回滚条件必须是一句能执行的话，不能是含糊的临场判断。若故障表现为连接超时或 TLS 错误，可先按连接超时、TLS 握手和代理出口稳定性记录确认是否属于出口链路问题，再按发布指标决定是否回滚。推荐写成两句：“当某单元连续 5 分钟、样本量不低于最小请求数、核心路径成功率低于 A% 时，值班人按预案确认后在 10 分钟内回滚到上一版本。”“当某单元 1 小时窗口内 5xx 率持续达到基线 B 倍时同样处理；基线接近 0 时改用绝对阈值，避免倍数失效。核心路径完全不可用时可跳过确认直接紧急回滚。”",{"type":25,"children":93},[94],{"text":95,"type":29},"同时把三个角色写死：谁有权发起回滚、回滚到哪个版本号、回滚后由谁确认恢复。缺一项，真出事时就会卡在“谁来拍板”上。这里的 A%、B 倍、10 分钟都是示例值，按业务影响设定；“问题集中在单一地区且流量占比低于 5% 时只摘除该地区”同样是示例，低流量比例本身不能作为不回滚的理由。",{"type":31,"level":32,"children":97},[98],{"text":99,"type":29},"用一次演练验证告警和回滚流程",{"type":25,"children":101},[102],{"text":103,"type":29},"阈值没演练过，第一次真正用它，往往就是故障当天。在测试环境把错误率人为推高，完整走一遍告警、判断、回滚、恢复确认，记录每一步耗时。若演练耗时超过团队约定的响应目标，应检查值班链路、告警送达和操作权限，再决定是否调整流程。",{"type":25,"children":105},[106],{"text":107,"type":29},"> 表格中的阈值、用例编号和结果如无测试记录支持，均应视为演示样例；实际验收标准以项目需求、历史基线或团队约定为准。",{"type":109,"children":110},"code",[111],{"text":112,"type":29},"| 字段 | 记录内容 | 用途 |\n| --- | --- | --- |\n| 发布单元 | 单元名、包含地区、流量占比 | 确认影响面 |\n| 触发指标 | 窗口长度、错误率、基线、倍数 | 判断是否达标 |\n| 执行动作 | 回滚或摘除地区、执行人、时间 | 还原决策链 |\n| 恢复确认 | 恢复时间、复核指标 | 证明真的恢复 |",{"type":25,"children":114},[115],{"text":116,"type":29},"演练记录可分别填写告警触发、值班确认、执行回滚和指标恢复的时间。若要展示时间线，应标为单次演练示例，不把示例耗时当作响应承诺。",{"type":31,"level":32,"children":118},[119],{"text":120,"type":29},"FAQ",{"type":31,"level":21,"children":122},[123],{"text":124,"type":29},"错误率基线多久更新一次？",{"type":25,"children":126},[127],{"text":128,"type":29},"每月或每个大版本后重算。用半年前的数字，阈值会失真。",{"type":31,"level":21,"children":130},[131],{"text":132,"type":29},"错误率回落就说明恢复了吗？",{"type":25,"children":134},[135],{"text":136,"type":29},"不一定。先看请求量回来没有，流量被摘走时错误率也会降。",{"type":31,"level":21,"children":138},[139],{"text":140,"type":29},"灰度期间两个版本怎么比？",{"type":25,"children":142},[143],{"text":144,"type":29},"同单元、同窗口，只差版本号。跨地区比没有意义。",{"type":31,"level":21,"children":146},[147],{"text":148,"type":29},"回滚之后还要做什么？",{"type":25,"children":150},[151],{"text":152,"type":29},"确认成功率回到基线，再决定是否重新放量。别在未确认时二次发布。","",[155,274,396],{"source":6,"id":156,"documentId":157,"translationKey":157,"locale":9,"slug":158,"path":159,"_path":159,"title":160,"description":161,"excerpt":161,"image":162,"publishedAt":163,"updatedAt":164,"author":17,"tags":165,"featured":19,"sortOrder":20,"readingTime":32,"bodyType":22,"bodyBlocks":166,"bodyHtml":153},3736,"p2uytzcif87o37qgf4p4hlw1","saas-scheduled-task-timezone-testing","\u002Fblog\u002Fsaas-scheduled-task-timezone-testing","SaaS 定时任务执行时间错误，如何检查时区与地区配置？ | 全球代理","区分 UTC 存储与用户时区展示，覆盖 UTC 日界、夏令时跳过与重复小时、用户改时区三类场景，分别核对执行、到达与展示三段时间。","https:\u002F\u002Fcms.quanqiudaili.com\u002Fuploads\u002Flarge_saas_cover_20e90c740e.webp","2026-10-27T06:02:37.700Z","2026-10-27T06:02:37.686Z",[],[167,171,175,179,183,187,191,195,199,203,207,211,215,219,223,227,231,235,239,242,246,250,254,258,262,266,270],{"type":25,"children":168},[169],{"text":170,"type":29},"定时任务“跑错时间”，多数不是调度器坏了，而是时区语义没对齐。先确认任务按 UTC 触发还是按用户所在时区触发，再测三类边界：跨 UTC 日界、夏令时跳过或重复的那一小时、用户中途改时区；最后分别核对执行时间、到达时间和页面展示时间。下面整理一套边界用例和记录表。",{"type":31,"level":32,"children":172},[173],{"text":174,"type":29},"先明确任务的时间语义和时区规则",{"type":25,"children":176},[177],{"text":178,"type":29},"一个任务涉及三个时间：存储时间、触发时间、展示时间。绝对时间戳通常以 UTC 存储；对“当地每天 9 点”这类周期任务，还要保存 IANA 时区标识和明确的夏令时策略。触发按用户时区还是按租户时区，必须在需求里写死；展示则跟随用户当前时区。",{"type":25,"children":180},[181],{"text":182,"type":29},"这三者没定义清楚，测试就无法判断“9 点执行”指的是哪个 9 点。很多争议到最后不是 bug，而是需求没写。代理 IP 只改变网络出口地区，不改系统时区，两者要分开设。跨地区页面回归是另一条线，不能替代任务调度本身的时区验证。测试地区可参考[全球代理 IP 产品页](https:\u002F\u002Fwww.quanqiudaili.com\u002Fproduct\u002Fdynamic-residential)选择；调度预期仍应依据产品设定的时区规则和 IANA 时区数据库确认。",{"type":31,"level":32,"children":184},[185],{"text":186,"type":29},"验证 UTC 日界与当地日期的对应关系",{"type":25,"children":188},[189],{"text":190,"type":29},"UTC 日界是最容易出错的地方。用户在东八区设置“每天 0 点执行”，对应 UTC 前一天 16 点；如果调度器按 UTC 日期归组，这条任务会被算到前一天，表现为“当天没跑”或“跑了两天”。",{"type":25,"children":192},[193],{"text":194,"type":29},"测试方法：选取不同时区各设一条“每日 0 点”的任务，观察触发日期与展示日期是否符合需求。具体城市和夏令时规则可查[IANA 时区数据库](https:\u002F\u002Fwww.iana.org\u002Ftime-zones)，不要把固定 UTC 偏移当成全年不变的地区时区。",{"type":31,"level":32,"children":196},[197],{"text":198,"type":29},"验证夏令时跳过和重复小时",{"type":25,"children":200},[201],{"text":202,"type":29},"夏令时切换日期和规则因地区而异。测试前应按目标时区核对当年的转换规则；IANA 时区数据库提供可查的地区时区资料。春季落在被跳过那一小时里的任务，要么顺延，要么明确跳过；秋季落在重复那一小时的任务，可能执行两次。",{"type":25,"children":204},[205],{"text":206,"type":29},"这两种行为都要有明确规则，并在测试里验证。没有规则，线上就会出现“某天漏跑”或“某天重复扣款”这类事故。",{"type":31,"level":32,"children":208},[209],{"text":210,"type":29},"确认用户改时区后任务归属",{"type":25,"children":212},[213],{"text":214,"type":29},"用户从东八区改到 UTC-5，已有任务跟谁走？常见两种设计：跟随用户当前时区重新计算，或固定在创建时的时区。两种都可以，但必须一致，且要在界面上说清楚。",{"type":25,"children":216},[217],{"text":218,"type":29},"测试时要覆盖改时区前后的下一次触发，以及改回原时区后是否恢复原状。",{"type":31,"level":32,"children":220},[221],{"text":222,"type":29},"分别核对执行、通知和页面显示时间",{"type":25,"children":224},[225],{"text":226,"type":29},"执行时间看服务端日志，到达时间看消息或通知记录，展示时间看用户界面。三者不一致时，先判断是哪一段错了，再定位到调度、队列还是格式化。",{"type":25,"children":228},[229],{"text":230,"type":29},"> 表格中的阈值、用例编号和结果如无测试记录支持，均应视为演示样例；实际验收标准以项目需求、历史基线或团队约定为准。填真实记录时至少补齐 IANA 时区标识、经 IANA 核对的当年转换日期、任务本地计划时间、产品所选策略（跳过或顺延）、预期 UTC、实际 UTC 和任务 ID，否则无法按规则复算。",{"type":109,"children":232},[233],{"text":234,"type":29},"| 场景 | 输入时区 | 期望执行时间 | 实际执行 | 展示时间 | 判定 |\n| --- | --- | --- | --- | --- | --- |\n| 每日 0 点 | UTC+8 | 前一日 16:00 UTC | 前一日 16:00 | 当日 00:00 | 通过 |\n| 夏令时春季 | Europe\u002FBerlin（如 2026-03-29） | 顺延策略下应为 03:00 CEST = 01:00 UTC | 02:30 CEST 与 03:00 CEST 均未触发 | 03:00 | 异常（顺延未生效） |\n| 夏令时秋季 | Europe\u002FBerlin（如 2026-10-25） | 02:30 出现两次，按幂等规则只执行一次 | 02:30 CEST 与 02:30 CET 各执行一次 | 02:30 | 异常（重复执行） |\n| 改时区后 | UTC+8 → UTC-5 | 按新时区下一次 | 仍按旧时区 | 新时区 | 异常 |",{"type":25,"children":236},[237],{"text":238,"type":29},"表格里“期望”一列必须来自需求，不能来自上一次的实际结果，否则错误会被当成基线继承下去。",{"type":31,"level":32,"children":240},[241],{"text":120,"type":29},{"type":31,"level":21,"children":243},[244],{"text":245,"type":29},"换代理IP 会改变任务执行时区吗？",{"type":25,"children":247},[248],{"text":249,"type":29},"不会。任务按存储的 UTC 或用户设的时区触发，出口不参与。",{"type":31,"level":21,"children":251},[252],{"text":253,"type":29},"夏令时切换当晚没有日志，怎么查？",{"type":25,"children":255},[256],{"text":257,"type":29},"先确认调度器是跳过还是排队，再对该时区的下一次触发。",{"type":31,"level":21,"children":259},[260],{"text":261,"type":29},"两个用户看到的时间不同，正常吗？",{"type":25,"children":263},[264],{"text":265,"type":29},"正常。展示跟随各自时区，执行时间只有一条。",{"type":31,"level":21,"children":267},[268],{"text":269,"type":29},"存 UTC 还要保留原始时区吗？",{"type":25,"children":271},[272],{"text":273,"type":29},"建议保留。不存的话，用户改过时区后就无法回溯当时的设置。",{"source":6,"id":275,"documentId":276,"translationKey":276,"locale":9,"slug":277,"path":278,"_path":278,"title":279,"description":280,"excerpt":280,"image":281,"publishedAt":282,"updatedAt":283,"author":17,"tags":284,"featured":19,"sortOrder":20,"readingTime":21,"bodyType":22,"bodyBlocks":285,"bodyHtml":153},3735,"belku71wykpbo1n0zjch92pu","saas-regional-file-upload-reliability","\u002Fblog\u002Fsaas-regional-file-upload-reliability","SaaS 文件上传如何测试？检查跨地区网络下的续传与文件完整性 | 全球代理","用合成文件固定大小、类型与网络条件，分别测上传耗时、断点续传、校验和与失败清理，给出可复现的记录字段、判定标准与失败重试规则。","https:\u002F\u002Fcms.quanqiudaili.com\u002Fuploads\u002Flarge_saas_cover_cf1033347d.webp","2026-10-27T06:02:20.647Z","2026-10-27T06:02:20.635Z",[],[286,290,294,298,302,306,310,314,318,322,326,330,334,338,342,346,350,354,357,361,364,368,372,376,380,384,388,392],{"type":25,"children":287},[288],{"text":289,"type":29},"文件上传是否可靠，不能只看最后有没有上传成功。如出现连接中断或 TLS 错误，可参考连接超时、TLS 握手和代理出口稳定性记录。要固定文件大小、类型、带宽和丢包，分别记录上传耗时、暂停后续传、校验和比对、失败后的临时文件清理；四项里任何一项不稳定，跨地区的体验都会明显变差。同一组测试里，出口带宽和代理类型要保持一致。接下来分别检查耗时、续传、完整性和失败清理，并为每项记录通过标准。",{"type":31,"level":32,"children":291},[292],{"text":293,"type":29},"定义测试文件、网络条件和上传指标",{"type":25,"children":295},[296],{"text":297,"type":29},"测试文件要写死三件事：大小、类型、内容。大小至少覆盖三档：1 MB 以内、中档（约为上限的 10%–50%）、接近上限（产品配置上限的 90%–100%，按授权测试环境容量调整）；只有产品上限约为 1 GB 时，第三档才是 1 GB 左右；类型覆盖图片、PDF、压缩包和纯文本；内容用可生成随机数据的合成文件，避免用真实客户文档。",{"type":25,"children":299},[300],{"text":301,"type":29},"网络条件也要写死：带宽、延迟、丢包率。发现异常后先区分网络波动与产品缺陷：换出口、换时段各复测一次，再看失败是否跟着文件或接口走。跨地区测试常见的错误是只换出口不控网络，结果测到的是网络质量，不是产品行为。目标地区可参考[全球代理 IP 产品页](https:\u002F\u002Fwww.quanqiudaili.com\u002Fproduct\u002Fdynamic-residential)选择；出口自身的可用率与延迟，可单独参照[代理 IP 可用率、延迟和稳定性测试](https:\u002F\u002Fwww.quanqiudaili.com\u002Fblog\u002Fproxy-ip-availability-latency-stability-test)记录。出口带宽与类型同样要固定，混用会让耗时不可比。",{"type":31,"level":32,"children":303},[304],{"text":305,"type":29},"比较不同地区的上传耗时和成功率",{"type":25,"children":307},[308],{"text":309,"type":29},"耗时按分位数记录，不记平均值。平均值会掩盖长尾，而上传体验恰恰由长尾决定：10 次里 9 次 20 秒、1 次 3 分钟，用户感受到的是 3 分钟。",{"type":25,"children":311},[312],{"text":313,"type":29},"成功率要预先按项目目标定义：成功怎么算、重试是否计入、同一文件重复多少次。10 次只作冒烟样例，不能把固定失败次数或 90% 这类脱离业务的口径当成通用验收标准。小样本下的分位数只能作探索观察，报告里必须同时列出样本量和原始耗时，否则 P95 在 10 次样本上没有统计意义。实际判定以下表“通过标准”一栏的项目阈值和团队约定为准。失败要记录失败阶段：是连接建立失败、中断在 90%、还是服务端返回 5xx，三者对应完全不同的修法。",{"type":31,"level":32,"children":315},[316],{"text":317,"type":29},"验证网络中断后的断点续传",{"type":25,"children":319},[320],{"text":321,"type":29},"续传要测三种中断：主动暂停、网络中断、页面刷新。但只有产品声明支持的恢复方式才能作为通过断言：主动暂停和断网通常要求服务端保留分片或偏移记录；页面刷新续传还额外要求上传会话能跨刷新持久化。产品没有这项能力时，把对应场景记为“不支持”，不要记为“失败”。",{"type":25,"children":323},[324],{"text":325,"type":29},"判定续传是否真的生效，看的不是界面提示，也不是总传输量。抓一次网络记录，同时核对服务端的分片或偏移记录：恢复后只传剩余部分才算生效。存在协议重发开销时总量可能略大于文件大小，开启压缩时又可能小于文件大小，所以不能只凭“总量等于文件大小”就判成伪续传。",{"type":31,"level":32,"children":327},[328],{"text":329,"type":29},"用校验和确认文件完整性",{"type":25,"children":331},[332],{"text":333,"type":29},"上传完成后比对源文件与服务端文件的校验和（MD5 或 SHA-256）。跨地区链路出现静默损坏的概率不高，但一旦发生，用户拿到的是打不开的文件，比上传失败更难排查。",{"type":25,"children":335},[336],{"text":337,"type":29},"校验要在服务端做，不要只在前端算。前端算完传到服务端、服务端再算一遍，两者一致才算通过。",{"type":31,"level":32,"children":339},[340],{"text":341,"type":29},"检查失败清理和重试去重",{"type":25,"children":343},[344],{"text":345,"type":29},"失败清理和去重是两件事：一个看临时数据有没有被及时收走，一个看重试有没有生成两份业务记录。可执行用例按这个顺序走：",{"type":25,"children":347},[348],{"text":349,"type":29},"1. 记录本次上传的 upload \u002F session ID，作为后续核对的主键。\n2. 在分片上传中途强制断网，或主动取消，模拟真实中断。\n3. 在产品规定的保留期内重连，确认已完成分片仍在、可以续传——这是“中断就立刻清理”最容易踩的坑。\n4. 超过清理窗口或主动终止后，再查临时分片、临时对象和上传任务的状态是否被清掉。\n5. 用同一份文件重试上传，确认最终只生成一份业务记录，没有重复行、重复计费或两份存储对象。",{"type":25,"children":351},[352],{"text":353,"type":29},"表格里要写清清理的触发条件（超时、取消、失败次数）和允许保留期，否则“清理了”和“该清理的没清理”都无从判断。重试策略也要有上限：无限重试在弱网下会放大流量，还可能触发服务端限流。",{"type":25,"children":355},[356],{"text":107,"type":29},{"type":109,"children":358},[359],{"text":360,"type":29},"| 指标 | 测试方法 | 通过标准 | 记录字段 |\n| --- | --- | --- | --- |\n| 上传耗时 | 三档文件按团队设定的重复次数测试（例如每档 10 次） | P95 在阈值内 | 文件大小、P50\u002FP95、地区 |\n| 成功率 | 同一文件按预设次数重复上传（例如 10 次） | 失败率不超过项目预设阈值 | 失败次数、失败阶段 |\n| 断点续传 | 暂停、断网、刷新各一次 | 从断点继续 | 已传字节、恢复后字节 |\n| 校验和 | 服务端比对 SHA-256 | 与源文件一致 | 两个哈希值 |\n| 失败清理 | 强制中断后检查 | 临时文件被清理 | 残留文件数、清理触发条件、允许保留期 |",{"type":31,"level":32,"children":362},[363],{"text":120,"type":29},{"type":31,"level":21,"children":365},[366],{"text":367,"type":29},"测上传需要专门用住宅 IP 吗？",{"type":25,"children":369},[370],{"text":371,"type":29},"不一定。模拟用户体验可使用符合测试目标的住宅出口并控制带宽，测服务端上限则应隔离网络变量。代码接入需设置代理时，按所用语言与代理网关的接口文档配置主机、端口、账号和密码。",{"type":31,"level":21,"children":373},[374],{"text":375,"type":29},"小文件和大文件的指标差很多，正常吗？",{"type":25,"children":377},[378],{"text":379,"type":29},"正常。分档记录，不要跨档比较 P95。",{"type":31,"level":21,"children":381},[382],{"text":383,"type":29},"上传成功但用户打不开，算哪类问题？",{"type":25,"children":385},[386],{"text":387,"type":29},"先查校验和与存储路径，再核对响应码和服务端日志；问题定位为连接层时，可参考连接超时、TLS 握手和代理出口稳定性记录。",{"type":31,"level":21,"children":389},[390],{"text":391,"type":29},"移动端弱网要单独测吗？",{"type":25,"children":393},[394],{"text":395,"type":29},"要。4G\u002F5G 切换会中断连接，续传用例必须覆盖。",{"source":6,"id":397,"documentId":398,"translationKey":398,"locale":9,"slug":399,"path":400,"_path":400,"title":401,"description":402,"excerpt":402,"image":403,"publishedAt":404,"updatedAt":405,"author":17,"tags":406,"featured":19,"sortOrder":20,"readingTime":32,"bodyType":22,"bodyBlocks":407,"bodyHtml":153},3734,"efod1ujg76jb5w6n1moibokw","saas-regional-fallback-testing","\u002Fblog\u002Fsaas-regional-fallback-testing","某地区依赖服务不可用时，如何验证 SaaS 产品的降级与恢复？ | 全球代理","先盘点依赖与核心路径，再在授权环境模拟超时、5xx 与 DNS 失败，验证降级提示、重试、恢复与告警，并区分核心与非核心功能。","https:\u002F\u002Fcms.quanqiudaili.com\u002Fuploads\u002Flarge_saas_cover_077e340989.webp","2026-10-27T06:02:00.367Z","2026-10-27T06:02:00.344Z",[],[408,412,416,420,424,428,432,436,440,444,461,465,469,473,477,481,485,489,492,496,500,503,507,511,515,519,523,527,531],{"type":25,"children":409},[410],{"text":411,"type":29},"降级测试要回答两个问题：核心功能是否仍可用，用户是否知道下一步该做什么。先标出哪些依赖挂了会影响核心路径，再在授权环境里模拟超时、5xx 和 DNS 失败。每模拟一种，逐项检查四件事：提示文案、重试次数、恢复后的状态、告警是否触发。降级是否按预期生效，最终要看发布后的地区错误率和回滚记录。有些问题只在特定地区的出口上出现，可在受控条件下切换出口复测。测试地区可用[全球代理 IP 产品页](https:\u002F\u002Fwww.quanqiudaili.com\u002Fproduct\u002Fdynamic-residential)规划；网络连接异常可参考连接超时、TLS 握手和代理出口稳定性记录。可以按依赖、故障注入、用户提示、恢复验证四层逐步检查。",{"type":31,"level":32,"children":413},[414],{"text":415,"type":29},"盘点依赖与核心业务流程",{"type":25,"children":417},[418],{"text":419,"type":29},"先把依赖列出来，按“挂了会不会阻断核心路径”分两类。登录、支付、数据读写这类属于核心路径的依赖，挂了必须有降级或明确的阻断提示；统计这类非核心能力可以静默降级；推荐、富文本编辑能不能静默处理，要看它是否承载核心流程、失败会不会丢数据，涉及草稿保存或内容丢失的应给明确提示。",{"type":25,"children":421},[422],{"text":423,"type":29},"每一类依赖再标四个值：超时时间、重试次数、降级方式、告警阈值。这四个值决定测试的预期，没有它们就只能凭感觉判断“体验好不好”。",{"type":31,"level":32,"children":425},[426],{"text":427,"type":29},"在授权环境模拟超时、5xx 和 DNS 故障",{"type":25,"children":429},[430],{"text":431,"type":29},"模拟只在自己可控的测试环境做，不动生产。三种失败方式分别对应三类故障：超时对应慢依赖，5xx 对应服务不可用，DNS 失败对应解析或网络配置问题。",{"type":25,"children":433},[434],{"text":435,"type":29},"模拟时只改一个依赖，其他依赖保持正常。同时改两个，出了问题也说不清是哪个触发的降级。模拟“某地区依赖不可用”之前，先确认这条依赖请求是浏览器发出的，还是服务端发出的：如果依赖由服务端发起，切换客户端出口根本不在那条链路上，测到的只是客户端到 SaaS 的一段。这类场景要在授权测试环境里用 mock、故障注入或受控网络策略，按目标地区或部署单元选择请求，分别注入超时、5xx、DNS 失败，并保留一组正常对照。仅换出口不等于已经注入依赖故障。",{"type":31,"level":32,"children":437},[438],{"text":439,"type":29},"检查降级提示、重试上限和失败状态",{"type":25,"children":441},[442],{"text":443,"type":29},"用户可见的部分有三项要查：",{"type":445,"format":446,"children":447},"list","unordered",[448,453,457],{"type":449,"children":450},"list-item",[451],{"text":452,"type":29},"**提示文案**：说清“哪个功能暂时不可用”，不要只写“系统繁忙”。",{"type":449,"children":454},[455],{"text":456,"type":29},"**下一步**：给一个用户能做的动作，比如稍后重试、改用备用方式或联系客服。",{"type":449,"children":458},[459],{"text":460,"type":29},"**可恢复性**：区分“稍后重试”和“暂时无法恢复”，别让用户反复点。",{"type":25,"children":462},[463],{"text":464,"type":29},"重试要测上限。若待测链路包含代理出口的请求重试，可参考代理请求的超时、重试和故障转移设计，但它不能替代 SaaS 依赖自身的重试与补偿验证。重试三次和重试三十次，对用户和后端的压力完全不同；超过上限后应该有明确的失败态，而不是一直转圈。",{"type":31,"level":32,"children":466},[467],{"text":468,"type":29},"验证服务恢复、数据状态和告警",{"type":25,"children":470},[471],{"text":472,"type":29},"撤销故障注入、确认依赖本身恢复健康，只是这一步的起点，不是结论。按下面五步走完再宣布恢复：",{"type":25,"children":474},[475],{"text":476,"type":29},"1. **开关状态**：观察降级开关、熔断器和限流是否自动解除，是否还有地区被锁在降级分支上。\n2. **新请求**：恢复后新发起的请求应走完整链路，结果与故障前基线一致。\n3. **遗留请求**：故障期间被拒绝、排队或超时的请求，要单独确认最终状态——是已失败、已补偿，还是仍在队列里。\n4. **数据核对**：对订单、扣款、消息投递、任务状态逐项对账，只对确认未完成的操作按幂等规则补做，不要把“有状态操作”整类重放一遍，那样会造出重复扣款。\n5. **告警与指标**：确认告警已解除、通知发到了正确的值班人、恢复后的错误率和延迟回到基线。",{"type":25,"children":478},[479],{"text":480,"type":29},"记录三组时间：故障开始、依赖解除、各项功能恢复完成；并写明每一步的预期状态与实际状态。没有这组记录，下次同类故障无法判断是恢复得慢，还是根本没恢复。",{"type":31,"level":32,"children":482},[483],{"text":484,"type":29},"记录用户可见结果和系统指标",{"type":25,"children":486},[487],{"text":488,"type":29},"记录以用户视角为主，工程指标为辅。同一次模拟，要有“用户看到了什么”和“系统记了什么”两份证据。",{"type":25,"children":490},[491],{"text":107,"type":29},{"type":109,"children":493},[494],{"text":495,"type":29},"| 依赖 | 失败方式 | 核心路径表现 | 期望降级 | 实际 |\n| --- | --- | --- | --- | --- |\n| 支付网关 | 超时 | 下单中断 | 提示稍后重试，订单保留 | 提示成功但未扣款 |\n| 推荐服务 | 5xx | 首页可打开 | 隐藏推荐位 | 显示空白区块 |\n| 短信服务 | DNS 失败 | 注册可继续 | 切换备用通道 | 直接报错 |",{"type":25,"children":497},[498],{"text":499,"type":29},"“期望降级”一列来自设计文档，不是来自这次的实际表现，否则缺失的降级会被当成正常。",{"type":31,"level":32,"children":501},[502],{"text":120,"type":29},{"type":31,"level":21,"children":504},[505],{"text":506,"type":29},"恢复后要不要补数据？",{"type":25,"children":508},[509],{"text":510,"type":29},"先看这类操作在故障期间是否留下了未完成记录：订单、扣款、消息投递这类有状态操作要逐条核对并做幂等补偿；纯展示类不需要。补偿规则应在设计阶段就写进方案，测试时验证它是否真的被执行。",{"type":31,"level":21,"children":512},[513],{"text":514,"type":29},"依赖恢复了，用户还在报错，先查什么？",{"type":25,"children":516},[517],{"text":518,"type":29},"先看降级状态是否解除，再查缓存是不是还挂着旧结果。",{"type":31,"level":21,"children":520},[521],{"text":522,"type":29},"模拟故障会触发真实告警吗？",{"type":25,"children":524},[525],{"text":526,"type":29},"会。先通知值班人，或改到测试告警通道里演练。",{"type":31,"level":21,"children":528},[529],{"text":530,"type":29},"只降级不报警行不行？",{"type":25,"children":532},[533],{"text":534,"type":29},"不行。静默降级最难发现，核心路径必须有告警。",[536],{"source":6,"id":7,"documentId":8,"translationKey":8,"locale":9,"slug":10,"path":11,"_path":11,"title":12,"description":13,"excerpt":13,"image":14,"publishedAt":15,"updatedAt":16,"author":17,"tags":537,"featured":19,"sortOrder":20,"readingTime":21,"bodyType":22,"bodyBlocks":538,"bodyHtml":153},[],[539,542,545,548,551,554,557,560,563,566,569,572,575,578,581,584,587,590,593,596,599,602,605,608,611,614,617,620,623,626,629],{"type":25,"children":540},[541],{"text":28,"type":29},{"type":31,"level":32,"children":543},[544],{"text":35,"type":29},{"type":25,"children":546},[547],{"text":39,"type":29},{"type":25,"children":549},[550],{"text":43,"type":29},{"type":31,"level":32,"children":552},[553],{"text":47,"type":29},{"type":25,"children":555},[556],{"text":51,"type":29},{"type":25,"children":558},[559],{"text":55,"type":29},{"type":31,"level":32,"children":561},[562],{"text":59,"type":29},{"type":25,"children":564},[565],{"text":63,"type":29},{"type":31,"level":21,"children":567},[568],{"text":67,"type":29},{"type":25,"children":570},[571],{"text":71,"type":29},{"type":31,"level":21,"children":573},[574],{"text":75,"type":29},{"type":25,"children":576},[577],{"text":79,"type":29},{"type":25,"children":579},[580],{"text":83,"type":29},{"type":31,"level":32,"children":582},[583],{"text":87,"type":29},{"type":25,"children":585},[586],{"text":91,"type":29},{"type":25,"children":588},[589],{"text":95,"type":29},{"type":31,"level":32,"children":591},[592],{"text":99,"type":29},{"type":25,"children":594},[595],{"text":103,"type":29},{"type":25,"children":597},[598],{"text":107,"type":29},{"type":109,"children":600},[601],{"text":112,"type":29},{"type":25,"children":603},[604],{"text":116,"type":29},{"type":31,"level":32,"children":606},[607],{"text":120,"type":29},{"type":31,"level":21,"children":609},[610],{"text":124,"type":29},{"type":25,"children":612},[613],{"text":128,"type":29},{"type":31,"level":21,"children":615},[616],{"text":132,"type":29},{"type":25,"children":618},[619],{"text":136,"type":29},{"type":31,"level":21,"children":621},[622],{"text":140,"type":29},{"type":25,"children":624},[625],{"text":144,"type":29},{"type":31,"level":21,"children":627},[628],{"text":148,"type":29},{"type":25,"children":630},[631],{"text":152,"type":29},null,[],[]]