预约窗口 · 锁 TTL · 队列优先级 · 冲突可观测
当 SSH、签名与依赖缓存都已就位,团队仍会看到「同一台机器上两个 Job 争用工作目录」「美东产物覆盖新加坡半成品」「锁文件悬挂导致队列假死」。根因是席位与互斥没有在架构评审里与 Runner 拓扑同级对待;它们与任务链幂等键和staged publish强相关,缺字段时排障只能依赖个人记忆。
同机双写税:两个任务共用同一检出目录或同一 DerivedData 根,表现为偶发链接错误与签名不一致;标签正确也无法拯救目录级竞态。
跨节点重复产物税:同一构建号在两地同时推进,指针切换前读者看到撕裂集;没有租约与版本指针时回滚只能猜时间点。
锁悬挂税:进程崩溃未释放租约,后续任务永久等待;缺少 TTL、续租失败告警与人工清理门槛会把平均恢复时间拉到小时级。
优先级反转税:低优先级长任务占满席位,高优先级热修被饿死;没有二级队列与抢占策略时只能半夜手工 kill。
观测盲区税:只记录构建时长却不记录 queue_wait_ms 与 lock_contention_count,评审会只能用「感觉慢」替代数据。
把以上五条写成可勾选清单,再进入下一节选型互斥模型,才能从「能跑」升级到「可验收的共享池」。与SSH 与 VNC 接力对照阅读时,请区分交互会话与无人值守作业对锁语义的不同假设。
三条路径没有绝对优劣,只有与团队规模、跨区延迟预算与合规审计是否匹配。本地文件锁实现快但可观测性弱;远端协调服务(例如基于对象存储或轻量协调器的租约表)增加依赖但能把冲突率变成指标;调度器内置队列最省心却要接受平台语义。多地区 Mac 场景下还要把区域亲和与失败域写进契约,否则锁在 A 区、跑在 B 区会把 RTT 放大成排队时间。
| 维度 | 本地文件锁 | 远端协调租约 | 调度器队列 |
|---|---|---|---|
| 一致性语义 | 依赖本地 FS 与单挂载点;跨挂载即失效 | 显式租约 ID、TTL、续租与 fencing token | 平台保证串行与重试;需核对标签与并发上限 |
| 跨区适用性 | 弱;只适合单机池内互斥 | 强;可把租约表放在低延迟区并复制只读副本 | 中;取决于 Runner 调度是否跨区透明 |
| 可观测性 | 需自行埋点;常见只有 mtime | 租约表天然可导出指标与审计字段 | 平台队列深度与等待时间通常开箱 |
| 运维成本 | 低起步;后期排障贵 | 中;要处理时钟漂移与脑裂预案 | 低;但复杂拓扑可能被平台能力限制 |
| 典型踩坑 | NFS 锁语义与本地锁混用 | 续租失败静默、清理任务无租约 | 标签风暴与隐式共享工作区 |
共享池是否可靠,取决于「冲突能否被度量」而不是「成功时能否偶尔跑完」。
若你已在实践共享构建池 Runner 编排,把本节选型结论贴进架构说明,可避免「池子有了,但互斥仍靠口头约定」的半截工程化。
下面六步刻意保持厂商无关:无论你用 Jenkins、GitHub Actions 还是自研调度,只要交付物一致,新同事可以在半天内验证链路。每一步都应对应一条可检查的变更描述;与任务链 handoff组合时,请把租约 ID 写回信封。
定义席位上限:按 CPU、磁盘 IO 与交互会话需求给每台 Mac 设置 max_concurrent_jobs,并在 Dashboard 公示。
冻结工作区前缀:每任务独立检出目录与 DerivedData 根,禁止多任务共用可变前缀;与缓存键策略对齐。
选择互斥层:单机池优先文件锁加本地哨兵;跨区池优先远端租约;需要抢占与多级队列时回到调度器能力评估。
设定锁 TTL 与续租:TTL 取构建 P95 的 2–3 倍并设硬上限;续租失败必须告警,不得静默失效。
定义队列优先级:热修与主干门禁高于长周期归档;同级内 FIFO 或公平轮转写清,避免「口头插队」。
演练脑裂与清理:随机 kill 持有租约的进程,验证清理任务只在租约过期后触发且带审计日志。
LEASE_ID="${CI_PIPELINE_ID}-${CI_JOB_ID}"
LEASE_TTL_SEC=$(( BUILD_P95_SEC * 3 ))
curl -sf -X PUT "${COORD_URL}/leases/${LEASE_ID}" \
-H "Content-Type: application/json" \
-d "{\"ttl_sec\":${LEASE_TTL_SEC},\"owner\":\"${GITLAB_USER_LOGIN}\",\"region\":\"${RUNNER_REGION}\"}"
提示:示例中的协调端点可用对象存储条件写入、轻量 KV 或自建微服务实现;关键是 TTL、续租与 fencing 三角缺一不可。
没有度量就没有 SLO。建议至少采集 队列等待分位、锁冲突次数、续租失败率 与 因互斥导致的构建取消率,并与构建时长并列展示;否则优化会误判为「编译慢」而反复加核。排障顺序建议先确认租约与队列深度,再检查产物指针与缓存键,最后才怀疑工具链。
队列先看:queue_wait_p95 大于单次构建入口时间 10% 时优先扩容席位或调整优先级,而不是盲目优化编译参数。
锁再看:lock_contention_per_hour 连续升高时检查是否有共享前缀或未释放租约。
产物最后:当 staged publish 与指针切换指标异常时,再回到字节路径与校验字段。
注意:清理悬挂锁前必须确认没有读者仍持有旧指针;暴力删除往往换来更长的 mystery outage。
下列三条来自大量跨区 iOS 与 macOS 流水线的经验区间,用于立项前核对而非性能保证;你应用真实直方图替换它们,并在评审附件保留原始分布。
queue_wait_p95 大于端到端时长 15%,优先调整席位与优先级,再考虑横向加机器。| 团队规模 | 发布节奏 | 更稳的第一选择 |
|---|---|---|
| ≤ 8 人 | 日更主干 | 调度器队列 + 每任务独立工作区;单机文件锁加哨兵 |
| 9–30 人 | 多分支并行 | 远端租约表 + 明确优先级;区域亲和读 |
| 30 人以上 | 多租户合规 | 强制租约审计 + 不可变构建号;独立命名空间 |
| 强合规 | 跨区域受限 | 分区协调服务 + 禁止公共读桶;日志留存与责任人字段 |
个人笔记本、临时借用机器与「谁有空谁 ssh」在审计隔离与并发一致性上会持续欠账;即便锁设计正确,底层节点休眠与更新窗口也会让指标失真。相较之下,可合同化的云端 Mac 节点才能把席位、租约与 SLA 落在可验收条款上。
常见误区:把「远程桌面流畅」当成「无人值守作业健康」;交互会话与自动化作业对锁与休眠的要求相反,混用会拖垮整条链。
若团队既要 iOS 与 macOS 持续交付,又要给夜间回归与自动化留出确定性席位,自建固定资产往往卡在采购周期与多地布线;借用个人设备则难以满足密钥轮换与并发隔离。对需要生产级共享池与可观测互斥 的场景,VpsMesh 的 Mac Mini 云端租赁通常是更优解:按周期弹性计费、区域可选、节点专用可审计,让队列指标与池容量讨论建立在真实可用性之上,而不是口头承诺。