分布式治理面试
分布式治理面试
可观测性
【简单】什么是可观测性?它包含哪三大支柱?⭐⭐
可观测性(Observability) 是指通过系统的外部输出(指标、日志、链路)来推断系统内部状态的能力。在云原生和微服务架构下,系统由众多分布式服务组成,传统监控已不足以应对复杂故障定位,可观测性应运而生。
可观测性三大支柱
可观测性由三大支柱构成,三者相互补充、协同定位问题:
| 维度 | Metrics(指标) | Logging(日志) | Tracing(链路追踪) |
|---|---|---|---|
| 核心作用 | 监控告警、趋势分析 | 故障定位、审计 | 请求级故障定位、性能分析 |
| 数据特征 | 数值型、时序、聚合 | 文本、离散事件 | 树形/DAG 结构、有因果关系 |
| 数据量 | 小(聚合后) | 大(每请求多条) | 中(采样后) |
| 成本 | 低 | 高(存储 + 检索) | 中 |
| 典型场景 | "CPU 使用率 90%" | "NullPointerException at line 42" | "请求 A→B→C 共耗时 500ms,B 占 400ms" |
| 代表工具 | Prometheus、Micrometer | ELK、Loki、Fluentd | Jaeger、Zipkin、SkyWalking |
三者的协同关系
- Metrics 发现问题:告警系统基于指标触发告警(如错误率 > 1%)。
- Tracing 定位范围:通过 TraceID 找到出问题的请求链路,定位到具体服务。
- Logging 查明根因:在出问题的服务中,通过 TraceID 关联日志,查看详细错误栈。
关键实践
在日志中打印 TraceID,实现 Metrics、Logging、Tracing 三者的关联。这是可观测性的核心实践,没有关联,三大支柱就是三个孤岛。
可观测性 vs 监控
- 监控:是可观测性的子集,关注"已知未知"(known unknowns),即预定义的指标和告警。
- 可观测性:更广泛,关注"未知未知"(unknown unknowns),即探索性分析,能处理意料之外的故障模式。
【中等】OpenTelemetry 是什么?为什么重要?⭐⭐
OpenTelemetry(简称 OTel)是 CNCF 主导的可观测性数据采集标准,由 OpenTracing 和 OpenCensus 两个项目合并而来,目标是统一 Metrics、Logging、Tracing 三类数据的采集、处理和导出。
解决的核心问题
在 OpenTelemetry 之前,可观测性领域存在严重的厂商锁定问题:
- 应用集成 Zipkin 的 SDK 后,想切换到 Jaeger 需要重写所有埋点代码。
- 不同语言、不同工具的埋点 API 各不相同,跨语言维护成本高。
- Metrics、Logging、Tracing 各自独立的 SDK,集成复杂。
OpenTelemetry 通过提供统一的 API 和 SDK,让应用与后端存储/展示工具解耦。
架构
应用代码
│
▼
OpenTelemetry API(厂商无关的接口)
│
▼
OpenTelemetry SDK(实现,可配置 Exporter)
│
▼
Exporter(导出器:OTLP/Jaeger/Prometheus/...)
│
▼
后端(Jaeger/Zipkin/Prometheus/Tempo/...)核心组件
- API:厂商无关的接口定义,应用代码只依赖 API。
- SDK:API 的实现,可配置采样、批处理、导出器等。
- Collector:独立部署的数据收集代理,接收、处理、导出遥测数据,支持多后端转发。
- Instrumentation Libraries:主流框架(HTTP、gRPC、JDBC、Kafka 等)的自动埋点库。
价值
- 避免厂商锁定:切换后端只需修改 Exporter 配置,无需改代码。
- 统一三类数据:Metrics、Logging、Tracing 共用一套 SDK 和 Context 传播机制。
- 自动埋点:通过 Java Agent 等机制,零代码侵入接入主流框架。
- 生态广泛:已成为行业标准,主流后端(Jaeger、Prometheus、Datadog、Grafana Cloud 等)均支持 OTLP 协议。
【中等】Dapper 论文的核心思想是什么?⭐⭐
Google 于 2010 年发表的 《Dapper, a Large-Scale Distributed Systems Tracing Infrastructure》 是分布式链路追踪的奠基性论文,几乎所有主流链路追踪系统(Zipkin、Jaeger、SkyWalking)都受其启发。
核心概念
- Trace(追踪):一次完整的分布式请求链路,由全局唯一的 TraceID 标识。
- Span(跨度):链路中的一个工作单元,对应一次方法调用。Span 包含:
- SpanID:本 Span 的唯一标识。
- ParentSpanID:父 Span 的 ID(建立调用关系)。
- 开始/结束时间:计算耗时。
- Annotations:关键事件点。
- BinaryAnnotations:键值对形式的标签(如 HTTP 状态码、业务字段)。
- 调用树:通过 ParentSpanID 将所有 Span 组织成树形结构,还原调用链路。
核心设计
埋点(Instrumentation):
- 应用级埋点:在关键路径(如 RPC 客户端/服务端、数据库访问)植入埋点代码。
- 线程本地存储:使用 ThreadLocal 传递 Span 上下文。
- 跨进程传播:通过请求头(如 HTTP Header、RPC metadata)将 TraceID/ParentSpanID 传递给下游。
采样(Sampling):
- 链路追踪数据量大,全量采集成本高。
- Dapper 采用头部采样(Head Sampling):在链路入口决定是否采样,若采样则整条链路都采集;若不采样则整条链路都不采集。避免下游重复决策。
- 采样率可动态调整,故障时提高采样率。
收集与存储:
- 应用将 Span 数据异步上报到本地 Agent(降低网络开销)。
- Agent 定期批量上报到 Collector。
- Collector 写入存储(Bigtable / Cassandra / ES)。
低开销:
- Dapper 的开销控制在请求总耗时的 1% 以内。
- 关键手段:异步上报、批量处理、采样、本地缓冲。
关键洞察
- 采样而非全量:1/1024 的采样率已足够发现绝大多数问题。
- 上下文透传是核心:TraceID/ParentSpanID 的跨进程传递是链路串联的基础。
- 低侵入:通过框架级埋点(而非业务代码埋点)实现低侵入。
链路追踪
【中等】如何实现链路追踪?⭐⭐
链路追踪是一种分布式系统的可观测性技术,用于记录一次请求在多个服务间的完整调用路径、调用耗时以及执行状态,帮助开发者理解系统行为、定位性能瓶颈和排查故障。
核心概念
- Trace:一次完整的请求链路,由全局唯一的 TraceID 标识。
- Span:链路中的单个工作单元,记录一次远程调用或本地操作,包含 SpanID、ParentSpanID、开始/结束时间、标签等。
- 上下文传播:通过 HTTP 头、RPC 元数据等方式将 TraceID 和 SpanID 透传给下游服务,实现调用链串联。
实现原理
- 埋点:在服务框架或业务代码中植入追踪 SDK,自动拦截 RPC 调用、HTTP 请求、数据库访问等关键操作,创建 Span。
- 采样:为避免性能开销,通常采用采样策略(如固定概率采样、动态采样),只记录部分请求的链路数据。
- 传输:追踪数据异步上报至 Collector(收集器),常用协议有 gRPC、Thrift、HTTP。
- 存储:Collector 将数据存入后端存储(如 Elasticsearch、Cassandra、HBase)。
- 展示:UI 服务提供查询界面,展示调用拓扑图和 Span 详情。
关键难点与对策
- 低侵入性:利用 Java Agent 字节码增强(如 SkyWalking)或框架拦截器(如 Spring Cloud Sleuth)实现无代码侵入。
- 低延迟:采样、异步上报、本地缓冲区,避免阻塞业务线程。
- 采样策略:固定概率采样简单但可能漏掉重要请求;动态采样根据流量自适应;头部采样可保证完整链路。
- 上下文传播:需支持多种协议(HTTP/gRPC/消息队列)的透传,处理异步线程传递(如 ThreadLocal 与线程池的兼容)。
- 存储压力:链路数据量大,需设计合理索引、TTL、降采样。
主流方案对比
- SkyWalking:Java Agent 探针,无代码侵入,支持多种语言,UI 功能强大,社区活跃。
- Zipkin:Twitter 开源,基于 Brave 库埋点,支持多种存储,轻量级。
- Jaeger:Uber 开源,受 Dapper 和 OpenZipkin 启发,原生支持 OpenTracing,适合云原生环境。
- Pinpoint:基于字节码注入,功能全面,但部署较重,依赖 HBase。
实践要点
- 采样率配置:生产环境一般 1%-10%,根据流量调整。
- 存储选型:ES 适合快速检索,但成本较高;Cassandra 适合高写入。
- 与日志、指标联动:在日志中打印 TraceID,实现链路与日志的关联;聚合 Span 数据生成服务拓扑和性能指标。
- 告警:基于链路错误率、延迟分位数设置告警。
配置中心
【简单】什么是配置中心?⭐⭐
配置中心核心作用
| 作用 | 说明 |
|---|---|
| 集中管理 | 所有服务配置统一存放,告别配置文件散落 |
| 动态更新 | 修改配置无需重启,实时生效 |
| 环境隔离 | 开发/测试/生产环境配置分离 |
| 版本追溯 | 配置变更可回滚、可审计 |
| 权限控制 | 配置修改需审批,防误操作 |
配置中心应用场景
- 开关控制:功能灰度、降级开关
- 参数调优:线程池大小、超时时间
- 业务规则:黑名单、费率配置
- 数据库连接:动态切换数据源
【困难】如何实现一个配置中心?⭐
配置存储方式
- 数据库:如 MySQL,存储结构化配置(表:namespace、key、value、版本、环境等)
- Git:配置文件版本化管理(Spring Cloud Config)
- 分布式 KV 存储:etcd/ZooKeeper,利用其强一致性和 watch 机制
- 本地文件:测试环境或简单场景
动态更新与通知
- 长轮询:客户端发起请求,服务端有变更立即返回,否则 hold 住请求一段时间
- 长连接:WebSocket 或 gRPC 流,服务端主动推送变更
- 对比版本号:客户端定期拉取对比本地版本,有变化则更新
- 消息广播:配置变更后,通过消息队列通知所有客户端
环境隔离
- Namespace/Group:逻辑隔离,如 dev、test、prod(Apollo 的 namespace)
- 独立数据库/表:不同环境使用不同数据库或表前缀
- Git 分支:不同环境对应不同分支(Spring Cloud Config)
- 配置文件命名:
application-dev.yml,application-prod.yml
灰度发布
- 按 IP/机器:指定某些实例优先应用新配置
- 按标签/用户:根据请求头或用户 ID 灰度
- 百分比灰度:逐步放量,监控稳定后全量
- 配置中心支持:如 Apollo 的灰度发布,先推送到灰度实例,验证后再全量
版本管理与回滚
- 版本号:每次修改生成新版本号,记录历史
- 历史记录表:存储每次变更的旧值、新值、操作人、时间
- 回滚操作:选择历史版本,将当前配置重置为指定版本
- 发布审批:重要配置修改需审批,避免误操作
减少客户端访问频率
- 本地缓存:客户端拉取配置后缓存到内存,减少网络请求
- 定期刷新:设置缓存过期时间(如 30 秒),到期后异步拉取
- 长轮询/长连接:变更时服务端主动通知,避免频繁轮询
DevOps
【简单】什么是灰度发布、金丝雀部署以及蓝绿部署?⭐⭐
- 金丝雀部署是实例维度的灰度,关注部署过程的安全
- 灰度发布是流量维度的控制,关注用户感知的平滑
- 蓝绿部署是环境维度的切换,关注切换速度与回滚能力
三者可组合使用,如先蓝绿部署,再通过金丝雀逐步切流。
灰度发布
灰度发布是一种平滑过渡的发布方式,指让部分用户继续使用旧版本,部分用户开始使用新版本,如果新版本运行稳定,则逐步扩大新版本范围,直至全部切换为新版本。
核心机制:
- 按流量比例或特定条件(如地域、用户标签)逐步放量
- 实时监控新版本运行状态,发现问题可随时回切
- 新旧版本同时在线,用户无感知
适用场景:功能迭代、AB测试、降低发布风险
金丝雀发布
金丝雀部署是灰度发布的一种具体实现方式,得名于“煤矿中的金丝雀”用于预警危险。
核心机制:
- 先部署少量新版本实例(金丝雀),仅引入一小部分流量
- 验证金丝雀实例的稳定性、性能、业务逻辑
- 确认无误后,逐步替换剩余旧版本实例
关键特征:先小范围验证,再滚动替换。与灰度发布的区别在于,金丝雀通常指实例级别的分批替换,而灰度更强调流量控制。
蓝绿发布
蓝绿部署是一种零停机发布策略,通过维护两套独立的环境(蓝环境、绿环境)来实现快速切换。
核心机制:
- 蓝环境:当前生产环境,运行旧版本
- 绿环境:新版本部署环境,完全独立
- 绿环境验证通过后,通过路由切换(如负载均衡器)将所有流量从蓝瞬间切换到绿
- 蓝环境作为备份,若发现问题可立即切回
关键特征:瞬间切换、快速回滚、环境完全隔离。
核心区别
| 维度 | 灰度发布 | 金丝雀部署 | 蓝绿部署 |
|---|---|---|---|
| 核心思想 | 逐步放量 | 先验证再替换 | 环境切换 |
| 流量切换 | 逐步调整比例 | 随实例替换自然迁移 | 瞬间全量切换 |
| 回滚方式 | 逐步减少新版本流量 | 重新部署旧版本 | 切回原环境 |
| 资源消耗 | 适中 | 适中 | 高(需双倍资源) |
| 适用场景 | 功能发布、AB测试 | 滚动升级、风险验证 | 核心系统、版本大升级 |
网关
【简单】什么是网关?⭐⭐
网关是连接不同网络或协议的入口节点,提供了流量入口统一管理的能力。

网关的核心功能大致如下:
- 请求代理/反向代理:客户端向 API 网关发送 HTTP 请求。
- 安全防护:跨域(cors)、防 XSS 攻击、IP 黑白名单、WAF 规则、请求体大小限制、风控等。
- 认证授权:支持 JWT、OAuth2、API 等认证方式,统一进行身份认证和权限控制。
- 流量控制:对请求应用速率限制规则。如果超过限制,请求将被拒绝。
- 动态路由:根据请求路径、Host、Header、JWT claim 等信息灵活匹配到上游服务,不重启即可更新路由规则。
- 负载均衡: 将请求均匀分布到多个服务器。
- 缓存:暂时存储响应,减少重复处理的需求。
- 协议转换:API 网关将请求转换为相应协议,并发送到后端微服务。
- 可观测:对请求进行埋点,采集日志、指标、链路监控数据,以便于全方位监控。
【中等】网关如何技术选型?⭐⭐

主流网关方案对比:
| 网关 | 核心特点 | 优势 | 适用场景 |
|---|---|---|---|
| Kong | 基于 Nginx + Lua,插件丰富 | 300+社区插件,生态好 | 云原生、需要灵活扩展 |
| APISIX | 国产高性能,支持 WASM 插件 | 动态路由,性能优异 | 高并发、国产化 |
| Spring Cloud Gateway | Java 生态,Reactive 编程 | 与 Spring Boot 无缝集成 | Java 技术栈微服务 |
| Nginx | 成熟稳定,高吞吐 | 10 万+RPS,内存占用低 | 传统架构、静态内容 |
| Envoy | 云原生,xDS 动态配置 | 低延迟,服务网格集成 | K8s 环境、Istio 配合 |
| Traefik | 自动服务发现 | 配置简单,原生支持 K8s | K8s 原生环境 |
| 云厂商网关 | 全托管免运维 | 99.99%SLA,安全集成 | 上云首选、Serverless |
选型建议:
- Java 技术栈 → Spring Cloud Gateway
- K8s 原生 → Traefik 或 Envoy+Istio
- 高并发插件生态 → Kong 或 APISIX
- 不想运维 → 云厂商 API 网关
- 简单可靠 → Nginx
【中等】网关如何实现 API 版本管理?⭐
版本管理方式
| 方式 | 原理 | 示例 | 特点 | 适用场景 |
|---|---|---|---|---|
| URI 路径 | 版本号在 URL 路径中 | /v1/orders /v2/orders | 最直观、缓存友好 | 最常用,清晰直观 |
| 请求参数 | 版本号在 Query 参数 | /orders?version=1 | 优点是 URL 路径干净 缺点是缓存命中率低 | 简单临时场景 |
| Header 头 | 版本号在自定义 Header | Accept-Version: v1 | 版本参数容易和业务参数混在一起 CDN 缓存也容易污染 | 保持 URI 整洁 |
| 域名 | 不同版本用不同域名 | v1.api.com v2.api.com | 隔离性强,运维复杂 | 大规模版本隔离 |
版本兼容性原则
| ✅ 兼容(无需新版本) | ❌ 不兼容(必须新版本) |
|---|---|
| 新增可选字段 | 删除字段/接口 |
| 扩展现有枚举 | 修改字段类型/名称 |
| 放宽输入约束 | 修改必填字段 |

服务网格
【简单】什么是服务网格?⭐⭐
服务网格是基础设施层的一个专用层,用于处理服务间通信,其核心特点是将服务治理能力(如服务发现、负载均衡、熔断、可观测性)从业务代码中下沉到由轻量级网络代理组成的中间层。
服务网格通常由数据平面和控制平面构成。
- 数据平面
- 由一组与业务容器并行运行的网络代理组成,通常采用Sidecar模式部署。
- 每个代理拦截对应服务的所有进出流量,执行路由、负载均衡、认证、监控等功能,而对业务容器本身无侵入。
- 控制平面
- 管理并配置数据平面的代理,下发统一的策略和规则。
- 提供服务发现、配置管理、证书签发、访问控制等能力,并聚合来自代理的遥测数据。

核心优势
- 治理下沉,业务无感:服务治理能力从代码中剥离,开发者只需关注业务逻辑,升级治理能力无需修改代码。
- 多语言支持:Sidecar代理独立于业务应用,任何语言开发的服务都可获得统一的治理能力。
- 精细化流量管控:支持根据权重、Header、路径等条件进行灰度发布、A/B测试和金丝雀发布。
- 可观测性增强:自动收集服务拓扑、指标、日志和链路追踪数据。
- 安全加固:提供服务间的双向TLS加密、细粒度的访问控制策略。
与现有技术的关系
- 对比传统微服务框架:Spring Cloud等框架将治理能力集成在SDK中,对业务有侵入,且多语言支持困难。服务网格将能力剥离到独立代理层。
- 与Kubernetes的关系:服务网格通常运行在Kubernetes之上,利用其调度能力部署Sidecar。K8s解决了容器编排问题,服务网格解决了Pod间的通信治理问题。
主流产品
- Istio:目前最流行的服务网格,功能丰富,生态强大,但复杂度较高。
- Linkerd:专注于轻量、简单和高性能,对Kubernetes原生支持好。
- Consul Connect:由HashiCorp推出,与Consul服务发现生态深度集成。
【简单】什么是 Sidecar?⭐
Sidecar 是一种部署设计模式,指在应用程序容器旁边启动一个辅助进程,两者共享相同的生命周期和网络命名空间。
核心工作原理
- 辅助进程作为本地代理,拦截进出主应用的所有网络流量。
- 主应用对 Sidecar 无感知,所有服务治理逻辑(如服务发现、负载均衡、熔断、监控)都在 Sidecar 中执行。
- 应用只需关注业务代码,Sidecar 负责处理分布式系统通信的复杂问题。
在服务网格中的角色
- Sidecar 构成了服务网格的数据平面,每个服务实例伴生一个 Sidecar 代理。
- 所有服务间调用都通过双方的 Sidecar 完成,形成去中心化的网状通信架构。
- 控制平面统一配置所有 Sidecar,实现全局一致的治理策略。
核心价值
- 业务无侵入:治理能力从代码中剥离,开发者无需关注底层通信细节。
- 多语言友好:Sidecar 独立于应用,任何语言开发的服务都能获得相同的治理能力。
- 统一管控:所有服务的行为可通过控制平面集中配置,无需逐个修改业务代码。
- 可观测性增强:Sidecar 自动采集流量指标、日志和链路数据。
【中等】服务网格 vs. 网关?⭐
网关和服务网格虽然都用于管理服务通信,但它们解决的问题和所处的架构层级有本质区别。
网关是系统的门户,负责与外部的交互;服务网格是系统的血管,负责内部通信的治理。

核心区别
| 维度 | 网关 | 服务网格 |
|---|---|---|
| 流量方向 | 处理南北向流量(外部请求进入内部系统) | 处理东西向流量(内部服务之间的相互调用) |
| 部署位置 | 部署在系统边界,作为整个集群或业务域的单一入口 | 以 Sidecar 模式伴随每个服务实例部署,形成网状结构 |
| 治理粒度 | 粗粒度,关注外部请求的路由、认证、限流 | 细粒度,关注每个服务间调用的重试、超时、熔断、加密 |
| 功能范围 | 协议转换、请求聚合、IP黑白名单、防爬虫等 | 服务发现、负载均衡、可观测性、mTLS、访问控制 |
| 变更影响 | 变更可能影响所有流入的流量,需谨慎操作 | 变更由控制平面下发,影响范围可控,对业务无感 |
逻辑关系
在典型微服务架构中,两者通常协同工作,并非替代关系:
- 入口处:所有外部请求先到达网关,由网关完成全局的认证、流控后,再路由到具体的后端服务。
- 内部调用:当服务A需要调用服务B时,流量被其伴生的Sidecar代理拦截,服务网格根据控制平面下发的策略处理这次调用(如选择实例、记录指标、自动重试)。
设计理念差异
- 网关是集中的:它是一个节点或一组节点,所有流量汇聚于此。
- 服务网格是分布的:治理能力被分散到每个服务旁边,形成无处不在的智能代理。
【中等】Istio vs Linkerd 有什么区别?⭐⭐
Istio 和 Linkerd 是最主流的两个服务网格产品,两者在架构、性能和易用性上有显著差异。
核心对比
| 维度 | Istio | Linkerd |
|---|---|---|
| 数据平面 | Envoy(C++,功能强大) | Linkerd2-proxy(Rust,轻量高性能) |
| 开发语言 | Go(控制平面)+ C++(数据平面) | Rust(数据平面)+ Go(控制平面) |
| 功能丰富度 | 非常丰富(流量管理、安全、可观测) | 精简(聚焦核心治理) |
| 复杂度 | 高(概念多、配置项多) | 低(简单易用) |
| 资源开销 | 较高(Envoy 内存占用大) | 极低(Rust 代理轻量) |
| 性能 | 良好 | 优秀(Rust 无 GC,延迟低) |
| mTLS | 支持(自动证书轮转) | 支持(自动证书轮转) |
| 多集群 | 支持(复杂) | 支持(较简单) |
| 社区生态 | 强大(Google/IBM/Lyft 背书) | 活跃(CNCF 毕业项目) |
| 学习曲线 | 陡峭 | 平缓 |
选型建议
- 功能优先、团队有能力运维 → Istio:功能最全,生态最大,适合对流量管控、安全策略有复杂需求的大型组织。
- 简单优先、性能敏感 → Linkerd:轻量、低延迟、易上手,适合中小规模或对性能要求高的场景。
- K8s 原生 + 渐进式 → 先用 Linkerd 起步,后续如需更复杂能力再迁移到 Istio。
Sidecar 的性能开销
服务网格引入 Sidecar 会带来额外延迟和资源开销:
- 延迟:每次调用经过 Sidecar 代理(入站 + 出站共 2 跳),增加约 1~3ms 延迟。
- 资源:每个 Pod 需额外分配 Sidecar 的 CPU 和内存(Istio/Envoy 约 100~200MB 内存/Pod)。
- 应对方案:eBPF(如 Cilium Service Mesh)、Sidecarless 架构(如 Istio Ambient Mesh)正在探索绕过 Sidecar 的方案。
服务容错
【简单】什么是服务容错?包含哪些手段?⭐⭐
服务容错(Fault Tolerance) 是指在分布式系统中,当部分服务或依赖出现故障时,系统仍能提供降级服务或快速失败,避免故障扩散导致雪崩。
容错的核心手段
| 手段 | 作用 | 典型实现 |
|---|---|---|
| 隔离 | 防止故障在资源间传播 | 线程池隔离、信号量隔离、集群隔离 |
| 超时 | 防止长时间等待拖垮系统 | 连接超时、读取超时、请求超时 |
| 限流 | 防止上游流量冲垮自身 | 令牌桶、漏桶、滑动窗口 |
| 熔断 | 防止被下游故障拖垮 | Circuit Breaker 状态机 |
| 降级 | 故障时返回兜底响应 | 静态降级、动态降级、Mock 降级 |
| 重试 | 应对瞬时故障 | 指数退避 + 抖动 |
| 回滚 | 故障后恢复到之前稳定版本 | 蓝绿回滚、版本回退 |
各手段的定位
上游服务 ──限流──► 本服务 ──熔断──► 下游服务
│ │
超时/重试 超时/重试
│ │
降级 降级
│ │
隔离 隔离- 限流:保护自己不被上游冲垮。
- 熔断:保护自己不被下游拖垮。
- 超时:防止任何一层长时间阻塞。
- 隔离:防止一个故障影响其他资源。
- 降级:故障时给用户兜底体验。
- 重试:应对瞬时抖动,但需配合幂等和退避。
【中等】服务降级有哪些策略?⭐⭐
服务降级是故障发生时,主动牺牲部分功能或质量,保证核心功能可用的策略。
降级策略分类
| 策略 | 说明 | 示例 |
|---|---|---|
| 返回默认值 | 故障时返回预设的兜底值 | 推荐服务故障,返回热门商品列表 |
| 返回缓存 | 故障时返回历史缓存数据(接受数据过期) | 库存查询故障,返回上次缓存库存 |
| 返回 Mock | 故障时返回模拟数据,保证流程不中断 | 风控服务故障,返回"低风险"默认结果 |
| 异步化 | 故障时将同步调用改为异步(先返回,后处理) | 短信发送故障,先返回成功,异步重试 |
| 功能关闭 | 故障时关闭非核心功能 | 大促时关闭评论、积分等非核心功能 |
| 读降级 | 读请求降级到缓存或静态数据 | 详情页故障,返回简化版静态页 |
| 写降级 | 写请求降级为异步(先存队列,后落库) | 下单故障,先写消息队列异步处理 |
降级的触发方式
- 手动降级(开关降级):通过配置中心下发开关,人工触发降级。适合可预见的流量高峰(如大促)。
- 自动降级(熔断降级):熔断器打开时自动降级。适合应对突发故障。
- 限流降级:超过限流阈值的请求直接降级返回。
- 超时降级:请求超时后返回降级响应。
降级的原则
- 有损服务:降级必然有损,关键是保核心、弃边缘。
- 分级降级:按业务重要性分级,逐级降级(如先降推荐、再降评论、最后降搜索)。
- 可观测:降级触发必须记录监控和告警,便于事后分析。
- 可恢复:降级是临时的,故障恢复后应及时取消降级。
【中等】如何设计一个高可用的微服务容错方案?⭐⭐⭐
容错设计原则
- 失败即常态:假设所有依赖都会失败,设计时必须考虑故障场景。
- 快速失败:宁可快速失败,也不要长时间阻塞(超时 + 熔断)。
- 优雅降级:故障时提供可接受的兜底体验,而非完全不可用。
- 隔离爆炸半径:一个服务的故障不应影响其他服务(隔离)。
- 可观测:所有容错行为必须可监控、可告警、可追溯。
端到端容错方案
1. 入口层(网关):
- 全局限流:保护整个集群不被外部流量冲垮。
- 黑白名单:拦截恶意请求。
- 超时:入口请求总超时控制。
2. 服务间调用(RPC):
- 超时:连接超时 1s,读取超时 3s,按链路层级递减。
- 重试:对幂等接口重试 2 次,指数退避 + 抖动。
- 熔断:基于异常比例/慢调用比例熔断,HALF_OPEN 探测恢复。
- 降级:熔断或超时后返回兜底数据。
- 隔离:按服务/接口划分线程池或信号量,防止相互影响。
3. 资源层(数据库/缓存/MQ):
- 连接池:限制最大连接数,防止连接耗尽。
- 超时:SQL 执行超时、缓存操作超时。
- 降级:缓存故障降级到数据库(需评估数据库压力)。
- 熔断:数据库故障时熔断,快速失败。
4. 基础设施:
- 多机房部署:容灾。
- 弹性伸缩:基于负载自动扩缩容。
- 混沌工程:主动注入故障验证容错能力。
容错组件选型
- Spring Cloud 生态 → Sentinel(功能全、控制台好)或 Resilience4j(轻量、响应式)。
- Dubbo 生态 → Dubbo 内置容错策略(Failover/Failfast/Failsafe/Forking/Broadcast)。
- Service Mesh → Istio/Linkerd(下沉到 Sidecar,业务无侵入)。
Dubbo 内置容错策略
Dubbo 提供了 6 种集群容错策略:
| 策略 | 说明 | 适用场景 |
|---|---|---|
| Failover | 失败自动重试,切换到其他服务器(默认) | 读操作或幂等写操作 |
| Failfast | 快速失败,只发起一次调用 | 非幂等写操作 |
| Failsafe | 失败安全,忽略异常 | 写审计日志等不关键操作 |
| Failback | 失败自动恢复,后台记录失败请求,定时重试 | 消息通知等最终一致场景 |
| Forking | 并行调用多个服务器,一个成功即返回 | 实时性要求高的读操作 |
| Broadcast | 广播调用所有服务器,逐个调用,任一报错则报错 | 更新本地缓存或日志 |
参考资料
- 数据密集型应用系统设计 - 这可能是目前最好的分布式存储书籍,强力推荐【进阶】