题干与适用场景
假设入口建立 2 秒用户预算,A 已耗时 500 毫秒后调用 B,B 还会调用 C 和非关键审计服务。说明 deadline、取消、重试和观测契约。时钟并不完全同步;只读 RPC 或带幂等键的命令才允许重试。目标是在保留序列化与传输余量的同时停止注定失败的工作。
面试官考察点
公开的 Staff 系统设计准备资料要求候选人澄清延迟、失败和规模,再解释组件边界与取舍。强回答应明确:入口只建立一个绝对截止时间;每跳计算剩余预算;取消沿调用树传播;重试受幂等性和剩余时间约束;指标能区分 deadline 超时、调用方取消、排队和取消后的无效工作。
回答前需要澄清的问题
- 2 秒是硬截止时间还是可接受的 SLO?硬截止时间意味着迟到结果无效;异步任务才可以继续。
- 哪些下游决定响应?审计、推荐可降级,授权不能省略。
- 写操作是否幂等?无保护副作用不能盲目重试。
- RPC 框架是否自动传播上下文?否则用拦截器统一实现并跨语言测试。
- 导出等任务是否必须完成检查点?若必须,改成有状态异步任务,不要让同步 RPC 忽略取消。
30 秒回答框架
“入口创建唯一 deadline,所有 RPC 从上下文计算剩余时间并预留响应余量。服务在入队和长任务循环中检查取消,重试只使用剩余预算且要求幂等。调用方断开或 hedge 有赢家时,取消沿调用树传播到所有分支。我会记录每跳剩余预算、排队时间、重试次数和停止延迟,并用慢下游、取消竞态和时钟偏差注入测试验证契约。”
分步骤深入解答
1. 统一预算表示
入口记录 t0 + 2s 的绝对 deadline,而不是让每跳重新增加 2 秒。服务计算 remaining = deadline - now,再扣除序列化和传输余量。gRPC 文档区分 deadline 与 timeout,并将传播值转换成已扣除耗时的剩余时间,以降低时钟偏差影响。应使用 RPC 上下文传递,不要依赖容易漏传的自定义字符串头。
2. 按关键路径花费预算
A 用掉 500 毫秒后,最多把 1.5 秒交给 B。若 B 需要 400 毫秒本地处理并保留 100 毫秒响应余量,调用 C 的预算不能超过剩余值和 C 的上限。并行分支共享父 deadline,不能各自获得完整的 1.5 秒。排队前先判断预计排队时间;已经来不及就快速拒绝或返回文档化的降级结果。
3. 传播取消
截止时间到期、客户端断开和 hedge 赢家都属于取消原因。子 RPC 继承父上下文,工作线程在入队前和长循环的有界间隔检查取消,释放许可并关闭流。Google SRE 指出只传播 deadline 仍可能泄漏调用树中的工作;下游失败后,取消应回传并扩散到兄弟分支。需要安全检查点的任务应改为独立异步作业。
4. 让重试服从预算
attemptdeadline = min(parentremaining - responsemargin, perattempt_cap)。下次尝试无法在父 deadline 前完成时立即停止。只重试瞬时错误,且操作必须天然幂等或带幂等键。hedge 共享父预算,首个可接受响应返回后取消其他尝试。日志保留原始 deadline 和 attempt 编号,避免把濒临过期的重试误认为新请求。
5. 定义可观测失败
对 deadline 超时返回稳定状态(如 gRPC DEADLINE_EXCEEDED),保留原始取消原因。Trace 记录入口和出口剩余预算、排队耗时、尝试次数和取消到停止的延迟。用三跳测试验证:C 慢于剩余预算、B 排队时 A 取消、首个 hedge 成功、机器存在时钟偏差;断言子任务停止、重试终止且许可释放。
高质量示范回答
“我会让入口独占 2 秒 deadline。A 消耗 500 毫秒后把剩余预算放进 RPC 上下文交给 B,B 扣除响应余量后调用 C;并行分支共享父预算。每个子调用在入队和长任务中检查取消,客户端断开或 hedge 获胜时取消向下游扩散。重试必须幂等并受剩余时间限制。审计可以转成可追踪的异步作业,但关键响应不能把迟到工作算作成功。最后用慢依赖、排队、取消竞态和时钟偏差做集成测试,并在 trace 中显示每跳预算。”
常见错误
- 每跳重新设 2 秒 → 调用链按跳数放大延迟 → 传播单一 deadline。
- 只传播超时不传播取消 → hedge 和断开的请求继续占用线程 → 取消上下文扇出并测停止延迟。
- 所有超时都重试 → 非幂等写入重复副作用 → 分类错误、限制尝试并要求幂等。
- 先排队再检查预算 → 注定失败的请求占满容量 → 入队前拒绝或降级。
- 固定余量没有数据 → 大响应持续失败或浪费预算 → 用传输和序列化分位数推导余量。
追问及应对
服务时钟不一致怎么办?
不要直接比较不同机器的墙上时钟。使用 RPC 框架的剩余时间转换,或传播扣除已耗时的 timeout,并在测试中注入时钟偏移。
下游能否延长 deadline?
同步响应不能延长;迟到结果已不符合父契约。需要继续处理时应改成可查询的异步任务。
如何给慢响应预留余量?
分别测量序列化和网络尾延迟,设置有界余量并限制载荷;余量长期吃掉预算时调整 SLO 或响应形状。
取消后哪些工作可以继续?
只有幂等且持久化的检查点或审计事件,并通过任务 ID 观测;不能继续占用同步连接和工作线程。