Uber Eats System Design Interview: A Pro Grade Answer for SDE NG
Uber Eats System Design Interview: A Pro Grade Answer for SDE NG
Uber Eats System Design Interview (2026): SDE New Grad Pro Grade 完整答题模板
很多同学把 Uber 的 System Design 面试当成“画几个服务 + 上 Redis + Kafka”就能过。现实是,面试官真正看的不是你会不会背组件名,而是你能不能在 40-60 分钟里给出一个 可落地、可扩展、可解释 trade-off 的系统方案。
这篇文章围绕经典题目 Design a Food Delivery App (like Uber Eats),给你一套可直接用于面试的高质量回答框架。你可以把它当作“答题脚本 + 技术地图 + 复盘清单”。
如果你还没建立 System Design 基础框架,建议先看 SDE NG System Design Primer。
目录
- 面试官到底在考什么
- Requirement Clarification(先问再画)
- Capacity Estimation(量级感)
- API 与数据模型(落地能力)
- 高层架构(Microservices + Event-driven)
- 核心难点一:Dispatch / Driver Matching
- 核心难点二:实时位置与状态同步
- 核心难点三:支付、幂等与一致性
- 可扩展性与高可用设计
- 可观测性与线上故障处理
- 安全与反作弊
- 面试高分回答模板(可背)
- 高频追问题库(30 题)
- 10 天冲刺计划
- 最容易挂掉的 15 个坑
- 站内延伸阅读(SEO 内链)
面试官到底在考什么
Uber 这类题目的本质,不是做“架构赏析”,而是评估你是否具备 L4/L5 工程师的系统化思维。
面试官通常在看 5 件事:
- 你有没有产品 sense:知道用户真正要什么
- 你有没有数据建模能力:能把业务对象落到 schema
- 你有没有分布式系统基本功:一致性、可用性、延迟的平衡
- 你有没有工程判断:知道哪里要强一致,哪里可最终一致
- 你有没有沟通结构:被追问后还能保持主线清晰
如果你经常在“会技术但讲不清”上丢分,可以补 北美 SDE 面试 SOP。
Requirement Clarification(先问再画)
很多候选人一上来就画组件,这是常见扣分项。正确顺序是先锁定需求边界。
Functional Requirements(MVP)
- User 浏览餐厅与菜单
- User 下单并支付
- Restaurant 接单、出餐、更新状态
- Courier 接单、取餐、配送、上报位置
- User 实时看到订单状态与骑手位置
Non-Functional Requirements
- Latency: 关键交互(下单、状态更新)P95 < 300ms
- Availability: 核心下单链路 99.95%+
- Consistency: 支付与订单状态需要强一致边界
- Scalability: 午晚高峰请求量为平峰 5-10 倍
- Durability: 订单与支付记录不可丢失
你可以主动澄清的范围
- 城市级单区域,还是多城市多区域
- 是否支持 group order / scheduled order
- 是否讨论 ETA 预测模型细节
- 是否涵盖退款、改派、取消策略
Capacity Estimation(量级感)
面试不要求你算得极准,但要能给一个合理量级。
假设:
- DAU: 2M
- 峰值并发在线用户: 200K
- 峰值下单 QPS: 8K
- 位置上报频率: 每个骑手 2 秒一次
- 在线骑手峰值: 100K
推导:
- 位置更新写入吞吐约 50K events/s
- 订单状态事件高峰约 10K events/s
- WebSocket fanout 高峰需要百万级连接管理
你给出这类量级后,后面的 Kafka 分区、缓存策略、分片策略就有了依据。
API 与数据模型(落地能力)
Core APIs
GET /restaurants?lat=&lng=&cuisine=GET /restaurants/{id}/menuPOST /ordersPOST /orders/{id}/payPOST /orders/{id}/cancelPOST /courier/locationGET /orders/{id}/tracking
Core Entities
- User
- Restaurant
- MenuItem
- Order
- Payment
- Courier
- CourierLocation
- DispatchTask
Order 状态机(建议画给面试官)
CREATED -> PAID -> ACCEPTED -> PREPARING -> READY_FOR_PICKUP -> PICKED_UP -> DELIVERING -> DELIVERED
异常分支:
CANCELLED_BY_USERCANCELLED_BY_RESTAURANTFAILED_PAYMENTREFUND_PENDING / REFUNDED
这一步是面试加分点,因为它体现你在做真实业务系统,而不是抽象演讲。
高层架构(Microservices + Event-driven)
一个可讲清楚的高层架构可以是:
- API Gateway
- Auth Service
- User Service
- Restaurant Catalog Service
- Order Service
- Payment Service
- Dispatch Service
- Courier Service
- Tracking Service
- Notification Service
- ETA Service
- Search Service
中间件:
- Redis: 热数据缓存、短期状态
- Kafka/PubSub: 订单与位置事件总线
- Postgres/MySQL: 强一致交易数据
- Cassandra/DynamoDB: 时序位置历史
- Elasticsearch/OpenSearch: 餐厅搜索
关键说明:
- 订单主记录放关系型数据库,确保事务能力
- 位置流与追踪事件走消息总线,解耦生产者和消费者
- 读多写少的菜单、餐厅状态用缓存提速
核心难点一:Dispatch / Driver Matching
这是整题最核心的系统能力点。
Step 1: 候选骑手召回(Candidate Retrieval)
可选方案:
- Geohash + nearby cell 查询
- S2/H3 网格索引
- Redis GEO 索引(简单快速)
面试回答建议:
- 先用半径 2-3km 召回
- 如果候选不足,逐层扩大半径
- 过滤离线、已接单、评分过低骑手
Step 2: 评分排序(Ranking)
打分函数可考虑:
- ETA to restaurant
- ETA to customer
- 当前负载(是否多单)
- 历史接单率/取消率
- 区域熟悉度
简化表达:
score = w1*eta_pickup + w2*eta_dropoff + w3*reliability + w4*load_penalty
Step 3: Offer + Timeout + Re-dispatch
- 给 Top-N 骑手并行或分批发 offer
- 超时未响应自动重试下一批
- 达到阈值后触发“扩大搜索半径 + 提高奖励”
高并发下的关键风险
- 同一骑手被多单并发占用(双花问题)
- 解决方案:分布式锁 + 乐观并发控制 + 幂等任务 ID
核心难点二:实时位置与状态同步
用户体验最敏感的是“地图是否实时”。
传输协议选择
- Polling: 实现简单,但浪费资源
- Long Polling: 好于 polling,但仍有连接负担
- WebSocket: 双向低延迟,最适合 tracking
标准答法:
- App 与 Tracking Gateway 用 WebSocket 保持连接
- Courier App 上报位置到 Courier Service
- 位置事件写入 Kafka
- Tracking Service 消费事件并推送给订阅用户
扇出(Fanout)与削峰
- 热点订单会有多个订阅方(用户、商家、运营)
- 使用 channel 分组推送
- 限流策略:位置变动不足阈值时不推送
- 动态降频:高峰时 1s -> 2-3s 推送间隔
数据精度与成本平衡
- 不需要每个点都持久化到长存
- 近期轨迹放 Redis,长期轨迹异步写入冷存储
核心难点三:支付、幂等与一致性
支付链路基本原则
- 下单与支付分离,避免大事务
POST /pay需要 idempotency key- 支付回调是最终状态来源之一
常见一致性问题
- 支付成功但订单未更新
- 订单取消与支付成功同时发生
- 用户重复点击导致重复扣款
可行方案
- Outbox Pattern: 本地事务 + 异步发布事件
- Saga / 状态补偿:失败时触发回滚逻辑
- 幂等表去重:按
order_id + payment_intent_id
你要主动说明“强一致只放在资金与订单核心状态上,其他链路用最终一致”。这句话能明显体现工程成熟度。
可扩展性与高可用设计
扩展策略
- 服务无状态化,水平扩容
- 按城市/区域进行数据分片
- Kafka 按
city_id或order_id分区 - 热 key 缓存分层 + 本地缓存
高可用策略
- 多可用区部署(Multi-AZ)
- 关键服务主备/多副本
- 断路器、限流、熔断、超时重试
- 降级策略:地图失败时展示离散状态文本
多区域(可选加分)
- Active-Active 复杂但容灾能力强
- 订单归属单写区域,跨区读副本
- Global traffic routing + regional failover
可观测性与线上故障处理
面试官很喜欢问“上线后你怎么知道系统健康”。
必备监控指标
- 下单成功率
- 支付成功率
- Dispatch 成功率与平均匹配时长
- 配送准时率
- WebSocket 连接数与消息延迟
- P95/P99 API latency
日志与链路追踪
- 统一 request id / order id 贯穿全链路
- OpenTelemetry + tracing 平台
- 关键事件审计日志可回溯
典型故障演练
- Kafka 积压
- Redis 故障
- 支付服务超时
你要给出 runbook 思路:先限流保核心,再隔离故障域,再做异步补偿。
安全与反作弊
基础安全
- OAuth/JWT 鉴权
- HTTPS 全链路
- PII 脱敏与最小化存储
- 数据库加密与密钥轮换
反作弊点
- 虚假 GPS(Mock Location)检测
- 异常取消/刷单行为识别
- 设备指纹 + 风险评分
即使面试官没问,主动提 1-2 句安全与风控也很加分。
面试高分回答模板(可背)
开场 60 秒模板
- 我先确认目标与范围
- 我给出 MVP 功能与非功能约束
- 我给高层架构,再 deep dive 两个最难点
- 最后讲 trade-off 和扩展路径
被追问时模板
- 先承接问题:"Good point"
- 给结论:"I would prioritize X"
- 给依据:"because of latency/consistency/cost"
- 给替代:"alternative is Y, trade-off is Z"
收尾 45 秒模板
- 重申系统目标
- 总结核心设计决策
- 给出上线优先级(Phase 1/2/3)
- 说明最大风险和监控闭环
如果你想把答题表达从“会做”提升到“会讲”,可以看 SDE 面试官真正想听什么。
高频追问题库(30 题)
- 为什么订单数据不用 NoSQL 全部存?
- 位置更新为什么要消息队列而不是直写 DB?
- WebSocket 连接百万级时怎么扩?
- Dispatch 如何避免同一骑手重复分配?
- ETA 模型误差大怎么办?
- 高峰期如何降级保证核心链路?
- 餐厅临时关店怎么处理未完成订单?
- 用户改地址后配送路径怎么重算?
- 如何支持 batch delivery(多单拼送)?
- 为什么要把支付和订单拆服务?
- 如何处理支付成功但下单失败?
- 幂等 key 过期策略怎么定?
- 如何做跨城市扩展?
- 如何处理热点商圈流量倾斜?
- 如果 Redis 故障,系统如何退化?
- Kafka 延迟飙升时先做什么?
- 如何确保通知不重复轰炸用户?
- 如何做 SLA 分层(普通用户 vs 会员)?
- 如何支持 scheduled delivery?
- 如何设计退款流程?
- 如何保障审计与合规要求?
- 如何定义“配送准时率”?
- 如何在成本和实时性之间权衡?
- 如何做灰度发布与回滚?
- 如何避免缓存雪崩?
- 如何做 API 限流与恶意请求防护?
- 如何设计 feature flag 驱动策略实验?
- 如何评估 dispatcher 改版收益?
- 如何处理第三方支付服务不稳定?
- 给一个你会优先上线的 MVP 路线图。
10 天冲刺计划
Day 1-2:框架和表达
- 固化开场模板(需求 -> NFR -> 架构 -> deep dive)
- 每天 3 次 60 秒架构讲解
Day 3-4:核心难点
- Dispatch + Tracking 专项
- 手写状态机与关键 API
Day 5-6:一致性与故障
- Outbox/Saga/幂等专项
- 故障演练问答 20 题
Day 7-8:全真 mock
- 每天两轮 45 分钟
- 强制加入打断和反问
Day 9:查漏补缺
- 复盘最常被追问的 10 个点
- 优化 trade-off 表达
Day 10:终版输出
- 固化最终答题脚本
- 录音复听,修正语速和冗余
你在求职阶段如果还想同步优化全局节奏,可以参考 湾区 New Grad SDE 求职生存指南。
45 分钟面试时间分配建议(非常实用)
很多候选人不是不会,而是时间分配崩盘。下面是比较稳妥的 45 分钟打法。
0-5 分钟:澄清需求与目标
- 明确用户角色与关键流程
- 锁定 3-5 个非功能约束
- 对范围做边界切分(MVP vs nice-to-have)
5-12 分钟:高层架构与核心数据流
- 画主要服务与数据通路
- 明确同步调用与异步事件边界
- 先讲 happy path,再点异常流入口
12-28 分钟:Deep Dive 两个核心难点
- Dispatch/Matching 机制
- 实时 Tracking 与消息扇出
- 主动讲 trade-off,而不是等面试官追问
28-36 分钟:一致性、容错、扩展
- 幂等、去重、补偿
- 限流、降级、熔断
- 分片与扩容策略
36-42 分钟:监控、安全、上线计划
- KPI/SLI/SLO 设计
- 反作弊与审计
- Phase 1/2/3 迭代路线
42-45 分钟:总结与反问
- 30 秒重申系统目标与关键决策
- 30 秒说明最大风险与缓解策略
- 用 1 个反问展示工程 maturity
Trade-off 决策表(面试官最爱听)
如果你能把选择讲成“业务目标驱动下的工程取舍”,分数会明显更高。
SQL vs NoSQL(订单主数据)
- 选择 SQL:事务一致性强,适合支付和订单状态
- 代价:横向扩展复杂,写入热点需要额外治理
- 结论:订单主表用 SQL,长尾事件和轨迹用 NoSQL
WebSocket vs Polling(实时追踪)
- 选择 WebSocket:低延迟、双向通信、用户体验更好
- 代价:连接管理复杂,网关层需要专门扩展
- 结论:核心 tracking 用 WebSocket,低优先级端点可降级轮询
同步调用 vs 异步事件(服务间协作)
- 选择同步:链路简单、可读性高
- 代价:耦合高、故障传播快
- 选择异步:解耦好、抗峰值强
- 代价:排障难度和一致性复杂度上升
- 结论:下单核心路径同步最短链路,通知与分析链路异步化
单区域强一致 vs 多区域高可用
- 单区域:一致性更容易保证,复杂度低
- 多区域:容灾强,但跨区一致性成本高
- 结论:先区域内强一致,再做跨区容灾和读副本扩展
分阶段上线路线图(Phase 1/2/3)
这部分非常像真实工程决策,能明显区分“会做系统”与“会讲概念”。
Phase 1(MVP,先跑通)
- 用户下单、支付、餐厅接单、骑手配送全链路
- 基础 dispatch(最近可用骑手)
- 基础状态推送(下单、接单、送达)
- 最小监控:成功率、延迟、错误率
Phase 2(体验增强)
- ETA 预测模型迭代
- 更精细的 dispatch 排序(可靠性/负载/多单)
- WebSocket 优化与推送降频策略
- 异常流程完善(改派、退款、超时补偿)
Phase 3(规模化与商业化)
- 多城市分片与跨区域容灾
- 动态激励与供需平衡
- 风控反作弊升级
- 数据平台建设(运营策略实验、A/B 平台)
端到端关键时序(文字版)
你在面试里可以用“事件时序”把抽象架构讲得非常具体。
下单到送达的核心链路
- User 调用
POST /orders,Order Service 创建订单(状态CREATED)。 - User 调用支付接口,Payment Service 成功后发布
payment_succeeded事件。 - Order Service 消费事件,将状态改为
PAID,并发布order_ready_for_dispatch。 - Dispatch Service 召回候选骑手,打分排序,发出 dispatch offer。
- Courier 接单后,Dispatch 发布
courier_assigned,订单状态变为ACCEPTED。 - 餐厅出餐更新
READY_FOR_PICKUP,骑手取餐后更新PICKED_UP。 - 配送中位置持续上报,Tracking Service 推送给用户端。
- 骑手送达后订单置为
DELIVERED,通知服务发送最终确认。
失败与补偿链路(必须会讲)
- 支付成功但订单未更新:由幂等消费 + 重试 + 对账任务补齐
- 派单超时无人接:自动扩圈 + 动态奖励 + 用户预期管理
- WebSocket 断连:降级为短轮询并提示“连接重建中”
面试实战对话模板(追问场景)
下面给两段高频追问对话。你可以直接拿来做 mock role-play。
对话 1:一致性追问
- Interviewer: "What if payment succeeds but order creation fails?"
- Candidate: "I would separate order creation and payment capture. First create order intent, then execute payment with idempotency key. If payment callback arrives but order state is stale, an outbox-driven reconciler updates order state exactly once."
- Interviewer: "How do you prevent duplicate charge?"
- Candidate: "Store
payment_intent_idwith unique constraint, reject repeated capture requests, and keep a reconciliation job for eventual correctness."
这段回答的关键点是:
- 明确事件顺序
- 解释 exactly-once 的工程近似做法
- 给出在线防重 + 离线对账双保险
对话 2:扩展性追问
- Interviewer: "At city scale, dispatch latency spikes at dinner peak. What do you do first?"
- Candidate: "I would first protect the critical path. Add rate limiting on non-critical endpoints, isolate dispatch worker pools by zone, and expand candidate retrieval radius adaptively only when local pool is exhausted."
- Interviewer: "What metric proves your fix works?"
- Candidate: "Primary metric is dispatch success rate within SLA window. Secondary metrics are median matching latency, P95 order-to-assign delay, and courier utilization."
这段回答的关键点是:
- 先保核心路径,再谈优化
- 每个动作都能落到可观测指标
- 体现你有 incident response 思维
现场表达小技巧
- 不要说 "it depends" 就停住,后面要接 decision criteria
- 不要只说组件名,要说 why now, why here
- 每次被追问都用同一模板:结论 -> 理由 -> 取舍 -> 指标
最容易挂掉的 15 个坑
- 一上来画图,不先澄清需求
- 只讲功能,不讲 NFR
- 不做容量估算,架构没有依据
- 组件堆砌,不讲 trade-off
- Dispatch 只说“找最近骑手”
- 不懂幂等,支付链路会翻车
- 不会解释一致性边界
- 只会 happy path,不会异常流
- 不提降级与容灾
- 不提监控与报警
- 术语很多,但没有落到 API/数据模型
- 被追问就改口,没有逻辑闭环
- 忽略成本约束
- 没有分阶段上线思路
- 总结时没有风险与 next step
站内延伸阅读(SEO 内链)
按你的准备路径继续补:
- 系统设计入门框架: SDE NG System Design Primer
- 两个月系统设计备考法: 系统设计面试攻略
- 面试表达 SOP: 北美 SDE 面试 SOP
- Code Review 回答流程: 北美 SDE Code Review 面试全流程
- 面试官视角: 美国 SDE Interview 面试官想听什么
- 简历补强: 北美 SDE NG 简历大厂加分项
- 进阶职业路径: 如何进入 FAANG 当 SDE
- 求职执行节奏: 湾区 New Grad SDE 求职生存指南
结语
Uber Eats 这道题的高分关键,不是你用了多少“高级组件”,而是你能否把系统设计讲成一个可执行的工程方案:
- 需求边界清楚
- 数据与状态流闭环
- 一致性与可用性取舍明确
- 故障与监控预案可落地
按这篇模板去练,System Design 面试会从“想到哪说到哪”,变成“结构化输出 + 高压可追问”的状态。
