分布式高频面试题

一、基础理论

CAP 定理是什么?分别解释一致性、可用性、分区容错性。

CAP 定理是分布式系统的核心理论,它指出:一个分布式系统无法同时满足一致性、可用性和分区容错性 ,由于网络分区无法完全避免(P 是客观存在的),系统必须在 CP (牺牲可用性)和 AP(牺牲一致性)之间做出选择。

C - 一致性(Consistency)

所有节点在同一时间看到的数据是相同的。即:一个客户端写入数据后,后续的读操作必须能读到这个最新值(强一致性)。对应到分布式系统,要求数据副本保持同步。

A - 可用性(Availability)

每个请求都能在有限时间内收到非错误的响应(但不保证返回的是最新数据)。即系统一直可用,不会超时或拒绝服务。

P - 分区容错性(Partition Tolerance)

当集群中部分节点之间网络通信中断(出现网络分区)时,系统仍能继续对外提供服务。由于网络不可靠,分布式系统必须考虑分区容错,因此实际中往往在 CP 和 AP 之间做权衡。

对资金、库存等核心数据,优先保证一致性(CP) ,在分区时宁可返回错误也不允许脏数据;对于商品浏览、点赞计数等非核心场景,优先保证可用性(AP)

为什么分布式系统中无法同时满足 CAP?举例说明。

分布式系统无法同时满足 CAP,是因为网络分区(P)是客观存在的 ,当分区发生时,必须在**一致性(C)可用性(A)**之间二选一。

核心原因

假设一个系统有两个节点 A 和 B,中间网络断开(发生分区)。此时:

  • 客户端向 A 写入一个新值 x=1
  • 由于网络不通,A 无法将更新同步给 B,B 上的 x 仍然是旧值(比如 x=0)。

为了保证 一致性(C) :系统必须拒绝 B 节点的读请求(因为 B 的数据不是最新的),或者直接报错,这就牺牲了 可用性(A)

为了保证 可用性(A) :系统必须让 B 节点继续返回数据(哪怕数据是旧的),这就牺牲了 一致性(C)

所以,只要分区存在,CA 两者就无法兼得。

举例说明
  • CP 系统(放弃 A):ZooKeeper。当发生网络分区时,ZooKeeper 会暂停服务(不可用),直到分区恢复、数据达成一致。保证数据一致,但牺牲了部分可用性。
  • AP 系统(放弃 C):Eureka。当分区发生时,Eureka 优先保证服务注册和发现功能可用,即使各节点数据不一致(比如有的节点还保留已下线的服务),也继续对外服务,牺牲强一致性,保证最终一致即可。

BASE 理论是什么?与 ACID 的区别?

  • BA(Basically Available,基本可用):系统出现故障时,允许损失部分功能(如响应变慢、部分服务降级),但整体仍可用。
  • S(Soft State,软状态):允许系统中存在中间状态(如数据同步延迟),不要求实时强一致。
  • E(Eventually Consistent,最终一致性):经过一段时间后,所有数据最终会达到一致状态。

在分布式系统设计中,ACID 追求强一致性,而 BASE 则是通过牺牲短期的强一致性来换取系统的高可用性和最终一致性

什么是最终一致性?常见实现方案有哪些?

最终一致性是指:在分布式系统中,数据更新后不要求立即在所有节点上保持一致,而是允许一段时间的"不一致窗口",但保证经过一段时间后,所有副本最终会达到一致状态。它是 BASE 理论中 E(Eventually Consistent)的核心。

1. 旁路缓存(Cache-Aside)模式

先更新数据库,再删除缓存"策略,保证最终一致性。

2. 异步复制机制

在 Redis 主从架构中,主节点处理完写请求后会立即响应客户端 ,并异步转发命令给从节点。但在主从同步完成前,数据存在短暂的不一致窗口。

**2.本地消息表 **

业务系统在同一个本地事务中同时写入业务数据和消息记录,再由独立的服务轮询消息表并将消息投递到 MQ(如 Kafka、RocketMQ)。下游服务消费消息并执行对应逻辑,从而保证跨服务数据的最终一致。

4. Saga 模式(补偿事务)

针对长流程的分布式事务,Saga 模式将其拆分为多个独立的本地事务。每个正向操作都有对应的反向补偿操作。如果某一环节失败,系统会按反向顺序调用补偿事务来回滚已提交的动作,确保整体业务流程的最终正确性。

二、分布式事务

什么是 2PC(两阶段提交)?有什么优缺点?

  • 原理:引入一个协调者(Coordinator),将事务分为"准备阶段"和"提交阶段"。所有参与者先锁定资源并执行操作(但不提交),等协调者确认所有参与者都准备就绪后,再统一发起提交。
  • 优点:实现了强一致性,逻辑相对简单,对业务代码侵入性较低(数据库层面支持)。
  • 缺点性能极差,准备阶段会长时间锁定数据库资源,导致高并发下系统吞吐量骤降;且协调者存在单点故障风险。

什么是 3PC?与 2PC 的区别是什么?

3PC(三阶段提交)是为了解决 2PC 的阻塞和单点故障问题而提出的改进协议。它将流程拆分为三个阶段:

  1. CanCommit(询问):仅检查节点状态,不锁定资源。
  2. PreCommit(预提交):执行事务并锁定资源,但不真正提交。
  3. DoCommit(正式提交):完成最终提交或回滚。
与 2PC 的核心区别
  1. 拆分阶段 :比 2PC 多了一个 CanCommit 纯询问阶段,提前过滤异常,减少了不必要的资源锁定浪费。
  2. 引入超时机制(核心) :2PC 只有协调者有超时机制;而 3PC 在协调者和参与者中双向引入了超时机制。若长时间未收到指令,参与者可自动决策(中断或提交),有效缓解了单点故障导致的死锁问题。

TCC(Try-Confirm-Cancel)是什么?适用于什么场景?

TCC 是一种柔性分布式事务解决方案。将一个事务拆分为三个阶段:Try(预留资源,如冻结库存)、Confirm(确认执行,真正扣减)、Cancel(取消执行,释放预留资源)

适用于对一致性要求较高、且核心链路较短的场景,比如金融支付、核心交易系统等。

什么是本地消息表?如何保证最终一致性?

本地消息表是一种基于数据库本地事务 的最终一致性方案。核心思想是:业务系统在同一个本地事务中同时写入业务数据和消息记录,再由独立的服务轮询消息表并将消息投递到 MQ(如 Kafka、RocketMQ)。下游服务消费消息并执行对应逻辑,再配合异步轮询重试 + 幂等消费,从而保证跨服务数据的最终一致。

分布式场景下,如何保证跨服务的事务一致性?有哪些常见方案?

"目前业界主流的分布式事务解决方案主要有以下四种,它们分别适用于不同的业务场景:"

1. 两阶段提交(2PC / XA)

  • 原理:引入一个协调者(Coordinator),将事务分为"准备阶段"和"提交阶段"。所有参与者先锁定资源并执行操作(但不提交),等协调者确认所有参与者都准备就绪后,再统一发起提交。
  • 优点:实现了强一致性,逻辑相对简单,对业务代码侵入性较低(数据库层面支持)。
  • 缺点性能极差,准备阶段会长时间锁定数据库资源,导致高并发下系统吞吐量骤降;且协调者存在单点故障风险。
  • 结论 :由于严重的性能问题,在互联网高并发业务中极少使用,通常只出现在对一致性要求极高、并发量不大的传统金融或银行核心系统中。

2. TCC(Try-Confirm-Cancel)

  • 原理TCC 是一种柔性分布式事务解决方案。将一个事务拆分为三个阶段:Try(预留资源,如冻结库存)、Confirm(确认执行,真正扣减)、Cancel(取消执行,释放预留资源)。
  • 优点:性能较好,资源锁定粒度细(只在 Try 阶段锁定),能够实现准实时的一致性。
  • 缺点业务侵入性极强,每个服务都需要开发 Try、Confirm、Cancel 三个接口;且需要手动处理幂等性、空回滚、资源悬挂等复杂的边界问题。
  • 结论 :适用于对一致性要求较高、且核心链路较短的场景,比如金融支付、核心交易系统等。

3. 异步消息机制

  • 原理 :业务系统在同一个本地事务中同时写入业务数据和消息记录,再由独立的服务轮询消息表并将消息投递到 MQ(如 Kafka、RocketMQ)。下游服务消费消息并执行对应逻辑,再配合异步轮询重试 + 幂等消费,从而保证事务的最终一致。(通过本地事务表或 MQ 的半消息机制,保证"本地操作"与"消息发送"的原子性)

  • 优点彻底解耦,系统吞吐量极高,不阻塞主流程,业务侵入性相对较低。

  • 缺点:只能保证最终一致性,存在秒级甚至分钟级的数据延迟;且消费端必须做好幂等处理。

  • 结论 :这是互联网高并发场景下最常用的方案,非常适合非核心链路或允许短暂延迟的业务,比如下单成功后异步扣减积分、异步发送通知等。

4. Saga(/ˈsɑːɡə/ ) 模式

  • 原理:适用于长事务。将一个长事务拆分为多个本地短事务,每个短事务都有一个对应的补偿操作。如果某一步失败,则依次反向调用前面所有步骤的补偿操作,把数据"补"回去。
  • 优点:适合流程极长、跨服务极多的业务,并发性能好。
  • 缺点:补偿逻辑编写复杂,且缺乏隔离性(其他事务可能会看到中间状态的数据)。
  • 结论 :适用于业务流程极长的场景,比如复杂的物流履约流程、跨多个部门的审批流程等。

压轴环节:生产环境如何选择?

"在实际的生产环境选型中,我不会盲目追求强一致性,而是会根据业务容忍度来做决策:

  • 如果是高并发的核心交易链路 (如电商下单扣库存、支付),为了保证性能和用户体验,我会优先选择 TCC 模式 (通常会借助 Seata 等成熟框架来降低开发复杂度),或者结合 可靠消息队列 来异步处理非核心步骤。
  • 如果是对实时性要求不高、追求极致解耦 的场景(如订单完成后发优惠券、发短信),我会毫不犹豫地选择 基于 MQ 的可靠消息最终一致性方案
  • 至于 2PC ,由于其严重的性能瓶颈,我通常不会在分布式微服务架构中推荐使用

什么是事务消息(如 RocketMQ 的事务消息)?

事务消息(如 RocketMQ 的事务消息)是一种通过"半消息(Half Message)+ 二阶段提交 + 事务状态回查"机制,将本地数据库操作与 MQ 消息发送绑定,从而保障分布式场景下数据最终一致性的方案

🕒 阶段一:发送半消息 (Prepare/Half Phase)

生产者向 Broker(即RocketMQ服务端)发送一条对消费者暂不可见 的消息,即"半消息"(Half Message)。并持久化到 RMQ_SYS_TRANS_HALF_TOPIC 主题中。

🗄️ 阶段二:执行本地事务+二次确认

生产者接收到半消息的成功确认后,立即开始执行本地业务逻辑(如扣减库存、更新订单状态)。本地事务成功,生产者通知Broker提交半消息,消费者最终能消费到该消息 。本地事务失败,生产者通知Broker回滚半消息,消息被删除,消费者不会收到

事务回查 (Check Mechanism) ------ 可靠性保障

如果生产者因故障、网络等原因未及时发送二次确认(或因 Unknow 状态而等待超时),Broker会在一定时间后(如默认1分钟)主动向生产者发起回查请求,询问该消息对应的本地事务状态。生产者实现 TransactionListener 接口,由 checkLocalTransaction 方法负责回复当前本地事务的最终状态。

Seata 支持哪些分布式事务模式?AT 模式的原理是什么?

Seata 支持 AT、TCC、SAGA、XA 四种模式;AT 模式通过本地事务和 undo_log 快照实现自动补偿,一阶段提交业务数据和回滚日志,二阶段全局回滚时利用快照反向生成 SQL 恢复数据。

三、分布式锁

分布式锁需要满足哪些条件?

  1. 互斥性:任意时刻,只有一个客户端能持有锁。
  2. 防死锁(自动释放):锁需设置过期时间(TTL),防止客户端崩溃导致锁永不释放。
  3. 原子性与安全性(防误删):加解锁操作须原子化,且严格校验身份,确保"谁加的锁谁来解"。
  4. 高可用与容错性:锁服务自身需高可用,即使部分节点故障,不影响加锁和解锁。
  5. 可重入性:同一客户端可重复获取已持有的锁。
  6. 自动续期能力(看门狗机制):在业务未完成时后台定时延长锁的有效期,防止因执行超时导致锁提前释放。

Redis 实现分布式锁如何保证原子性?SET NX EX 是否足够?

Redlock 算法的原理是什么?它有什么问题?

ZooKeeper 如何实现分布式锁?与 Redis 锁的优缺点对比?

客户端在锁路径下创建临时顺序节点,序号最小的节点获得锁,其他客户端监听前一个节点;释放锁时删除自己的临时节点,触发下一个节点获取锁。

ZooKeeper 锁 强一致、防死锁、公平但性能较低 ,适合金融级强一致性场景;Redis 锁 高性能、低延迟但极端场景可能失效(如主从切换瞬间),适合高并发且能容忍小概率异常的业务。

分布式锁中如何防止锁超时导致业务未完成而释放?

实现自动续期:当我们成功拿到Redis分布式锁后,同时也异步启动一个线程,这个就是看门狗线程 ,它会判断对应key是否到过期时间的1/3,如果到了,则对key进行续期,直到任务完成。当然,实现看门狗的任务通过lua脚本来完成。

看门狗主要解决自动续期问题 ,确保锁过期时间大于业务执行时间的问题。

四、分布式 ID 生成

分布式ID有哪些?优点和缺点有哪些?如何选择?

常见方案及优缺点
  1. UUID / GUID
    • 优点:本地生成,全球唯一。
    • 缺点:无序且过长
    • 结论不适合作为数据库主键,仅适用于非核心链路(如请求追踪ID)。
  2. 数据库自增ID
    • 优点:实现简单,严格递增,对索引友好。
    • 缺点:单库性能受限,分库分表则扩展性差
    • 结论 :适用于单机或小规模系统,大型分布式系统不建议直接使用。
  3. Redis 自增(INCR)
    • 优点:严格递增,性能较高。
    • 缺点:持久化可能导致数据丢失导致ID重复。
    • 结论:可接受一定丢失风险的场景可以使用。
  4. 雪花算法(Snowflake)
    • 优点性能极强 :本地生成,单机可达几十万甚至百万QPS。趋势递增:64位整数,紧凑且对索引友好。
    • 缺点
      • 时钟回拨:若机器时钟被回调,可能产生重复ID。
      • 机器ID分配:需要在分布式环境中为每个节点分配唯一的WorkerID。
    • 解决方案:通过ZooKeeper自动分配WorkerID,并实现时钟回拨容错(如等待或告警降级)。
    • 结论 :适合超高并发、对性能极致要求的场景,但需要解决时钟问题。
  5. 号段模式(Segment Mode)
    • 代表实现:美团Leaf、滴滴Tinyid。
    • 原理:从数据库批量获取ID号段(例如一次获取1000个),在本地内存中递增,用完后重新获取。
    • 优点性能高且稳定 :减少数据库访问压力,QPS可达数万。严格递增:ID对数据库友好。
    • 缺点:依赖数据库,如果数据库宕机且本地号段耗尽,则无法生成ID。
    • 结论:适合中小型分布式系统。

选择策略:

  • 绝对避免 :直接使用UUID作为数据库主键,它的无序性和长度会严重拖垮数据库性能。
  • 个人项目 / 初期单体应用 :直接用数据库自增ID,简单够用。
  • 中小型分布式系统 :优先选用号段模式 的开源实现,比如美团Leaf-segment滴滴Tinyid。它们稳定可靠,运维成本低,能覆盖绝大多数业务。
  • 超高并发(如秒杀、订单ID生成) :采用雪花算法,并配套ZooKeeper管理机器ID,实现时钟回拨容错机制。例如美团的Leaf-snowflake(/ˈsnəʊfleɪk/)。

分布式 ID 需要满足哪些特性?

分布式 ID 必须满足 全局唯一性、趋势递增性、高性能、高可用性、安全性 五大核心特性

雪花算法(Snowflake)的原理是什么?如何解决时钟回拨问题?

雪花算法通过 将64位ID划分为时间戳(41位)、机器ID(10位)和序列号(12位),利用位移运算生成全局唯一且趋势递增的ID

雪花算法解决时钟回拨的核心方法是:对轻微回拨(通常≤5ms)采用等待策略使时钟自然追平,对严重回拨则通过切换机器ID、启用逻辑时钟或直接拒绝服务来保障ID唯一性, 避免因时间倒退导致ID重复。,

数据库自增 ID 在分布式下有什么缺陷?

  • 单库性能受限:所有ID请求都落到同一台数据库,成为写入瓶颈,无法支撑高并发。
  • 分库分表则扩展性差:虽然通过设置不同步长和偏移量可以保证全局唯一,但扩缩容时需要重新计算所有实例的步长、迁移数据、调整配置,过程复杂且易出错,缺乏弹性。

美团 Leaf 和百度 UidGenerator 的核心思想是什么?

五、服务治理与 RPC

服务注册与发现的核心组件有哪些?工作原理是什么?

服务注册与发现的核心组件包括:服务提供者服务消费者注册中心

工作原理

  1. 服务注册:服务提供者启动时,将自己的网络地址(IP+端口)及元数据注册到注册中心。
  2. 服务发现:服务消费者从注册中心获取所需服务的提供者地址列表,并缓存到本地。
  3. 健康检查:注册中心通过心跳机制定期检测服务提供者的健康状态,若检测失败则将其从列表中移除。
  4. 变更通知:当服务提供者列表发生变化(新增、删除或故障),注册中心会通知服务消费者更新本地缓存。

典型实现:ZooKeeper、Eureka、Nacos、Consul 等。

ZooKeeper、Eureka、Nacos、Consul 作为注册中心的区别?

特性 ZooKeeper Eureka Consul Nacos
CAP 模型 CP (一致性优先) AP (可用性优先) CP (一致性优先) CP/AP 可切换
数据一致性 强一致性 (ZAB 协议) 最终一致性 强一致性 (Raft 协议) CP 模式强一致,AP 模式最终一致
高可用特性 Leader 选举期间短暂不可用 高可用 ,任意节点故障不影响服务,有自我保护机制 Leader 选举期间短暂不可用 CP 模式 Leader 选举期间不可用,AP 模式高可用
健康检查 基于 Session 心跳 基于 Client 心跳续约 丰富的检查 (TCP/HTTP/Script) 支持多种检查方式(TCP/HTTP/MySQL)
功能范围 分布式协调服务 服务注册发现 服务发现 + KV + 健康检查 + 多数据中心 服务发现 + 配置管理
主流版本状态 活跃 2.0 版本已停止维护 活跃 活跃
生态与趋势 老牌方案,生态成熟,多用于 Hadoop/Spark 等大数据组件 Spring Cloud Netflix 早期标配,已被替代 HashiCorp 出品,云原生友好,多用于 K8s 或非 Java 生态 阿里开源,云原生主力,Spring Cloud Alibaba 核心组件

CAP 视角下,ZooKeeper 和 Eureka 分别偏向哪个?

ZooKeeper 偏向 CP (一致性 + 分区容错性),Eureka 偏向 AP(可用性 + 分区容错性)。

RPC 和 HTTP 调用的区别?为什么 RPC 更高效?

Dubbo 的核心架构包含哪些角色?(Provider、Consumer、Registry、Monitor)

Dubbo 支持哪些负载均衡策略?默认是哪种?

什么是服务熔断、降级、限流?分别如何实现?

服务熔断、降级、限流是分布式系统保障稳定性的三大手段。

1、服务熔断(Circuit Breaker)

定义:当某个下游服务持续超时或失败,调用方主动切断对其的调用,快速失败。

实现熔断器通过"关闭→开启→半开"状态机实现:关闭时统计失败率,达阈值则开启熔断直接失败;窗口期后进入半开放行试探请求,成功则恢复关闭,失败则继续熔断。 主流实现用滑动窗口计数,框架有 Hystrix、Resilience4j、Sentinel。

  1. 服务降级(Fallback / Degradation)

定义:当系统压力过大或依赖服务不可用时,自动关闭非核心功能或返回兜底数据,保证核心功能可用。

实现

  • 触发条件:熔断、超时、资源不足(线程池/连接池满)时触发。

  • 降级逻辑:返回缓存数据、静态默认值、错误提示,或调用备用逻辑。

  • 代码示例(Sentinel):

    java 复制代码
    @SentinelResource(value = "getOrder", fallback = "orderFallback")
    public Order getOrder(Long id) { ... }
    
    public Order orderFallback(Long id, Throwable ex) {
        return new Order(-1L, "降级订单");
    }

  1. 服务限流(Rate Limiting)

定义:控制访问 QPS 或并发数,超过阈值的请求直接拒绝或排队,防止系统过载。

实现

  • 算法:令牌桶(允许突发)、漏桶(平滑)、计数器(简单滑动窗口)。
  • 维度:接口级、IP级、用户级、集群级。
  • 主流实现:Guava RateLimiter(单机)、Sentinel(分布式限流)、Nginx(网关限流)、Redis + Lua(分布式计数器)。

一句话总结:限流是"挡住多余请求",熔断是"关掉故障通道",降级是"简化服务内容"。三者常配合使用,如 Sentinel 或 Hystrix 可同时支持熔断与降级。

Sentinel 和 Hystrix 的区别是什么?

Sentinel 比 Hystrix 功能更全面(支持流量控制)、性能更好、支持动态规则热更新,且项目处于活跃维护状态,而 Hystrix 已停止开发

六、负载均衡

常见负载均衡算法有哪些?(轮询、加权轮询、最少连接、一致性哈希等)

  1. 轮询(Round Robin)

    按顺序将请求依次分配给后端服务器,循环往复。简单公平,适合服务器性能相近的场景。

  2. 加权轮询(Weighted Round Robin)

    为每台服务器设置权重,权重高的服务器被分配更多请求。适用于服务器性能不均的情况。

  3. 最少连接(Least Connections)

    将请求分配给当前活动连接数最少的服务器。适用于长连接或请求处理时间差异大的场景,能动态避免负载倾斜。

  4. 随机(Random)

    随机选择一台服务器。实现简单,在大流量下近似均匀,但可能存在不均匀分布。

  5. 源地址哈希(IP Hash)

    根据客户端 IP 的哈希值分配固定服务器,保证同一客户端始终访问同一台后端,常用于会话保持。

    text 复制代码
    服务器编号 = hash(客户端IP) mod 服务器总数

    缺点:源地址哈希在节点增减时,会导致绝大部分请求的映射关系发生改变,导致请求重新分配,缓存命中率骤降。

  6. 一致性哈希(Consistent Hashing)

    一致性哈希是一种分布式哈希算法,将服务器和客户端IP映射到一个哈希环上,按顺时针找最近的服务器。在增减服务器时只影响环上小部分请求,从而最小化数据迁移量。非常适合分布式缓存等需要高扩展性的场景。

什么是一致性哈希?解决了什么问题?虚拟节点的作用是什么?

一致性哈希是一种分布式哈希算法,将服务器和客户端IP映射到一个哈希环上,按顺时针找最近的服务器。在增减服务器时只影响环上小部分请求,从而最小化数据迁移量。非常适合分布式缓存等需要高扩展性的场景。

虚拟节点通过让每个物理节点在环上"出现多次",使数据分布更均匀、节点增减影响更平滑

七、消息队列

为什么使用消息队列?有哪些优缺点(解耦、削峰、异步)?

如何保证消息不丢失?(生产端、Broker、消费端分别考虑)

如何保证消息不被重复消费?幂等性如何设计?

如何保证消息的顺序性?

Kafka、RocketMQ、RabbitMQ 的适用场景有什么区别?

八、分布式会话与缓存

分布式会话如何管理?(Session 共享方案)

  1. 集中式存储(最常用、推荐)

原理 :将用户的 Session 数据从各服务实例中抽离,统一存放在一个外部的高性能缓存中间件中(通常是 Redis 集群)。所有服务实例在需要 Session 时,都去这个共享缓存中读取。

优点

  • 支持水平扩展,节点增减无感知
  • 性能高(Redis 内存操作)
  • 服务无状态,便于容器化部署(如 Docker、K8s)

缺点

  • 引入额外组件(Redis 集群),需保证其高可用
  • 一次网络开销(但通常可接受)

实现方式(Spring Boot + Redis Session):

java 复制代码
// 引入依赖 spring-session-data-redis
@EnableRedisHttpSession  // 启用 Redis 托管 Session
public class Config { ... }

用户请求的 JSESSIONID 不变,但 Session 数据实际存储在 Redis 中。


  1. 客户端存储(如 JWT)

原理:服务器不存储 Session,而是将用户状态信息(如用户 ID、权限)加密后写入一个令牌(如 JWT),直接返回给客户端。客户端在后续请求中携带该令牌,服务器解密验证后直接使用。

优点

  • 完全无状态,无需共享存储
  • 适合移动端、跨域场景
  • 避免 Session 同步问题

缺点

  • 令牌体积较大(每次请求都携带)
  • 无法主动失效(除非配合黑名单)
  • 敏感信息不应存入 JWT

适用:RESTful API、前后端分离、对实时注销要求不高的场景。

方案 是否无状态 扩展性 性能 实现复杂度 适用场景
Redis 集中存储 ✅ 是 中等 主流推荐,绝大多数分布式 Web 应用
JWT 客户端存储 ✅ 是 高(但令牌体积大) 前后端分离、移动端 API
Session 粘滞 ❌ 否 小规模、非关键、可容忍宕机丢失
Session 复制 ❌ 否 极低 已弃用,不推荐

缓存穿透、缓存击穿、缓存雪崩分别是什么?如何解决?

如何保证缓存与数据库的双写一致性?

九、分布式幂等性

什么是幂等性?如何设计幂等接口?

接口幂等性是指同一个请求执行 1 次和执行 N 次,对业务产生的副作用和结果完全一样。在分布式系统中,由于网络波动重试、用户重复点击、消息队列重复消费等原因,重复请求非常常见。

常见的幂等实现方案有哪些?(Token、去重表、乐观锁等)

  1. Token 令牌机制(最常用)

这是目前分布式系统中最通用的方案,适用于表单提交、下单、支付等场景。

  • 实现原理
    1. 前端在进入页面或点击提交前,先调用后端接口获取一个全局唯一的 Token(如 UUID)。
    2. 后端将 Token 存入 Redis 并设置过期时间。
    3. 前端提交业务请求时,在请求头或参数中携带该 Token。
    4. 后端接口通过拦截器或 AOP 拦截请求,利用 Redis 的原子操作(如 del 或 Lua 脚本)校验并删除 Token。
    5. 如果删除成功,说明是第一次请求,放行执行业务;如果删除失败(Token 不存在),则判定为重复请求并直接拒绝。
  • 优缺点:能完全防住重放请求,适合分布式环境;但需要额外增加一次获取 Token 的网络请求。
  1. 数据库唯一索引(兜底方案)

利用数据库的唯一约束来防止重复插入,是最简单可靠的兜底方案。

  • 实现原理 :在业务表的特定字段(如订单号 order_no、支付流水号)上建立唯一索引(Unique Index)。当重复请求尝试插入相同数据时,数据库会抛出唯一键冲突异常,业务层捕获该异常后返回"请勿重复操作"。
  • 优缺点:实现简单,强一致性;但仅适用于插入场景,且高并发下频繁触发异常会对数据库性能造成一定影响。
  1. 状态机控制(适合有状态流转的业务)

适用于订单状态流转、审批流程等具有明确状态变更的业务。

  • 实现原理 :在更新数据时,将旧状态作为更新条件。例如支付接口,SQL 语句写为 UPDATE order SET status = 'PAID' WHERE order_id = 1001 AND status = 'UNPAID'
  • 优缺点:天然幂等,无需额外存储;但如果重复请求到达时状态已变更,后续请求会因影响行数为 0 而失败。
  1. Redis 分布式锁

适用于高并发下的更新操作或防重复执行。

  • 实现原理:在执行业务逻辑前,先尝试获取一个以业务唯一标识(如订单ID)为 Key 的分布式锁。获取锁成功则执行业务,执行完毕后释放锁;获取失败则直接返回"重复请求"。
  • 优缺点:性能高,适合分布式;但需要合理设置锁的过期时间以防死锁,且锁的粒度要控制精细。
  1. 防重表(独立去重记录)
  • 实现原理:建立一张独立的去重表,表中包含请求的唯一标识(幂等键)并设置唯一索引。业务执行前先向防重表插入一条记录,插入成功则继续执行业务,失败则说明是重复请求。
  • 优缺点:对业务表无侵入,灵活可控;但增加了一次数据库写操作。
  1. 前端防重(辅助手段)
  • 实现原理:用户点击提交按钮后,立即将按钮置灰或禁用,并显示"提交中",防止用户短时间内多次点击。
  • 优缺点 :实现简单,提升用户体验;但只能防住前端的误操作,无法防御恶意攻击、网络重放或后端重试,必须配合后端方案使用

方案对比与选型建议

方案 核心原理 适用场景 优缺点
Token 令牌 请求前获取令牌,执行时原子删除 表单提交、下单、支付 适合分布式,防重效果好;需额外网络开销
唯一索引 数据库唯一约束阻止重复插入 插入操作(创建订单、流水) 简单可靠,强一致;仅限插入,性能受限
状态机控制 更新时带上前置状态条件 订单状态流转、审批 天然幂等;仅限有状态流转的业务
分布式锁 业务唯一键加锁,防并发执行 更新操作、防重复执行 性能高;需处理锁超时与释放问题
前端防重 按钮置灰、防抖 所有提交场景 体验好;治标不治本,仅作辅助

在生产环境中,通常不会单一依赖某一种方案,而是采用组合拳

  1. 前端:通过按钮置灰/防抖拦截大部分用户误操作。
  2. 高并发层:使用 Redis Token 或分布式锁作为第一道防线,拦截绝大部分重复请求。
  3. 数据层:通过数据库唯一索引或状态机作为最终的兜底保障,确保数据的绝对安全。

十、分布式链路追踪

什么是分布式链路追踪?(Trace、Span 的含义)

OpenTracing 规范是什么?SkyWalking、Zipkin 等如何工作?

相关推荐
love_muming4 小时前
链表每日一练
java·开发语言·数据结构·链表·idea·每日一练
范什么特西4 小时前
重点:mybatis注意细节
java·mysql·mybatis
乐观勇敢坚强的老彭4 小时前
GESP一级核心算法:循环与条件判断的结合
java·数据结构·算法
雪宫街道4 小时前
SpringBoot 向 IOC 容器注册组件的两种姿势:@Configuration 与 @Import
java·spring boot·后端·spring
北城以北88884 小时前
虚拟机安装JDK,Tomcat,部署项目
java·开发语言·tomcat
终将老去的穷苦程序员4 小时前
基于Android Studio开发的安卓图书借阅管理系统
java·sqlite·android studio·android-studio
技术小结-李爽5 小时前
【工具】Maven的使用
java·maven
sou_time5 小时前
从 0 到 商用:AI Agent x SKILL x MCP 全栈实战教程:L2 高等篇:MCP 协议 + Spring AI + Agent 编排
java·人工智能·spring
冷小鱼5 小时前
高级研发编码习惯:从规范到艺术,再到AI+时代的人机协同
java·开发语言·python·编码习惯
齐 飞5 小时前
JDK21虚拟线程
java·后端