跳到主要内容

分布式系统设计面经

分布式核心知识

1. 分布式 ID 生成

方案优点缺点
数据库自增简单有序单点,性能差
UUID无需协调无序,存储空间大
雪花算法(Snowflake)高性能、趋势递增依赖时钟,时钟回拨有风险
号段模式(Leaf)DB 友好需 DB,有号段浪费
Redis INCR简单Redis 持久化有风险

雪花算法结构(64 bit)

1 bit (符号位=0) | 41 bit (时间戳ms) | 10 bit (机器ID) | 12 bit (序列号)
  • 可用约 69 年,单机每毫秒 4096 个 ID

2. 分布式锁

Redis 实现

-- 加锁
SET lock_key unique_value NX EX 30

-- 释放锁(Lua 脚本保证原子性)
if redis.call('get', KEYS[1]) == ARGV[1] then
return redis.call('del', KEYS[1])
end
return 0
  • 锁续期(看门狗):Redisson 默认 30s 过期,持锁期间每 10s 续期
  • Redlock:向 N 个独立 Redis 实例加锁,超过半数成功则加锁成功

ZooKeeper 实现

  • 创建临时有序节点,序号最小的获得锁
  • 监听前一个节点删除事件,避免羊群效应

3. 分布式事务

2PC(两阶段提交)

阶段1:协调者发 Prepare → 各参与者执行事务(不提交)并返回 Yes/No
阶段2:全部 YesCommit;任一 NoRollback
  • 问题:协调者单点,阻塞协议,网络分区时数据不一致

TCC(Try-Confirm-Cancel)

  • Try:预占资源(冻结库存)
  • Confirm:确认提交(扣减库存)
  • Cancel:取消回滚(解冻库存)
  • 业务侵入性强,需实现三个接口

Saga

  • 长事务拆成多个本地事务,每步有对应补偿事务
  • 编排模式(Choreography)vs 指挥模式(Orchestration)

消息最终一致性

本地事务 + 发消息 → MQ → 消费者执行 → 失败则重试
  • 使用事务消息(RocketMQ)保证发消息和本地事务原子性

4. 一致性哈希

  • 将节点和数据 key 都映射到 0~2³² 的环上
  • key 顺时针找到第一个节点
  • 增减节点只影响相邻节点的数据迁移
  • 虚拟节点:每个物理节点映射多个虚拟节点,负载更均衡

5. 分布式缓存架构

多级缓存

请求 → 本地缓存(Caffeine)→ 分布式缓存(Redis)→ 数据库

缓存与 DB 一致性策略

  • Cache Aside:读:先缓存后 DB;写:先更新 DB,再删缓存
  • Write Through:写 DB 和缓存同步进行(强一致但慢)
  • 延迟双删:更新 DB → 删缓存 → 延迟 500ms 再删一次

6. 服务治理

熔断器状态机

Closed(正常)→ [失败率超阈值]Open(熔断)
[等待超时]
Half-Open(试探)
[成功]
Closed

限流算法对比

算法特点
固定窗口简单,临界点突刺问题
滑动窗口解决突刺,内存稍多
漏桶平滑输出,不允许突发
令牌桶允许一定突发,更常用

7. 高频面试题

  • BASE 和 ACID 的关系? BASE 是 CAP 中 AP 的实践,用最终一致性换可用性
  • 如何保证消息不丢失? 生产者确认 + MQ 持久化 + 消费者手动 ack
  • 如何保证消息幂等? 消费端去重(唯一 ID + 数据库唯一约束 / Redis SET NX)
  • Raft 和 Paxos 的区别? Raft 更易理解,强 Leader,leader 处理所有请求;Paxos 更通用复杂