什么是CAP原则?

CAP原则⼜称CAP定理,指的是在⼀个分布式系统中,Consistency(⼀致性)、 Availability(可⽤性)、Partition tolerance(分区容错性)这3个基本需求,最多只能同时满⾜其中的2个。

  1. Consistency(⼀致性):所有节点在同一时间看到的数据完全相同(强一致性)。例如写入操作后,所有读请求必须返回最新值,否则报错。
  2. Availability(可用性):每个请求都能得到响应(不保证是最新数据),系统始终可用。例如:即使部分节点故障,用户仍能读写数据(可能读到旧数据)。
  3. Partition tolerance(分区容错性):系统在网络分区(节点间通信中断)时仍能继续运行。例如:即使部分节点无法通信,系统仍能提供服务。

为什么CAP不可兼得呢?

根据CAP定理,分布式系统只能选择以下三种组合之一:

  1. CP(一致性 + 分区容错性)
    • 牺牲可用性:当网络分区发生时,系统会拒绝请求(如返回错误或阻塞),直到数据一致。
    • 典型场景:分布式数据库和分布式锁。
  2. AP(可用性 + 分区容错性)
    • 牺牲一致性:允许返回旧数据,确保服务始终可用。
    • 典型场景:Web缓存和DNS。
  3. CA(一致性 + 可用性)
    • 牺牲分区容错性:仅适用于单机或理想网络环境(无分区),现实中分布式系统必须面对网络问题,因此CA组合实际很少见。
  4. CAP中的“P”是必须的:分布式系统无法避免网络分区(如机房断网、延迟),因此实际选择常在CP或AP之间权衡。

什么是BASE理论?

BASE(Basically Available、Soft state、Eventual consistency)是基于CAP理论逐步演化而来的,核心思想是即便不能达到强一致性(Strong consistency),也可以根据应用特点采用适当的方式来达到最终一致性(Eventual consistency)的效果。

  1. Basically Available(基本可用,BA):什么是基本可用呢?假设系统出现了不可预知的故障,但还是能用,只是相比较正常的系统而言,可能会有响应时间上的损失,或者功能上的降级。
  2. Soft State(软状态,S):什么是硬状态呢?要求多个节点的数据副本都是一致的,这是一种“硬状态”。软状态也称为弱状态,相比较硬状态而言,允许系统中的数据存在中间状态,并认为该状态不影响系统的整体可用性,即允许系统在多个不同节点的数据副本存在数据延时。
  3. Eventually Consistent(最终一致性):上面说了软状态,但是不应该一直都是软状态。在一定时间后,应该到达一个最终的状态,保证所有副本保持数据一致性,从而达到数据的最终一致性。这个时间取决于网络延时、系统负载、数据复制方案设计等等因素。

有哪些分布式锁的实现方案?

MySQL

  1. 创建一张锁表,数据库对字段作唯一性约束。
  2. 加锁的时候,在锁表中增加一条记录即可;释放锁的时候删除记录就行。
  3. 如果有并发请求同时提交到数据库,数据库会保证只有一个请求能够得到锁。
  4. 这种属于数据库 IO 操作,效率不高,而且频繁操作会增大数据库的开销,因此这种方式在高并发、高性能的场景中用的不多。

Redis

  1. Redis实现分布式锁,是当前应用最广泛的分布式锁实现方式。
  2. Redis执行命令是单线程的,Redis实现分布式锁就是利用这个特性。
  3. 实现分布式锁最简单的一个命令:setNx(set if not exist)。

什么是分布式事务?

  1. 分布式事务是指 跨多个数据库、服务或节点 的事务操作,需要保证这些操作的 原子性(Atomicity)、一致性(Consistency)、隔离性(Isolation)和持久性(Durability)(即 ACID 特性)。由于数据或服务分布在不同的节点上,传统的单机事务(如 MySQL 事务)无法直接适用,因此需要专门的分布式事务解决方案。

  2. 在分布式系统中,业务逻辑可能涉及多个独立的服务或数据库,例如:

    1. 电商下单:扣减库存(库存服务) → 创建订单(订单服务) → 支付(支付服务)。
    2. 银行转账:A账户扣款(账户A服务) → B账户加款(账户B服务)。
    3. 如果其中某个步骤失败,必须保证所有操作都能回滚,否则会导致数据不一致(如库存扣减但订单未创建)。

分布式事务有哪些场景的实现方案?

分布式常见的实现方案有 2PC3PCTCC本地消息表MQ消息事务最大努力通知SAGA事务 等等。

什么是业务入侵?

业务入侵指技术方案需要改造或适配现有业务代码和数据结构,导致业务逻辑与技术实现产生耦合的程度。

入侵性越高,业务代码需要为技术需求(如事务、一致性)做的修改越多,系统维护成本和复杂度随之上升。理想方案是在保证功能的前提下,尽量减少对业务逻辑的侵入

什么是2PC?

  1. 2PC(两阶段提交,Two-Phase Commit)是一种分布式事务实现方案,其核心思想是引入一个 协调者(Coordinator) 来管理事务的提交或回滚。

  2. 2PC的实现有两个阶段:

    1. 准备阶段(Prepare Phase):所有参与者执行事务但不提交,协调者询问所有参与者(Participants)是否可以提交事务,然后参与者依照自身状态返回应答。
    2. 提交阶段(Commit Phase):如果所有参与者都返回 Yes,协调者发送 Commit 命令,参与者提交事务。如果有任一参与者返回 No,协调者发送 Rollback 命令,所有参与者回滚事务。
  3. 优点:具有强一致性,适合数据库层面的分布式事务。

  4. 缺点:

    1. 同步阻塞:参与者必须等待协调者指令才可以提交事务,导致参与者长时间占据资源。
    2. 单点故障:协调者宕机可能导致事务挂起,参与者所占据的资源无法被释放。
    3. 数据不一致风险:如果部分参与者因为网络问题未收到 Commit 指令,会导致参与者之间的数据不一致(部分提交,部分未提交)。

什么是3PC

  1. 3PC(三阶段提交,Three-Phase Commit)是2PC的升级版本,它将事务提交分为3个阶段:

    1. CanCommit(询问阶段):协调者询问参与者是否可以执行事务,参与者检查自身状态(如资源是否足够、网络是否正常),但不锁定资源,然后返回应答。
    2. PreCommit(预提交阶段):如果所有参与者都返回 Yes,协调者发送 PreCommit 命令,参与者执行事务操作,锁定资源但不提交事务,并返回确认。
    3. DoCommit(提交阶段):如果所有参与者都成功 PreCommit,协调者发送 DoCommit,参与者正式提交事务。
  2. 3PC的优点:

    1. 减少阻塞时间:询问阶段可以提前过滤不可行的事务,避免资源长时间锁定。
    2. 提高可用性:在PreCommit和DoCommit阶段引入超时机制,如果等待 预提交请求 超时,参与者直接回到准备阶段之前。如果等到提交请求超时,那参与者就会提交事务了。
  3. 3PC的缺点:

    1. 仍无法避免数据不一致,因为可能导致某些节点因为网络问题超时而提交,但实际上协调者是要回滚事务。
    2. 相比 2PC,多了一个阶段,实现更复杂。
    3. 多一轮网络通信,延迟比 2PC 更高。

什么是TCC?

  1. TCC(Try-Confirm-Cancel)是业务层面的分布式事务,将分布式事务拆分为 三个阶段

    1. Try(预留资源):检查资源并预留(如冻结库存、预扣款)。如果所有参与者的 Try 成功,进入 Confirm 阶段;否则进入 Cancel 阶段。
    2. Confirm(确认提交):真正执行业务逻辑(如扣减库存、完成支付)。必须保证幂等性(重复调用不会重复生效)。
    3. Cancel(取消回滚):释放 Try 阶段预留的资源(如解冻库存、返还预扣款)。必须保证幂等性。
  2. 优点: 把数据库层的二阶段提交交给应用层来实现,规避了数据库的 2PC 性能低下问题,不需要使用锁,可自定义 Confirm/Cancel 逻辑。

  3. 缺点:TCC 的 Try、Confirm 和 Cancel 操作功能需业务提供,开发成本高,业务侵入性较大。

什么是本地消息表?

  1. 将分布式事务拆分为本地事务 + 异步消息:

    1. 本地事务:业务操作和消息记录同时存入数据库(保证原子性)。
    2. 异步投递:定时任务扫描未发送消息,调用下游服务。
    3. 最终一致:通过重试机制确保消息必达。
  2. 优点:

    1. 简单可靠:仅依赖数据库事务,无复杂中间件。
    2. 低延迟:消息投递延迟可控(通常秒级)。
    3. 无单点瓶颈:无需全局锁,适合高并发场景。
  3. 缺点:

    1. 侵入业务:需手动维护消息表,代码耦合。
    2. 消息可能重复:需消费者实现幂等性(如唯一键防重)。
    3. 依赖定时任务:大量消息时可能扫描性能瓶颈。

什么是MQ消息事务?

  1. 消息事务的原理是将两个事务通过消息中间件进行异步解耦
  2. 执行流程:
    1. 发送prepare消息到消息中间件
    2. 发送成功后,执行本地事务
    3. 如果事务执行成功,则commit,消息中间件将消息下发至消费端
    4. 如果事务执行失败,则回滚,消息中间件将这条prepare消息删除
    5. 消费端接收到消息进行消费,如果消费失败,则不断重试
  3. 消息事务依赖于消息中间件的事务消息,例如RocketMQ就支持事务消息(半消息),也就是只有收到发送方确定才会正常投递的消息。
  4. 这种方案也是实现了最终一致性,对比本地消息表实现方案,不需要再建消息表,对性能的损耗和业务的入侵更小。

什么是最大努力通知?

  1. 最大努力通知实现简单,适用于一些对最终一致性实时性要求没那么高的业务,比如支付通知,短信通知。
  2. 执行流程:
    1. 业务系统调用支付平台支付接口, 并在本地进行记录,支付状态为支付中
    2. 支付平台进行支付操作之后,无论成功还是失败,同步给业务系统一个结果通知
    3. 如果通知一直失败则根据重试规则异步进行重试,达到最大通知次数后,不再通知
    4. 支付平台提供查询订单支付操作结果接口
    5. 业务系统根据一定业务规则去支付平台查询支付结果

什么是Seata?

  1. Seata(Simple Extensible Autonomous Transaction Architecture)是阿里巴巴开源的一站式分布式事务解决方案,支持 AT、TCC、SAGA、XA 四种模式,适用于微服务架构下的数据一致性场景。

  2. Seata中包含三大组件:

    1. TC(Transaction Coordinator):事务协调者。管理全局的分支事务的状态,用于全局性事务的提交和回滚。
    2. TM(Transaction Manager):事务管理者。用于开启、提交或回滚事务
    3. RM(Resource Manager):资源管理器。用于分支事务上的资源管理,向 TC 注册分支事务,上报分支事务的状态,接收 TC 的命令来提交或者回滚分支事务
  3. Seata的执行流程(AT):

    1. 服务A中的 TMTC 申请开启一个全局事务,TC 就会创建一个全局事务并返回一个唯一的 XID
    2. 服务A中的 RMTC 注册分支事务,然后将这个分支事务纳入 XID 对应的全局事务管辖中
    3. 服务A开始执行分支事务
    4. 服务A开始远程调用B服务,此时 XID 会根据调用链传播,即从A传播到B
    5. 服务B中的 RM 也向 TC 注册分支事务,然后将这个分支事务纳入 XID 对应的全局事务管辖中
    6. 服务B开始执行分支事务
    7. 每个服务的RM会向TC返回其分支事务执行结果
    8. 如果所有分支事务均成功,则提交全局事务,让每个分支事务异步提交。若任意分支事务失败,则所有分支事务进行回滚。

什么是分布式一致性算法?

  1. 分布式一致性算法是在分布式系统中保证多个节点数据状态一致的协议,核心解决网络分区、节点故障、消息延迟/丢失等场景下的数据一致性问题。
  2. 经典的一致性算法有Paxos、Raft。

什么是Paxos?

Paxos算法通过提议者(Proposer)、接收者(Acceptor)和学习者(Learner)三个角色的协作,确保分布式系统对某个值达成一致。其核心流程分为两个阶段:准备阶段和接收阶段。

其优点是具有强一致性保证,理论严谨。缺点是理解与实现困难,需要设置较多的边界条件。

准备阶段

  1. 提议者选择一个全局唯一的提案编号N,向所有接收者发送Prepare(N)请求
  2. 每个接收者收到Prepare(N)请求后:
    • 如果N大于它已响应的任何Prepare请求的编号,则承诺不再接受编号小于N的提案
    • 同时返回它已接受的最高编号提案(如果有的话)

接收阶段

  1. 如果提议者收到多数接收者的承诺响应:
    • 如果没有任何接收者返回已接受的提案,则提议者可以自由选择值V
    • 如果有接收者返回了已接受的提案,则必须选择其中编号最大的提案值V
  2. 提议者发送Accept(N,V)请求给接收者
  3. 接收者收到Accept(N,V)请求后:
    • 如果未承诺过拒绝编号N的提案,则接受该提案
    • 否则忽略该请求
  4. 当提议者收到多数接收者对Accept(N,V)的确认后,该值V即被选定
  5. 学习者最终学习被选定的值V

什么是Raft?

  1. Raft算法通过领导者(Leader)、跟随者(Follower)和候选人(Candidate)三个角色的协作,确保分布式系统对日志序列达成一致。其核心流程分为两个主要机制:领导者选举和日志复制。
  2. 领导者选举步骤如下:
    1. 每个Follower启动一个随机选举超时计时器
    2. 如果超时未收到Leader心跳,则转变为Candidate
    3. Candidate递增当前任期号(Term),给自己投票
    4. 向所有节点发送RequestVote RPC请求
    5. 节点在同一任期内只能投一次票(先到先得)
    6. 必须满足Candidate的日志至少和自己一样新
    7. 获得多数票的Candidate成为Leader
    8. 立即发送心跳确立权威
    9. 若票数不足,等待超时后发起新一轮选举
  3. 由于日志复制机制比较复杂,这里不作讨论
  4. Raft的算法有以下特点:
    1. 强领导制:所有写请求必须通过Leader,简化了冲突处理
    2. 工程友好:明确分离选举和复制两个阶段

你了解什么限流算法?

  1. 固定窗口计数器(Fixed Window Counter):
    1. 将时间划分为固定窗口(如10秒),每个窗口内统计请求次数,超过阈值则拒绝请求。
    2. 比如每10秒限流100次,10秒内第101个请求被拒绝,第11秒重新计数。
    3. 优点:实现简单
    4. 缺点:窗口切换时可能出现流量突增(比如第10秒和第11秒可能激增200次请求)
  2. 滑动窗口(Sliding Window):
    1. 将固定窗口细分为更小的子窗口(如10秒=10个1秒子窗口),统计最近N个子窗口的总请求数。
    2. 比如限流100次/10秒,统计当前时间点往前10秒内的所有子窗口计数总和。
    3. 优点:解决固定窗口的临界问题,精度更高。
    4. 缺点:实现较复杂,需存储多子窗口数据,而且仍无法完全消除短时间流量波动。
  3. 漏桶算法(Leaky Bucket):
    1. 模拟一个固定容量的桶,请求以任意速率流入,以恒定速率流出(如10次/秒),桶满则拒绝请求。
    2. 比如队列+定时任务(或异步线程)处理请求。
    3. 优点:严格平滑流量输出(削峰填谷),避免突发流量冲击,保护下游系统。
    4. 缺点:无法应对突发流量(即使系统空闲时也强制匀速处理)。
  4. 令牌桶算法(Token Bucket):
    1. 桶中存放令牌,以固定速率生成(如10个/秒),请求需获取令牌才能执行,无令牌则拒绝。
    2. 比如Guava的 RateLimiter、Nginx的限流模块。
    3. 优点:允许突发流量(桶内令牌可累积),可以灵活控制平均速率和峰值。
    4. 缺点:实现较复杂(需维护令牌生成和消耗)。

参考资料

分布式八股文(背诵版)