九、微服务、发布、容量与可靠性进阶(81~90)

81. 如果让你设计一个 RPC 框架,核心模块有哪些?

场景与难点。 RPC 框架要让调用像本地方法一样简单,但底层要处理序列化、连接、负载均衡、超时、重试、服务发现、熔断和观测。面试重点不是造轮子,而是说清边界。

方案。 客户端通过 IDL 生成 stub,调用时走序列化、连接池、负载均衡和拦截器。服务端注册服务和方法,做反序列化、执行、返回。控制面提供服务发现和配置;数据面负责请求。框架内置 deadline、trace、metrics、错误码规范和限流熔断插件。

具体示例

具体设定。 OrderService.GetOrder 被 100 个服务调用,P99 要小于 50ms。

落地例子。 客户端从注册中心拿实例列表,按 P2C + 权重选实例;每个实例维护 HTTP2/长连接池。请求带 trace_id 和 deadline,超时后按幂等配置决定是否重试。服务端指标按 method、caller、error_code 维度上报。

面试可讲。 RPC 框架的关键是治理能力:超时、重试、负载均衡、观测和兼容,而不是只讲网络传输。

82. 服务发现和负载均衡怎么设计,避免流量打到坏实例?

场景与难点。 服务实例会扩缩容、重启、异常、跨机房。客户端如果拿到过期实例或负载均衡不感知延迟,就会把流量打到坏节点。

方案。 实例启动后向注册中心注册,并通过心跳或租约维持;停止前先摘流再退出。客户端本地缓存实例列表,通过 watch 或轮询更新。负载均衡结合权重、机房、健康状态、延迟和错误率。异常实例进入熔断或降权,恢复后小流量探测。

具体示例

具体设定。 某服务扩容 100 台新实例,其中 10 台启动后依赖连接失败。

落地例子。 实例只有通过 readiness check 才注册为可用;客户端 P2C 选择两个候选,优先选 inflight 少且延迟低的实例。错误率超过阈值的实例本地熔断 30 秒,半开时只放少量请求探测。

面试可讲。 服务发现解决“有哪些实例”,负载均衡解决“选哪个实例”。健康检查、摘流和半开探测是关键。

83. 熔断、自适应并发和限流之间有什么区别?如何组合?

场景与难点。 三者都在保护系统,但目标不同。限流控制进入流量,熔断避免持续打坏依赖,自适应并发根据延迟和错误动态调整并发。

方案。 入口限流按用户/租户/API 防止过载;调用下游时设置熔断器,错误率或超时率过高则快速失败;自适应并发根据排队时间或 P99 调整最大 inflight。三者都要有降级响应和观测指标,避免静默丢请求。

具体示例

具体设定。 推荐服务依赖特征服务,特征服务偶发延迟从 20ms 升到 2s。

落地例子。 推荐服务给特征调用设置 50ms deadline;超时率超过 20% 熔断 10 秒,使用缓存特征或默认特征。自适应并发把对特征服务的 inflight 从 200 降到 50,防止排队扩大。

面试可讲。 熔断不是限流。组合目标是让故障局部化,并给用户可接受的降级结果。

84. 线程池、连接池打满导致雪崩,怎么隔离?

场景与难点。 一个慢依赖会占满线程池或连接池,导致同进程其他接口也不可用。要区分 CPU、IO、连接池、队列和下游限制。

方案。 按依赖或业务优先级拆线程池/连接池,使用有界队列和快速失败。连接池设置最大连接、获取超时、空闲回收和慢查询监控。对低优先级任务限流或降级,保护核心接口。指标要看队列长度、活跃线程、连接等待时间和拒绝数。

具体示例

具体设定。 报表接口查数仓很慢,占满 Web 线程,导致下单接口也超时。

落地例子。 报表查询迁到独立线程池和连接池,队列最多 100,超过直接返回“稍后重试”;下单接口使用独立核心线程池,不受报表影响。慢报表改为异步任务。

面试可讲。 隔离的关键是有界资源和优先级。共享无限队列是雪崩常见来源。

85. 如何做到服务无损发布和优雅停机?

场景与难点。 服务发布时如果直接杀进程,正在处理的请求会失败,注册中心也可能还把流量打到旧实例。长连接、MQ 消费者和定时任务更复杂。

方案。 停机分三步:先从注册中心摘流或 readiness 置 false;等待负载均衡不再分配新请求;处理完已有请求后关闭。设置最大 drain 时间,超过后中断。MQ 消费者先停止拉新消息,处理完已拉取消息再提交 offset。发布按批次灰度,观察指标后继续。

具体示例

具体设定。 一个订单服务实例正在处理 30 个请求,发布系统要重启它。

落地例子。 实例收到 SIGTERM 后立刻 readiness=false,注册中心 5 秒内摘流;HTTP 服务不接新连接,等待 inflight 请求完成,最多 30 秒。MQ consumer 暂停 poll,处理完当前 batch 后提交 ACK,再退出。

面试可讲。 优雅停机要和注册中心、负载均衡、连接池、MQ 消费一起设计。只捕获 SIGTERM 不够。

86. 自动扩缩容怎么设计,避免越扩越慢或反复抖动?

场景与难点。 扩容指标选错会造成抖动,比如 CPU 低但队列积压高,或者扩容太慢赶不上突发。缩容也可能杀掉正在处理任务的实例。

方案。 根据业务类型选择指标:在线服务看 QPS、CPU、P99、inflight;消费者看 lag、消费速率和最老消息年龄;任务系统看队列长度和任务耗时。扩容要有预热和冷启动时间,缩容要有冷却窗口和优雅摘流。重大活动采用预测扩容 + 自动扩容结合。

具体示例

具体设定。 MQ 消费者 CPU 只有 30%,但消息 lag 从 10 万涨到 5000 万。

落地例子。 如果只按 CPU 不会扩容。应按 lag / per_instance_consume_rate 估算需要实例数,并检查下游 DB 是否能承受。扩容后每个实例预热连接池,消费者按分区重新均衡。

面试可讲。 自动扩缩容不是看 CPU 一项。要根据瓶颈指标扩容,并确认下游容量。

87. 大促或春晚级活动前如何做容量评估和压测?

场景与难点。 容量评估不是拍脑袋加机器,要根据流量模型、依赖链路和降级策略计算。压测还要避免污染真实数据。

方案。 先拆入口流量、核心接口 QPS、读写比、峰值系数、热点比例和依赖放大倍数。压测使用影子流量或压测标识隔离数据,覆盖缓存命中、DB、MQ、下游和第三方。压测结果产出容量水位、瓶颈点、扩容计划和降级开关。活动前做预案演练。

具体示例

具体设定。 预计活动入口峰值 100 万 QPS,领取接口有效请求 10 万 QPS。

落地例子。 网关压测 100 万 QPS 静态校验,领取服务压 10 万 QPS,库存和资格服务压有效流量。压测请求带 x-test-traffic=true,写入影子表和影子 MQ,不影响真实库存。

面试可讲。 容量评估要算流量漏斗和依赖放大。压测必须可隔离、可观测、可回滚。

88. 核心依赖故障时,如何做降级和隔离?

场景与难点。 真实线上故障常来自依赖服务、第三方 API、存储或网络。调用方要能在依赖异常时保护自己,并给用户可接受的结果。

方案。 先给依赖分级:强依赖失败则核心流程失败,弱依赖失败可降级。强依赖要有超时、重试预算、熔断和备用路径;弱依赖使用缓存、默认值、异步补偿或隐藏模块。降级开关要可灰度,降级结果要可观测。

具体示例

具体设定。 下单页依赖推荐优惠券服务,但该服务超时。

落地例子。 下单主流程不等待优惠券推荐超过 50ms;超时则隐藏推荐券模块,用户仍可手动选择已有券。服务记录降级指标,优惠券服务恢复后自动半开探测。

面试可讲。 先区分强弱依赖。不要让非核心推荐模块拖垮交易主链路。

89. 共享资源池如何做公平调度,避免大客户占满?

场景与难点。 批量任务、导出、模型训练、消息发送等共享资源容易被少数大租户占满。公平调度要兼顾优先级、配额和吞吐。

方案。 每个租户有基础配额、突发额度和优先级。调度器按 weighted fair queue 或令牌桶分发任务,核心业务队列和普通业务队列隔离。空闲资源可借用,但租约到期或高优先级任务到来时要回收。任务状态可抢占或可暂停时,支持优先级抢占。

具体示例

具体设定。 一个头部商家提交 1 亿条导出任务,小商家的 1 万条导出不能排队一天。

落地例子。 导出平台按租户维护队列,头部商家权重 10,小商家权重 1,但每轮调度都给所有活跃租户机会。单租户最大并发 20,平台总并发 500。小任务可走快速队列。

面试可讲。 公平不是平均,而是在配额、权重和优先级下避免饥饿。要讲借用和回收机制。

90. 配置推送如何做到秒级生效,同时避免推送风暴?

场景与难点。 配置中心需要快速生效,但如果每次变更都让所有客户端同时拉全量,会造成推送风暴。客户端断连、漏通知和配置错误也要处理。

方案。 推送只传版本号,客户端随机抖动后拉差量或按需拉全量。配置按 namespace 分片,客户端只订阅自己需要的 namespace。服务端保留版本历史和灰度规则;客户端校验 schema 和签名后原子切换,失败继续使用旧版本。定期全量校准防漏通知。

具体示例

具体设定。 5000 个服务实例订阅风控阈值,运营把阈值从 80 改到 90,希望 10 秒内生效。

落地例子。 配置中心发布 risk_threshold:v32,通过长连接通知实例。实例在 0 到 3 秒随机延迟后拉取差量,校验通过后切换;如果拉取失败,继续使用 v31 并告警。

面试可讲。 快速生效和防风暴要一起设计。版本通知、随机抖动、差量拉取、旧版本兜底是关键。

更多推荐