《互联网产品的客户端架构·规模化与架构演进》附录 B 多端问题排查手册

卷四附录 B:按十类症状组织多端排查手册,包括功能在某端不可用、同一笔订单状态不同、组件样式漂移、发布后白屏、性能退化、线上问题无法定位、第三方 SDK 隐私风险、区域格式错误、读屏不可用与迁移卡住;每类给出先查什么、常见根因、验证方式与预防动作。

使用方式

这份手册按症状组织,不按章节。线上出问题时,人通常只知道「某个端不对劲」,不知道它属于承诺、能力还是构建问题。先找到最接近的症状,再按「先查什么」的顺序排除。

每条症状分六段:现象、先查什么、常见根因、验证方式、修复动作、预防动作。顺序不能颠倒:先确认事实,再猜原因;先验证修复,再谈预防。

症状一:功能在某个端不可用

现象:同一功能,四个端正常,一个端入口消失或点击无响应。

先查什么:

  1. 能力快照里这项是 native、polyfill 还是 absent?
  2. 功能开关在该端是开还是关?
  3. 实验分组是否排除了该端?
  4. 客户端版本是否低于最低支持版本?
  5. 系统权限是否被拒绝?

常见根因:

  • 能力探测默认返回「支持」,实际设备不支持。
  • 开关按端配置,某个端的配置漏了。
  • 旧版本客户端没有新接口,前端直接隐藏入口。
  • 权限被拒绝后没有降级路径,只显示空白。

验证方式:让用户提供端、版本、系统版本与功能 id;对照事件日志里的 featureAvailability 五个字段。五项都正常才进入代码排查。

修复动作:按能力策略补降级路径;开关补齐该端配置;旧版本给出升级提示而不是静默隐藏。

预防动作:能力表默认 absent;开关配置纳入发布检查;每个功能至少有一条降级用例。

对应章节:1.3、5.2、3.3。

症状二:同一笔订单在两端状态不同

现象:Web 显示「已支付」,iOS 显示「处理中」,客服无法判断哪一个是真相。

先查什么:

  1. 两端拿到的是同一份服务端状态,还是各自推导?
  2. 支付状态与订单状态是否被压进同一个字段?
  3. 是否有端在本地做了乐观更新且未回滚?
  4. 缓存是否跨版本复用了旧结构?

常见根因:

  • 端上根据支付回调自行推断订单状态。
  • 状态字段含义在不同端映射不同。
  • 乐观更新失败后没有回滚,界面停留在临时状态。
  • 本地缓存没有版本号,旧数据被新代码读取。

验证方式:取同一订单 id,比对服务端原始状态、两端展示状态、两端本地缓存。三者不一致时,以服务端为准,检查端的映射表。

修复动作:状态只由服务端事实驱动;端上映射表集中到共享内核;缓存加 schema 版本。

预防动作:把订单状态纳入 identical 承诺,做跨端契约测试;禁止端上推导支付结果。

对应章节:1.1、1.2、12.2。

症状三:组件样式在各端漂移

现象:同一个按钮,五个端的圆角、间距、字号都略有不同。

先查什么:

  1. token 是否按三层结构使用,还是各端直接写死值?
  2. 主题覆盖是否按优先级生效?
  3. 组件是否被某个端单独 fork 过?
  4. 设计稿更新后,token 是否同步?

常见根因:

  • 组件库有 token,但业务代码绕过组件直接写样式。
  • 多品牌覆盖顺序不明确,后加载的覆盖了前一个。
  • fork 后的组件没有回流,逐渐分叉。
  • token 命名按视觉值而非语义,换主题时失效。

验证方式:抽取同一组件的计算样式,逐端比对 token 解析结果;检查是否存在 fork 目录与深层覆盖。

修复动作:统一 token 解析入口;删除 fork,改为变体参数;主题覆盖按「基础 → 品牌 → 业务」固定顺序。

预防动作:样式检查纳入 CI;组件契约版本化;每季度清理一次 fork。

对应章节:2.1、2.2、2.3。

症状四:发布后白屏或崩溃

现象:新版本在部分设备上启动白屏,或进入某页面即崩溃。

先查什么:

  1. 崩溃率按端、机型、系统版本如何分布?
  2. 是否与某个灰度批次强相关?
  3. 最近是否改动了启动路径或动态配置?
  4. 是否引入了新的第三方 SDK?

常见根因:

  • 动态配置下发了当前版本不认识的字段。
  • 插件或热更新包与宿主 API 版本不匹配。
  • 新 SDK 初始化阻塞启动,超时后崩溃。
  • 降级开关本身依赖了故障服务。

验证方式:按版本与批次切片看崩溃率;回滚最近一次配置或插件;在本地用相同系统版本复现。

修复动作:立即回滚配置/插件;关闭相关灰度;修复后重新走小比例灰度。

预防动作:配置 schema 校验;插件协议版本区间校验;启动路径禁止同步网络调用;灰度观察窗口内不扩大比例。

对应章节:3.1、3.3、5.2、6.3。

症状五:版本迭代后性能持续退化

现象:每个版本首屏慢一点,几个版本后累计多了几百毫秒,但找不到单点。

先查什么:

  1. 是否有分端、分阶段的预算与基线?
  2. 退化发生在哪个阶段:网络、解析、渲染还是脚本?
  3. 是否新增了同步依赖或初始化逻辑?
  4. 预算超限是否在合并前被拦截?

常见根因:

  • 只测总量,没有阶段归因。
  • 新增依赖在启动时同步初始化。
  • 基线长期不更新,回归比较失效。
  • 预算没有 owner,超限无人处理。

验证方式:用同一设备、同一网络、同一版本对比两个构建;按阶段拆分耗时,找出占比增长最大的阶段。

修复动作:把同步初始化改为延迟;拆分大依赖;更新基线并记录变更原因。

预防动作:预算进入 CI;每次合并比较阶段耗时;每月复核一次基线。

对应章节:4.1、4.2、4.3。

症状六:线上问题无法定位

现象:用户反馈「用不了」,但日志里找不到对应记录,或记录字段不全。

先查什么:

  1. 事件是否满足最小字段契约?
  2. 错误与阻塞事件是否被采样?
  3. 是否有 trace id 串联前后端?
  4. 告警是否有 owner 与 runbook?

常见根因:

  • 字段命名不统一,无法按功能聚合。
  • 采样率对所有事件一致,错误被大量丢弃。
  • 日志在采集端未脱敏,敏感字段被整体关闭。
  • 告警只发群,无明确处理人。

验证方式:用用户提供的端、版本、时间窗检索;检查该事件是否命中采样;检查 trace 是否可跨端关联。

修复动作:补齐必填字段;错误与阻塞改为全量;按功能建立查询视图。

预防动作:事件契约纳入评审;采样策略按等级;每条告警绑定 owner 与 runbook。

对应章节:7.1、7.2、7.3。

症状七:第三方 SDK 带来隐私风险

现象:合规扫描发现某 SDK 采集了未声明的数据,或初始化早于用户同意。

先查什么:

  1. SDK 是否在清单中,版本与权限是否登记?
  2. 初始化时机是否在同意之后?
  3. 采集字段是否超出功能所需?
  4. 是否有退出与替换方案?

常见根因:

  • 业务直接接入 SDK,未经过平台团队。
  • SDK 在 Application 启动时自动初始化。
  • 权限申请与功能使用时机脱节。
  • 清单长期未更新,已下线 SDK 仍在采集。

验证方式:抓包与静态扫描结合;核对同意记录时间与 SDK 初始化时间;比对清单与实际依赖。

修复动作:延迟初始化到同意之后;关闭非必要采集;下线无主 SDK。

预防动作:SDK 接入走白名单;初始化统一收口;每季度复核清单。

对应章节:8.1、8.2、8.3。

症状八:区域格式错误

现象:中东用户看到金额小数位错误,或美洲用户看到日期差一天。

先查什么:

  1. 金额是否用整数最小单位存储与计算?
  2. 时区是否统一存 UTC、按区域展示?
  3. 小数位与舍入规则是否按币种配置?
  4. 日期格式是否依赖系统 locale?

常见根因:

  • 用浮点数存金额,累加后出现分级误差。
  • 展示时直接取本地时间,未做时区转换。
  • 所有币种统一两位小数,忽略了零小数位币种。
  • 文案拼接导致语序与复数错误。

验证方式:构造边界金额与跨时区时间,逐区域跑格式化测试;比对服务端与端上展示。

修复动作:金额改整数;时间统一 UTC;按币种配置小数位与舍入;文案改用带参数的模板。

预防动作:格式化纳入共享内核;每个区域至少一条回归用例。

对应章节:9.1、9.2、9.3。

症状九:读屏用户无法完成操作

现象:视障用户反馈按钮读不出、焦点跳走、状态变化无播报。

先查什么:

  1. 控件是否有角色、名称与状态?
  2. 焦点顺序是否与视觉顺序一致?
  3. 状态变化是否有播报?
  4. 是否只靠颜色传达信息?

常见根因:

  • 用不可聚焦的容器模拟按钮。
  • 自定义弹窗没有焦点陷阱与恢复。
  • 异步加载后焦点丢失。
  • 错误提示只变红,没有文本。

验证方式:开启读屏走一遍主流程;检查焦点顺序;用高对比与放大字体复测。

修复动作:改用语义控件;补名称与状态;修复焦点管理;错误提示加文本。

预防动作:无障碍检查进入组件契约;主流程每版本人工走查一次。

对应章节:10.1、10.2、10.3。

症状十:迁移长期卡在中途

现象:新旧两套架构并存一年多,新路径流量上不去,旧路径没人敢删。

先查什么:

  1. 迁移是否有明确的退出条件?
  2. 双写是否有一致性校验?
  3. 卡住的原因是技术、数据还是组织?
  4. 旧路径是否还有独占功能?

常见根因:

  • 只定义了开始,没有定义结束。
  • 双写长期不一致,团队不敢切流量。
  • 旧路径仍有未迁移的边界功能。
  • 没有 owner 推动收尾。

验证方式:统计新旧路径流量、差异率、未迁移功能清单;访谈相关负责人确认阻塞点。

修复动作:补齐退出条件;先修数据差异;拆分剩余功能;指定收尾 owner 与截止时间。

预防动作:迁移启动时同时写退出条件;每两周复核差异率;设置「无流量观察期」后再删除。

对应章节:12.1、12.2、12.3。

排查的通用顺序

十类症状背后有一条共同顺序:

  1. 确认事实:哪个端、哪个版本、哪个用户、什么时间。
  2. 定位层:能力、开关、契约、构建、运行时,逐层排除。
  3. 比对基线:与上一个正常版本、另一个正常端比较。
  4. 验证修复:在相同条件下复现并确认消失。
  5. 补预防:把这次排查变成一个检查项或一条用例。

跳过前三步直接改代码,通常会修错地方;跳过第五步,同一个问题会以另一种形式回来。

一页纸速查

症状第一问最可能的层
功能不可用能力快照是什么?能力/开关
状态不一致谁推导了状态?承诺/契约
样式漂移是否绕过 token?设计系统
白屏崩溃最近改了什么配置?插件/配置
性能退化哪个阶段变慢?预算/归因
无法定位字段齐吗?被采样了吗?可观测性
隐私风险SDK 何时初始化?安全/合规
格式错误金额怎么存?时区怎么转?国际化
读屏不可用控件有角色吗?无障碍
迁移卡住退出条件是什么?治理/迁移

速查表不能替代排查,但能让你从正确的层开始。

继续阅读

探索更多技术文章

浏览归档,发现更多关于系统设计、工具链和工程实践的内容。

全部文章 返回首页

「books」更多文章

  1. 《互联网产品的 AI 架构·平台化与治理》附录 C 平台化评审清单
  2. 《互联网产品的 AI 架构·平台化与治理》附录 B 能力目录与配额字段速查
  3. 《互联网产品的 AI 架构·平台化与治理》附录 A 治理角色与职责速查