发版节奏常被「单机串行跑完所有 UI 测试」拖住。本文说明何时值得分片、用一张矩阵对比单机与多机策略、如何设计 Runner 标签与运行预算,并给出八步清单,把 XCTest UI 工作摊到多台 NodeMac 独占 Mac mini M4 上,让队列可预测。
若已采用 自托管 GitHub Actions macOS Runner,分片是把「一台快 Mac」变成机群的直接手段。构建侧并行可参考 并行 Mac 构建节点与 CI/CD。
为何单台强机仍达不到 UI 测试 SLA
Xcode 对单元测试并行很友好,但 UI 测试大量时间花在启动模拟器、动画与 SpringBoard 等待上,单主机上未必随 CPU 核数线性缩短。
- 模拟器 GPU 争用:同一台 M4 同时跑三套重 UI,帧时间常超过测试隐含的 33 ms 级假设,导致误点与假失败。
- 磁盘放大:每个分片重复写 DerivedData;SSD 若小于 500 GB 或剩余空间低于约 15%,并行任务易集体崩溃。
- 队列不透明:无分片标签时,团队分不清慢 PR 是卡在 UI 还是编译,往往超配编译机仍赶不上 UI 截止。
决策矩阵:单机 vs 分片机群
| 维度 | 单台 M4 全能机 | 专用 UI 分片 Mac |
|---|---|---|
| 90 分钟 UI 总时长墙钟 | 串行约 90 分钟 | 3 分片平衡后约 35~40 分钟 |
| 抖动敏感 | 过载时高 | 单机单套件时更低 |
| 运维复杂度 | 低 | 中;需标签与看板 |
| 地域建议 | 任意 | 港·日·韩·新·美 贴近开发者 |
扩容前先给用例分桶
分片本质是调度问题。按 p95 耗时把套件分桶,每桶与中位数的偏差尽量控制在 ±20% 内,避免总有一个分片每轮都是长尾。
- 从 Xcode Cloud、XCTest 日志或 CI 数据库导出历史耗时,按 p95 排序。
- 登录重流程单独成桶,避免阻塞可并行的结账、设置等流。
- 需真机实验室的用例单独标记——云 Mac 擅长模拟器,不替代 USB 农场。
- 单桶仍超 25 分钟 则按功能模块再拆。
- 将分桶映射纳入 Git(如
ui-shards.json)保证可复现。
提示:编译与 UI 分片使用不同标签。混用会导致重型 xcodebuild test 抢走为模拟器预留超时的机器。
UI 分片的 Runner 标签约定
| 标签组合 | 用途 | runs-on 示例 |
|---|---|---|
| self-hosted, macOS, m4, ios-compile | 仅构建与单元测试 | [self-hosted, macOS, m4, ios-compile] |
| self-hosted, macOS, m4, ios-ui, shard-1 | UI 桶 A | [self-hosted, macOS, m4, ios-ui, shard-1] |
| self-hosted, macOS, m4, ios-ui, shard-2 | UI 桶 B | B/C/D 同理扩展 |
GitHub Actions 矩阵:避免重复调度到同一台机
常见失误是同时声明 shard: [1,2,3] 与过宽的 runs-on,导致多个分片落到同一 Runner,硬件白买。应用唯一标签或主机名变量做一对一映射。
matrix:
shard: [1, 2, 3]
include:
- shard: 1
runner_labels: [self-hosted, macOS, m4, ios-ui, shard-1]
- shard: 2
runner_labels: [self-hosted, macOS, m4, ios-ui, shard-2]
- shard: 3
runner_labels: [self-hosted, macOS, m4, ios-ui, shard-3]
jobs:
ui-tests:
runs-on: ${{ matrix.runner_labels }}
timeout-minutes: 40
可用仓库规则要求 UI 任务必须带 shard-* 标签,防止贡献者无意合并并行度。多区域时复制标签族(如 shard-1-sg)使网络路径在 YAML 里一目了然。
在云 Mac mini M4 上落地 UI 分片的八个步骤
假设已通过 SSH 使用 NodeMac 主机,连接说明见 帮助中心。
- 租用 N 台机器,N = 目标分片数 + 1 台热备用于抖动重跑。
- 预装一致 Xcode 与模拟器运行时,避免「只在某分片能通过」。
- 注册 GitHub Runner,唯一名称且只挂对应分片标签。
- 为工作流设置
timeout-minutes,UI 分片可先设 40 再按 p95 收紧。 - 通过 scheme 或 test plan 把分片 ID 传入
xcodebuild(-only-testing列表)。 - 关闭显示器睡眠;若 harness 需 GUI 会话,在安全评审中固化策略。
- 集中上传 JUnit/截图,文件名带分片名便于排障。
- 若某分片连续三轮耗时超其它分片 1.5 倍,重新平衡分桶。
常见问题
一台 Mac mini M4 能跑几个 UI 测试分片?
除非已实测余量,否则将每个重模拟器 UI 分片视为单机单任务;轻量套件可试双分片,但 GPU 与存储争用常抵消墙钟收益。
分片是否应与纯编译任务共用 Runner 标签?
否。使用 ios-ui-shard 等专用标签,避免编译任务占用预装多模拟器、依赖图形会话的机器。
若需在港、日、韩、新、美快速增加分片,请对照 套餐页面 与上文队列估算,避免凭感觉超配或欠配。
Mac mini M4 适合作为 iOS UI 分片单元:Apple Silicon 单线程性能利于 XCTest 编排,统一内存可支撑多模拟器服务,PR 间隙 idle 功耗也相对可控。NodeMac 提供独占物理 Mac mini,支持 SSH 与 VNC,节点覆盖香港、日本、韩国、新加坡与美国,每个分片对应可远程排障的真实硬件。相较一次性采购机柜,按需租用 便于先用真实遥测验证分桶再扩展机群。