服务治理:注册发现、负载均衡与韧性
本章面向 Java(编程语言)全栈高级开发面试,主线不是背诵组件名,而是解释一次调用如何从“找到实例”走到“在故障中守住业务不变量”。案例持续绑定 WMS(仓储管理系统)、支付资金一致性、跨境物流轨迹和 IoT(物联网)报警风暴治理。
阅读地图与迁移计划
服务治理的核心,是在实例持续变化、网络存在延迟和下游能力有限的条件下,让请求被送到“此刻可用且有余量”的实例,并在失败时控制时间、流量和资源损失。注册发现回答“去哪里”,负载均衡回答“选哪台”,超时与重试回答“等多久、再试几次”,限流、熔断、隔离、降级与背压回答“压力超过能力时如何有序收缩”,可观测性与业务审计回答“如何证明系统做过什么”。
旧材料迁移时不做机械拼接,按下列规则归位:旧题中的注册中心、负载均衡、超时重试、限流熔断题分别迁入对应知识节;旧图统一重绘为本章 Mermaid(图表语法)图;旧表按“机制、边界、风险、决策证据”重组;旧数据统一改写为带输入、公式、计算、结论的数据演绎;旧项目话术拆入 WMS(仓储管理系统)、支付、轨迹、IoT(物联网)案例。涉及库存与资金时,数据库唯一约束、条件更新和事务才承载最终不变量,分布式锁只用于降低竞争或协调流程,不能冒充数据库不变量。
| 迁移对象 | 旧内容处理 | 本章落点 | 验收标准 |
|---|---|---|---|
| 旧题 | 去重后重写,不保留孤立答案 | 14 个知识节及综合口述题 | 每个知识节 3 道六字段题 |
| 旧图 | 合并同义图,补失败路径 | 15 幅 Mermaid(图表语法)图 | 语法可渲染,节点含业务语义 |
| 旧表 | 从名词对比升级为决策表 | 12 张表 | 能支持选型、排障或复盘 |
| 旧数据 | 补输入、公式和边界 | 14 个数据演绎 | 数字可复算,结论可行动 |
| 旧话术 | 从组件罗列改为问题闭环 | 32 道综合口述题 | 每题含 3–5 个追问直答与真实链接 |
flowchart LR
A["调用方 Client(客户端)"] --> B["Discovery(服务发现)"]
B --> C["Load Balancer(负载均衡器)"]
C --> D["Timeout Budget(超时预算)"]
D --> E["Retry(重试)/Hedge(对冲请求)"]
E --> F["Rate Limit(限流)"]
F --> G["Circuit Breaker(熔断器)"]
G --> H["Bulkhead(隔离舱)"]
H --> I["服务实例"]
I --> J["日志/指标/Trace(链路追踪)/审计"]
J -.反馈.-> B
J -.反馈.-> C
J -.反馈.-> F1. 注册、发现、租约与健康检查是不同状态机
服务注册把实例地址、端口、区域、版本和能力标签写入注册中心;服务发现把可用候选传播给调用方。Lease(租约)表示“实例必须在期限内续约,否则目录可以把它判为失联”,它解决故障检测的时间边界,却不能证明业务线程、数据库连接或依赖调用正常。Heartbeat(心跳)只证明心跳路径仍能运行;Health Check(健康检查)应分为进程存活、接流准备和业务能力三层,避免线程池耗尽的实例仍因心跳正常而接单。
| 检查层次 | 回答的问题 | 失败后的动作 | 不能证明什么 |
|---|---|---|---|
| Liveness(存活检查) | 进程是否需要重启 | 由编排平台重启 | 业务是否能接新请求 |
| Readiness(就绪检查) | 实例是否应进入流量池 | 摘除新流量 | 已接请求是否结束 |
| Dependency Check(依赖检查) | 关键依赖是否满足业务能力 | 局部降级或摘流 | 所有依赖都必须同步健康 |
| Lease(租约)续约 | 注册目录中的实例是否失联 | 到期删除或标记不健康 | 实例内部资源是否充足 |
stateDiagram-v2
[*] --> 启动中
启动中 --> 已注册: 建立租约
已注册 --> 可接流: 就绪检查通过
可接流 --> 疑似异常: 续约丢失或业务探测失败
疑似异常 --> 可接流: 连续探测恢复
疑似异常 --> 已摘流: 租约到期或主动摘流
已摘流 --> [*]: 注销并退出数据演绎 1:租约故障窗口。 假设续约间隔为 5s,租约有效期为 15s,注册中心每 3s 扫描一次,客户端目录推送与本地生效最坏再用 2s。实例在刚续约后立刻宕机,最坏摘除时间约为 15 + 3 + 2 = 20s。若该实例原承接 200 QPS(每秒查询率),窗口内理论上最多有 4000 次请求仍可能命中它。结论不是把租约盲目调到 3s,而是同时用被动失败摘除、连接失败快速切换和业务探针缩小窗口,并评估注册中心与网络抖动造成的误摘流。
热门面试题
问题:注册中心到底解决什么问题?
- 考点:动态地址、租约、发现传播、健康边界。
- 回答思路:从实例动态变化讲到目录传播,再限定它不负责业务正确性。
- 详细答案:注册中心维护服务名到实例元数据的动态映射,让调用方不依赖静态地址;租约、主动注销和健康状态帮助目录收敛,订阅或查询把变化传播给客户端。但目录中的“健康”通常只是控制面判断,不能证明库存线程池、支付数据库或物流依赖可用,因此还要有就绪检查、被动失败统计和调用侧保护。
- 进阶追问:注册中心不可用时所有调用都要失败吗?
- 进阶回答:不应。调用方可在明确陈旧窗口内使用最后一次成功的本地列表,但要保留过期指标、失败摘除和无候选时的降级策略。
问题:心跳正常但业务请求全部超时,为什么会发生?
- 考点:控制面与数据面、线程池耗尽、依赖健康。
- 回答思路:解释心跳路径独立,再给分层探测与摘流动作。
- 详细答案:心跳线程可能仍能定时发送,而业务线程池已被慢请求占满,数据库连接池也可能耗尽;此时控制面看见实例存活,数据面却不能处理请求。应让就绪检查覆盖关键资源水位,用真实轻量业务探测和调用侧错误率补充,先摘除新流量,再保留诊断现场,而不是用重启掩盖下游慢因。
- 进阶追问:健康检查能否把所有下游都串行调用一遍?
- 进阶回答:不能,重检查会把依赖抖动扩散成全量摘流;只检查决定当前核心能力的依赖,并允许非核心能力独立降级。
问题:租约越短,故障恢复一定越快吗?
- 考点:检测速度、误判、控制面负载、故障窗口。
- 回答思路:用续约、扫描、传播三个时间项解释双向成本。
- 详细答案:短租约可以缩短最坏失联窗口,但会提高续约和扫描负载,也更容易把短暂网络抖动、暂停或注册中心拥塞误判为实例死亡。工程上先按业务可承受失败窗口反推租约,再配合连续失败阈值、被动探测、连接快速失败和分区隔离;支付与库存还要保证超时后的幂等和查单,不能把故障检测当结果判断。
- 进阶追问:误摘流最危险的后果是什么?
- 进阶回答:剩余实例瞬间承压,可能从局部抖动演变成容量雪崩,因此摘流和恢复都要限速并观察余量。
2. 优雅启动与优雅下线必须覆盖流量和在途请求
Graceful Startup(优雅启动)要求实例完成配置、连接池预热、缓存加载和必要依赖检查后才进入流量池。Graceful Shutdown(优雅下线)按“先停止接新流量、等待目录传播、处理在途请求、停止消费者与定时任务、释放资源、最后退出”执行。只调用注销接口就立刻杀进程,会在目录收敛前制造连接重置;只等待在途请求却不停止接流,则永远等不空。
| 阶段 | 入口控制 | 在途处理 | 超时后的决定 |
|---|---|---|---|
| 启动预热 | 就绪状态为假 | 不接生产流量 | 预热失败则启动失败 |
| 主动摘流 | 就绪状态为假并注销 | 已接请求继续 | 等待传播窗口 |
| 排空 | 拒绝新连接或新请求 | 短请求完成,长任务转移 | 达到排空上限后取消或持久化 |
| 退出 | 停消费者和调度器 | 提交可确认结果 | 未完成任务进入可恢复状态 |
sequenceDiagram
participant P as 发布平台
participant I as 服务实例
participant R as 注册目录
participant C as 调用方
P->>I: 发送终止信号
I->>I: 就绪状态改为不可接流
I->>R: 主动注销
R-->>C: 推送实例删除
I->>I: 等待在途请求和消费者排空
I-->>P: 资源释放后退出数据演绎 2:下线排空时间。 调用方目录推送的 P99(99 分位响应时间) 为 2s,连接池最多每 5s 刷新一次,业务请求最大合理执行时间为 8s,安全余量为 2s。下线排空上限至少应覆盖 max(2, 5) + 8 + 2 = 15s。若平台只给 10s 终止宽限期,仍可能在旧连接命中后的第 5s 开始执行 8s 请求并被强杀。应把宽限期提高到 15s 以上,或缩短连接刷新并让长任务先持久化交接。
热门面试题
问题:库存服务实例频繁上下线,调用方如何及时感知?
- 考点:主动注销、目录推送、本地缓存、被动摘除。
- 回答思路:分别说明正常下线和异常宕机的传播链。
- 详细答案:正常发布先把就绪状态改为不可接流并主动注销,注册中心推送删除,调用方更新本地列表与连接池后再排空退出;异常宕机依靠租约到期和调用侧连接失败收敛。客户端不能只等中心通知,还应对连续失败实例做有时限的本地隔离,并在新列表到达后校正,避免永久黑名单。
- 进阶追问:为什么主动注销后还要等待?
- 进阶回答:通知传播、客户端调度和旧连接淘汰都有延迟,立即退出会让窗口内请求遭遇连接重置。
问题:优雅下线为什么要先停接流再停消费者?
- 考点:流量入口、在途工作、确认时机、可恢复交接。
- 回答思路:按新工作入口逐个关闭,再处理已拥有的工作。
- 详细答案:若先停业务线程却仍在负载池,新请求会继续进入并失败;若消息消费者在业务事务完成前确认,退出会丢工作。正确顺序是关闭接流和拉取入口,等待目录传播,再让已接请求、已拉消息和定时任务到达可恢复边界,最后确认、释放连接并退出;超过上限的任务要回到队列或持久化中间状态。
- 进阶追问:长达数分钟的物流任务怎么排空?
- 进阶回答:不要把它绑在进程生命周期内,应持久化任务状态和所有权,安全点续跑,并用幂等键吸收重复接管。
问题:服务启动成功为何还不能立即注册为健康?
- 考点:冷启动、缓存预热、连接建立、虚假容量。
- 回答思路:区分进程启动与可承载业务流量。
- 详细答案:进程端口监听只证明运行时已启动,首次类加载、数据库连接建立、规则缓存与热点数据仍可能未就绪。立即接流会把发布流量集中到冷实例,拉高尾延迟并触发误熔断。应先完成必要预热和就绪检查,再小比例放量;预热不能调用有副作用的真实支付或扣库存接口。
- 进阶追问:预热是否越全面越好?
- 进阶回答:不是,预热应覆盖关键无副作用路径并设置上限,否则启动会被非核心依赖拖死。
3. 本地列表提高可用性,也引入陈旧路由窗口
调用方缓存实例列表,可以在注册中心短暂不可达时继续调用,并把负载选择放在本地完成;代价是列表可能陈旧。陈旧来源包括推送丢失、轮询间隔、客户端暂停、网络分区、订阅处理积压和进程长期未刷新。治理目标不是追求瞬时一致,而是限定 Staleness(陈旧度),对已知失败快速本地隔离,并定期与权威快照校准。
| 风险 | 识别证据 | 处置 | 防止过度反应 |
|---|---|---|---|
| 已下线实例仍在列表 | 连接失败集中于单实例 | 临时本地隔离并触发刷新 | 隔离设置有效期 |
| 新实例迟迟不可见 | 列表版本落后 | 主动拉取全量快照 | 限制刷新频率 |
| 客户端列表分裂 | 同服务不同版本分布差异 | 对比目录版本与更新时间 | 按区域分别判断 |
| 注册中心不可达 | 刷新失败但旧列表仍有候选 | 使用最后成功快照 | 超过陈旧上限转降级 |
flowchart TD
A["收到目录增量版本 108"] --> B{"本地版本是否为 107"}
B -->|是| C["应用增量并刷新连接"]
B -->|否| D["检测到版本缺口"]
D --> E["限速拉取全量快照"]
E --> F{"快照是否在陈旧上限内"}
F -->|是| C
F -->|否| G["停止关键写或进入降级"]数据演绎 3:陈旧列表的错误量。 共有 20 个库存实例,每个承接 50 QPS(每秒查询率)。其中 2 个异常退出,客户端平均 6s 后收到删除通知;若仍均匀随机路由,窗口内失败请求约为 2 × 50 × 6 = 600。加入“单实例连续 3 次连接失败后本地隔离 10s”,假设每个客户端在 100ms 内完成三次不同请求,错误可显著缩小,但若把任何业务失败都当实例故障,会误摘除健康实例。因此被动摘除只应使用连接拒绝、握手失败和明确的实例级系统错误,不使用库存不足等业务码。
热门面试题
问题:为什么调用方要缓存服务列表?
- 考点:控制面故障、本地负载均衡、陈旧风险。
- 回答思路:先讲可用性收益,再讲版本、时间和失败校正。
- 详细答案:本地列表让调用不必每次查询注册中心,也能在控制面短暂故障时继续使用最后成功快照,并完成本地负载选择。它不是永久真相,必须记录列表版本、更新时间和来源;增量有缺口时拉全量快照,超过陈旧上限后对支付、库存等关键写停止冒险,对只读展示可带陈旧标识降级。
- 进阶追问:注册中心恢复后客户端会自动正确吗?
- 进阶回答:不一定,丢失的增量不会凭空补齐;需要版本连续性检查和周期性全量校准。
问题:陈旧列表中的坏实例应该永久拉黑吗?
- 考点:瞬时失败、隔离有效期、目录校准、容量恢复。
- 回答思路:区分临时本地判断和权威目录状态。
- 详细答案:不应永久拉黑。连接失败可能来自调用方局部网络、短暂暂停或单连接损坏。客户端可以按实例记录连续系统失败并短时隔离,隔离到期后允许少量探测;同时以注册目录新版本校正。永久黑名单会让已恢复实例永远得不到流量,剩余容量持续偏低,还可能造成各客户端视图不可解释地分裂。
- 进阶追问:业务错误率高能否触发实例摘除?
- 进阶回答:只有能归因于实例能力的系统错误才适合;库存不足、风控拒绝等业务结果不能作为摘流证据。
问题:本地列表为空时是否回退到硬编码地址?
- 考点:降级边界、陈旧快照、关键写风险。
- 回答思路:按业务风险选择失败、只读兜底或受控静态应急。
- 详细答案:默认不应悄悄回退到未经治理的硬编码地址,因为该地址可能已下线、跨环境或绕过灰度与安全策略。可优先使用有签名和时间边界的最后成功快照;关键库存扣减、支付写入在无可信候选时明确失败或排队,只读查询可以返回带版本的缓存。静态应急清单若确有必要,应受配置版本、审批和演练约束。
- 进阶追问:为什么列表为空不代表服务真的全挂?
- 进阶回答:也可能是订阅权限、命名空间、网络或客户端解析故障,需同时核对目录权威视图和数据面探测。
4. 负载均衡必须与连接池、慢实例和业务键一起设计
Round Robin(轮询)假设实例能力与请求成本接近;Weighted Round Robin(加权轮询)允许按容量分配;Least Connections(最少连接)更适合连接持续时间差异大的场景,但连接数不等于正在执行的请求数;Consistent Hashing(一致性哈希)可让同一业务键稳定命中一组实例,却会带来热点和扩缩容迁移。连接池会复用旧连接,如果只更新实例列表而不排空旧池,流量仍可能粘在下线或过载实例上。
| 策略 | 适用前提 | 主要风险 | WMS(仓储管理系统)例子 |
|---|---|---|---|
| 轮询 | 实例同构、请求近似 | 慢实例继续等量接流 | 普通商品查询 |
| 加权轮询 | 容量可量化 | 权重陈旧导致过载 | 新旧规格实例混部 |
| 最少请求 | 可观测在途数 | 短请求抖动造成追逐 | 物流聚合查询 |
| 一致性哈希 | 业务键稳定 | 热键压垮单组实例 | 按仓库编号路由缓存 |
| 峰值功率选择 | 可采集延迟与在途数 | 指标噪声和实现复杂 | 高尾延迟调用 |
flowchart LR
A["候选实例列表"] --> B["过滤未就绪与本地隔离实例"]
B --> C["按区域/版本/租户约束筛选"]
C --> D["依据权重、在途请求和延迟选实例"]
D --> E{"连接池有健康连接?"}
E -->|有| F["复用并计入在途数"]
E -->|无| G["受连接超时约束新建连接"]
G --> F数据演绎 4:连接池掩盖权重调整。 三个实例权重原为 1:1:1,每个客户端对每实例保留 20 条长连接,请求在连接上均匀复用。实例甲因中央处理器水位过高被降权到 0.2,若选择发生在“建连接”阶段而现有 60 条连接不重平衡,甲仍可能收到约三分之一流量,而不是理论上的 0.2 / 2.2 ≈ 9.1%。应在“每次请求”层选择实例,或让连接池按新权重逐步排空与补建,同时设置每实例连接上限,避免恢复时一次性建立连接冲击。
热门面试题
问题:轮询为什么可能把慢实例拖垮?
- 考点:请求成本、在途积压、反馈型负载均衡。
- 回答思路:说明轮询只看次数,再引入在途数与延迟反馈。
- 详细答案:轮询给每个实例相同请求数,却不知道某实例因垃圾回收、依赖抖动或热点数据而处理更慢。慢实例的在途请求持续累积,仍收到同等新流量,最终线程和连接耗尽。可以先短时本地隔离明确失败实例,再按在途请求、近期延迟和静态权重综合选择;反馈指标必须平滑并设恢复探测,避免流量在实例间来回震荡。
- 进阶追问:最少连接是否一定优于轮询?
- 进阶回答:不一定,多路复用连接可承载大量并发,连接数与负载不再成正比,应使用在途请求或协议流指标。
问题:连接池和负载均衡之间有什么隐藏耦合?
- 考点:连接复用、实例摘流、权重生效、连接风暴。
- 回答思路:从地址选择时机解释旧连接为何绕过新决策。
- 详细答案:如果负载选择只在建连接时发生,连接长期复用会让旧拓扑和旧权重持续生效;实例已从目录摘除,池中连接仍可能继续发请求。正确做法是让连接池感知实例状态,摘流后停止借出旧连接并逐步排空;扩容或恢复时限制新建并发、增加预热,防止所有客户端同时建连形成连接风暴。
- 进阶追问:能否在摘流时立即断开所有连接?
- 进阶回答:故障实例可快速断开,正常发布应先停止新借用并等待在途请求完成,避免主动制造失败。
问题:一致性哈希适合库存写入吗?
- 考点:亲和路由、热点、权威不变量、故障转移。
- 回答思路:肯定局部性价值,再否定它承担正确性的能力。
- 详细答案:一致性哈希可让同一商品或仓库的缓存请求稳定命中,改善局部性,也能减少扩缩容迁移;但节点故障会重新映射,热门商品会形成热分片,它不能保证库存只扣一次或不为负。库存正确性仍由数据库条件更新、唯一流水和事务保护,哈希路由只用于降低竞争;故障转移后重复请求继续复用幂等键。
- 进阶追问:如何缓解单个热门商品的哈希热点?
- 进阶回答:可用虚拟分片、热点键拆分和独立容量池,但最终扣减仍要在权威存储合并校验。
5. 端到端超时预算要从用户截止时间向内分配
本地函数失败通常会立即返回明确异常,远程调用则可能在请求发送、排队、执行、提交或响应途中超时,调用方只能得到“在 Deadline(截止时间)前未观察到结果”。因此要从端到端 SLO(服务等级目标)反推 DNS(域名系统)解析、连接、TLS(传输层安全协议)握手、客户端排队、服务执行、下游调用和返回余量,并把同一个 Deadline(截止时间)随链路传播。只配置 Read Timeout(读取超时)会漏掉排队和连接阶段;每一跳都重新给完整时限,会让最外层早已放弃后,内层仍继续消耗资源。
| 预算项 | 典型边界 | 过大风险 | 过小风险 |
|---|---|---|---|
| Connect Timeout(连接超时) | 建连与握手 | 坏地址长期占连接槽 | 跨区抖动被误判 |
| 排队超时 | 等待线程或连接 | 过期请求挤占容量 | 短突发被拒绝 |
| Read Timeout(读取超时) | 等首字节或响应 | 慢依赖拖住线程 | 合法长请求失败 |
| Deadline(截止时间) | 整个业务调用 | 上游已取消仍执行 | 业务成功率下降 |
flowchart LR
A["用户预算 1000 毫秒"] --> B["网关 80 毫秒"]
B --> C["订单服务剩余 920 毫秒"]
C --> D["连接与排队 120 毫秒"]
D --> E["库存调用 300 毫秒"]
E --> F["支付预创建 350 毫秒"]
F --> G["序列化与返回余量 150 毫秒"]数据演绎 5:端到端预算分配。 下单接口目标 P99(99 分位响应时间) ≤ 1000ms(毫秒)。网关与网络预留 80ms(毫秒),订单服务自身校验 120ms(毫秒),库存预占 250ms(毫秒),支付单创建 350ms(毫秒),返回与安全余量 200ms(毫秒),合计正好 1000ms(毫秒)。订单服务收到请求时若已消耗 300ms(毫秒),剩余 700ms(毫秒),就不能仍给库存 250ms(毫秒)、支付 350ms(毫秒)再额外重试;需按剩余时间缩减或直接转异步处理中。预算同时用于取消传播,使已过期工作尽早释放线程和连接。
热门面试题
问题:远程调用和本地调用最大的区别是什么?
- 考点:部分失败、未知结果、超时、序列化与网络。
- 回答思路:从观察边界讲清“没收到响应”不等于“没执行”。
- 详细答案:远程调用跨进程和网络,存在连接、排队、序列化、传输、服务执行、提交和响应丢失等独立失败点。调用方超时后无法仅凭异常判断服务端是否提交,结果处于未知态;所以接口要有 Deadline(截止时间)、幂等键、权威查询和取消传播。本地调用的异常通常与同进程控制流绑定,没有同样的网络观察缺口。
- 进阶追问:超时后把数据库事务回滚就能消除未知吗?
- 进阶回答:调用方无法回滚远端已提交事务或外部支付副作用,只能查询权威状态并通过幂等、补偿和对账收敛。
问题:为什么每一跳都配置一秒超时仍可能耗时三秒?
- 考点:嵌套预算、排队、重试、截止时间传播。
- 回答思路:说明独立计时会串行累加,必须传播剩余预算。
- 详细答案:订单、库存和支付若各自在开始调用时重新获得一秒,串行链路就可能接近三秒,客户端虽已超时,内部仍继续执行;再叠加连接池排队和重试,实际更长。应由入口生成绝对 Deadline(截止时间)或剩余预算,每一跳扣除已消耗时间和返回余量,预算不足时拒绝开始新工作,并把取消信号传入下游。
- 进阶追问:所有请求都用同一超时值行不行?
- 进阶回答:不行,查询、库存写、批量导出和异步受理的成本与业务时限不同,应按接口类别和分位数据配置。
问题:连接超时和读取超时应如何配合?
- 考点:失败阶段、连接池、总调用时限。
- 回答思路:先分阶段,再用总截止时间收口。
- 详细答案:连接超时限制建立新连接和握手的等待,读取超时限制连接建立后的响应等待,两者都不能覆盖客户端队列、重试和完整调用。应额外设置总 Deadline(截止时间),并让连接超时明显小于剩余预算,以便坏实例仍有切换余量;连接池借用也要有队列上限,不能无限等待一个空闲连接。
- 进阶追问:连接池已有连接时连接超时还有用吗?
- 进阶回答:复用成功时不触发新建阶段,但连接失效、扩容或池为空仍会建连,因此仍需配置和监控。
6. 重试必须受幂等、退避、抖动和预算共同约束
Retry(重试)只适合瞬时且可能恢复的失败,例如连接重置、明确限流后允许稍后再试;参数错误、库存不足和权限拒绝不可重试。Exponential Backoff(指数退避)让间隔随次数增长,Jitter(抖动)打散同一时刻恢复的客户端;Retry Budget(重试预算)限制重试流量占总流量比例。多层同时重试会乘法放大,最接近失败源的一层通常负责短重试,其他层保持一次调用并共享 Deadline(截止时间)。
| 失败类型 | 是否重试 | 前置条件 | 退出动作 |
|---|---|---|---|
| 连接建立失败 | 可有限重试 | 有其他健康实例和剩余预算 | 记录实例失败并降级 |
| 服务限流 | 按建议等待 | 请求可延后且有幂等键 | 排队、异步或明确拒绝 |
| 响应超时 | 谨慎 | 先判断是否可查结果 | 查单或保持未知态 |
| 参数/权限错误 | 不重试 | 无 | 修正请求或告警 |
| 库存不足 | 不重试 | 无 | 返回业务结果 |
flowchart TD
A["首次调用失败"] --> B{"错误可重试?"}
B -->|否| H["返回明确结果"]
B -->|是| C{"幂等且剩余预算足够?"}
C -->|否| I["查询结果或进入未知态"]
C -->|是| D{"重试预算未耗尽?"}
D -->|否| J["负载卸除或降级"]
D -->|是| E["指数退避并加入随机抖动"]
E --> F["选择不同健康实例重试"]
F --> A数据演绎 6:三层重试放大。 入口流量为 1000 QPS(每秒查询率),网关、订单和库存客户端都配置“失败后再试 3 次”,即每层最多 4 次尝试。最坏下游尝试量为 1000 × 4 × 4 × 4 = 64000 QPS(每秒查询率),是原流量 64 倍。旧数据中“耗时从 50ms(毫秒) 升到 3s(秒) 后重试三次”的风险不只是延迟,而是线程、连接和请求数同时放大。若统一只允许库存客户端再试 1 次,并设重试流量不超过成功首试流量的 10%,则总量上限约 1100 QPS(每秒查询率),过量请求直接快速失败或异步排队。
热门面试题
- 问题:重试为什么可能引发事故?
- 考点:乘法放大、资源占用、未知结果、幂等。
- 回答思路:先量化多层放大,再说明写请求重复副作用。
- 详细答案:下游变慢时,原请求已经占住线程和连接;多层重试又在最缺容量时增加请求,形成乘法放大。写请求首次可能已提交但响应丢失,换幂等键重试还会重复扣库存或创建支付单。治理上只在一层做有限重试,使用同一幂等键、共享 Deadline(截止时间)、指数退避和随机抖动,并以 Retry Budget(重试预算)硬限制额外流量。
- 进阶追问:重试换一台实例就一定安全吗?
- 进阶回答:只能避开实例级故障,无法消除共享数据库、公共依赖故障和首次调用已成功的未知结果。
问题:物流下单接口超时后应该怎么处理?
- 考点:外部副作用、业务号、主动查单、人工兜底。
- 回答思路:按“查本地、查渠道、同号重放、转人工”排序。
- 详细答案:先保持物流单为处理中,使用稳定业务号查询本地请求流水和承运商查单接口;若渠道明确无单且预算允许,才用同一业务号有限重放。若渠道也未知,不能生成新号反复下单,应延迟查单并在时限后进入人工队列。运单号、请求报文摘要、每次尝试和渠道响应都要审计,防止重复购买面单或重复扣费。
- 进阶追问:承运商没有幂等和查单接口怎么办?
- 进阶回答:把自动重试降到最保守,先持久化请求与未知态,利用业务侧对账或人工确认,不能假装基础设施能提供一次语义。
问题:退避为什么还需要抖动?
- 考点:同步重试、惊群、恢复容量。
- 回答思路:解释确定性间隔让所有客户端再次同频。
- 详细答案:如果大量请求同时失败,并都按固定的
100ms(毫秒)、200ms(毫秒)、400ms(毫秒)重试,它们会在相同时间再次冲击刚恢复的依赖。Jitter(抖动)在退避窗口内随机分散尝试,降低瞬时峰值;同时仍需全局预算和恢复放量,因为随机化只打散时间,不能减少总请求数。 - 进阶追问:随机等待会不会破坏业务顺序?
- 进阶回答:有严格顺序的事件不应靠并发客户端重试维序,应由分区顺序、状态版本和幂等消费保证。
7. 幂等要重放同一业务结果,而不是只阻止重复请求
Idempotency(幂等)表示同一业务意图被执行多次,业务有效结果与执行一次等价。完整分层包括:入口 Idempotency Key(幂等键)识别业务意图;数据库唯一索引阻止重复实体;条件更新与版本号限制合法状态迁移;去重表记录消息处理;结果表保存首次响应以供重放。分布式锁可以减少并发竞争,但锁可能过期、失联或被旧持有者继续执行,不能替代库存非负、支付只入账一次等数据库不变量。
| 层次 | 保护对象 | 可靠落点 | 失败边界 |
|---|---|---|---|
| 请求键 | 同一调用意图 | 业务请求表唯一约束 | 键选错会合并不同请求 |
| 唯一索引 | 唯一实体/流水 | 数据库提交 | 只能保护索引表达的约束 |
| 条件更新 | 状态与数量 | 版本、状态、余量条件 | 受影响行数必须检查 |
| 去重表 | 消息处理 | 与业务写同一事务 | 分库时需重新设计边界 |
| 结果重放 | 相同业务结果 | 首次结果快照 | 需处理结果过期与隐私 |
| 分布式锁 | 降低并发 | 有期限的协调记录 | 不能证明数据库提交唯一 |
sequenceDiagram
participant C as 调用方
participant S as 库存服务
participant D as 权威数据库
C->>S: 请求键 K 扣减 2 件
S->>D: 插入请求 K 并条件扣减
alt K 首次且余量充足
D-->>S: 提交结果版本 73
S-->>C: 重放凭证与版本 73
else K 已存在
D-->>S: 返回首次结果
S-->>C: 重放同一凭证
else 余量不足
D-->>S: 明确业务失败
S-->>C: 重放库存不足
end数据演绎 7:锁不能守住库存不变量。 商品可售量为 1,请求甲拿到 5s 分布式锁后因暂停执行 8s;第 5s 锁过期,请求乙获得新锁并扣减成功。第 8s 请求甲恢复,如果只检查“自己曾拿到锁”也继续扣减,库存变为 -1。正确落点是数据库执行 UPDATE inventory SET available = available - 1, version = version + 1 WHERE sku_id = ? AND available >= 1 AND version = ?,并检查影响行数;业务请求号有唯一索引。锁可减少同时竞争,但即使锁失效,条件更新仍拒绝第二次非法扣减。
热门面试题
- 问题:什么是接口幂等,为什么重复返回成功还不够?
- 考点:业务意图、状态等价、结果重放、副作用。
- 回答思路:把请求次数与业务结果分开,并说明相同键的响应语义。
- 详细答案:幂等要求同一业务意图重复提交后,有效业务状态与执行一次等价;不能第二次什么都不做却随便返回成功,因为调用方还需要知道首次生成的支付单号、库存冻结号或失败原因。服务应按稳定 Idempotency Key(幂等键)保存首次结果,重复请求校验关键参数一致后重放;参数不同却复用同一键要明确冲突。
- 进阶追问:查询接口天然幂等吗?
- 进阶回答:读取通常不改变业务状态,但可能触发计费、审计或懒加载副作用,仍要按真实语义判断。
- 问题:唯一索引和分布式锁哪个更可靠?
- 考点:正确性落点、锁过期、并发冲突、事务。
- 回答思路:拒绝二选一,说明数据库约束守底线、锁做优化。
- 详细答案:对支付流水唯一、请求号唯一等可由数据库表达的不变量,唯一索引在事务提交点提供最终拒绝,是正确性底线。分布式锁可能因租约过期、网络分区、暂停和误释放失效,只能降低并发与热点冲突。库存非负还需条件更新,状态迁移需版本和前置状态;锁可放在外层优化,但任何绕过锁的请求仍必须被数据库约束拒绝。
- 进阶追问:有唯一索引后锁是否完全没用?
- 进阶回答:不是,热点冲突很高时锁可减少数据库回滚和外部调用,但不能成为唯一防线。
- 问题:MQ(消息队列)重复消费如何保证幂等?
- 考点:消息标识、业务事务、去重表、确认窗口。
- 回答思路:从“业务写成功、确认丢失”的重复窗口出发。
- 详细答案:消费者用事件标识或业务键建立去重记录,并让去重插入、业务状态条件更新和结果流水尽量在同一数据库事务提交;重复投递命中唯一约束后读取已处理结果,再安全确认。仅在内存 Set(集合接口)去重会因重启丢失,仅靠消息中间件标识也不能阻止业务键重复。跨库副作用要用收件箱、状态机与对账补充。
- 进阶追问:先写去重表再调用外部物流安全吗?
- 进阶回答:不安全,外部调用失败会留下“已处理”假象;应记录处理中与结果,使用同一业务号查单,并让状态可恢复。
8. 限流是在容量边界内决定谁现在可以执行
Fixed Window(固定窗口)实现简单但边界突刺明显;Sliding Window(滑动窗口)更平滑但状态成本更高;Leaky Bucket(漏桶)以稳定速率排出,适合整形;Token Bucket(令牌桶)允许额度内突发;Concurrency Limit(并发数限制)直接约束在途工作,更能反映慢请求占用;排队限制吸收短突发但必须有长度和等待时限。限流维度至少考虑租户、仓库、接口、设备、规则和下游依赖,返回明确拒绝或可重试时间,不能统一伪装成功。
| 算法 | 核心状态 | 突发能力 | 典型场景 |
|---|---|---|---|
| 固定窗口 | 当前窗口计数 | 边界可双倍突发 | 低成本粗限额 |
| 滑动窗口 | 分桶或时间记录 | 较平滑 | 租户接口配额 |
| 漏桶 | 队列与固定排出速率 | 弱 | 承运商匀速发送 |
| 令牌桶 | 令牌数与补充速率 | 可控突发 | IoT(物联网)报警接入 |
| 并发限制 | 当前在途数 | 随完成释放 | 慢支付依赖保护 |
| 有界排队 | 队列长度与年龄 | 吸收短峰值 | Runner(执行器)任务 |
flowchart TD
A["请求进入"] --> B{"租户配额是否足够"}
B -->|否| H["返回限流与重试建议"]
B -->|是| C{"依赖并发槽是否可用"}
C -->|是| D["立即执行"]
C -->|否| E{"队列未满且等待预算足够"}
E -->|是| F["进入有界队列"]
E -->|否| G["负载卸除或异步受理"]
F --> D数据演绎 8:窗口突刺与并发容量。 某物流渠道限制 100 QPS(每秒查询率)。固定窗口在第 0.99s(秒) 放行 100 个请求,又在第 1.01s(秒) 放行 100 个,20ms(毫秒) 内出现 200 个请求,瞬时等价 10000 QPS(每秒查询率)。若渠道平均耗时从 100ms(毫秒) 升到 2s(秒),即使严格维持 100 QPS(每秒查询率),在途数也约为 100 × 2 = 200。因此要同时用滑动窗口控制速率、并发上限保护连接池,并把超出部分放入有年龄上限的队列。
热门面试题
问题:限流、熔断和降级有什么区别?
- 考点:触发信号、保护对象、业务行为。
- 回答思路:分别回答“谁能进、是否继续调、失败后给什么”。
- 详细答案:限流依据配额、速率或并发决定请求现在能否进入,保护容量;熔断依据依赖近期失败和慢调用,暂时停止继续尝试,阻断故障扩散;降级是在能力不足时选择保留哪些核心结果、舍弃哪些非核心结果。三者可组合,但拒绝必须可观测,支付和库存不能把未执行伪装成成功。
- 进阶追问:限流后都返回稍后重试可以吗?
- 进阶回答:只有请求可重试且有幂等键、退避建议和预算时才行,否则会把拒绝变成同步重试风暴。
问题:令牌桶和漏桶如何选择?
- 考点:突发、整形、下游能力、队列风险。
- 回答思路:从业务是否允许短突发和下游是否要求匀速回答。
- 详细答案:令牌桶按速率补充令牌并允许消费累积额度,适合设备报警平时低流量、异常时允许有限突发;漏桶以稳定速率排出,更适合承运商明确要求匀速调用。若桶后有队列,必须限制长度和消息年龄,否则只是把超载延后,并可能在业务已过期后继续执行。
- 进阶追问:桶容量设为一分钟额度有什么风险?
- 进阶回答:可能在一瞬间释放整分钟流量,压垮只能承受小突发的依赖;容量应由可承受突发而非总额度决定。
问题:为什么慢依赖更需要并发限制而不只是每秒限流?
- 考点:在途数、Little’s Law(利特尔法则)、连接池耗尽。
- 回答思路:用到达率乘耗时解释资源占用。
- 详细答案:速率相同但耗时从
50ms(毫秒)升到2s(秒),在途请求会放大约40倍,线程、连接和内存首先耗尽。并发限制直接约束正在占资源的工作,慢时自然减少新流量;再配合短队列和 Deadline(截止时间)丢弃过期请求,比仅维持固定每秒速率更能保护系统。 - 进阶追问:并发上限是否固定不变?
- 进阶回答:可根据延迟、错误和资源水位渐进调整,但必须设硬边界并防止反馈震荡。
9. 熔断器用状态机阻止对已知故障的持续施压
Circuit Breaker(熔断器)在 Closed(关闭)状态允许调用并统计合格样本;错误率或慢调用率越过阈值后转 Open(打开),在等待期内快速失败;到期进入 Half-Open(半开),只允许少量探测,满足恢复条件才回到 Closed(关闭),否则重新 Open(打开)。统计窗口、最小样本量、慢调用定义、忽略异常和探测并发必须基于版本文档与真实流量校准。熔断不等于故障修复,也不替代超时、限流和隔离。
| 状态 | 流量行为 | 进入条件 | 离开条件 |
|---|---|---|---|
| Closed(关闭) | 正常放行并统计 | 初始或恢复验证通过 | 达到最小样本且失败阈值越界 |
| Open(打开) | 快速拒绝或降级 | 失败/慢调用越界 | 等待期结束 |
| Half-Open(半开) | 只放少量探测 | Open(打开)等待结束 | 探测成功回 Closed(关闭),失败回 Open(打开) |
stateDiagram-v2
[*] --> Closed: 正常放行
Closed --> Open: 最小样本满足且失败/慢调用越界
Open --> HalfOpen: 等待期结束
HalfOpen --> Closed: 探测达到恢复门槛
HalfOpen --> Open: 任一关键探测失败
Closed --> Closed: 业务拒绝不计系统故障数据演绎 9:小样本误熔断。 某支付查询接口夜间只有 2 QPS(每秒查询率)。若滑动窗口看最近 10 个请求、失败率阈值 50% 且无最小样本限制,短暂出现 5 次网络失败就立即熔断,可能把仍有能力的渠道完全切断。若设最小样本 100,则需约 50s 才能判断,关键故障又可能发现过慢。更合理的是结合连续连接失败快速路径、20 个样本的短窗口和 60s(秒) 长窗口,同时让 Half-Open(半开)仅放 3 个探测;支付结果未知仍走查单,不把熔断拒绝写成支付失败。
热门面试题
问题:熔断器有哪些状态,各自做什么?
- 考点:关闭、打开、半开、探测与恢复。
- 回答思路:按状态转移解释触发和流量行为。
- 详细答案:Closed(关闭)正常放行并统计足量样本;达到错误率或慢调用率阈值后进入 Open(打开),等待期内快速拒绝以停止施压;到期进入 Half-Open(半开),只允许受控探测。探测达到成功门槛才恢复 Closed(关闭),失败则再次 Open(打开)。业务拒绝与系统失败要分开统计,避免库存不足触发熔断。
- 进阶追问:半开为什么不能直接放全部流量?
- 进阶回答:依赖可能只恢复少量容量,全放会立即压回故障;探测必须小批量且与正常恢复放量衔接。
问题:熔断阈值应该只看错误率吗?
- 考点:慢调用、最小样本、窗口、业务异常分类。
- 回答思路:说明错误之前资源可能已被慢调用耗尽。
- 详细答案:不能。依赖可能仍返回成功但耗时从
50ms(毫秒)升到3s(秒),调用方线程和连接已接近耗尽;应同时看慢调用率、系统错误率和最小样本量。阈值还需按接口与依赖隔离,低流量接口避免小样本误判,高流量接口用短长窗口兼顾发现速度和稳定性。 - 进阶追问:超时都算失败吗?
- 进阶回答:对调用保护可以计系统失败,但业务结果仍可能成功,支付等场景必须另行查权威状态。
问题:熔断打开后直接返回缓存就够了吗?
- 考点:降级数据版本、写请求、用户语义。
- 回答思路:按读写风险拆分,并标明缓存陈旧度。
- 详细答案:只读商品或轨迹摘要可返回带生成时间和版本的缓存,但库存可售决策、支付状态和资金结果不能用普通缓存伪造。写请求可进入有界异步受理或明确失败,并给查询凭证。缓存本身也要隔离容量、防止击穿;熔断只是停止调用,降级结果仍需业务定义和审计。
- 进阶追问:缓存为空时能返回默认成功吗?
- 进阶回答:不能,未知不能伪装成功;应明确不可用、处理中或需要人工确认。
10. 隔离、背压与负载卸除要切断资源传染
Bulkhead(隔离舱)把不同依赖、租户或业务优先级放入独立资源池,使物流慢调用不能耗尽支付和库存线程。线程池隔离强、可限制队列但有切换成本;Semaphore Isolation(信号量隔离)轻量,却仍占调用线程;Connection Pool Isolation(连接池隔离)防止单依赖吃光连接。Backpressure(背压)把“下游处理不过来”反馈给上游,Load Shedding(负载卸除)在过载时主动丢弃低价值或已过期工作;无限队列不是韧性,只是延迟故障。
| 手段 | 保护资源 | 适用场景 | 失败边界 |
|---|---|---|---|
| 线程池隔离 | 线程与队列 | 阻塞式第三方调用 | 池过多增加内存与调度成本 |
| 信号量隔离 | 并发槽 | 快速、非阻塞调用 | 慢调用仍占上游线程 |
| 连接池隔离 | 套接字与数据库连接 | 多依赖共享客户端 | 池总量可能压垮服务端 |
| 背压 | 上游生产速率 | 流式轨迹、报警处理 | 上游不响应会继续积压 |
| 负载卸除 | 总工作量 | 已过期查询、低优先级报警 | 需明确不可丢业务 |
flowchart LR
A["入口请求"] --> B{"业务优先级"}
B -->|库存/支付| C["核心资源池"]
B -->|物流查询| D["外部依赖资源池"]
B -->|报表/低级报警| E["可卸除资源池"]
D --> F{"队列与并发水位"}
F -->|高| G["向上游背压"]
E --> H{"请求是否过期"}
H -->|是| I["丢弃并记录原因"]数据演绎 10:共享线程池的传染。 服务总线程数 200,物流接口在渠道变慢后每次占线程 3s(秒),入口仍有 100 QPS(每秒查询率),理论在途需求为 300,会迅速占满全部线程,连原本 20ms(毫秒) 的库存查询也无法执行。若物流隔离池上限 60、队列 40 且等待 200ms(毫秒),最多占 60 个执行线程和 40 个排队槽,超出部分异步受理或拒绝;核心池仍有 140 个线程。隔离上限还必须结合渠道连接上限,不能让 60 个线程争 10 条连接。
热门面试题
问题:线程池隔离和信号量隔离如何选择?
- 考点:阻塞、上下文切换、调用线程占用、队列。
- 回答思路:按依赖是否阻塞和需要多强故障域决定。
- 详细答案:阻塞且延迟不可控的第三方物流调用适合独立线程池,可限制执行与排队并切断资源传染;快速、非阻塞且开销敏感的调用可用信号量限制并发。信号量拒绝虽快,但调用执行时仍占上游线程;线程池也不能无限拆分,否则线程内存、切换和配置复杂度反噬。
- 进阶追问:每个接口一个线程池是否最隔离?
- 进阶回答:隔离更细但总线程不可控,应按共同故障域和业务优先级分组,再设全局资源预算。
问题:背压和限流有什么区别?
- 考点:反馈方向、动态容量、协议协作。
- 回答思路:说明限流是入口决策,背压是下游向上游反馈。
- 详细答案:限流依据预设或自适应容量决定请求能否进入;背压是消费者根据当前处理能力要求生产者减速、暂停或减少拉取。IoT(物联网)报警链路中,消费者积压可降低上游拉取并聚合低级报警;若设备协议无法减速,就必须在入口限流、落盘缓冲或负载卸除,不能只发一个无人处理的信号。
- 进阶追问:消息队列存在就自动有背压吗?
- 进阶回答:不自动,生产者可能继续无限写入;仍要监控积压年龄、磁盘和消费能力,并让生产策略响应。
问题:什么请求可以被负载卸除?
- 考点:业务价值、截止时间、可恢复性、审计。
- 回答思路:用“过期、低价值、可重建”判断,列出不可丢边界。
- 详细答案:已超过 Deadline(截止时间)的查询、可重建统计、重复低级报警和用户已取消的工作可以优先卸除;库存扣减结果、支付回调、资金流水和严重报警不能静默丢弃,应持久化、限速处理或转人工。每次卸除记录租户、业务键、原因和数量,调用方得到明确状态,便于后续重放和容量复盘。
- 进阶追问:返回空列表算卸除吗?
- 进阶回答:若空列表会被理解为“确实没有数据”就不安全,应返回明确降级标识或可查询凭证。
11. 降级、缓存兜底与恢复放量必须保持业务诚实
Degradation(降级)是在资源不足时保留核心能力并改变非核心体验;Fallback(兜底)是具体替代结果。读场景可使用带版本和生成时间的缓存,写场景可返回受理凭证后异步处理,不能把“未执行”包装成“成功”。恢复时先修复依赖,再 Warm-up(预热),随后 Canary Probe(金丝雀探测)和分级放量;若所有熔断器同时关闭、客户端同时重连和刷新缓存,会形成恢复风暴。热点租户、仓库、商品和设备规则应独立隔离,防止平均指标掩盖局部过载。
| 业务 | 可接受降级 | 禁止做法 | 恢复证据 |
|---|---|---|---|
| 商品展示 | 返回带时间的旧缓存 | 伪造实时库存 | 回源延迟和版本差归常 |
| 库存扣减 | 进入待确认或明确拒绝 | 返回扣减成功但未落库 | 库存流水与余量守恒 |
| 支付查询 | 返回处理中并主动查单 | 把未知写成失败或成功 | 渠道状态与本地账一致 |
| 物流轨迹 | 展示最后已确认节点 | 乱序事件直接覆盖终态 | 积压年龄与版本差归零 |
| IoT(物联网)报警 | 聚合低级报警 | 丢弃严重报警不留痕 | 严重报警送达与积压闭环 |
flowchart LR
A["依赖恢复"] --> B["单实例健康探测"]
B --> C["连接池限速预热"]
C --> D["1% 请求放量"]
D --> E{"错误、延迟、饱和度达标?"}
E -->|是| F["10% -> 30% -> 100%"]
E -->|否| G["退回隔离并保留降级"]
F --> H["核对业务积压与审计差异"]数据演绎 11:恢复放量。 故障前物流依赖稳定承载 1000 QPS(每秒查询率),故障期间积压 600000 个任务,恢复后当前实时流量仍为 800 QPS(每秒查询率)。若立刻用剩余理论容量 200 QPS(每秒查询率) 回放,清空需 3000s(秒),约 50min(分钟);若误以故障前峰值 1000 QPS(每秒查询率) 直接回放积压,再叠加实时 800 QPS(每秒查询率),会以 1800 QPS(每秒查询率) 再次压垮依赖。恢复应从 1% 探测开始,确认延迟与错误后给回放独立 100 QPS(每秒查询率) 预算,并按任务年龄和优先级处理。
热门面试题
问题:第三方物流接口超时,如何保护系统并恢复?
- 考点:超时、隔离、熔断、异步、查单、渐进恢复。
- 回答思路:按止损、业务诚实、恢复放量三阶段回答。
- 详细答案:先用短连接与总 Deadline(截止时间)、独立线程和连接池限制资源,慢调用越界后熔断;物流创建转为带业务号的异步受理,未知结果优先查单,不能换号盲重试。恢复后先小流量探测、限速建连,再把实时请求与积压回放分配独立预算,按年龄和优先级处理,持续核对重复运单与渠道费用。
- 进阶追问:熔断期间新订单怎么办?
- 进阶回答:可持久化为待下单并给用户可查询状态;超过履约时限转人工或切换已验证的备用渠道。
问题:降级为什么不能统一返回成功?
- 考点:业务语义、未知状态、补偿与用户体验。
- 回答思路:说明技术可用不等于业务完成。
- 详细答案:统一成功会让上游推进发货、扣款或通知等后续状态,掩盖实际未执行,最终制造更难修复的不一致。降级应明确返回缓存数据及版本、处理中凭证、可重试拒绝或人工状态;前端体验可以友好,但机器语义必须真实。支付和库存结果还要能由权威流水证明,不能用展示文案替代事实。
- 进阶追问:为了可用性返回旧库存可以吗?
- 进阶回答:展示参考值可以标陈旧,最终下单扣减必须回到权威条件更新,不能据旧值承诺成功。
问题:为什么恢复阶段比故障阶段更容易再次过载?
- 考点:积压、同步重连、缓存击穿、流量门禁。
- 回答思路:列出实时流量与历史债务叠加,再给分阶段门禁。
- 详细答案:故障期间积累了请求、消息、查单和缓存失效;恢复信号会让客户端同时重试、熔断器同时半开、连接池同时建连,实时流量与积压叠加,瞬时需求远超正常峰值。应限制半开探测,给实时与回放分开配额,连接和缓存分批预热,按
1%、10%、30%放量,任何阶段指标恶化立即回退。 - 进阶追问:只看错误率能决定继续放量吗?
- 进阶回答:不能,还要看尾延迟、饱和度、队列年龄、业务重复与差异,否则成功响应可能隐藏资源逼近极限。
12. 日志、指标和链路追踪回答不同的排障问题
Log(日志)记录离散事件和上下文,适合解释某次请求发生了什么;Metrics(指标)聚合时间序列,适合发现范围、趋势和告警;Trace(链路追踪)用 Span(跨度)串起一次请求跨服务的因果路径,适合定位时间花在哪一跳。三者要通过 TraceId(链路标识)、业务号、服务版本、实例、租户和时间窗口关联。Trace(链路追踪)通常被采样,Log(日志)可能限速,Metrics(指标)是聚合数据,都不能替代完整业务审计。
flowchart TD
A["告警:下单尾延迟升高"] --> B["Metrics(指标):确认范围与起点"]
B --> C["Trace(链路追踪):定位慢跨度"]
C --> D["Log(日志):读取实例错误上下文"]
D --> E["业务审计:确认库存/支付真实状态"]
E --> F["止血、修复并用同组证据验证"]数据演绎 12:平均值掩盖长尾。 一分钟内有 10000 次下单调用,其中 9900 次耗时 50ms(毫秒),100 次耗时 5000ms(毫秒)。平均耗时为 (9900 × 50 + 100 × 5000) / 10000 = 99.5ms(毫秒),看似正常,但最慢 1% 已达到 5s(秒),线程和连接可能被长尾占满。应同时监控请求率、错误率、延迟分位和饱和度;再按版本、区域和下游拆分 Trace(链路追踪),最后用业务审计确认超时请求是否实际完成。
热门面试题
问题:日志、指标和链路追踪分别解决什么问题?
- 考点:事件细节、聚合趋势、调用因果、审计边界。
- 回答思路:用发现、定位、解释、证明四步分工。
- 详细答案:Metrics(指标)先发现什么时候、哪一范围异常;Trace(链路追踪)展示一次请求经过哪些服务及每个 Span(跨度)耗时;Log(日志)补充实例内分支、错误和关键参数摘要。最后库存流水、支付单与渠道账等业务审计证明真实状态。链路可能采样、日志可能丢弃,不能据“没搜到”断言业务没发生。
- 进阶追问:有链路追踪后还需要日志吗?
- 进阶回答:需要,链路强调跨边界时序,实例内部决策、异常堆栈和业务校验细节通常仍在结构化日志中。
问题:微服务应监控哪些通用信号?
- 考点:流量、错误、延迟、饱和度与业务指标。
- 回答思路:先四类技术信号,再补业务不变量和依赖维度。
- 详细答案:至少监控请求率、系统错误率与业务拒绝率、延迟分位、线程/连接/队列饱和度,并按服务版本、区域和依赖拆分。还要补库存条件更新失败、支付未知态年龄、物流积压年龄和严重报警送达等业务指标。只看中央处理器平均值无法发现连接池耗尽,只看成功率也会漏掉长尾。
- 进阶追问:为什么错误率要区分业务错误?
- 进阶回答:库存不足和风控拒绝是预期结果,混入系统失败会误触发熔断并掩盖真实容量问题。
问题:线上下单慢,应先查日志还是链路?
- 考点:证据顺序、范围判断、采样缺失、实例定位。
- 回答思路:先指标定范围,再链路定跳点,最后日志与审计验证。
- 详细答案:先用 Metrics(指标)确认开始时间、影响比例、区域、版本和饱和资源,避免在海量日志里盲搜;再选慢样本的 Trace(链路追踪)定位网关、订单、库存或支付哪一段增长;随后按 TraceId(链路标识)、实例和业务号查 Log(日志)。若链路未采样,用访问日志、依赖指标和业务流水拼接证据,最后复现并验证修复。
- 进阶追问:单条慢链路能代表根因吗?
- 进阶回答:不能,它只是样本;要结合分位分布、同版本对照和资源指标确认是否具有代表性。
13. 上下文传播、采样与高基数决定可观测性是否可用
同步请求可通过标准请求头传播链路上下文;异步线程必须在提交任务时捕获,在执行时恢复并在结束后清理,防止线程复用串链;消息应把上下文写入消息属性,消费端建立新的 Span(跨度)并用 Link(链路关联)表达批处理或多来源关系。Sampling(采样)控制成本,但头部采样可能丢掉后来才失败的请求,尾部采样需要缓存轨迹并增加成本。高基数的订单号、设备号和 TraceId(链路标识)不应作为普通 Metrics(指标)标签,应进入 Log(日志)、Trace(链路追踪)或审计索引。
sequenceDiagram
participant H as 请求线程
participant E as 执行器
participant M as 消息队列
participant C as 消费者
H->>E: 捕获链路上下文并提交任务
E->>E: 恢复上下文,创建子跨度
E->>M: 消息属性写入上下文
E->>E: 清理线程上下文
M->>C: 投递消息与上下文
C->>C: 创建消费跨度并关联业务号数据演绎 13:高基数成本。 1000000 台设备每台都把 device_id(设备标识) 作为 Metrics(指标)标签,再叠加 10 个报警类型和 5 个区域,理论组合上限为 50000000 条时间序列。即使每条活跃序列仅占 2KB(千字节) 内存,也可能达到约 100GB(吉字节),还不含索引和副本。应把区域、报警级别等有限枚举保留为指标标签,设备号进入结构化 Log(日志)或审计明细;指标用总量与分布发现异常,再按样本设备下钻。
热门面试题
问题:TraceId(链路标识)如何跨线程、跨服务和消息传递?
- 考点:上下文注入提取、线程复用、异步消息、清理。
- 回答思路:按同步请求、线程池和消息三条路径回答。
- 详细答案:同步请求在客户端把链路上下文注入标准请求头,服务端提取并创建子 Span(跨度);提交线程池时捕获当前上下文,在任务执行前恢复,结束后必须清理;生产消息时写入消息属性,消费者提取后创建消费跨度。批处理多个消息可用 Link(链路关联),不能强行选一个父链路丢掉其他来源。
- 进阶追问:为什么线程池里会出现链路串号?
- 进阶回答:上下文常存在线程本地变量,任务结束未清理会被下一任务复用,必须使用作用域自动恢复与释放。
问题:链路采样会带来什么排障盲区?
- 考点:头部采样、尾部采样、错误保留、审计边界。
- 回答思路:解释采样决策时机,再给指标与日志补证据。
- 详细答案:头部采样在请求刚进入时决定,尚不知道后面是否超时或失败,低比例下可能丢掉关键异常;尾部采样可在看到完整结果后保留错误和慢链路,但需要缓存轨迹、处理超时和跨节点汇总。无论哪种采样,Trace(链路追踪)都不是完整账本;支付和库存要保留业务流水,排障时用 Metrics(指标)确定总体,再用未采样访问日志补齐。
- 进阶追问:错误链路全部采样就够了吗?
- 进阶回答:不够,慢成功、状态未知和被业务层吞掉的异常也重要,还要按延迟、属性和随机基线组合策略。
问题:为什么订单号不能直接作为指标标签?
- 考点:高基数、时间序列爆炸、下钻设计。
- 回答思路:区分聚合维度与实体标识。
- 详细答案:订单号几乎每请求唯一,会让 Metrics(指标)系统为每个值创建新时间序列,放大内存、索引和查询成本,最终让监控系统本身过载。指标标签应使用服务、区域、版本、错误类别等有限枚举;订单号、运单号和设备号放在 Log(日志)、Trace(链路追踪)或审计库,并通过 Exemplars(示例关联)从异常分位跳转到代表样本。
- 进阶追问:租户号也不能作为标签吗?
- 进阶回答:取决于租户数量和活跃度;大规模长尾租户应分层聚合,只对白名单关键租户保留受控维度。
14. 业务审计负责证明事实,技术遥测负责解释过程
业务审计应保存不可抵赖且可关联的关键事实:业务请求号、主体、金额或数量、前后状态、版本、幂等键、渠道号、操作来源、发生时间和处理结果。它服务于资金核对、库存守恒、物流争议和人工修复审批,保留策略通常比技术 Log(日志)更严格。技术遥测可采样、聚合和过期,用于解释延迟与故障;业务审计不能把敏感信息无控制地复制到日志,也不能依赖 TraceId(链路标识)作为唯一业务键。
flowchart LR
A["业务请求号"] --> B["入口审计:主体与意图"]
B --> C["状态机:前态/后态/版本"]
C --> D["副作用凭证:库存/渠道/账务流水"]
D --> E["对账:内部权威源与外部账单"]
E --> F{"是否存在差异"}
F -->|否| G["闭环归档"]
F -->|是| H["审批、补偿、冲正或人工处理"]
H --> E数据演绎 14:采样链路不能证明资金完整。 一天有 2000000 次支付相关调用,Trace(链路追踪)采样率为 1%,理论只保留约 20000 条链路。当天发生 40 笔渠道成功但内部状态未知的差异,即便随机采样独立,期望被采到仅 0.4 笔,完全可能一条都没有。业务审计必须 100% 记录商户订单号、渠道单号、金额、状态版本与账务事件,再用渠道账单逐笔对账;Trace(链路追踪)只用于已知差异的性能和调用路径定位。
热门面试题
问题:为什么链路追踪不能替代支付审计流水?
- 考点:采样、保留期限、业务完整性、合规。
- 回答思路:从覆盖率、语义和可修复性三方面比较。
- 详细答案:Trace(链路追踪)可能采样、丢段和短期过期,Span(跨度)记录的是调用过程,不保证金额、前后状态和会计方向完整。支付审计必须逐笔记录业务号、渠道号、金额、状态版本、验签结果和账务凭证,并支持对账、冲正与审批。链路可解释为什么慢或在哪失败,但不能证明全部资金事实。
- 进阶追问:审计表写失败时还能继续支付吗?
- 进阶回答:关键审计与业务提交应在同一可靠边界或可证明补写;无法留证的资金动作通常应拒绝或进入受控未知态。
问题:库存防超卖需要记录哪些证据?
- 考点:权威库存、请求键、条件更新、流水守恒。
- 回答思路:围绕可售、冻结、扣减和释放的数量守恒回答。
- 详细答案:至少记录仓库与商品、业务请求号、变更类型、数量、变更前后版本、订单号、冻结号、受影响行数和事务时间。权威表用条件更新保证可售量不为负,流水唯一约束防重复;定期核对期初、入库、冻结、释放、扣减和期末守恒。分布式锁记录可以辅助诊断竞争,但不能作为库存真实变更凭证。
- 进阶追问:发现库存差异可以直接改余量吗?
- 进阶回答:不能静默改表,应定位缺失或重复流水,经审批生成调整凭证,并复核受影响订单。
问题:事故中如何建立从告警到业务事实的证据链?
- 考点:时间线、指标、链路、日志、审计、验证。
- 回答思路:按影响、止血、保存现场、定位、修复、验证组织。
- 详细答案:先用 Metrics(指标)确定影响时间、范围和资源瓶颈,执行限流、摘流或降级并记录变更;保留配置版本、实例列表、线程与连接水位。再用 Trace(链路追踪)找慢跳,Log(日志)解释实例分支,最后以订单、库存、支付、物流审计确定真实业务状态。修复后用同一组指标和逐笔对账验证,不能只因错误率下降就结束事故。
- 进阶追问:为什么要记录止血操作本身?
- 进阶回答:限流、切流和补偿会改变系统状态,不留时间与操作者就无法区分原始故障和处置副作用。
知识节复习清单
- 能否区分 Lease(租约)、Heartbeat(心跳)、Liveness(存活检查)和 Readiness(就绪检查)。
- 能否计算宕机到目录、客户端和连接池全部收敛的最坏窗口。
- 能否按端到端 Deadline(截止时间)拆连接、排队、执行和返回预算。
- 能否量化多层 Retry(重试)的乘法放大,并给出 Retry Budget(重试预算)。
- 能否用请求键、唯一索引、条件更新、状态机和结果重放解释 Idempotency(幂等)。
- 能否明确分布式锁不承担数据库库存与资金不变量。
- 能否比较六类限流,并用在途数解释慢请求资源占用。
- 能否画出 Circuit Breaker(熔断器)的 Closed(关闭)、Open(打开)、Half-Open(半开)状态机。
- 能否区分隔离、Backpressure(背压)、Load Shedding(负载卸除)和 Degradation(降级)。
- 能否设计依赖恢复后的探测、预热、连接限速、分级放量和积压预算。
- 能否把 Log(日志)、Metrics(指标)、Trace(链路追踪)和业务审计串成证据链。
- 能否解释上下文跨线程和消息传播、Sampling(采样)缺失与高基数成本。
- 能否为 WMS(仓储管理系统)、支付、轨迹和 IoT(物联网)分别给出治理边界。
- 能否在事故结束前用权威流水、对账和同组指标证明恢复。
14.2 综合题库过渡(非知识型)
本节仅结束上一知识节,不配置知识标记。下面 32 道综合题用于训练 560 至 1000 个有效字符的完整口述,每题通过真实相对链接回到权威知识节,并提供 3 至 5 组追问直答。
综合面试题库
- 问题(综合题):请系统设计一个支付创建接口的幂等方案。
考点:业务意图、幂等键、唯一约束、状态机、结果重放、未知结果。
口述答案:我会先把幂等定义成“同一业务意图重复到达,业务有效结果与执行一次等价”,而不是简单拒绝第二次请求。支付创建以商户订单号或服务端签发的 Idempotency Key(幂等键)识别意图,键的作用域要包含商户和业务类型,关键参数做摘要;同一键参数不同直接返回冲突,不能把两个付款意图合并。
正确性落在数据库。支付请求表对商户、业务类型和幂等键建唯一索引,首次请求在事务中创建支付单和状态流水;重复请求命中唯一约束后读取首次结果,重放相同支付单号、状态和可查询凭证。状态更新使用前置状态与版本条件,渠道回调按渠道单号和事件标识去重,账务事件也有独立唯一约束。分布式锁只用于降低热门订单并发,不承担“只创建一次”的最终保证。
网络超时后结果是未知,调用方必须复用原键查询,不生成新键重做。若本地已创建而渠道未知,系统保持处理中,用原商户订单号主动查单;有限重试使用退避、抖动和预算。渠道明确无单才能同号重放,长期未知进入差错队列和人工核对。返回“成功”必须有本地支付单或渠道凭证,不能为体验伪造。
验证时我会并发发送同键相同参数、同键不同参数,并在数据库提交后响应前注入断连。验收要求只有一张支付单和一条有效账务事件,相同参数得到同一结果,不同参数明确冲突;再通过渠道账单对账证明没有重复扣款。这样入口键、数据库约束、状态机、外部查单和审计构成完整闭环。
追问 1:幂等记录保存多久?
直接回答:至少覆盖客户端最大重试、渠道回调和对账窗口;资金主记录按审计要求长期保存,不能只依赖短期缓存。
追问 2:随机请求标识能否直接由客户端每次生成?
直接回答:可以由客户端生成,但重试必须复用;每次都生成新值会绕过幂等边界。
追问 3:唯一索引冲突就是异常失败吗?
直接回答:对重复请求它是并发裁决信号,应读取首次结果并校验参数,而不是统一报系统错误。
- 问题(综合题):如何为 WMS(仓储管理系统)下单链路设计端到端超时?
考点:截止时间、阶段预算、取消传播、结果未知、异步化。
口述答案:我先从用户和业务承诺反推,而不是给每个客户端复制同一个超时。假设下单接口的
P99(99 分位响应时间)目标为1000ms(毫秒),网关与网络预留80ms(毫秒),订单校验120ms(毫秒),库存预占250ms(毫秒),支付预创建350ms(毫秒),剩余200ms(毫秒)用于序列化、返回和抖动。入口生成绝对 Deadline(截止时间),每一跳读取剩余预算,不能重新获得完整一秒。每个阶段继续区分连接、连接池排队、执行和读取。连接超时必须短于该跳剩余预算,队列等待也有上限;预算不足时不再启动注定过期的工作。上游取消后把取消信号传播下去,但取消只是释放资源的提示,不能假定远端事务一定回滚。支付和库存调用超时后都进入未知态,需要稳定业务键、权威查询和状态机收敛。
对用户必须给真实语义。库存未能在同步预算内确认时,可返回待确认凭证并转异步,而不是返回扣减成功;支付结果未知则显示处理中,后台同号查单。批量波次、报表和物流下单本来就是长任务,应持久化任务后快速受理,不占用请求线程等待数分钟。所有重试共享剩余 Deadline(截止时间)和 Retry Budget(重试预算)。
上线前我会用链路分位而非平均值校准预算,注入连接慢、线程池排队和响应丢失,检查最外层超时后内层是否仍大量运行。监控剩余预算分布、阶段超时、取消成功率、未知状态年龄和最终收敛率。验收标准既包括
P99(99 分位响应时间),也包括库存不超卖、支付不重复和过期工作及时释放。追问 1:读取超时设置一秒是否覆盖全部调用?
直接回答:不覆盖连接、连接池排队和多次重试,还需要总 Deadline(截止时间)。
追问 2:超时能否直接标订单失败?
直接回答:不能,远端可能已提交;应保持待确认并查询库存或支付权威状态。
追问 3:取消信号为什么不是事务回滚?
直接回答:信号到达时远端可能已经提交或正在执行不可取消的外部副作用,只能尽力停止与后续收敛。
- 问题(综合题):熔断与降级如何配合,才能既保护系统又不制造业务假象?
考点:熔断状态机、错误分类、降级语义、恢复探测、业务审计。
口述答案:我会先区分两者。Circuit Breaker(熔断器)根据依赖近期系统错误和慢调用,在 Closed(关闭)、Open(打开)、Half-Open(半开)之间转换,目的是停止对已知故障持续施压;Degradation(降级)定义不能调用依赖时,业务还可以提供什么真实能力。熔断不是修复,降级也不能把失败统一包装成成功。
配置上先按接口和依赖隔离统计,业务拒绝不能算系统失败;设置最小样本、滑动窗口、慢调用阈值和等待期,防止低流量小样本误熔断。Open(打开)时快速失败以释放线程和连接,Half-Open(半开)只放少量探测。探测成功后也不直接全量关闭保护,而是连接池预热并按
1%、10%、30%渐进放量,同时观察错误、尾延迟和饱和度。降级按业务风险设计:商品信息可返回带版本与生成时间的缓存;物流轨迹可显示最后确认节点;支付查询返回处理中并主动查单;库存扣减无法确认时明确待确认或拒绝。任何写请求若转异步,都要返回受理凭证并有状态查询、补偿和人工出口。严重 IoT(物联网)报警不能因降级静默丢弃,只能为低级报警聚合或延迟。
验证会注入第三方物流慢调用,确认物流隔离池触发熔断而库存和支付资源仍有余量;检查熔断拒绝码、缓存版本和未知状态是否被审计。恢复时回放积压使用独立预算,防止实时流量与历史债务叠加。最终以业务流水、重复运单和渠道费用核对证明保护没有改变正确性。
追问 1:熔断打开后为什么还需要限流?
直接回答:熔断保护特定故障依赖,入口和其他路径仍可能过载;限流控制总体容量与公平性。
追问 2:半开探测全部成功能否立刻全量?
直接回答:不能,少量成功只证明小容量恢复,还需渐进放量验证真实并发。
追问 3:缓存降级最重要的字段是什么?
直接回答:数据版本和生成时间,让调用方知道陈旧程度,并禁止用于必须实时裁决的库存和资金写入。
- 问题(综合题):请比较常见限流算法,并为 IoT(物联网)报警风暴选型。
考点:窗口突刺、令牌桶、漏桶、并发、排队、公平性。
口述答案:Fixed Window(固定窗口)只维护当前窗口计数,实现简单,但窗口交界可能在极短时间放出两倍额度;Sliding Window(滑动窗口)用分桶或时间记录平滑统计,成本更高。Token Bucket(令牌桶)按速率补充令牌,允许桶容量内突发;Leaky Bucket(漏桶)以稳定速率排出,适合对下游整形。Concurrency Limit(并发数限制)约束正在占资源的请求,有界队列吸收短峰值,但必须限制长度和年龄。
IoT(物联网)报警不能只做一个全局每秒限额。我会按租户、设备、规则、报警级别分层:入口用令牌桶允许真实故障的短突发,桶容量按可承受峰值而非一分钟总额度设置;相同设备与规则在时间窗内聚合重复低级报警;严重报警使用保留配额穿透。发送短信或工单的外部渠道再用漏桶匀速,消费端用并发上限保护线程和连接。
当消费者处理变慢时,单纯保持
QPS(每秒查询率)仍会让在途数上升,所以还要背压:降低拉取、推迟低优先级事件,并对超过业务时限的可丢通知执行 Load Shedding(负载卸除)。原始严重报警先可靠落盘,不能因限流返回假成功后丢失。租户配额要防止一个客户占满公共资源,同时为全局事故预留应急容量。验证时构造窗口边界双峰、单设备抖动、百万设备同时报警和外部短信变慢四类流量,观察放行率、排队年龄、严重报警送达、低级报警聚合比和租户公平性。限流响应提供明确原因与重试建议,但设备端重试也必须退避和抖动,避免拒绝反过来制造更大风暴。
追问 1:令牌桶容量越大越好吗?
直接回答:不是,过大会一次释放长期积累额度,瞬间压垮下游;容量由允许突发决定。
追问 2:排队能否替代拒绝?
直接回答:不能,无界排队会增加内存和过期工作;队列必须有长度、年龄与卸除策略。
追问 3:严重报警为何也需要上限?
直接回答:需要独立保留容量和极高上限防止系统性失控,但不能与低级报警共享同一易耗尽配额。
- 问题(综合题):为什么分布式锁不能作为库存和资金不变量的最终防线?
考点:租约过期、暂停、网络分区、条件更新、唯一约束、栅栏。
口述答案:分布式锁本质是有期限的协调许可,不是数据库提交约束。持有者可能在长时间暂停、网络隔离或续约失败后失去锁,却仍在本地继续执行;新实例已经取得锁,两者就会并发写。若下游只相信“我曾拿到锁”,库存可能扣成负数,支付流水也可能重复。删除锁时若不校验所有者,还可能误删后来者的锁。
对库存,最终底线是数据库条件更新,例如可售量必须大于等于扣减量,并检查受影响行数;业务请求号和冻结流水有唯一索引,状态迁移带前置状态与版本。对资金,商户订单号、渠道单号和账务事件各有唯一约束,金额与方向在事务内校验。这些约束即使绕过锁也会拒绝非法提交,才是权威不变量。
锁仍有价值:热门商品并发很高时,可降低数据库冲突、重复外部调用和回滚成本;Runner(执行器)所有权切换还可结合单调递增 Fencing Token(栅栏令牌),让下游拒绝旧持有者。但令牌必须在真正执行副作用的资源处比较,只在调度器日志里打印没有保护作用。锁过期后的操作也要可幂等和可审计。
我会用暂停故障测试:请求甲拿锁后暂停超过租约,请求乙取得新锁并提交,随后恢复甲。验收要求甲的数据库条件更新或旧栅栏令牌被拒绝,最终库存守恒、资金流水唯一。再测试锁服务不可用时,系统可选择限流或增加数据库冲突,但不能失去正确性。这样锁是性能优化和协调手段,不是业务事实来源;数据库冲突与锁等待分开监控,才能证明优化没有越过正确性边界。
追问 1:锁自动续约能否消除过期问题?
直接回答:不能,进程暂停或网络分区会阻断续约,且外部副作用可能超过锁系统可见范围。
追问 2:数据库唯一索引能保护库存非负吗?
直接回答:不能单独保护数量关系,还需带余量条件的原子更新或等价事务约束。
追问 3:栅栏令牌放在哪里校验?
直接回答:必须在最终写资源或副作用接收方校验并拒绝旧令牌。
- 问题(综合题):如何系统防止一次下游变慢演变成微服务雪崩?
考点:超时、重试放大、隔离、限流、熔断、降级、恢复。
口述答案:雪崩通常不是一个错误码造成,而是慢依赖占住线程和连接,上游继续排队,多层重试增加流量,最终共享资源耗尽并向更多服务传播。我会先定义端到端 Deadline(截止时间),把连接、排队、执行和返回预算分开,过期请求不再开始新工作,并传播取消。调用只在一层做有限重试,复用幂等键,采用指数退避、随机抖动和 Retry Budget(重试预算)。
资源侧按故障域隔离。第三方物流使用独立线程池和连接池,核心库存、支付保留资源;并发限制直接约束在途慢请求,有界队列只吸收短突发。入口按租户、接口和优先级限流,已过期、低价值且可重建的工作优先卸除。慢调用率或系统错误率达到足量样本后熔断,Open(打开)期间快速拒绝,避免继续消耗。
业务侧为每条路径定义诚实降级。商品读可返回带版本缓存,物流创建可异步受理,支付未知必须查单,库存扣减不能伪造成功。所有拒绝、降级和未知态都有业务号、状态查询与人工出口。指标同时看流量、错误、延迟和饱和度,按依赖、实例、版本和租户拆分,不能只看平均中央处理器。
恢复阶段同样受控:少量半开探测、限速建连、缓存预热,再按
1%到全量放量;实时流量与历史积压分配独立预算。演练会让下游从50ms(毫秒)变为3s(秒),验证总尝试量不超过预算、核心池仍可服务、降级语义真实,并通过业务流水确认没有重复副作用;同时核对拒绝量是否只是被转移到无人处理的人工队列。追问 1:只加熔断器能防雪崩吗?
直接回答:不能,触发前慢请求已占资源,还需超时、并发限制、隔离、限流和重试预算。
追问 2:队列加大是否能提高抗峰值能力?
直接回答:只对短突发有效,过大会积累过期请求并扩大内存和恢复压力。
追问 3:恢复后为什么不能立刻关闭所有保护?
直接回答:积压、重连和缓存回源会叠加实时流量,必须渐进放量防止二次过载。
- 问题(综合题):如何用可观测性定位跨境物流下单慢,同时避免把采样链路当完整事实?
考点:指标、链路、日志、采样、上下文传播、业务审计。
口述答案:我会按“范围、路径、细节、事实”组织证据。先用 Metrics(指标)确定异常从何时开始、影响多少请求、集中在哪个版本、区域或承运商,并同时看请求率、错误率、延迟分位、线程池、连接池和队列饱和度。平均值可能掩盖
1%的数秒长尾,因此重点比较P95(95 分位响应时间)、P99(99 分位响应时间)与正常基线。再从慢样本的 Trace(链路追踪)查看网关、订单、物流适配器和承运商各 Span(跨度)耗时,判断是本地排队、建连、远端执行还是响应返回。按 TraceId(链路标识)、业务号、实例和配置版本查结构化 Log(日志),确认超时类型、重试次数和熔断状态。若跨线程或消息后断链,要检查上下文捕获、消息属性注入和线程结束清理。
采样链路只能提供样本。头部采样可能在请求尚未失败时就丢弃,尾部采样也可能因缓存和导出故障缺段;所以没有 Trace(链路追踪)不能证明调用没发生。应使用访问日志、依赖调用计数和未采样业务流水补齐。运单是否创建、是否重复扣费最终以本地请求审计、承运商查单和账单为准,而不是以某条链路是否存在为准。
止血后保留时间线和变更记录,修复可能是连接池隔离、超时预算或渠道限流。验证使用同一组分位、饱和度、重复运单和未知状态年龄指标,并抽样逐笔查单。只有技术延迟恢复且业务差异闭环,才算事故结束;未采样比例也应作为证据缺口展示,不能隐藏在成功率里。
追问 1:单条完整慢链路能直接定根因吗?
直接回答:不能,它可能是异常样本;需结合整体分布、同版本对照和资源指标验证代表性。
追问 2:为什么业务号不能做普通指标标签?
直接回答:几乎每次唯一,会造成高基数时间序列爆炸,应放日志、链路或审计索引。
追问 3:链路断在消息队列后怎么关联?
直接回答:生产时注入上下文到消息属性,消费时提取并创建新跨度,批处理可用 Link(链路关联)。
问题(综合题):服务降级如何兼顾用户体验、业务正确性和后续恢复?
考点:能力分级、真实语义、缓存版本、异步凭证、人工闭环。
口述答案:我先按业务不变量和用户可接受窗口给能力分级,而不是统一写一个 Fallback(兜底)。商品描述、历史轨迹等只读信息可使用缓存,但响应必须带生成时间、版本或“数据可能延迟”的机器可识别状态;库存展示可以作为参考,最终扣减仍回到权威数据库条件更新。支付查询遇到渠道不可达时返回处理中并主动查单,不能猜测成功或失败。
对写请求,如果业务允许延后,先可靠持久化业务意图并返回受理凭证,用户可以查询进度;例如物流下单进入待处理,恢复后用同一业务号调用并查重。若无法可靠受理,就明确拒绝,不返回虚假成功。严重 IoT(物联网)报警优先保留送达能力,低级重复报警可聚合、静默或延迟,但每次卸除都记录原因和数量。
降级也要受资源保护。缓存需防击穿并限制回源并发,异步队列有长度和消息年龄,人工队列有服务目标与升级规则。前端文案可以友好,但接口状态必须区分成功、处理中、已降级和失败;否则上游会错误推进发货、通知或账务。支付、库存的最终状态由业务流水、渠道凭证和对账证明。
恢复时先验证依赖,小比例流量预热,再分级放量;实时请求优先于历史积压,过期任务不应机械重放。验收不仅看错误率下降,还看缓存版本差、积压年龄、未知态收敛、重复副作用和用户补偿。降级命中率和持续时长也要告警,防止临时方案长期固化,并定期演练;这样降级是在故障中缩小承诺,不是篡改事实。
追问 1:返回空列表为什么可能不安全?
直接回答:调用方会把它理解为真实无数据,而不是服务不可用,可能触发错误业务决策。
追问 2:异步受理是否等于成功?
直接回答:不等于业务完成,只代表意图已可靠记录,必须返回可查询凭证与最终状态。
追问 3:降级开关谁来关闭?
直接回答:由恢复门禁根据探测、资源和业务差异共同决定,并保留人工控制与变更审计。
问题(综合题):注册中心故障时,服务调用如何继续并控制陈旧风险?
考点:控制面与数据面、本地快照、陈旧上限、失败摘除、关键写降级。
口述答案:我先区分控制面和数据面。注册中心负责维护与传播候选实例,真正的业务请求在调用方和实例之间传输;所以注册中心短暂不可达,不应让所有现有调用立即失败。客户端保留最后一次成功的实例快照,记录服务名、实例元数据、目录版本、获取时间和命名空间,在明确的 Staleness(陈旧度)窗口内继续做本地负载均衡。
继续调用不等于盲信旧列表。客户端对连接拒绝、握手失败和明确实例级系统错误做短时被动隔离,隔离有有效期,并触发限速全量刷新;库存不足、权限拒绝等业务结果不能用于摘实例。增量版本不连续时拉取全量快照,不能假设恢复连接后丢失的变更会自动补齐。连接池还要停止借出已摘流实例的旧连接,否则列表更新了,数据面仍粘在旧地址。
业务按风险使用陈旧目录。商品读和轨迹查询可在较长窗口内继续并标记数据版本;库存扣减、支付写入若候选全部失去可信度,应明确失败、排队或进入待确认,不能回退到未经审核的硬编码地址。无候选也可能是命名空间、权限或客户端解析故障,要对照注册中心权威视图与跨区域探测,不直接宣布服务全挂。
演练时我会隔离注册中心网络,同时滚动下线部分实例,验证旧列表可维持短期调用、坏实例在本地快速隔离、版本恢复后能全量校准。指标包括快照年龄、版本差、刷新失败、被动隔离数、旧连接命中和无候选请求;超过陈旧上限触发分级降级。恢复后逐步刷新和建连,避免所有客户端同时冲击控制面与实例。
追问 1:本地快照能永久使用吗?
直接回答:不能,实例会扩缩容、换版本或变更安全属性,必须设置业务相关的陈旧上限。
追问 2:发现一个实例连接失败就立即删除吗?
直接回答:可短时隔离并探测,但要防调用方局部网络误判,最终由目录版本和恢复探测校正。
追问 3:能否直接查询数据库拿实例地址?
直接回答:不应绕过注册治理边界;应使用受控快照或应急配置,并保留版本、审批和审计。
问题(综合题):如何设计一次无损的服务滚动发布和优雅下线?
考点:就绪检查、主动摘流、目录传播、连接排空、消费者交接。
口述答案:无损发布要同时管理新实例接流和旧实例退流。新实例启动后先保持 Readiness(就绪检查)失败,完成配置校验、关键连接建立、必要缓存预热和无副作用路径检查,再用少量流量预热;进程端口已监听只代表 Liveness(存活检查)通过,不代表业务容量已经可用。预热失败应阻止进入负载池,而不是边接生产流量边修复。
旧实例收到终止信号后,第一步把 Readiness(就绪检查)改为不可接流并主动向目录注销;第二步等待注册变更传播和客户端连接池停止借出旧连接;第三步才排空在途请求、消息消费者、定时任务和 Runner(执行器)工作。短请求可以完成,长任务必须在安全点持久化状态和所有权,交给新实例用相同幂等键接管。消息在业务提交后才确认。
排空时间按最坏窗口计算:目录传播、连接刷新取较大值,加最长合理请求时间和安全余量。若平台终止宽限期短于该值,强杀仍会制造连接重置。达到排空上限时不能无限等待,应取消可取消请求,把任务退回队列,或记录待恢复状态;外部支付与物流副作用需要查单,不能假设进程退出会回滚。
验证时持续发压并滚动发布,跟踪每个版本请求数、连接重置、在途数、重复消费和任务接管。故意让目录推送延迟、长请求跨越下线窗口,确认旧实例不再接新流量且已接工作有明确结果。发布完成后核对库存与支付业务流水,证明技术成功率之外没有重复或丢失副作用。
追问 1:主动注销后为何不能立即退出?
直接回答:目录通知、客户端调度和旧连接淘汰存在传播时间,窗口内仍会有请求到达。
追问 2:消费者应先停止拉取还是先等待业务?
直接回答:先停新拉取,再完成或安全交接已拉消息,最后确认和退出。
追问 3:预热能否调用真实扣库存接口?
直接回答:不能,预热应无副作用或使用隔离数据,避免发布本身制造业务交易。
- 问题(综合题):如何发现并治理客户端服务列表陈旧或分裂?
考点:列表版本、增量缺口、全量校准、区域差异、连接残留。
口述答案:客户端目录不是无状态缓存,我会让每份列表携带目录版本、更新时间、来源注册节点、区域和命名空间。增量更新只有在前一版本连续时才能应用;发现版本缺口、订阅积压或长时间未刷新,就限速拉取全量快照。周期性对比客户端视图摘要与注册中心权威快照,可以发现某批客户端停在旧版本,也能区分合法区域差异和异常分裂。
数据面证据同样重要。若某些客户端持续访问已下线地址,检查本地列表之外还要检查连接池,因为旧的长连接可能绕过新列表。对单实例连接拒绝可短时本地隔离,对业务错误不能摘流;隔离到期后放少量探测,并由新目录版本校正。列表为空时先排查订阅权限、命名空间和解析问题,不直接回退到硬编码地址。
我会定义陈旧服务目标,例如
99.9%客户端在变更后5s(秒)内生效,关键写快照不超过30s(秒),超过后停止新写或转待确认;只读展示可容忍更长,但响应记录目录版本。监控客户端版本分布、快照年龄分位、刷新失败、目录版本差、被动隔离和已删除实例命中率,避免只看注册中心自身健康。故障演练包括丢一条增量、暂停客户端订阅线程、让注册中心短暂分区、下线实例但保留连接。验收要求版本缺口触发全量校准,旧连接被排空,坏实例错误量受控;恢复时刷新限速,不能让数千客户端同时拉快照和建连接。不同语言客户端还要执行一致的版本契约测试,这样陈旧是一项可测量风险,而不是“最终会更新”的口号。
追问 1:为什么周期性全量拉取仍有必要?
直接回答:增量可能丢失或应用失败,全量快照用于纠偏并验证版本连续性。
追问 2:客户端视图不一致一定是故障吗?
直接回答:不一定,区域、版本和租户路由可能本就不同,要先按治理维度比较。
追问 3:已删除实例命中率为什么比列表版本更直接?
直接回答:它反映真实数据面仍在发送请求,能暴露连接池残留和更新未生效。
- 问题(综合题):负载均衡为什么必须与连接池、慢实例和业务键联合设计?
考点:选择时机、连接复用、反馈负载、亲和路由、热点。
口述答案:负载均衡不是从地址数组里随机挑一个就结束。Round Robin(轮询)适合同构实例和近似请求成本,但慢实例会继续得到等量流量,在途请求越积越多;加权轮询能表达规格差异,权重却可能陈旧。更稳健的客户端会先过滤未就绪与短时隔离实例,再按区域、版本和租户约束筛选,最后结合静态权重、在途请求和近期延迟选择。
连接池决定选择何时真正生效。如果只在建连接时选实例,长连接复用会让旧拓扑和旧权重长期存在;目录已摘流,池中连接仍可能继续发请求。正常下线应停止借出并排空旧连接,故障连接快速关闭;扩容和恢复要限制并发建连、逐步预热。每实例连接上限还要与服务端承载匹配,不能让所有客户端各建大量连接。
Consistent Hashing(一致性哈希)能让同一仓库或商品的缓存请求稳定命中,提高局部性,但热门键会形成单点热点,扩缩容也会迁移。它不能承担库存只扣一次或资金唯一入账,正确性仍靠数据库条件更新与唯一流水。可以用虚拟分片、热点拆分和独立容量池缓解,再对真实业务键监控倾斜。
验证时用同构、异构、单实例变慢、实例摘流和热点商品五类压测,比较各实例请求、在途数、延迟和连接分布。动态降权后检查每次请求选择是否生效,而不是只看新连接。任何反馈算法都要平滑与探测,避免流量在实例间追逐震荡;最终以尾延迟和过载实例恢复速度评价,而非只追求请求数均匀。
追问 1:最少连接为什么不适合所有协议?
直接回答:多路复用的一条连接可承载许多并发,连接数不等于在途工作量。
追问 2:动态权重更新后旧连接怎么办?
直接回答:停止按旧权重借用并渐进排空、补建,避免立即断开在途请求或权重长期不生效。
追问 3:请求数绝对均匀就是好负载均衡吗?
直接回答:不是,请求成本和实例能力不同,应关注在途、尾延迟、饱和度和业务键热点。
- 问题(综合题):如何制定重试策略和重试预算,避免流量乘法放大?
考点:错误分类、单层重试、退避抖动、预算、截止时间。
口述答案:我先按错误语义分类。参数错误、权限拒绝、库存不足等确定性结果不重试;连接建立失败、连接重置等瞬时系统错误,在有其他健康实例和剩余时间时可有限重试;响应超时最危险,因为原操作可能已提交,必须先看接口是否幂等、是否能查询权威结果。支付和物流写入复用原业务号,不能换键盲重做。
多层调用只选最接近失败源且最了解语义的一层重试。假设网关、订单和库存每层都“再试三次”,最坏尝试数是
4 × 4 × 4 = 64倍;即使各层只重试一次也会有8倍。上游保持一次调用,由库存客户端做一次快速切换,并共享入口 Deadline(截止时间),剩余预算不足时不重试。时间策略采用 Exponential Backoff(指数退避)和 Jitter(抖动),防止大量客户端同频再冲击。数量上设置 Retry Budget(重试预算),例如额外尝试不超过近期首试流量的
10%;预算耗尽后快速失败、异步排队或降级。服务端返回明确可重试错误和建议等待,但调用方仍受自己的业务时限约束,不能无限遵从。上线验证会让下游从正常延迟变慢、返回限流、随机断连和提交后丢响应,统计首试与重试
QPS(每秒查询率)、成功收益、额外负载和重复副作用。只有重试确实提高成功率且下游饱和度受控才保留;恢复时重试预算继续生效,避免积压、重连和实时流量叠加。每次策略变更还需比较“额外尝试带来的成功数”,淘汰收益接近零的重试。追问 1:换实例重试是否不算放大?
直接回答:仍算额外尝试,只是可能绕开实例故障,依然消耗共享下游资源。
追问 2:为什么固定等待不够?
直接回答:同批失败请求会在同一时刻再次到达,抖动用于打散同步峰值。
追问 3:重试预算按单请求还是全局?
直接回答:单请求限制次数和时间,全局或依赖级预算限制总体额外流量,两者都需要。
- 问题(综合题):支付调用超时后,如何处理“成功、失败还是未知”的状态?
考点:观察边界、稳定业务号、主动查单、状态机、对账。
口述答案:客户端在 Deadline(截止时间)前没收到响应,只能证明“没有观察到结果”,不能证明渠道未扣款。请求可能未到达、已提交但响应丢失、仍在渠道处理或本地排队。因此支付单状态必须包含处理中或未知,不能二值化为成功和失败;商户订单号作为稳定业务键,所有重试、查询和回调都关联同一意图。
处置顺序是先查本地支付请求表和状态流水,再调用渠道权威查单。若渠道明确成功,用状态条件与版本推进本地支付单,生成唯一账务事件;若明确失败,记录渠道原因并允许业务按规则重新支付;若仍未知,保持处理中,采用有限退避查单并设置最大年龄。只有渠道明确无单且协议允许,才用同一业务号重放,不能生成新号绕过幂等。
达到自动预算后进入差错队列,保留订单号、渠道号、金额、每次尝试、验签证据和最后权威响应。日内巡检与次日账单逐笔对账,发现渠道成功但内部未入账时按审批补记,重复入账则冲正;在状态未确认前暂停自动发货或退款等不可逆后续。Trace(链路追踪)可帮助定位超时,但采样数据不承担资金事实。
测试要覆盖请求发送前断网、渠道提交后响应丢失、重复回调、查单超时和账务消费重复。验收要求同一商户订单只有一笔有效支付和账务方向,未知状态在服务目标内收敛,超过时限自动升级人工。用户端展示处理中和查询入口,既不制造恐慌,也不伪造结果;高金额订单可采用更短升级时限和更严格的发货冻结策略。
追问 1:渠道查单也超时怎么办?
直接回答:继续保持未知,按预算退避查询并最终转对账或人工,不能据第二次超时猜结果。
追问 2:可以直接退款消除风险吗?
直接回答:未确认是否扣款时退款同样可能失败或重复,应先取得渠道事实,再执行有幂等号的退款。
追问 3:为什么要暂停发货?
直接回答:未知支付若继续履约会扩大资损,业务保护动作要与状态年龄和订单价值联动。
- 问题(综合题):如何同时处理库存热点竞争、重复请求和锁过期?
考点:条件更新、请求唯一、锁优化、结果重放、库存守恒。
口述答案:我先定义权威不变量:可售量不能小于零,同一订单和冻结意图只生效一次,冻结、扣减、释放之间数量守恒。数据库库存行用带余量和版本的原子条件更新,受影响行数为零时区分余量不足、版本冲突和重复请求;冻结流水以仓库、商品和业务请求号建立唯一约束,并在同一事务记录前后状态。
热门商品竞争高时,可以按商品与仓库使用分布式锁或单键串行队列减少冲突,但它只是优化。请求甲持锁后暂停超过租约,请求乙可能取得新锁并提交;甲恢复后仍必须被数据库版本或余量条件拒绝。若采用 Fencing Token(栅栏令牌),最终写资源比较单调令牌,旧持有者不能继续写。释放锁还需校验所有者,避免误删后来者。
入口 Idempotency Key(幂等键)绑定订单行与冻结类型,重复请求读取首次冻结号和结果;参数不同复用同键则冲突。超时后调用方先按冻结号查询,不换键重做。消息重复释放或扣减使用事件唯一标识和状态机前置条件,已释放不能被迟到扣减逆向推进;人工调整也要生成审批流水,不能直接改余量。
压测与故障注入会并发提交同键和不同键请求,暂停锁持有者、让锁服务不可用,并在数据库提交后丢响应。验收以数据库余量、冻结流水和订单明细对账,证明库存不负、同一意图一次生效且重复得到同一结果。锁故障可以让冲突率变高或吞吐下降,但不能让正确性下降;热点冲突率、条件更新失败率与锁等待还要分别设置容量告警。
追问 1:版本冲突后可以无限重试吗?
直接回答:不能,应重新读取并在有限预算内重算;热点时排队或失败,避免活锁和数据库风暴。
追问 2:库存缓存能否先扣再异步落库?
直接回答:除非有完整持久化和一致性设计,否则缓存不是最终权威,失败会丢失或重复扣减。
追问 3:人工调库存为何也要流水?
直接回答:调整会改变不变量,必须可审计、可对账并能追溯受影响订单。
- 问题(综合题):消息消费者怎样做到重复投递不重复产生业务副作用?
考点:至少一次、去重表、业务事务、外部副作用、确认窗口。
口述答案:至少一次投递下,最典型窗口是消费者已经提交业务数据库,但确认消息前崩溃,恢复后同一消息再次到达。因此目标不是要求消息永不重复,而是让业务处理具备 Idempotency(幂等)。事件要有稳定标识,业务还要选择真正的幂等键,例如订单号与状态迁移、支付单与账务方向,不能只依赖中间件本次投递标识。
数据库内处理时,去重记录、业务状态条件更新和结果流水放在同一事务。首次插入去重标识成功才执行,重复命中唯一约束后读取已处理结果;状态机同时拒绝迟到或逆向事件。事务提交后再确认消息,若确认丢失,重复投递会被数据库吸收。内存 Set(集合接口)会在重启后丢失,短期缓存过期也不能覆盖长期回放。
外部物流、短信或支付副作用不能与本地事务天然原子。先持久化待执行状态和业务号,再用同一业务号调用外部;超时保持未知并查单,结果写回状态机。不能先把消息标为已处理再调用外部,否则外部失败会永久漏做;也不能外部成功后没有本地审计。达到重试预算后进入隔离队列和人工闭环。
验证时在业务提交前、提交后确认前、外部调用后写结果前分别强制退出,随后重复投递。检查业务表、去重表、外部查单和审计流水,确保一次有效副作用、重复可安全确认。监控重复率、去重命中、处理年龄、重试次数和隔离积压,防止“没有重复告警”其实是观测缺失;还要定期回放历史消息验证幂等记录保留期覆盖真实恢复窗口。
追问 1:去重表可以先提交吗?
直接回答:不能与业务写分开先提交,否则后续失败会留下已处理标记并丢失业务动作。
追问 2:消息标识一定是业务幂等键吗?
直接回答:不一定,同一业务意图可能生成多条消息,还需订单号、事件类型和状态版本等业务键。
追问 3:重复命中后是否直接丢弃?
直接回答:应确认首次结果存在且参数一致,再安全确认;异常冲突要进入审计而非静默丢弃。
- 问题(综合题):如何治理百万设备同时上报造成的 IoT(物联网)报警风暴?
考点:分层限流、时间窗去重、优先级、背压、严重报警穿透。
口述答案:我会先把“事件接收”和“通知发送”拆开,防止短信或工单渠道慢拖垮设备入口。原始事件先按租户、设备、规则和事件时间可靠落盘,入口用 Token Bucket(令牌桶)允许真实故障的有限突发,同时设置全局、租户和设备级配额。桶容量按基础设施可承受峰值确定,而不是把一分钟额度一次性放出;超额事件返回明确结果并让设备退避抖动。
进入处理链后,同一设备、规则和时间窗内的重复低级报警聚合为一条事件,记录首次、最近、次数和样本;状态恢复时生成恢复通知。严重报警使用独立保留容量,可穿透低级报警静默,但仍需极高硬上限防止配置错误无限复制。规则版本和设备号参与幂等,迟到事件按业务状态机处理,不能只按服务器物理时间覆盖。
消费端根据队列年龄、处理耗时和外部渠道水位实施 Backpressure(背压),降低拉取并推迟低优先级通知。短信渠道用 Leaky Bucket(漏桶)匀速发送,并发上限保护连接;队列必须有长度和最大年龄,过期低级通知可 Load Shedding(负载卸除),但原始严重报警与卸除原因必须审计。一个租户的规则爆炸要被租户隔离,不能吃光公共资源。
演练会模拟百万设备在一分钟内同时报警、单设备高频抖动、通知渠道耗时升高和消费者重启。验收指标包括入口接收率、严重报警送达、聚合比、租户公平性、积压年龄、通知延迟和卸除量;再抽样核对原始事件、聚合事件与通知凭证。恢复时限制回放预算,优先严重且未过期事件,避免渠道刚恢复就被历史积压再次压垮。
追问 1:报警去重能只用设备号吗?
直接回答:不能,还要包含规则、事件类型、时间窗和版本,否则不同故障会被错误合并。
追问 2:低级报警丢弃后是否无需记录?
直接回答:仍要记录聚合计数、卸除原因和时间范围,便于审计风暴规模与规则质量。
追问 3:设备端重试如何避免二次风暴?
直接回答:返回明确退避时间,设备采用指数退避和随机抖动,并复用事件标识。
- 问题(综合题):第三方物流接口不稳定时,如何设计完整韧性链路?
考点:业务号、隔离、超时、熔断、查单、备用渠道、恢复回放。
口述答案:外部物流是不可控故障域,我先把调用从订单核心线程和数据库事务中解耦。订单提交后可靠记录待下单任务与稳定业务号,接口快速返回可查询状态;物流适配器使用独立线程池、连接池、并发上限和有界队列。端到端 Deadline(截止时间)继续拆连接、排队和读取预算,防止渠道变慢长期占用资源。
只有连接失败等明确瞬时错误才有限重试,所有尝试复用业务号,采用退避、抖动和 Retry Budget(重试预算)。响应超时表示结果未知,优先调用渠道查单;明确无单才同号重放。慢调用或系统错误达到足量样本后 Circuit Breaker(熔断器)进入 Open(打开),新任务保持待处理或按规则选择已验证备用渠道,不能生成新业务号重复购买面单。
备用渠道切换也有业务边界:服务区、费用、时效、标签格式和清关能力必须重新校验,高价值或特殊货物可转人工。每次请求、查单、渠道单号、费用和状态版本进入审计;超过自动处理时限生成工单。订单状态只根据权威物流结果推进,Trace(链路追踪)用于解释调用过程,不替代运单事实。
恢复时先少量探测、限速建连,再给实时与积压分开配额,按承诺时限和订单价值回放;过期任务先重新校验是否仍需下单。验收通过注入慢响应、提交后断连、重复响应和渠道恢复,核对重复运单率、未知状态年龄、核心订单线程余量和渠道费用,证明韧性既保护资源也不改变业务正确性。
追问 1:物流下单可以放数据库事务里同步等待吗?
直接回答:不应,外部资源不参与本地事务,长等待会持有锁和连接且仍无法回滚外部副作用。
追问 2:备用渠道是否在主渠道熔断后立即全切?
直接回答:不能,先校验能力并小比例放量,避免把主渠道故障转移成备用渠道过载。
追问 3:未知状态多久转人工?
直接回答:按截单时间、订单价值和渠道服务目标配置,达到自动预算就升级,不能无限重试。
- 问题(综合题):如何避免熔断器误触发或恢复震荡?
考点:错误分类、最小样本、短长窗口、半开探测、反馈稳定性。
口述答案:误触发常见于把库存不足、参数错误等业务结果算作系统故障,或低流量接口几次失败就达到高比例。我会先按依赖和接口拆统计,明确哪些异常计失败、哪些计慢调用、哪些忽略;同时设置最小样本量,结合短窗口快速发现连接级故障和长窗口判断持续异常,不能只用一个百分比覆盖所有流量形态。
时间阈值来自真实分位和资源风险。若依赖从
50ms(毫秒)变到3s(秒)但仍成功,慢调用率应在连接池耗尽前触发保护;低流量支付查单则要避免两个失败直接熔断。Open(打开)等待期不宜固定过短导致频繁探测,也不宜过长让已恢复容量闲置,可以按连续失败增加等待并设上限。Half-Open(半开)只允许少量探测,探测请求要有代表性但无高风险副作用。恢复不能仅因三次成功就全量,先限速建连和预热,再按阶段放量;任一阶段尾延迟、错误或饱和度恶化就退回 Open(打开)。多个实例或客户端的探测还需错峰,避免所有熔断器同时打开流量闸门。
验证会回放低流量、小样本业务拒绝、慢成功、随机错误和依赖逐步恢复五类曲线,观察状态转换、拒绝量和恢复时间。业务层还检查降级结果是否真实,支付未知是否进入查单。多实例环境要比较各客户端的状态分布,防止局部网络让一半实例长期熔断、另一半仍全量施压;规则调整采用小范围灰度并记录前后误拒绝率。熔断目标是减少无效施压和资源损失,不是追求状态切换次数越多越灵敏。
追问 1:错误率阈值设得越低越安全吗?
直接回答:不一定,会增加误熔断和可用性损失,应与最小样本、慢调用和业务风险共同校准。
追问 2:半开探测可以用真实支付创建吗?
直接回答:应优先用可查询、幂等且风险受控的请求,不能用不可逆高风险副作用做健康探针。
追问 3:如何发现状态震荡?
直接回答:监控单位时间状态切换、半开失败、恢复后延迟和放量回退次数。
- 问题(综合题):线程池、信号量和连接池隔离如何做容量设计?
考点:故障域、并发、排队、总资源预算、连接上限。
口述答案:隔离先按共同故障域和业务优先级划分,而不是每个接口随意建池。第三方物流、支付渠道、核心库存和低优先级报表的延迟与风险不同,应分资源池;同一依赖的接口可以共享受控池,避免池数量过多导致线程内存和上下文切换失控。阻塞且延迟不可控的依赖适合线程池隔离,快速非阻塞路径可用 Semaphore Isolation(信号量隔离)。
容量从到达率和耗时推导。在稳定状态下,在途数近似到达率乘平均耗时,但要用高分位和峰值留余量。例如物流
20 QPS(每秒查询率)、P99(99 分位响应时间)为2s(秒),仅高分位在途就可能接近40,可设执行并发50,而不是直接使用服务总线程200。队列只吸收短突发,等待时限必须小于剩余 Deadline(截止时间)。线程池并发要与连接池匹配。若有
60个执行线程却只有10条连接,其余线程只是阻塞借连接;若每个应用实例有100条连接、服务端有50个实例,扩容后总连接可能超出数据库或渠道上限。连接池按依赖隔离,设置借用超时、每实例上限和限速建连,正常摘流渐进排空。最后保留全局预算,所有隔离池之和不能超过进程和下游承载。监控执行并发、队列长度与年龄、拒绝、连接借用和服务端连接总量;故障演练让物流变慢,验收库存与支付仍有线程和连接,物流超出部分明确异步或拒绝。隔离的成功标准是局部故障不传染,而非把故障藏进更大的队列。
追问 1:线程池队列越大越能抗峰值吗?
直接回答:只对短突发有帮助,过大会积累过期请求并增加内存与恢复压力。
追问 2:信号量隔离为何仍可能拖住上游?
直接回答:获得信号量后调用仍在上游线程执行,慢依赖会持续占用该线程。
追问 3:连接池总量由谁限制?
直接回答:客户端每实例上限与服务端全局容量共同约束,扩容模型必须计算总连接数。
- 问题(综合题):消息和流式处理中的背压怎样落到工程动作?
考点:消费能力、积压年龄、拉取控制、生产反馈、卸除边界。
口述答案:Backpressure(背压)不是“队列存在”这么简单,而是下游根据当前能力把减速信号传给上游。消费者先观测处理吞吐、处理耗时、在途数、队列长度与最老消息年龄;接近并发或连接上限时减少批量、暂停分区拉取或延长下一次拉取间隔。若生产者能协作,入口降低发送速率并返回可重试时间,而不是继续无限写队列。
对不能减速的设备流量,要在入口完成分层限流、聚合或可靠落盘。IoT(物联网)严重报警保留独立容量,重复低级报警按设备、规则和时间窗聚合;跨境轨迹原始事件先保存,派生通知可延迟。队列仍有磁盘和恢复上限,不能把无限积压当成吸收能力。过期且可重建工作可以 Load Shedding(负载卸除),资金、库存与严重报警不能静默丢弃。
背压要跨层传播业务语义。同步接口可返回明确过载和建议等待,调用方采用退避抖动;异步受理返回任务凭证,前端展示处理中。Runner(执行器)调度器根据执行器剩余并发减少派发,失去租约的实例不能继续消费。任何暂停和卸除记录租户、业务键、原因与数量,便于后续重放和审计。
验证会让消费者吞吐逐步下降到生产速率的一半,检查拉取是否减速、积压年龄是否触发告警、生产端是否响应;再恢复消费者,确认回放使用独立预算而不是与实时流量抢满资源。最终看严重业务送达、低级聚合比、过期卸除和恢复时间,不只看队列有没有归零,并核对暂停分区是否造成租户间饥饿。
追问 1:消息积压数量和年龄哪个更重要?
直接回答:两者都要看,年龄更直接反映业务时效,数量用于容量和恢复估算。
追问 2:生产者不支持减速怎么办?
直接回答:入口限流、持久化缓冲、聚合和受控卸除,不能只依赖消费者内部信号。
追问 3:队列归零能证明业务恢复吗?
直接回答:不能,消息可能丢失或被错误确认,还需业务流水、状态年龄和对账验证。
- 问题(综合题):依赖恢复后,如何处理实时流量、积压和缓存回源?
考点:半开探测、预热、配额分离、优先级、二次过载。
口述答案:恢复不是把保护开关一次性关闭。首先用少量 Half-Open(半开)探测确认依赖能处理真实但风险受控的请求,并限制客户端同时探测;然后限速建立连接、加载必要缓存和完成实例预热。只有错误、尾延迟与饱和度同时达标,才按
1%、10%、30%到全量逐级放量,任何阶段恶化立即回退。实时流量、历史积压和缓存回源必须分配独立预算。假设依赖稳定容量
1000 QPS(每秒查询率),实时已有800 QPS(每秒查询率),不能再按1000 QPS(每秒查询率)回放积压;可以先给积压100 QPS(每秒查询率),保留安全余量。积压按业务时限、价值和可恢复性排序,已过期物流任务先重新校验,支付未知优先查单,低级过期通知可卸除并留痕。缓存恢复防止所有键同时回源。通过随机过期、请求合并、热点键预热和回源并发限制,逐批刷新;缓存值带版本,库存与资金决策仍查询权威源。连接池也分批补建,避免数千客户端同时握手。熔断器状态、回放调度和缓存预热需要同一恢复门禁协调,否则各自看见“已恢复”会叠加冲击。
验收使用依赖容量逐步恢复的演练,记录探测成功率、阶段放量、实时成功率、积压年龄、回源量和连接建立速率。业务侧核对重复运单、支付差异与报警送达。只有实时服务稳定、积压按目标收敛且业务差异闭环,才能撤销降级;队列变短或错误率暂降都不是充分证据,放量门禁本身也要可回滚和审计。
追问 1:积压是否按最早消息优先?
直接回答:不总是,应结合业务优先级、过期时间和副作用风险,严重且未过期工作优先。
追问 2:缓存一次性清空最干净吗?
直接回答:会制造回源风暴,应分批失效、合并请求并限制回源并发。
追问 3:何时可以全量关闭熔断?
直接回答:多阶段真实流量下错误、尾延迟、饱和度和业务差异持续达标后。
- 问题(综合题):为什么队列超时也必须纳入端到端超时预算?
考点:排队延迟、过期工作、连接池借用、取消与卸除。
口述答案:很多系统只设置连接和读取超时,却允许请求在线程池或连接池无限排队。请求可能在队列里已经消耗大部分用户预算,拿到资源后即使执行成功,响应也来不及返回;更糟的是上游早已超时重试,旧请求仍继续执行,形成重复副作用和资源浪费。因此排队超时必须是端到端 Deadline(截止时间)的一部分。
入口携带绝对 Deadline(截止时间)或剩余预算,进入任何队列前比较预计等待与返回余量。等待超限的查询快速拒绝,已过期任务直接 Load Shedding(负载卸除);支付和库存写若业务意图已可靠持久化,可返回受理凭证后异步处理,否则不能伪造成功。连接池借用也设置超时,避免大量线程只是在等待少数连接。
队列用于吸收短突发,容量由允许等待时间与消费速率推导,而不是内存能放多少。例如消费能力
100 QPS(每秒查询率)、允许额外等待200ms(毫秒),可吸收的理想短队列约20个请求,再加有限余量;队列1000只会让尾部等待约十秒。不同优先级分队列,防止报表挤压库存与支付。我会监控队列长度之外的最老年龄、入队到出队分位、出队时剩余预算和过期卸除数。压测制造短突发与持续过载,验证短峰值可吸收、持续过载会尽早拒绝,且上游收到明确语义。故障后检查是否还有已过期工作继续调用下游,并用业务幂等与审计确认没有重复提交;不同优先级还要验证不会互相饥饿并能及时止损。
追问 1:队列长度为零为何仍可能慢?
直接回答:延迟可能在连接、执行或下游,队列只是端到端路径中的一个阶段。
追问 2:任务已入队能否忽略用户取消?
直接回答:可取消且尚未产生副作用的任务应移除,已持久化业务意图则按真实状态继续并提供查询。
追问 3:如何估算队列上限?
直接回答:由可接受等待乘稳定消费速率推导,再结合突发与内存校验,不按最大可分配内存设置。
- 问题(综合题):WMS(仓储管理系统)下单延迟突然升高,如何按证据链排查?
考点:指标定范围、链路定跳点、日志查细节、审计证事实、止血验证。
口述答案:我先确认影响和变化,不直接重启。用 Metrics(指标)查看异常开始时间、请求率、错误率、
P95(95 分位响应时间)、P99(99 分位响应时间),按区域、租户、服务版本和接口拆分;同时看订单线程池、库存数据库连接、队列年龄与外部支付延迟。对照发布、配置、扩容和依赖变更,判断是全局容量、单版本还是单租户热点。止血与取证并行。若物流依赖变慢,先限流或隔离物流路径,保留库存与支付核心资源;若单实例异常则摘流,但先保存线程、连接和配置版本。选取慢请求 Trace(链路追踪),比较网关、订单、库存和支付 Span(跨度),再按 TraceId(链路标识)、订单号和实例查结构化 Log(日志)。链路未采样时用访问日志与依赖计数拼接,不能因查不到就断言未调用。
技术调用成功不代表业务正确,继续查订单状态流水、库存冻结号、支付单与渠道状态,确认超时请求是否实际提交。发现重试放大时立即收紧 Retry Budget(重试预算)和队列,过期请求负载卸除;支付未知保持处理中并查单,库存重复由唯一约束与条件更新吸收。所有切流、限流和配置变更记录时间与操作者。
根因修复后,用相同压测与故障条件复验,观察分位、饱和度和重试量是否恢复,再逐步放量。最后核对库存守恒、重复支付、未知订单年龄和人工差错队列。只有技术指标与业务审计都闭环,才结束事故并把触发条件、错误方案和长期防线写入复盘。
追问 1:为什么不先查所有错误日志?
直接回答:没有时间与范围会陷入海量噪声,先用指标缩小版本、区域和依赖更高效。
追问 2:摘掉慢实例后指标恢复能算根因吗?
直接回答:只能证明关联,仍需保存现场确认垃圾回收、连接、热点或依赖等具体原因。
追问 3:错误率下降为何不能结束事故?
直接回答:可能仍有未知支付、重复库存或积压任务,需要业务流水和对账证明收敛。
- 问题(综合题):链路上下文如何跨线程、远程调用和消息传播且不串链?
考点:注入提取、作用域、线程复用、消息关联、失败检测。
口述答案:同步远程调用遵循标准链路上下文:客户端在请求头注入链路标识和采样信息,服务端提取后创建子 Span(跨度),响应结束关闭作用域。业务订单号不替代 TraceId(链路标识),前者用于长期业务关联,后者描述一次技术调用;两者都应进入结构化 Log(日志)和审计索引,但敏感字段需要脱敏。
线程池是最容易串链的地方。提交任务时捕获当前上下文,执行前恢复到新作用域,任务完成无论成功失败都在最终清理;不能只把线程本地变量复制进去而不恢复原值,因为线程会被后续请求复用。异步任务跨越原请求生命周期时创建新 Span(跨度)并保持关联,而不是让原跨度无限不结束。超时取消也必须执行清理。
消息生产时把上下文写入消息属性,不能混入可能被业务修改的正文;消费端提取后创建消费 Span(跨度)。一条消息触发一条链路可使用父子关系,批量消费或多个事件汇聚时用 Link(链路关联)保留多个来源,避免强选一个父节点。消息重复投递会生成新的消费尝试跨度,但使用同一业务事件号关联幂等处理。
验证会在线程池复用、异常退出、超时取消、消息重投和批处理场景检查链路。指标监控无父跨度比例、上下文解析失败、跨服务断链和异常超长跨度;抽样把访问日志、Trace(链路追踪)和业务号对齐。即使链路传播失败,业务幂等和审计仍必须工作,可观测性故障不能改变库存与支付正确性。
追问 1:线程本地变量为何必须在最终清理?
直接回答:线程池复用线程,不清理会把上一请求上下文带入下一任务,造成串链和数据泄露。
追问 2:批量消费为什么适合链路关联而非单父节点?
直接回答:一个批次来自多个独立生产链路,关联能保留多来源而不伪造单一因果父子关系。
追问 3:TraceId(链路标识)能作为支付幂等键吗?
直接回答:不能,重试可能产生新链路,支付幂等键必须绑定稳定业务意图。
- 问题(综合题):如何控制可观测性中的高基数和采样成本,又保留排障能力?
考点:指标标签、日志索引、头尾采样、示例关联、成本边界。
口述答案:我先按数据用途分层。Metrics(指标)用于聚合趋势,标签只保留服务、接口、区域、版本、错误类别和有限租户分层等可控枚举;订单号、运单号、设备号和 TraceId(链路标识)几乎每次唯一,若作为标签会创建海量时间序列,应放入结构化 Log(日志)、Trace(链路追踪)或业务审计。设备百万级时,单个设备标签足以让监控系统自身过载。
下钻能力通过关联而非把所有实体塞入指标。延迟直方图可携带 Exemplars(示例关联)跳转到代表性 Trace(链路追踪),日志用业务号和时间范围建立受控索引;关键租户可白名单保留独立指标,长尾租户聚合到层级。错误原因先归一化为有限代码,原始异常文本放日志,防止每条消息成为新标签。
采样按目标组合。Head Sampling(头部采样)成本可预测但请求开始时不知道最终是否失败,可能漏掉关键异常;Tail Sampling(尾部采样)能优先保留错误、慢调用和特定属性,但需缓存完整轨迹并承担导出成本。实践中保留低比例随机基线,加错误、慢请求和高价值业务规则;达到容量上限时有明确丢弃指标,不能静默。
我会为遥测设存储、导出带宽和序列数预算,监控活跃时间序列、标签基数、日志摄入、链路丢弃和查询延迟。用已知异常注入验证被采样策略能发现,同时确认支付与库存审计是全量事实,不受链路采样影响。成本优化不能删除业务流水,也不能把敏感原文无限写日志。
追问 1:租户标识是否一定属于高基数?
直接回答:取决于租户规模和活跃度,应评估上限;大规模长尾租户采用分层与白名单。
追问 2:只保留错误链路有什么缺陷?
直接回答:会漏掉慢成功、正常基线和被业务层吞掉的异常,需要随机样本与延迟规则。
追问 3:指标里能否直接放异常消息?
直接回答:不应,原始消息值域不可控;用归一错误码作标签,详细消息进入日志。
- 问题(综合题):支付、库存、物流和报警的业务审计应如何设计?
考点:事实完整性、状态版本、外部凭证、对账、敏感数据。
口述答案:业务审计的目标是证明“谁以什么业务意图,在何时把状态从什么变为什么,产生了哪个外部凭证”,与用于排障的技术 Log(日志)不同。公共字段包括租户、主体、业务请求号、幂等键、前后状态、版本、数量或金额、来源、发生时间、处理结果和操作者;记录采用结构化不可静默覆盖的流水,修改通过新的更正或冲正事件表达。
支付审计保存商户订单号、渠道单号、金额、币种、验签结果、账务方向和对账状态;库存保存仓库、商品、冻结号、变更数量、前后版本和条件更新结果,并验证期初加流入减流出等于期末;物流保存请求摘要、渠道运单、费用、查单与取消结果;IoT(物联网)保存原始严重报警、规则版本、聚合次数、通知凭证和卸除原因。
审计写入必须与关键业务提交处于同一可靠边界,或有可证明的发件箱式补写机制。外部副作用超时时保留未知状态和所有尝试,不根据缺少响应删除记录;日内巡检和周期对账把内部权威源与渠道账单、库存明细或通知回执匹配。自动修复达到预算后进入审批,人工调整生成新流水,禁止直接改表抹平差异。
安全上按最小权限控制查询,敏感标识脱敏或加密,保留期按资金、库存与隐私要求分类;TraceId(链路标识)只做技术关联,不是唯一业务键。验证通过故意丢回调、重复消息和写后断连,确认审计仍能重建时间线、发现差异并支持修复。最终完整性用逐笔对账证明,而不是用采样链路或日志搜索结果推断。
追问 1:审计流水可以为了节省空间采样吗?
直接回答:关键资金、库存与严重报警事实不能采样;技术遥测可按策略采样。
追问 2:人工修复为何不能直接更新最终状态?
直接回答:会丢失原因和责任链,应通过审批生成可追溯调整或冲正流水。
追问 3:审计记录是否可以写完整支付报文?
直接回答:只保留必要证据并脱敏或加密,避免泄露密钥、卡号和个人信息。
- 问题(综合题):请为订单到库存、支付和物流的调用链设计一套完整治理方案。
考点:注册发现、负载、超时、重试、幂等、隔离、观测、审计。
口述答案:入口先通过可信服务目录发现实例,本地列表记录版本和陈旧时间,负载选择过滤未就绪与短时隔离实例,再结合区域、版本、在途请求和静态权重选目标;连接池感知摘流并渐进排空。新实例完成预热后接流,旧实例先摘流再排空,控制目录传播和旧连接窗口。
用户请求携带业务幂等键和端到端 Deadline(截止时间)。订单服务按剩余预算分配库存、支付和返回阶段,连接、排队与读取分别受限;只在最接近失败源的一层有限重试,采用退避、抖动和 Retry Budget(重试预算)。库存以数据库余量条件、版本和唯一冻结流水守正确性,支付超时保持未知并同号查单,分布式锁只减少热点竞争。
资源按故障域隔离:库存与支付保留核心线程和连接,第三方物流使用独立池、并发上限与有界队列。外部依赖慢调用越界后熔断,物流转可靠异步受理;入口按租户与接口限流,过期低价值工作卸除。降级返回缓存版本、处理中凭证或明确拒绝,任何未执行动作不伪装成功。恢复通过半开探测、连接预热与分级放量,实时与积压分配独立预算。
Metrics(指标)发现流量、错误、分位与饱和度,Trace(链路追踪)定位慢跨度,Log(日志)解释实例分支;订单号、冻结号、支付单和运单审计证明业务事实。演练覆盖实例宕机、目录故障、响应丢失、下游变慢、重复消息和恢复风暴。验收既看延迟与可用性,也看库存守恒、资金唯一、运单重复和未知状态收敛,形成从治理到业务正确性的闭环。
追问 1:哪一项机制最先做?
直接回答:先明确业务不变量和端到端时限,再做超时、幂等和资源边界,其他机制围绕它们组合。
追问 2:服务目录健康能证明调用成功吗?
直接回答:不能,它只是候选状态;仍需业务健康、超时、调用反馈和结果查询。
追问 3:为什么治理方案必须包含恢复阶段?
直接回答:积压、重连和缓存回源会在恢复时叠加,缺少放量门禁容易二次过载。
- 问题(综合题):如何复盘一次从慢调用演变成重试风暴的事故?
考点:影响、时间线、放大系数、止血、根因、长期防线。
口述答案:复盘先还原影响,不把“下游慢”当完整根因。记录开始与恢复时间、受影响租户和订单、
P99(99 分位响应时间)、错误率、未知支付、库存失败和人工积压。按分钟对齐发布、配置、下游延迟、线程池、连接池、队列与重试QPS(每秒查询率),计算放大系数:入口1000 QPS(每秒查询率),三层各最多四次尝试,理论最坏可到64000 QPS(每秒查询率)。止血阶段收紧 Retry Budget(重试预算),关闭上层重复重试,对故障依赖熔断并限制并发;过期请求负载卸除,物流转异步,支付未知改为查单,核心库存和支付资源与报表、物流隔离。所有操作记录时间、操作者和指标变化,防止后续把处置副作用误作原始故障。保存线程、连接、目录版本和代表链路,不能只重启清现场。
根因通常是一条机制链:第三方耗时从
50ms(毫秒)升到3s(秒),读取超时过大使线程占满,网关、订单和客户端同时重试,连接池排队又不受总 Deadline(截止时间)限制,最终健康检查仍正常但业务已假死。要分别指出触发因素、放大器和缺失防线,而不是笼统归因网络波动。长期修复包括端到端预算、单层有限重试、退避抖动、重试预算、并发隔离、慢调用熔断和渐进恢复。回归测试重现相同延迟曲线,证明总下游流量受控、核心池有余量、过期工作被停止。最后逐笔核对支付与库存,确认事故期间重复副作用和未知状态已闭环,再更新容量与演练基线。
追问 1:下游恢复后为何还要保持重试预算?
直接回答:实时流量、积压和重连仍会叠加,立即放开会造成二次过载。
追问 2:健康检查正常为何仍会雪崩?
直接回答:心跳线程可正常,而业务线程、连接和队列已经耗尽,需要就绪与业务探测。
追问 3:根因和放大器如何区分?
直接回答:下游变慢是触发,超时过大、多层重试和共享资源是把局部故障扩大的机制。
- 问题(综合题):如何用数据为限流、线程池、连接池和队列做容量估算?
考点:到达率、耗时、在途数、突发、总连接、验证边界。
口述答案:容量估算从业务峰值和依赖分位开始。假设物流稳定峰值
100 QPS(每秒查询率),平均耗时200ms(毫秒),理论平均在途约20;但P99(99 分位响应时间)为2s(秒)时,尾部阶段可能需要更高并发,所以先用历史分布和压测选执行上限,例如60,再保留进程总线程给库存与支付,不能把全部200个线程交给物流。连接池不应盲目等于线程数。若协议一请求占一连接,连接上限需覆盖目标并发并留建连余量;若多路复用,则按并发流限制而非连接条数。还要计算集群总连接:每个应用实例
50条,扩到40个实例就是2000条,必须小于渠道或数据库全局上限。连接借用有超时,恢复建连限速。限流同时控制速率与并发。令牌桶速率接近可持续吞吐,桶容量只覆盖允许突发;慢调用时并发限制会先保护资源。有界队列按允许额外等待乘稳定消费速率估算,例如
100 QPS(每秒查询率)和200ms(毫秒)等待约对应20个请求,再加小幅余量;队列1000只会产生十秒级过期工作。模型最终必须压测校准。逐步提高流量并注入延迟,观察吞吐何时不再增长、
P99(99 分位响应时间)何时拐点、线程与连接何时饱和,再把稳定点以下的容量作为安全上限。按租户和业务优先级验证公平性,扩缩容重新计算总连接;容量配置与报警阈值、降级和恢复预算一起版本化,不能靠一次经验值永久使用,季度容量演练还要覆盖依赖降速场景。追问 1:平均耗时能否直接用于线程数?
直接回答:只能作初估,尾延迟、阻塞比例和峰值会决定资源风险,必须看分布与压测。
追问 2:队列容量为何与等待时间相关?
直接回答:队列是延迟预算,超过可等待时间的容量只会保存注定过期的工作。
追问 3:扩容应用为何可能压垮数据库?
直接回答:每实例连接池随实例数线性叠加,应用吞吐增长可能超过数据库连接与执行能力。
- 问题(综合题):请给出一段 WMS(仓储管理系统)稳定性治理项目话术。
考点:背景量级、错误方案、机制链、业务结果、验证与反思。
口述答案:项目背景是 WMS(仓储管理系统)大促波次下单与库存冻结集中,平时约
800 QPS(每秒查询率),峰值达到3000 QPS(每秒查询率);同时跨境物流渠道偶发从100ms(毫秒)升到数秒。旧方案各层统一三次重试、共享线程池,物流变慢时订单线程被占满,注册心跳仍正常,最终连库存查询也超时。我们先通过指标和链路确认慢跨度,再用业务流水核对超时请求是否已冻结。改造第一层是正确性。库存请求使用订单行级幂等键,数据库唯一冻结流水和带余量条件的原子更新守住不超卖;分布式锁只降低热点冲突。支付与物流响应超时保持未知,复用业务号主动查单,达到预算进入人工。任何降级都返回处理中、明确拒绝或带版本缓存,不把未执行写成成功。
第二层是资源治理。入口 Deadline(截止时间)向下传播,连接、排队与执行分别限时;重试收敛到客户端一层,采用退避抖动和
10%Retry Budget(重试预算)。物流独立线程与连接池,使用并发上限、有界队列和慢调用熔断;库存和支付保留核心资源。恢复后先半开探测、限速建连,再把实时与积压分配独立额度渐进放量。结果上要用真实数据表达,例如下游最坏放大从理论
64倍压到不超过1.1倍,物流故障时核心库存接口仍满足既定成功率,未知订单在目标窗口内收敛。验证包括慢依赖、提交后断连、实例下线和恢复风暴演练;最终以库存守恒、重复运单、支付差异和审计队列闭环。反思是韧性不是组件清单,而是业务不变量、时间预算、资源隔离和证据模型共同设计。追问 1:项目收益能只说可用性提升吗?
直接回答:不够,应给放大倍数、尾延迟、核心成功率、未知态收敛和业务差异等可复核指标。
追问 2:为何心跳正常仍要摘流?
直接回答:心跳不代表业务线程和依赖可用,就绪与真实调用反馈才决定是否接流。
追问 3:这套方案最关键的底线是什么?
直接回答:库存与资金不变量留在权威数据库和流水,治理机制只能控制时间、流量和资源。
- 问题(综合题):超时、重试、限流、熔断、隔离、降级和背压应该按什么顺序组合?
考点:机制职责、触发顺序、失败语义、恢复闭环。
口述答案:我不把这些机制理解为固定串行中间件,而按职责组合。首先有端到端 Deadline(截止时间)和取消传播,限定一次请求最多占用多久;入口限流和并发限制决定当前容量允许谁进入,有界排队只吸收短突发。请求进入后由负载均衡选择健康且有余量的实例,连接池借用也受剩余预算约束。
调用失败时先按错误语义判断是否重试,只有瞬时、幂等且预算充足的错误才在单层有限尝试,使用退避、抖动和 Retry Budget(重试预算)。依赖持续慢或失败达到足量样本,Circuit Breaker(熔断器)Open(打开)以快速阻止继续施压;Bulkhead(隔离舱)从资源层保证该依赖不会耗尽库存、支付等其他路径。它们分别控制时间、额外流量和故障域,不能互相替代。
当能力不足时,Backpressure(背压)让生产者减速,无法协作时按优先级 Load Shedding(负载卸除);Degradation(降级)定义用户还能得到的真实结果。商品读可返回带版本缓存,物流写可可靠异步受理,支付未知查单,库存无法确认则待确认或拒绝。所有结果有业务号、状态查询和审计,不能为了技术成功率统一返回成功。
恢复顺序同样属于组合:半开小流量探测、实例和连接预热、实时与积压分配配额,再分级放量。Metrics(指标)看流量、错误、延迟和饱和度,Trace(链路追踪)与 Log(日志)解释过程,业务审计证明库存、资金和运单事实。最终选型从不变量、时限和资源开始,按故障演练验证机制之间没有冲突或重复放大。
追问 1:限流和熔断谁先?
直接回答:入口限流先控制总体容量,熔断在调用依赖前判断其近期健康;逻辑上可同时存在于不同边界。
追问 2:隔离后是否无需熔断?
直接回答:仍需要,隔离限制损失范围,熔断减少隔离池内无效调用和恢复压力。
追问 3:背压失败后怎么办?
直接回答:入口限流、可靠缓冲和受控卸除,并按业务优先级保留不可丢工作。
官方资料与版本边界
以下链接于 2026-07-14 以 HTTP(超文本传输协议)状态核验。本文讲的是机制与失败边界,不把任一产品当前默认值泛化到所有小版本;落地时仍需按项目锁定的发布版本、兼容矩阵和配置参考复核。
- Nacos(服务治理平台)官方概览:用于核对动态服务发现、配置与服务管理的产品职责边界。
- Resilience4j(容错库)Circuit Breaker(熔断器)官方文档:用于核对状态机、滑动窗口、最小调用数与半开探测概念。
- Resilience4j(容错库)Retry(重试)官方文档:用于核对最大尝试、等待策略、异常分类和事件指标能力。
- OpenTelemetry(开放遥测标准)Context Propagation(上下文传播)官方文档:用于核对上下文注入、提取和跨边界传播概念。
- OpenTelemetry(开放遥测标准)Sampling(采样)官方文档:用于核对头部采样、父级采样与采样决策边界。
- AWS Builders’ Library(亚马逊构建者资料库)超时、重试、退避与抖动:用于核对重试放大、退避、抖动和令牌预算的工程原则。
- Google SRE(谷歌站点可靠性工程)过载处理:用于核对请求成本、排队、负载卸除和优雅降级原则。
- Envoy(服务代理)Circuit Breaking(熔断)官方文档:用于核对连接、请求、重试和连接池资源阈值的代理侧边界。
