系统设计面试:如何设计基于 MASQUE 的 CONNECT-UDP 代理?
题干与适用场景
移动客户端只能稳定访问 HTTPS,但语音、游戏和实时探测依赖 UDP。请设计一个代理,让客户端通过 HTTP 建立到目标 UDP 主机的隧道,并覆盖连接生命周期、数据转发、鉴权、限流、DNS、故障转移和回退。
RFC 9298 定义了 CONNECT-UDP 方法和代理模板;RFC 9297 定义 HTTP Datagrams 与 Capsule Protocol,分别承载不可靠数据和可靠控制信息。高质量回答要把协议语义、代理资源和安全策略分层,不能把“加了 TLS”当成完整的滥用防护。
面试官考察点
- 能否区分 CONNECT-UDP 的隧道建立、数据转发和关闭。
- 是否说明 HTTP/3 Datagram 与 Capsule 的适用边界及无 Datagram 时的回退。
- 是否设计目标地址白名单、端口策略、用户鉴权和租户配额。
- 是否处理 DNS 解析、超时、重试、半开连接与故障转移。
- 是否给出带宽、并发、丢包、延迟、滥用和成本指标。
- 是否知道代理不能保证 UDP 的可靠性、顺序或端到端加密语义。
回答前需要澄清的问题
- 客户端和代理是否都支持 HTTP/3 Datagrams,还是必须兼容 HTTP/2?
- 目标是企业内网访问、实时媒体,还是开放互联网代理?目标决定白名单和滥用风险。
- 客户端是否提供目标主机名,代理是否代做 DNS?解析结果的生命周期和隐私要求是什么?
- 单个用户允许多少隧道、带宽和并发 UDP 流?是否需要按区域就近接入?
- 允许的最大空闲时间、单包大小和总会话时长是多少?
30 秒回答框架
我会先把代理限定为已鉴权的目标集合,再用 CONNECT-UDP 建立会话。控制消息走 Capsule,支持时用 HTTP/3 Datagram 承载 UDP 数据;不支持时回退到可靠封装或拒绝,不假装提供相同延迟。数据面按租户做令牌桶、并发和空闲超时,DNS 在受控解析器完成并绑定会话。节点异常时只重建可重放的会话,避免复制不可重放数据。验收同时看 p99 延迟、丢包、建连成功率、资源占用、拒绝率和滥用告警。
分步骤深入解答
1. 建立会话与状态机
客户端向代理发送 CONNECT-UDP,请求目标主机和端口。代理先验证身份、策略和配额,再解析目标并创建会话。状态至少包括待鉴权、已连接、排空和关闭;每个状态都设置超时与原因码,防止半开会话长期占用资源。
CONNECT / .well-known/masque/udp/example.test/443 HTTP/3
Host: proxy.example实际实现应遵循 RFC 9298 的请求模板和编码规则,示例只表达意图,不替代完整的协议字段。
2. 划分控制面与数据面
Capsule Protocol 适合可靠的会话控制、错误和关闭通知;HTTP/3 Datagram 适合不要求重传的 UDP 数据。代理把每个 Datagram 映射到对应的 UDP socket,并限制单包大小、队列深度和突发量。若路径不支持 Datagram,应明确回退到可靠封装或返回不支持,避免把可靠传输引入实时路径却不计成本。
3. 设计鉴权与目标策略
代理先验证短期令牌、租户状态和设备绑定,再依据目标域名、IP 段、端口及用途做 allowlist。禁止客户端任意指定内网地址、环回地址、云元数据地址或高风险端口。DNS 解析应在受控解析器完成,记录解析版本和 TTL,避免重新解析把同一会话悄悄切到不同租户边界。
4. 限流、配额与成本控制
按租户同时限制隧道数、每秒包数、字节速率、单会话时长和空闲时间。入口和出口都使用令牌桶,超过配额返回可观测的拒绝原因;节点还要保留全局保护阈值。统计代理 CPU、内核 socket、队列、出口带宽和每会话成本,避免只限制 HTTP 请求数而放过长时间 UDP 流。
5. 处理故障与回退
对建连失败、目标不可达、DNS 超时和代理过载分别记录原因。新会话可在健康节点重试;已发送的 UDP 数据通常不可安全重放,因此故障转移应只恢复控制状态或让上层重新建立会话。客户端不支持 Datagram 时,服务端应根据业务选择可靠封装或明确失败,并在指标中区分两种路径。
6. 观测与安全运营
每个会话记录租户、代理节点、目标策略版本、建立和关闭原因、字节数、包数、丢包估计、p50/p95/p99 延迟及限流事件。日志不得记录完整令牌或敏感载荷。检测端口扫描、异常目标集中度、突发放大和跨租户资源争抢,并准备按租户、目标和区域快速撤销策略。
7. 灰度与验收
先在固定区域和 allowlist 目标灰度,使用对照组比较直连、Datagram 路径和回退路径。压力测试覆盖丢包、乱序、代理重启、DNS 变化、半开连接和超额流量。发布门槛应包含建连成功率、实时请求 p99、丢包率、每会话资源、拒绝误报和滥用告警延迟;任一安全阈值超限就收紧策略或关闭新路径。
高质量示范回答
我会把它做成只服务已鉴权租户和明确目标集合的代理。客户端发起 CONNECT-UDP 后,代理验证令牌、目标和配额,受控 DNS 解析并创建会话。控制消息使用 Capsule;支持 HTTP/3 Datagram 时承载不要求重传的 UDP 数据,并为每个会话设置包大小、队列、速率、空闲和总时长上限。
出口策略阻断内网、环回、元数据和高风险端口,入口出口都做租户令牌桶。故障时新会话可切换健康节点,已发送 UDP 数据不自动重放。观测建连成功率、p99 延迟、丢包、资源和成本,同时监控扫描与放大行为。灰度对比 Datagram、回退和直连,安全或资源门槛超限就关闭新路径。
常见错误
- 只说“用 HTTPS 包住 UDP” → 没有定义隧道语义和数据承载 → 分开 CONNECT-UDP、Capsule 和 Datagram。
- 把代理当成可靠传输 → UDP 的丢包和顺序语义仍由上层负责 → 明确能力边界与指标。
- 允许任意目标地址 → 形成内网探测或反射放大器 → 使用目标和端口 allowlist,阻断特殊地址。
- 只按 HTTP 请求限流 → 长连接仍可耗尽 socket 和带宽 → 同时限制隧道、包、字节、时长和空闲。
- 故障时重放全部 UDP 数据 → 可能重复交易或破坏实时协议 → 只恢复可重放控制状态,让上层重建数据会话。
- 只测平均延迟 → 尾延迟和滥用会被隐藏 → 同时看 p99、丢包、拒绝和安全告警。
追问及应对
HTTP/2 不能发送 HTTP/3 Datagram 时怎么办?
根据业务选择可靠封装、长轮询式传输或明确拒绝,并单独计量延迟、CPU 和带宽成本;不要声称它与不可靠 Datagram 等价。
代理如何避免 SSRF?
在解析后和连接前都检查目标 IP,阻断环回、链路本地、私网、云元数据和策略外网段,并处理 DNS 重绑定;策略版本要绑定会话并可撤销。
UDP 丢包应由谁重试?
代理只报告可观测的传输结果,不擅自重放业务包。由具备幂等和序列语义的上层协议决定重试,实时媒体通常选择丢弃或纠错。
代理重启如何恢复会话?
优先让客户端重新鉴权并建立新会话;若必须保留控制状态,只恢复短期、可验证且不包含不可重放数据的状态,旧 socket 立即排空。
如何证明限流没有误伤?
按租户、区域、目标和客户端版本比较拒绝率与成功率,设置错误拒绝预算,并用回放流量验证突发、长连接和节点故障下的配额行为。