系统设计面试八股文(20题)

系统设计面试八股文(20 题)

📚 面试高频:本文覆盖系统设计核心知识点,从基础架构到高级设计,帮你系统掌握系统设计面试要点。

🎯 面试加分:每个问题都包含深度解析和面试加分回答,让你在面试中脱颖而出。

快速掌握:所有问题都附有通俗易懂的解释和实战经验分享。


📖 学习指南

🎯 学习目标:通过本文,你将系统掌握系统设计的核心概念、设计思路和实战技巧,能够自信地应对任何系统设计相关的面试问题。

适合人群

  • 🔰 初学者:想系统学习系统设计的开发者
  • 🚀 有经验者:想深入理解系统设计原理的高级开发者
  • 💼 面试准备者:想刷系统设计面试题的求职者

学习建议

  1. 先理解需求,再设计方案:先搞懂”要解决什么问题”,再搞懂”如何设计”
  2. 结合实战场景:不要死记硬背,要理解实际应用场景
  3. 动手实践:在自己电脑上搭建本文的示例系统
  4. 反复复习:面试前一周,每天复习 5 个问题

学习时间估算

  • ⏱️ 快速复习(只看一句话总结):1.5 小时
  • 📚 系统学习(看深度解析):2 天
  • 💪 深入理解(研究源码):1 个月+

🗺️ 知识图谱

mindmap
  root((系统设计))
    基础架构
      负载均衡
      CDN
      缓存
      数据库
      消息队列
    高级设计
      分布式锁
      分布式事务
      一致性哈希
      CAP 定理
    实战系统
      短链接系统
      限流器
      唯一 ID 生成
      秒杀系统
      推荐系统
      搜索引擎
      聊天系统
      视频网站

⚠️ 常见陷阱与误区

陷阱 1:混淆负载均衡算法

错误理解

  • 以为所有场景都适合轮询算法

正确认知

  • 轮询算法:适合服务器性能一致的场景
  • 加权轮询算法:适合服务器性能不一致的场景
  • 最少连接数算法:适合长连接场景
  • IP Hash 算法:适合需要会话保持的场景

陷阱 2:忽略缓存穿透、缓存击穿、缓存雪崩

错误做法

  • 只使用缓存,不考虑缓存问题

正确做法

  • 缓存穿透:使用布隆过滤器或缓存空值
  • 缓存击穿:使用互斥锁或逻辑过期时间
  • 缓存雪崩:使用过期时间随机化或集群部署

陷阱 3:混淆 CAP 定理的三个特性

错误理解

  • 以为 CAP 可以同时保证 C、A、P

正确认知

  • C(Consistency)一致性:所有节点在同一时间看到相同的数据
  • A(Availability)可用性:每个请求都能收到响应(不保证最新数据)
  • P(Partition tolerance)分区容错性:系统在网络分区时仍能正常运行
  • CAP 定理:分布式系统最多只能同时满足其中两个特性

💡 面试技巧

🎯 面试技巧:面试时遇到系统设计问题,不要只背方案,要结合实际项目经验回答。

回答思路

  1. 先问清楚需求:功能需求、非功能需求(QPS、延迟、数据量)
  2. 再给出高层设计:画出系统架构图(负载均衡、缓存、数据库、消息队列)
  3. 最后深入讨论细节:数据库 schema、缓存策略、消息队列选型

举例说明

问题:如何设计一个短链接系统?

一句话总结:短链接系统的核心是将长链接映射到一个短链接,通过重定向实现访问。

高层设计

  • 功能需求:输入长链接,返回短链接;访问短链接,重定向到长链接
  • 非功能需求:高可用、低延迟、可扩展
  • 系统架构:负载均衡 → API 服务 → 数据库(存储映射关系) → 缓存(提高读取性能)

面试加分回答

“在实际项目中,短链接系统需要考虑:

  1. 唯一 ID 生成:可以使用雪花算法或自增 ID
  2. 缓存策略:热点短链接放在 Redis 缓存中
  3. 数据库选型:MySQL(存储映射关系)、Redis(缓存)
  4. 可扩展性:使用一致性哈希分片数据”

Q1:如何设计一个短链接系统(URL Shortener)?

一句话总结:短链接系统的核心是将长链接映射到一个短链接,通过重定向实现访问,需要解决唯一 ID 生成、映射存储、重定向、高可用等问题。

深度解析

1. 需求分析

  • 功能需求
    • 输入长链接,返回短链接
    • 访问短链接,重定向到长链接
  • 非功能需求
    • 高可用(99.999%)
    • 低延迟(< 100ms)
    • 可扩展(支持亿级短链接)

2. 高层设计

1
2
3
用户 → 负载均衡(Nginx) → API 服务 → 数据库(MySQL)

缓存(Redis)

3. 核心问题

问题 1:如何生成短链接?

  • 方案 1:自增 ID + Base62 编码
    • 使用自增 ID(MySQL 自增主键或分布式 ID 生成器)
    • 将自增 ID 转换成 Base62 编码(0-9、a-z、A-Z,共 62 个字符)
    • 示例:自增 ID = 1234567890 → Base62 编码 = “1LPUP” → 短链接 = “https://short.url/1LPUP
  • 方案 2:哈希(MD5、SHA-1)+ Base62 编码
    • 对长链接进行哈希,取前 6-8 个字符作为短链接
    • 可能存在哈希冲突,需要重试

问题 2:如何存储映射关系?

  • 数据库 schema
    1
    2
    3
    4
    5
    6
    7
    8
    CREATE TABLE short_url (
    id BIGINT AUTO_INCREMENT PRIMARY KEY,
    short_key VARCHAR(10) UNIQUE NOT NULL,
    long_url TEXT NOT NULL,
    created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP,
    expires_at TIMESTAMP NULL
    );
    CREATE INDEX idx_short_key ON short_url(short_key);
  • 缓存策略
    • 热点短链接放在 Redis 缓存中
    • 缓存过期时间:24 小时

面试加分回答

“在实际项目中,短链接系统需要考虑:

  1. 唯一 ID 生成:推荐使用自增 ID + Base62 编码(简单、高效)
  2. 缓存策略:热点短链接放在 Redis 缓存中,提高读取性能
  3. 数据库选型:MySQL(存储映射关系)、Redis(缓存)
  4. 可扩展性:使用一致性哈希分片数据(如果用户量增长,可以增加数据库分片)”

Q2:如何设计一个限流器(Rate Limiter)?

一句话总结:限流器的核心是控制请求速率,防止系统被突发流量打垮,常见算法有固定窗口、滑动窗口、令牌桶、漏桶

深度解析

1. 限流的作用

  • 保护系统:防止系统被突发流量打垮
  • 公平使用:防止单个用户占用过多资源
  • 成本控制:控制调用次数,降低成本(如第三方 API 调用)

2. 限流算法

算法 1:固定窗口(Fixed Window)

  • 原理:将时间分成固定大小的窗口,每个窗口内最多允许 N 个请求
  • 优点:实现简单
  • 缺点:无法应对突发流量(如窗口边界处,可能有 2N 个请求)

算法 2:令牌桶(Token Bucket)

  • 原理:以固定速率生成令牌,放入桶中;请求到来时,从桶中获取令牌;如果桶中没有令牌,拒绝请求
  • 优点:允许突发流量(桶中有令牌时,可以一次性处理多个请求)
  • 缺点:实现复杂

3. 限流架构

  • 单机限流:使用内存计数器(如 Guava 的 RateLimiter
  • 分布式限流:使用 Redis + Lua 脚本(保证原子性)

面试加分回答

“在实际项目中,限流器的设计需要考虑:

  1. 限流算法选择
    • 如果允许突发流量:选择令牌桶算法
    • 如果要求流量平滑:选择漏桶算法
  2. 限流粒度
    • 对用户限流:防止单个用户占用过多资源
    • 对 IP 限流:防止恶意攻击
  3. 分布式限流:使用 Redis + Lua 脚本(保证原子性)”

Q3:如何设计一个分布式唯一 ID 生成系统?

一句话总结:分布式唯一 ID 生成系统需要保证全局唯一、有序、高性能、高可用,常见方案有UUID、数据库自增 ID、雪花算法、Redis、Leaf

深度解析

1. 唯一 ID 的要求

  • 全局唯一:ID 不能重复
  • 有序:ID 最好有序(方便数据库索引)
  • 高性能:生成 ID 的速度要快
  • 高可用:生成 ID 的服务不能宕机

2. 唯一 ID 生成方案

方案 1:UUID

  • 原理:128 位,全球唯一
  • 优点:实现简单,性能高
  • 缺点
    • 无序(不适合作为数据库主键,会导致索引碎片化)
    • 长度长(36 个字符,占用存储空间)
    • 可读性差

方案 3:雪花算法(Snowflake)

  • 原理:64 位 ID,由**时间戳(41 位)+ 机器 ID(10 位)+ 序列号(12 位)**组成
  • 优点
    • 有序(时间戳在高位,ID 按时间递增)
    • 高性能(每秒可生成 4096 * 2^10 = 419 万个 ID)
    • 高可用(不依赖外部服务)
  • 缺点
    • 时钟回拨问题(如果系统时钟回拨,可能生成重复 ID)
    • 机器 ID 需要手动配置(或使用时服务分配)

面试加分回答

“在实际项目中,分布式唯一 ID 生成系统的设计需要考虑:

  1. 有序性要求:如果用作数据库主键,推荐使用雪花算法或 Leaf(有序,避免索引碎片化)
  2. 性能要求:如果 QPS 很高,推荐使用雪花算法或 Redis
  3. 可用性要求:如果要求高可用,推荐使用雪花算法或 Leaf”

Q4:如何设计一个秒杀系统?

一句话总结:秒杀系统的核心是限流、削峰、异步处理,防止高并发流量打垮系统。

深度解析

1. 需求分析

  • 功能需求
    • 用户点击秒杀按钮,下单购买
    • 库存扣减(防止超卖)
    • 订单创建
  • 非功能需求
    • 高并发(10 万 QPS)
    • 低延迟(< 100ms)
    • 高可用(99.99%)

2. 核心挑战

  • 高并发读:商品详情页 QPS 很高
  • 高并发写:下单、支付 QPS 很高
  • 库存超卖:多个用户同时下单,库存扣减可能超卖

3. 设计方案

方案 1:前端限流 + 后端异步

1
用户 → Nginx(限流) → 网关 → Redis(预扣库存)→ MQ(异步下单)→ DB

方案 2:分层限流 + 多级缓存

1
CDN(静态页面) → Nginx(限流) → 网关(限流) → 服务 → Redis(缓存 + 分布式锁)→ DB

面试加分回答

“在实际项目中,秒杀系统的设计要点:

  1. 前端限流:按钮置灰、验证码、答题(防止脚本刷单)
  2. 网关限流:Nginx limit_req 模块、Sentinel 网关限流
  3. Redis 预扣库存:利用 Redis 单线程特性,原子性扣减库存
  4. MQ 异步下单:削峰填谷,防止数据库被打垮”

—### Q5:如何设计一个分布式锁?

一句话总结:分布式锁的核心是互斥性、可重入、防死锁、高可用,实现方案有 Redis、Zookeeper、etcd

深度解析

1. 分布式锁的要求

  • 互斥性:同一时间只有一个客户端能持有锁
  • 可重入:同一个客户端可以多次获取同一把锁
  • 防死锁:即使持有锁的客户端宕机,锁也能自动释放
  • 高可用:锁服务不能成为单点故障

2. 分布式锁实现方案

方案 1:Redis 实现分布式锁

  • 获取锁SET lock_key unique_value NX EX 10(NX:不存在才设置,EX:10 秒过期)
  • 释放锁:使用 Lua 脚本保证原子性
    1
    2
    3
    4
    5
    if redis.call('get', KEYS[1]) == ARGV[1] then
    return redis.call('del', KEYS[1])
    else
    return 0
    end
  • 优点:性能高,实现简单
  • 缺点
    • 时钟漂移问题(主从切换时可能丢失锁)
    • 锁过期时间难以估算(业务执行时间可能超过锁过期时间)

方案 2:Zookeeper 实现分布式锁

  • 原理:利用 Zookeeper 的临时顺序节点
    • 多个客户端在同一父节点下创建临时顺序节点
    • 序号最小的节点获取锁
    • 其他客户端监听前一个序号节点
    • 持有锁的客户端宕机,临时节点自动删除,下一个客户端获取锁
  • 优点
    • 可靠性高(CP 系统,强一致性)
    • 自带 Watch 机制,不用轮询
  • 缺点:性能不如 Redis

3. 方案对比

方案 一致性 性能 复杂度 推荐场景
Redis 最终一致 并发高,允许偶尔锁失效
Zookeeper 强一致 一致性要求高
etcd 强一致 中高 一致性要求高,K8s 环境

面试加分回答

“在实际项目中,分布式锁的选型:

  1. 并发高,允许偶尔锁失效:选择 Redis(如秒杀库存扣减)
  2. 一致性要求高:选择 Zookeeper 或 etcd(如金融转账)

实际面试中,可以深入讲解 Redis 分布式锁的缺陷

  • 时钟漂移:主节点时钟跳变,导致锁提前过期
  • 主从切换:主节点加锁成功,还没同步到从节点,主节点宕机,从节点升级为主节点,另一个客户端也能加锁成功(锁失效)”

Q6:如何设计一个消息队列(MQ)?

一句话总结:消息队列的核心是高性能、高可用、不丢消息、顺序性、幂等性

深度解析

1. 需求分析

  • 功能需求
    • 生产者发送消息
    • 消费者消费消息
    • 消息存储
    • 消息投递语义(至少一次、至多一次、精确一次)
  • 非功能需求
    • 高性能(10 万+ QPS)
    • 高可用(99.99%)
    • 不丢消息

2. 核心问题

问题 1:如何保证高性能?

  • 顺序写磁盘:消息追加到日志文件(比随机写快)
  • 零拷贝:sendfile() 系统调用,减少内核空间和用户空间之间的拷贝
  • 批量发送:生产者批量发送消息(减少网络往返)
  • 批量消费:消费者批量拉取消息(减少网络往返)

问题 2:如何保证高可用?

  • 集群部署:多 Broker 组成集群
  • 副本机制:每个分区(Partition)有多个副本(Leader + Follower)
  • Leader 故障自动切换:Controller 负责故障转移

面试加分回答

“在实际项目中,设计一个消息队列需要考虑:

  1. 存储选型:使用顺序写磁盘 + 零拷贝,提高性能
  2. 高可用:多 Broker + 多副本 + 自动故障转移
  3. 不丢消息:生产者 Confirm + Broker 持久化 + 消费者手动提交 Offset

实际面试中,可以举一个订单系统的例子:

  • 订单创建后,发送『订单创建』消息到 Kafka
  • 库存服务、支付服务、通知服务消费该消息
  • 保证不丢消息:生产者开启 Confirm,Broker 使用 3 副本,消费者手动提交 Offset”

Q7:如何设计一个分布式文件系统(如 HDFS、S3)?

一句话总结:分布式文件系统的核心是分块存储、多副本、高可用、高可靠

深度解析

1. 需求分析

  • 功能需求
    • 文件上传、下载
    • 文件分块存储
    • 文件副本管理
  • 非功能需求
    • 高可用(99.99%)
    • 高可靠(数据不丢失)
    • 可扩展(支持 PB 级存储)

2. 系统架构

1
2
3
客户端 → NameNode(元数据管理) → DataNode(数据存储)

副本管理、故障恢复

3. 核心问题

问题 1:如何分块存储?

  • 分块:文件分成固定大小的块(如 128 MB)
  • 优点
    • 支持大文件存储
    • 方便并行读写
    • 方便副本管理

问题 2:如何保证高可靠?

  • 多副本:每个块存储 3 个副本(不同机架)
  • 副本放置策略
    • 第一个副本:放在客户端所在节点
    • 第二个副本:放在不同机架的节点
    • 第三个副本:放在与第二个副本相同机架的不同节点

面试加分回答

“在实际项目中,设计分布式文件系统需要考虑:

  1. 分块大小选择:128 MB(平衡元数据开销和并行度)
  2. 副本数量选择:3 副本(可靠性 vs 存储成本)
  3. 机架感知:副本放在不同机架(防止机架故障)”

Q8:如何设计一个推荐系统?

一句话总结:推荐系统的核心是用户画像、物品画像、推荐算法、实时性

深度解析

1. 推荐算法

算法 1:协同过滤(Collaborative Filtering)

  • 基于用户:找到相似用户,推荐相似用户喜欢的物品
  • 基于物品:找到相似物品,推荐用户喜欢的物品的相似物品
  • 优点:简单,效果好
  • 缺点:冷启动问题、数据稀疏问题

算法 2:内容推荐(Content-Based Filtering)

  • 原理:根据用户历史行为,推荐相似物品
  • 优点:解决冷启动问题
  • 缺点:推荐结果单一

2. 系统架构

1
2
3
用户行为日志 → 实时计算(Flink)→ 用户画像

物品特征 → 推荐算法 → 推荐结果 → 排序 → 展示

面试加分回答

“在实际项目中,推荐系统的设计要点:

  1. 推荐算法选择:协同过滤(主流)+ 内容推荐(解决冷启动)
  2. 实时性:离线推荐 + 实时推荐(Flink)
  3. 排序:推荐结果需要排序(根据点击率、转化率)

实际面试中,可以举一个抖音推荐的例子:

  • 用户观看视频的行为(点赞、评论、分享)实时发送到 Kafka
  • Flink 实时计算用户画像(喜欢的视频类型、标签)
  • 推荐算法根据用画像推荐相似视频
  • 推荐结果排序(根据视频的热度、新鲜度)”

Q9:如何设计一个搜索引擎(如 Google、百度)?

一句话总结:搜索引擎的核心是爬取、索引、排序

深度解析

1. 系统架构

1
2
3
网页爬取 → 索引构建 → 倒排索引

搜索查询 → 排序 → 展示

2. 核心组件

组件 1:网页爬取(Crawler)

  • 原理:从种子 URL 开始,爬取网页,提取链接,继续爬取
  • 难点
    • 去重(同一网页多个 URL)
    • 反爬(网站禁止爬取)

组件 2:索引构建(Indexer)

  • 正排索引:文档 ID → 文档内容
  • 倒排索引:单词 → 文档 ID 列表
    1
    2
    单词:"Java"
    倒排索引:["Java", [文档1, 文档5, 文档10, ...]]

组件 3:排序(Ranking)

  • PageRank 算法:根据网页的链接数量和质量排序
  • TF-IDF:根据单词在文档中的频率和逆文档频率排序
  • 机器学习排序:使用机器学习模型排序(如 BERT)

面试加分回答

“在实际项目中,搜索引擎的设计要点:

  1. 倒排索引:核心数据结构,支持快速查询
  2. 排序算法:PageRank + 机器学习排序
  3. 索引更新:增量更新(新网页实时加入索引)”

Q10:如何设计一个聊天系统(如微信、WhatsApp)?

一句话总结:聊天系统的核心是实时消息传输、消息存储、消息推送、多端同步

深度解析

1. 需求分析

  • 功能需求
    • 一对一聊天
    • 群聊
    • 消息类型(文本、图片、语音、视频)
    • 消息状态(已发送、已送达、已读)
  • 非功能需求
    • 低延迟(< 100ms)
    • 高可用
    • 可扩展(支持亿级用户)

2. 核心问题

问题 1:如何保证实时消息传输?

  • 方案 1:WebSocket(推荐)
    • 客户端和服务器建立长连接
    • 服务器可以主动推送消息到客户端
  • 方案 2:长轮询(Long Polling)
    • 客户端发送请求,服务器有消息才返回,否则 Hold 住请求
    • 缺点:有延迟

问题 2:如何存储消息?

  • 消息存储
    • 关系型数据库(MySQL):存储消息内容
    • 时序数据库(InfluxDB):存储消息状态(已发送、已送达、已读)

面试加分回答

“在实际项目中,聊天系统的设计要点:

  1. 实时消息传输:使用 WebSocket(低延迟)
  2. 消息存储:MySQL(消息内容)+ Redis(消息 ID 同步)
  3. 消息推送:APNs(iOS)、FCM(Android)
  4. 多端同步:根据消息 ID 拉取消息

实际面试中,可以举一个微信消息同步的例子:

  • 用户在手机端发送消息
  • 消息同步到 PC 端、iPad 端
  • 实现方式:根据消息 ID 拉取消息(每个设备维护自己的消息 ID)”

—### Q11:如何设计一个视频网站(如 YouTube、B站)?

一句话总结:视频网站的核心是视频上传、转码、存储、分发、播放

深度解析

1. 需求分析

  • 功能需求
    • 视频上传
    • 视频转码(不同清晰度)
    • 视频存储
    • 视频分发(CDN)
    • 视频播放
  • 非功能需求
    • 低延迟(< 2s 起播)
    • 高可用
    • 可扩展(支持亿级视频)

2. 系统架构

1
2
3
4
5
6
7
客户端 → 上传服务 → 对象存储(S3

转码服务(FFmpeg)→ 多清晰度视频

CDN(视频分发)

客户端播放

3. 核心问题

问题 1:如何保证视频上传性能?

  • 分片上传:大视频分成多个分片,并行上传
  • 断点续传:记录已上传的分片,网络中断后继续上传

问题 2:如何转码?

  • 转码服务:使用 FFmpeg 转码成多种清晰度(480P、720P、1080P、4K)
  • 异步转码:视频上传后,异步转码(消息队列)

面试加分回答

“在实际项目中,视频网站的设计要点:

  1. 视频上传:分片上传 + 断点续传
  2. 视频转码:异步转码(消息队列)+ 多种清晰度
  3. 视频分发:CDN(就近访问)
  4. 视频播放:自适应码率(根据网络带宽切换清晰度)”

Q12:如何设计一个分布式缓存系统(如 Redis Cluster)?

一句话总结:分布式缓存系统的核心是数据分片、高可用、一致性哈希

深度解析

1. 需求分析

  • 功能需求
    • 数据分片存储
    • 高可用(主从复制、故障转移)
    • 数据一致性
  • 非功能需求
    • 低延迟(< 1ms)
    • 高可用(99.99%)
    • 可扩展(支持 TB 级数据)

2. 系统架构

1
2
3
客户端 → 负载均衡 → Redis Cluster16384 个槽位)

主从复制(每个主节点有从节点)

3. 核心问题

问题 1:如何分片数据?

  • 一致性哈希:将哈希空间组织成虚拟圆环,数据根据哈希值映射到圆环上
    • 优点:增加或删除节点时,只影响相邻节点
    • 缺点:数据倾斜(某些节点数据过多)
  • 虚拟节点:每个物理节点对应多个虚拟节点,解决数据倾斜问题

面试加分回答

“在实际项目中,分布式缓存系统的设计要点:

  1. 数据分片:一致性哈希 + 虚拟节点
  2. 高可用:主从复制 + 故障转移
  3. 数据一致性:最终一致性(主节点写,从节点读)”

Q13:如何设计一个 API 网关(如 Kong、Zuul)?

一句话总结:API 网关的核心是路由、负载均衡、限流、认证、监控

深度解析

1. 需求分析

  • 功能需求
    • 路由(根据请求路径,转发到后端服务)
    • 负载均衡(将请求分发到多个后端服务实例)
    • 限流(防止后端服务被突发流量打垮)
    • 认证(验证请求是否合法)
    • 监控(统计请求量、延迟、错误率)
  • 非功能需求
    • 低延迟(< 10ms)
    • 高可用
    • 可扩展(支持多种协议:HTTP、gRPC、WebSocket)

2. 系统架构

1
2
3
客户端 → API 网关 → 负载均衡 → 后端服务

限流、认证、监控

面试加分回答

“在实际项目中,API 网关的设计要点:

  1. 路由:根据请求路径转发到后端服务
  2. 负载均衡:将请求分发到多个后端服务实例
  3. 限流:令牌桶算法 + Redis
  4. 认证:JWT 或 OAuth 2.0”

Q14:如何设计一个微服务架构?

一句话总结:微服务架构的核心是服务拆分、服务通信、服务治理、服务监控

深度解析

1. 服务拆分

  • 按业务能力拆分:如订单服务、用户服务、商品服务
  • 按数据模型拆分:每个微服务有自己的数据库
  • 避免过度拆分:服务拆分过细,会增加服务通信成本

2. 服务通信

  • 同步通信:HTTP/REST、gRPC
  • 异步通信:消息队列(Kafka、RabbitMQ)

3. 服务治理

  • 配置中心:Apollo、Nacos
  • 服务熔断:Hystrix、Sentinel
  • 服务降级:返回默认值、返回缓存数据
  • 服务限流:Sentinel、Guava RateLimiter

面试加分回答

“在实际项目中,微服务架构的设计要点:

  1. 服务拆分:按业务能力拆分,避免过度拆分
  2. 服务通信:同步用 gRPC(高性能),异步用 Kafka(解耦)
  3. 服务治理:配置中心 + 熔断 + 降级 + 限流”

Q15:如何设计一个高可用系统?

一句话总结:高可用系统的核心是消除单点故障、故障自动转移、健康检查、监控告警

深度解析

1. 消除单点故障

  • 负载均衡:Nginx、HAProxy、云服务商的负载均衡器
  • 主从复制:数据库主从复制、Redis 主从复制
  • 集群部署:多实例部署(如 Kafka 多 Broker、Elasticsearch 多节点)

2. 故障自动转移

  • 数据库:主库故障,从库自动切换成主库(如 MHA、Orchestrator)
  • Redis:主节点故障,从节点自动切换(哨兵模式、Cluster 模式)

面试加分回答

“在实际项目中,高可用系统的设计要点:

  1. 消除单点故障:负载均衡 + 主从复制 + 集群部署
  2. 故障自动转移:数据库主从切换、Redis 哨兵模式
  3. 健康检查:服务健康检查 + 负载均衡器健康检查
  4. 监控告警:Prometheus + Grafana 监控,阈值告警”



🗺️ 学习路径总结

🎯 学习路线:从入门到精通,系统掌握系统设计知识的完整学习路径。

📚 第一阶段:入门基础(1-2 周)

目标:掌握系统设计的基础概念和常用模式

学习清单

  1. 基础架构:负载均衡、CDN、缓存、数据库
  2. 常见系统:短链接系统、限流器、唯一 ID 生成系统
  3. 面试技巧:如何回答系统设计问题

实战项目:设计一个简单的短链接系统

面试重点:Q1(短链接系统)、Q2(限流器)、Q3(唯一 ID 生成)


🚀 第二阶段:进阶实战(2-4 周)

目标:掌握复杂系统的设计方法

学习清单

  1. 高并发系统:秒杀系统、分布式锁、消息队列
  2. 大数据系统:分布式文件系统、推荐系统、搜索引擎
  3. 实时系统:聊天系统、视频网站

实战项目:设计一个高并发的秒杀系统

面试重点:Q4(秒杀系统)、Q5(分布式锁)、Q6(消息队列)、Q7(分布式文件系统)、Q8(推荐系统)、Q9(搜索引擎)、Q10(聊天系统)


💪 第三阶段:高级精通(1-2 个月)

目标:掌握分布式系统的核心原理和高级设计

学习清单

  1. 分布式理论:CAP 定理、一致性哈希、分布式事务
  2. 分布式系统:分布式缓存、API 网关、微服务架构
  3. 高可用设计:高可用系统、负载均衡、数据库分库分表

实战项目:设计一个高可用的电商系统

面试重点:Q11(视频网站)、Q12(分布式缓存)、Q13(API 网关)、Q14(微服务架构)、Q15(高可用系统)、Q16(CAP 定理)、Q17(一致性哈希)、Q18(负载均衡)、Q19(数据库分库分表)、Q20(分布式事务)


🏆 第四阶段:架构专家(持续学习)

目标:成为系统设计架构专家,能够设计大规模分布式系统

学习清单

  1. 大规模系统:设计支持亿级用户的系统
  2. 性能优化:QPS 优化、延迟优化、成本控制
  3. 安全设计:认证、授权、加密、防攻击
  4. 运维设计:监控、告警、故障恢复、容量规划

实战项目:设计一个支持亿级用户的社交网络

面试重点:系统设计综合能力、架构权衡能力、技术选型能力


📅 学习时间安排

阶段 时间投入 学习目标 实战项目
第一阶段:入门基础 1-2 周,每天 2 小时 掌握基础概念和常用模式 短链接系统
第二阶段:进阶实战 2-4 周,每天 2-3 小时 掌握复杂系统的设计 秒杀系统
第三阶段:高级精通 1-2 个月,每天 3-4 小时 掌握分布式系统原理 电商系统
第四阶段:架构专家 持续学习,每天 1-2 小时 成为架构专家 社交网络

🎯 面试准备建议

1. 基础设计(必须掌握)

  • Q1-Q3:短链接系统、限流器、唯一 ID 生成
  • Q4-Q6:秒杀系统、分布式锁、消息队列

2. 进阶设计(面试高频)

  • Q7-Q10:分布式文件系统、推荐系统、搜索引擎、聊天系统
  • Q11-Q13:视频网站、分布式缓存、API 网关

3. 高级设计(加分项)

  • Q14-Q17:微服务架构、高可用系统、CAP 定理、一致性哈希
  • Q18-Q20:负载均衡、数据库分库分表、分布式事务

4. 面试技巧

  • 先问清楚需求(功能需求、非功能需求)
  • 再给出高层设计(画出系统架构图)
  • 最后深入讨论细节(数据库 schema、缓存策略、消息队列选型)

📚 学习资源推荐

官方资源

书籍推荐

  • 《系统设计面试指南》(System Design Interview)
  • 《大规模系统设计》(Designing Data-Intensive Applications)

实战项目

社区


💡 学习建议

  1. 不要急于求成:系统设计知识体系庞大,需要循序渐进
  2. 动手实践:理论结合实践,多画画系统架构图
  3. 参与社区:在社区中回答问题,加深理解
  4. 持续学习:分布式系统不断发展,要保持学习状态


Q14: 如何设计分布式配置中心(Apollo/Nacos)?

一句话总结:分布式配置中心的核心是集中管理配置、支持动态刷新、配置历史管理和灰度发布。

深度解析

1. 为什么需要分布式配置中心?

传统配置方式的问题:

  • 配置写在本地文件中,修改需要重启服务
  • 配置分散在各个服务中,难以统一管理
  • 配置没有历史版本,无法回滚
  • 配置没有权限控制,任何人都能修改

分布式配置中心的优势:

  • 集中管理:所有配置在一个地方管理
  • 动态刷新:修改配置后,服务自动刷新(无需重启)
  • 历史管理:配置有历史版本,可以回滚
  • 灰度发布:配置可以按环境、按机器灰度发布
  • 权限控制:配置有权限控制,防止误操作

2. 分布式配置中心的核心功能

功能 说明
配置管理 集中管理所有配置(新增、修改、删除)
配置刷新 修改配置后,服务自动刷新(基于长轮询或 WebSocket)
配置历史 记录配置的历史版本,支持回滚
灰度发布 配置可以按环境(dev/test/prod)、按机器(IP)灰度发布
权限控制 配置有读写权限控制,防止误操作
配置监听 服务可以监听配置变化,实时刷新

3. Apollo 架构设计

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
┌─────────────────────────────────────────────────────┐
│ Apollo 架构 │
├─────────────────────────────────────────────────────┤
│ │
│ ┌─────────┐ ┌─────────┐ ┌─────────┐ │
│ │ Portal │─────▶│ Admin │─────▶│ Config │ │
│ │ (管理界面)│ │ (管理端) │ │ (配置服务)│ │
│ └─────────┘ └─────────┘ └─────────┘ │
│ │ │ │
│ │ ▼ │
│ │ ┌─────────────────┐│
│ │ │ ConfigDB ││
│ │ │ (配置存储) ││
│ │ └─────────────────┘│
│ │ │ │
│ │ ▼ │
│ │ ┌─────────────────┐│
│ │ │ Client ││
│ │ │ (客户端拉取配置) ││
│ │ └─────────────────┘│
│ │ │ │
│ │ ▼ │
│ │ ┌─────────────────┐│
│ │ │ Service ││
│ │ │ (业务服务) ││
│ │ └─────────────────┘│
└─────────────────────────────────────────────────────┘

核心组件

  • Portal:管理界面,供管理员配置
  • Admin Service:管理端,处理配置的增删改查
  • Config Service:配置服务,供客户端拉取配置
  • Client:客户端,定期拉取配置并缓存到本地

4. 配置刷新机制(长轮询)

Apollo 使用**长轮询(Long Polling)**实现配置动态刷新:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
// 客户端长轮询伪代码
public class ApolloLongPolling {

public void longPolling() {
while (true) {
// 1. 客户端向 Config Service 发起长轮询请求
// 2. Config Service 会 hold 住请求(最长 30 秒)
// 3. 如果在 30 秒内有配置变化,立即返回
// 4. 如果 30 秒内没有变化,返回 304(未修改)
// 5. 客户端收到响应后,立即发起下一次长轮询

HttpResponse response = httpClient.get(
"http://config-service/configs?appId=xxx&cluster=xxx"
);

if (response.getStatusCode() == 200) {
// 配置有变化,拉取最新配置
Config newConfig = parseResponse(response);
updateLocalCache(newConfig);
} else if (response.getStatusCode() == 304) {
// 配置无变化,继续长轮询
}
}
}
}

5. Nacos 架构设计

Nacos 相比 Apollo 更轻量,支持配置管理服务发现

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
┌─────────────────────────────────────────────────────┐
│ Nacos 架构 │
├─────────────────────────────────────────────────────┤
│ │
│ ┌─────────┐ ┌─────────┐ ┌─────────┐ │
│ │ Console │─────▶│ Nacos │─────▶│ Nacos │ │
│ │ (管理界面)│ │ Server │ │ Server │ │
│ └─────────┘ └─────────┘ └─────────┘ │
│ │ │ │
│ ▼ ▼ │
│ ┌─────────────────────────────┐ │
│ │ MySQL (配置存储) │ │
│ └─────────────────────────────┘ │
│ │ │
│ ▼ │
│ ┌─────────────────────────────┐ │
│ │ Client (客户端) │ │
│ └─────────────────────────────┘ │
└─────────────────────────────────────────────────────┘

6. 配置灰度发布

配置灰度发布的场景:

  • 场景 1:配置先在一台机器上生效,验证没问题后再全量发布
  • 场景 2:配置按环境(dev/test/prod)分开管理

实现方式(Apollo):

  1. 在 Portal 上配置灰度规则(按 IP、按环境)
  2. Config Service 根据灰度规则,返回不同的配置
  3. 客户端根据灰度规则,拉取对应的配置

7. 实战:Spring Boot 集成 Apollo

1
2
3
4
5
6
<!-- pom.xml -->
<dependency>
<groupId>com.ctrip.framework.apollo</groupId>
<artifactId>apollo-client</artifactId>
<version>2.1.0</version>
</dependency>
1
2
3
4
# application.properties
apollo.bootstrap.enabled = true
apollo.bootstrap.namespaces = application
apollo.meta = http://localhost:8080
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
import org.springframework.beans.factory.annotation.Value;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RestController;

@RestController
public class ApolloController {

@Value("${timeout:1000}")
private int timeout;

@GetMapping("/timeout")
public int getTimeout() {
return timeout; // 配置修改后,自动刷新(无需重启)
}
}

面试加分回答

实际项目经验

“在实际项目中,我们使用 Apollo 管理所有微服务的配置:

  1. 配置集中管理:所有微服务的配置都放在 Apollo 中,不再分散在各个 jar 包中
  2. 动态刷新:修改配置后,微服务自动刷新(基于长轮询),无需重启
  3. 灰度发布:配置先在一台机器上生效,验证没问题后再全量发布
  4. 权限控制:不同环境(dev/test/prod)有不同的权限,防止误操作

对比 Nacos:Nacos 更轻量,支持配置管理和服务发现,适合小型项目;Apollo 功能更完善,适合大型项目。”

面试高频追问

  • Q: Apollo 和 Nacos 的区别?
    • A: Apollo 功能更完善(灰度发布、权限控制、配置历史),适合大型项目;Nacos 更轻量,支持配置管理和服务发现,适合小型项目。
  • Q: 配置中心挂了怎么办?
    • A: 客户端会缓存配置到本地文件,配置中心挂了不影响服务启动。

Q15: 如何设计分布式日志系统(ELK)?

一句话总结:分布式日志系统的核心是日志收集、日志存储、日志搜索和日志分析,常用方案是 ELK(Elasticsearch + Logstash + Kibana)。

深度解析

1. 为什么需要分布式日志系统?

传统日志方式的问题:

  • 日志分散在各个服务器上,排查问题需要登录每台服务器
  • 日志量大,用 grep 搜索很慢
  • 日志没有统一格式,难以分析
  • 日志没有告警,问题发现不及时

分布式日志系统的优势:

  • 集中管理:所有日志集中在一个地方
  • 快速搜索:基于 Elasticsearch,秒级搜索 TB 级日志
  • 可视化分析:基于 Kibana,可视化展示日志趋势
  • 告警:日志异常时自动告警(基于 ElastAlert)

2. ELK 架构设计

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
┌─────────────────────────────────────────────────────────────┐
│ ELK 架构 │
├─────────────────────────────────────────────────────────────┤
│ │
│ ┌─────────┐ ┌─────────┐ ┌─────────┐ │
│ │ App │───▶│ Logstash│───▶│ Elasticsearch │ │
│ │ (业务应用)│ │ (日志收集)│ │ (日志存储/搜索)│ │
│ └─────────┘ └─────────┘ └─────────┘ │
│ │ │
│ ▼ │
│ ┌─────────────────┐ │
│ │ Kibana │ │
│ │ (日志可视化) │ │
│ └─────────────────┘ │
└─────────────────────────────────────────────────────────────┘

核心组件

  • Logstash:日志收集、过滤、转换(重量级,耗资源)
  • Filebeat:日志收集(轻量级,替代 Logstash)
  • Elasticsearch:日志存储和搜索(分布式搜索引擎)
  • Kibana:日志可视化(图表、仪表盘)

3. 日志收集流程

1
业务应用 → 日志文件 → Filebeat → Logstash → Elasticsearch → Kibana

Filebeat 配置(轻量级日志收集):

1
2
3
4
5
6
7
8
9
# filebeat.yml
filebeat.inputs:
- type: log
enabled: true
paths:
- /var/log/app/*.log # 监控的日志文件

output.logstash:
hosts: ["localhost:5044"] # 输出到 Logstash

Logstash 配置(日志过滤和转换):

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
# logstash.conf
input {
beats {
port => 5044 # 接收 Filebeat 的日志
}
}

filter {
# 解析日志中的时间戳
date {
match => [ "timestamp", "yyyy-MM-dd HH:mm:ss" ]
}

# 解析日志级别(INFO/WARN/ERROR)
if "ERROR" in [message] {
mutate {
add_tag => [ "error" ]
}
}
}

output {
elasticsearch {
hosts => [ "localhost:9200" ]
index => "app-logs-%{+yyyy.MM.dd}" # 按日期创建索引
}
}

4. Elasticsearch 存储设计

索引设计

  • 按日期创建索引:app-logs-2026.06.17(便于删除过期日志)
  • 分片数:3-5 个分片(根据日志量调整)
  • 副本数:1 个副本(保证高可用)

Mapping 设计

1
2
3
4
5
6
7
8
9
10
11
{
"mappings": {
"properties": {
"timestamp": { "type": "date" },
"level": { "type": "keyword" },
"service_name": { "type": "keyword" },
"message": { "type": "text" },
"stack_trace": { "type": "text" }
}
}
}

5. Kibana 可视化

常用图表

  • 日志量趋势图:按时间显示日志量(发现异常)
  • 错误日志占比:ERROR 日志的占比(监控健康度)
  • TOP 10 错误:出现最多的错误(优先解决)
  • 响应时间分布:P50、P95、P99 响应时间(性能分析)

6. 日志告警(ElastAlert)

1
2
3
4
5
6
7
8
9
10
11
12
13
14
# elastalert规则:ERROR 日志超过 100 条/分钟就告警
name: app-error-threshold
type: frequency
index: app-logs-*
num_events: 100
timeframe:
minutes: 1
filter:
- term:
level: "ERROR"
alert:
- "email"
email:
- "admin@example.com"

面试加分回答

实际项目经验

“在实际项目中,我们使用 ELK 搭建日志系统:

  1. 日志收集:每个服务用 Filebeat 收集日志,发送到 Logstash
  2. 日志过滤:Logstash 解析日志中的时间戳、日志级别、服务名称
  3. 日志存储:Logstash 将日志存储到 Elasticsearch(按日期创建索引)
  4. 日志可视化:Kibana 展示日志趋势、错误占比、TOP 10 错误
  5. 日志告警:ElastAlert 监控 ERROR 日志,超过阈值就邮件告警

优化点:

  • 日志量太大:只收集 WARN 和 ERROR 日志,INFO 日志不收集
  • Elasticsearch 磁盘占用高:设置索引生命周期策略(ILM),自动删除 7 天前的日志”

面试高频追问

  • Q: ELK 和 Loki 的区别?
    • A: ELK 功能强大(全文搜索、复杂聚合),但重量级;Loki 轻量级,只索引元数据(不索引日志内容),适合存储大量日志。
  • Q: 如何保证日志不丢失?
    • A: Filebeat 支持持久化(将日志缓存到磁盘),Logstash 支持持久化队列(防止 Elasticsearch 挂了丢失日志)。

Q16: 如何设计分布式监控告警系统(Prometheus + Grafana)?

一句话总结:分布式监控告警系统的核心是指标采集、指标存储、指标展示和告警,常用方案是 Prometheus + Grafana。

深度解析

1. 为什么需要分布式监控告警系统?

传统监控方式的问题:

  • 监控分散在各个系统中,没有统一视图
  • 监控数据没有持久化,历史数据丢失
  • 没有告警,问题发现不及时
  • 没有可视化,难以分析问题趋势

分布式监控告警系统的优势:

  • 统一监控:所有服务的指标集中在一个地方
  • 持久化存储:监控数据持久化(Prometheus TSDB)
  • 告警:指标异常时自动告警(基于 Prometheus Alertmanager)
  • 可视化:指标可视化展示(基于 Grafana)

2. Prometheus 架构设计

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
┌─────────────────────────────────────────────────────────────┐
│ Prometheus 架构 │
├─────────────────────────────────────────────────────────────┤
│ │
│ ┌─────────┐ ┌─────────┐ ┌─────────┐ │
│ │ App │───▶│ Exporter│───▶│ Prometheus │ │
│ │ (业务应用)│ │ (指标暴露)│ │ (指标采集/存储)│ │
│ └─────────┘ └─────────┘ └─────────┘ │
│ │ │
│ ▼ │
│ ┌─────────────────┐ │
│ │ Grafana │ │
│ │ (指标可视化) │ │
│ └─────────────────┘ │
│ │ │
│ ▼ │
│ ┌─────────────────┐ │
│ │ Alertmanager │ │
│ │ (告警管理) │ │
│ └─────────────────┘ │
└─────────────────────────────────────────────────────────────┘

核心组件

  • Exporter:暴露指标(如 http_requests_total
  • Prometheus Server:采集指标、存储指标(TSDB)
  • Grafana:指标可视化(图表、仪表盘)
  • Alertmanager:告警管理(去重、分组、路由)

3. 指标采集流程

业务应用暴露指标(Spring Boot Actuator):

1
2
3
4
5
6
7
8
9
<!-- pom.xml -->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-actuator</artifactId>
</dependency>
<dependency>
<groupId>io.micrometer</groupId>
<artifactId>micrometer-registry-prometheus</artifactId>
</dependency>
1
2
3
4
5
6
7
8
9
10
# application.yml
management:
endpoints:
web:
exposure:
include: prometheus # 暴露 Prometheus 指标
metrics:
export:
prometheus:
enabled: true

访问 http://localhost:8080/actuator/prometheus,可以看到指标:

1
2
3
4
# HELP http_server_requests_seconds HTTP 请求耗时
# TYPE http_server_requests_seconds histogram
http_server_requests_seconds_count{method="GET",status="200",uri="/api/users"} 100
http_server_requests_seconds_sum{method="GET",status="200",uri="/api/users"} 50.5

Prometheus 采集指标prometheus.yml):

1
2
3
4
5
scrape_configs:
- job_name: 'spring-boot'
scrape_interval: 15s # 每 15 秒采集一次
static_configs:
- targets: ['localhost:8080'] # Spring Boot 应用地址

4. Prometheus 查询语言(PromQL)

常用查询

1
2
3
4
5
6
7
8
9
10
11
# 1. 查询 QPS(每秒请求数)
rate(http_server_requests_seconds_count[1m])

# 2. 查询 P95 响应时间
histogram_quantile(0.95, sum(rate(http_server_requests_seconds_bucket[5m])) by (le))

# 3. 查询错误率
rate(http_server_requests_seconds_count{status=~"5.."}[1m]) / rate(http_server_requests_seconds_count[1m])

# 4. 查询 JVM 内存使用率
jvm_memory_used_bytes / jvm_memory_max_bytes

5. Grafana 可视化

常用仪表盘

  • QPS 趋势图:每秒请求数(发现流量突增)
  • 响应时间图:P50、P95、P99 响应时间(性能分析)
  • 错误率图:5xx 错误占比(监控健康度)
  • JVM 监控:堆内存、GC 次数、线程数(JVM 调优)

6. 告警规则(Prometheus Alertmanager)

1
2
3
# prometheus.yml
rule_files:
- "alerts.yml"
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
# alerts.yml
groups:
- name: app-alerts
rules:
# 告警规则 1:QPS 超过 1000
- alert: HighQPS
expr: rate(http_server_requests_seconds_count[1m]) > 1000
for: 5m # 持续 5 分钟才告警
labels:
severity: warning
annotations:
summary: "QPS 超过 1000"
description: "当前 QPS: {{ $value }}"

# 告警规则 2:错误率超过 5%
- alert: HighErrorRate
expr: rate(http_server_requests_seconds_count{status=~"5.."}[1m]) / rate(http_server_requests_seconds_count[1m]) > 0.05
for: 5m
labels:
severity: critical
annotations:
summary: "错误率超过 5%"
description: "当前错误率: {{ $value | humanizePercentage }}"

Alertmanager 配置(告警路由):

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
route:
receiver: 'email-notifications' # 默认接收者
group_by: ['alertname', 'service'] # 按告警名称和服务分组
group_wait: 10s # 等待 10 秒,合并同一组的告警
group_interval: 5m # 同一组告警,5 分钟内只发一次
repeat_interval: 1h # 告警恢复后,1 小时内不再发送

receivers:
- name: 'email-notifications'
email_configs:
- to: 'admin@example.com'
from: 'alert@example.com'
smarthost: 'smtp.example.com:587'
auth_username: 'alert@example.com'
auth_password: 'password'

面试加分回答

实际项目经验

“在实际项目中,我们使用 Prometheus + Grafana 搭建监控告警系统:

  1. 指标采集:每个服务暴露 Prometheus 指标(基于 Spring Boot Actuator)
  2. 指标存储:Prometheus 每 15 秒采集一次指标,存储到 TSDB
  3. 指标展示:Grafana 展示 QPS、响应时间、错误率、JVM 监控
  4. 告警:Prometheus Alertmanager 监控错误率、QPS、JVM 内存,超过阈值就邮件告警

优化点:

  • Prometheus 存储压力大:使用 Thanos 或 VictoriaMetrics 实现长期存储
  • 告警太多:优化告警规则,减少误报(增加 for: 5m 持续 5 分钟才告警)”

面试高频追问

  • Q: Prometheus 和 Zabbix 的区别?
    • A: Prometheus 适合云原生场景(Kubernetes),基于 Pull 模型;Zabbix 适合传统场景(物理机),基于 Push 模型。
  • Q: 如何保证告警不丢失?
    • A: Alertmanager 支持高可用部署(集群模式),Prometheus 支持联邦集群(分层采集)。

Q17: 如何设计高并发系统?

一句话总结:高并发系统的设计核心是缓存、异步、分流、限流、降级,通过多层防护保证系统稳定。

深度解析

1. 高并发系统的挑战

挑战 说明 解决方案
海量请求 QPS 从 1k 飙升到 100k 负载均衡、分布式部署
数据库压力 大量读请求打垮数据库 缓存、读写分离、分库分表
服务雪崩 一个服务挂了,导致整个系统雪崩 熔断、降级、限流
网络带宽 大量请求占用带宽 CDN、压缩、限流

2. 高并发系统的设计原则

1
2
3
4
5
6
7
8
9
10
11
┌─────────────────────────────────────────────────────────────┐
│ 高并发系统设计原则 │
├─────────────────────────────────────────────────────────────┤
│ │
│ 1. 缓存优先:能缓存的都缓存(本地缓存 → 分布式缓存) │
│ 2. 异步处理:能异步的都异步(消息队列) │
│ 3. 分流策略:能分流的都分流(负载均衡、分库分表) │
│ 4. 限流降级:保护核心服务(限流、熔断、降级) │
│ 5. 无状态设计:服务无状态,便于水平扩展 │
│ │
└─────────────────────────────────────────────────────────────┘

3. 高并发系统的架构设计

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
┌─────────────────────────────────────────────────────────────┐
│ 高并发系统架构 │
├─────────────────────────────────────────────────────────────┤
│ │
│ ┌─────────┐ ┌─────────┐ ┌─────────┐ │
│ │ User │───▶│ CDN │───▶│ LB │ │
│ │ (用户) │ │ (静态资源)│ │ (负载均衡)│ │
│ └─────────┘ └─────────┘ └─────────┘ │
│ │ │
│ ▼ │
│ ┌─────────────────┐ │
│ │ API Gateway │ │
│ │ (限流、鉴权) │ │
│ └─────────────────┘ │
│ │ │
│ ▼ │
│ ┌─────────────────┐ │
│ │ Service │ │
│ │ (业务逻辑) │ │
│ └─────────────────┘ │
│ │ │
│ ▼ │
│ ┌────────────────────────────────────┐ │
│ │ 缓存层 │ 消息队列 │ 数据库层 │ │
│ └────────────────────────────────────┘ │
└─────────────────────────────────────────────────────────────┘

4. 缓存设计

缓存层次

  1. 本地缓存(一级缓存):HashMap、Guava Cache、Caffeine(纳秒级)
  2. 分布式缓存(二级缓存):Redis、Memcached(毫秒级)
  3. 数据库(三级缓存):MySQL、PostgreSQL(毫秒级)

缓存策略

  • Cache-Aside(旁路缓存):优先读缓存,缓存没有则读数据库
  • Read-Through(读穿透):缓存层负责读数据库
  • Write-Through(写穿透):缓存层负责写数据库

缓存问题

  • 缓存穿透:查询不存在的数据(解决方案:布隆过滤器、缓存空值)
  • 缓存击穿:热点 Key 过期(解决方案:互斥锁、逻辑过期时间)
  • 缓存雪崩:大量 Key 同时过期(解决方案:过期时间随机化、集群部署)

5. 异步处理(消息队列)

适用场景

  • 下单后发送邮件(不需要实时)
  • 下单后扣减库存(不需要实时)
  • 下单后生成账单(不需要实时)

消息队列选型

  • RabbitMQ:功能丰富(延迟队列、死信队列),适合复杂场景
  • Kafka:高吞吐量(百万级 QPS),适合日志、埋点
  • RocketMQ:高可靠(金融级),适合电商、金融

6. 限流算法

算法 说明 优点 缺点
固定窗口 统计固定时间内的请求数 简单 临界问题(两个窗口交界处可能允许 2 倍流量)
滑动窗口 统计滑动时间内的请求数 精确 内存占用高
漏桶算法 请求以固定速率处理 流量平滑 不能应对突发流量
令牌桶算法 令牌桶中以固定速率生成令牌 允许突发流量 实现复杂

Guava RateLimiter(令牌桶)

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
import com.google.common.util.concurrent.RateLimiter;

@RestController
public class RateLimitController {

// 每秒生成 100 个令牌(允许 100 QPS)
private final RateLimiter rateLimiter = RateLimiter.create(100.0);

@GetMapping("/api/users")
public String getUsers() {
if (!rateLimiter.tryAcquire()) {
return "系统繁忙,请稍后再试"; // 限流
}

// 业务逻辑
return userService.getUsers();
}
}

7. 服务降级和熔断

降级:服务不可用时,返回默认值(如返回缓存数据、返回空数据)

熔断:服务错误率超过阈值时,直接拒绝请求(防止服务雪崩)

Hystrix 熔断规则

  1. 请求数达到阈值(如 20 个请求)
  2. 错误率达到阈值(如 50%)
  3. 触发熔断(后续请求直接失败,不调用服务)
  4. 熔断一段时间后,尝试恢复(半开状态)

面试加分回答

实际项目经验

“在实际项目中,我们设计高并发系统的经验:

  1. 缓存优先:热点数据放在 Redis 缓存中,缓存没有才读数据库
  2. 异步处理:下单后,发送邮件、扣减库存、生成账单都异步处理(基于 RocketMQ)
  3. 限流:API Gateway 使用令牌桶算法限流(1000 QPS)
  4. 熔断降级:订单服务不可用时,返回缓存的订单数据(基于 Hystrix)
  5. 无状态设计:所有服务都是无状态的,便于水平扩展

效果:系统支持的 QPS 从 1k 提升到 100k,数据库压力降低了 90%。”

面试高频追问

  • Q: 如何预估系统需要支持多少 QPS?
    • A: 根据业务场景预估(如日活用户 100 万,每人平均请求 10 次,集中在 4 小时,则 QPS = 100 万 * 10 / (4 * 3600) ≈ 700 QPS)。
  • Q: 缓存和数据库一致性如何保证?
    • A: 先更新数据库,再删除缓存(Cache-Aside 策略);或者使用消息队列异步更新缓存。

Q18: 如何设计秒杀系统?

一句话总结:秒杀系统的核心是流量分层过滤、异步处理、流量削峰,保证系统不被瞬时流量打垮。

深度解析

1. 秒杀系统的挑战

挑战 说明 解决方案
瞬时流量高 100 万人抢 100 件商品 流量分层过滤、限流
库存超卖 100 件商品被 200 人抢到 分布式锁、Redis 原子操作
数据库压力 大量下单请求打垮数据库 异步处理、消息队列
恶意刷单 黄牛用脚本刷单 验证码、风控系统

2. 秒杀系统的架构设计

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
┌─────────────────────────────────────────────────────────────┐
│ 秒杀系统架构 │
├─────────────────────────────────────────────────────────────┤
│ │
│ ┌─────────┐ ┌─────────┐ ┌─────────┐ │
│ │ User │───▶│ CDN │───▶│ LB │ │
│ │ (用户) │ │ (静态资源)│ │ (负载均衡)│ │
│ └─────────┘ └─────────┘ └─────────┘ │
│ │ │
│ ▼ │
│ ┌─────────────────┐ │
│ │ Nginx │ │
│ │ (限流、黑白名单) │ │
│ └─────────────────┘ │
│ │ │
│ ▼ │
│ ┌─────────────────┐ │
│ │ API Gateway │ │
│ │ (鉴权、限流) │ │
│ └─────────────────┘ │
│ │ │
│ ▼ │
│ ┌─────────────────┐ │
│ │ 秒杀服务 │ │
│ │ (校验库存、下单) │ │
│ └─────────────────┘ │
│ │ │
│ ▼ │
│ ┌────────────────────────────────────┐ │
│ │ Redis (库存预扣减) │ MQ (异步下单) │ │
│ └────────────────────────────────────┘ │
└─────────────────────────────────────────────────────────────┘

3. 流量分层过滤

第 1 层:CDN 过滤静态资源

  • 秒杀页面中的图片、CSS、JS 都放在 CDN 上
  • 用户请求 CDN,不打到后端服务器

第 2 层:Nginx 限流

  • 限制每个 IP 的请求频率(如每个 IP 每秒只能请求 1 次)
  • 黑名单:封禁恶意 IP

第 3 层:API Gateway 鉴权和限流

  • 鉴权:校验用户是否登录
  • 限流:限制每个用户的请求频率(如每个用户每秒只能请求 1 次)

第 4 层:秒杀服务校验库存

  • 校验库存是否充足(基于 Redis)
  • 校验用户是否已经抢过(基于 Redis Set)

第 5 层:消息队列异步下单

  • 下单请求放入消息队列,异步处理
  • 数据库批量插入订单(减少数据库连接)

4. 库存预扣减(Redis 原子操作)

问题:100 万人抢 100 件商品,如何防止超卖?

解决方案:使用 Redis 的 DECR 原子操作预扣减库存

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
import redis.clients.jedis.Jedis;

public class SeckillService {

private final Jedis jedis = new Jedis("localhost", 6379);

public boolean seckill(String userId, String productId) {
// 1. 校验用户是否已经抢过(Redis Set)
String userKey = "seckill:users:" + productId;
if (jedis.sismember(userKey, userId)) {
System.out.println("您已经抢过啦!");
return false;
}

// 2. 预扣减库存(Redis 原子操作 DECR)
String stockKey = "seckill:stock:" + productId;
Long remaining = jedis.decr(stockKey); // 原子操作

if (remaining < 0) {
System.out.println("库存不足!");
jedis.incr(stockKey); // 库存加回去
return false;
}

// 3. 记录用户已经抢过
jedis.sadd(userKey, userId);

// 4. 异步下单(放入消息队列)
String orderInfo = userId + ":" + productId;
jedis.lpush("seckill:orders", orderInfo);

System.out.println("抢购成功!");
return true;
}
}

5. 异步下单(消息队列)

问题:100 万下单请求同时打到数据库,数据库会挂!

解决方案:下单请求放入消息队列,异步处理

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
import org.springframework.kafka.annotation.KafkaListener;
import org.springframework.kafka.core.KafkaTemplate;

@Service
public class OrderService {

private final KafkaTemplate<String, String> kafkaTemplate;

public OrderService(KafkaTemplate<String, String> kafkaTemplate) {
this.kafkaTemplate = kafkaTemplate;
}

// 发送下单消息
public void sendOrder(String userId, String productId) {
String orderInfo = userId + ":" + productId;
kafkaTemplate.send("seckill-orders", orderInfo);
}

// 消费下单消息(异步下单)
@KafkaListener(topics = "seckill-orders", groupId = "order-group")
public void processOrder(String orderInfo) {
String[] parts = orderInfo.split(":");
String userId = parts[0];
String productId = parts[1];

// 插入订单到数据库
orderRepository.insert(userId, productId);

// 扣减数据库库存
productRepository.decrementStock(productId);
}
}

6. 防刷单(风控系统)

验证码

  • 秒杀前需要输入验证码(防止脚本刷单)

风控系统

  • 检测异常用户(如同一 IP 注册 100 个账号)
  • 检测异常订单(如同一用户下单 100 次)

面试加分回答

实际项目经验

“在实际项目中,我们设计秒杀系统的经验:

  1. 流量分层过滤:CDN → Nginx 限流 → API Gateway 鉴权限流 → 秒杀服务校验库存
  2. 库存预扣减:使用 Redis 的 DECR 原子操作预扣减库存,防止超卖
  3. 异步下单:下单请求放入 Kafka,异步处理(数据库批量插入订单)
  4. 防刷单:验证码 + 风控系统(检测异常用户和异常订单)

效果:100 万人抢 100 件商品,系统平稳运行,没有超卖,数据库压力降低了 99%。”

面试高频追问

  • Q: 如果 Redis 挂了怎么办?
    • A: Redis 集群部署(主从 + 哨兵),主节点挂了自动切换到从节点。
  • Q: 如何防止库存扣减成功但下单失败?
    • A: 使用分布式事务(如 Seata),保证库存扣减和下单要么同时成功,要么同时失败。

Q19: 如何设计分布式文件存储系统(FastDFS、MinIO)?

一句话总结:分布式文件存储系统的核心是文件分块、元数据管理、副本机制,保证文件高可用和高可靠。

深度解析

1. 为什么需要分布式文件存储系统?

传统文件存储方式的问题:

  • 文件存储在单机磁盘上,磁盘满了无法扩展
  • 文件没有备份,磁盘损坏文件丢失
  • 文件访问量大时,单机带宽不够

分布式文件存储系统的优势:

  • 水平扩展:文件分散存储在多台服务器上,容量不够就加机器
  • 高可用:文件有多个副本,一台服务器挂了不影响访问
  • 高性能:文件分散在多台服务器上,带宽聚合

2. FastDFS 架构设计

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
┌─────────────────────────────────────────────────────────────┐
│ FastDFS 架构 │
├─────────────────────────────────────────────────────────────┤
│ │
│ ┌─────────┐ ┌─────────┐ ┌─────────┐ │
│ │ Client │───▶│ Tracker │───▶│ Storage │ │
│ │ (客户端) │ │ (跟踪服务器)│ │ (存储服务器)│ │
│ └─────────┘ └─────────┘ └─────────┘ │
│ │ │ │ │
│ │ ▼ ▼ │
│ │ ┌─────────────────────────────┐ │
│ │ │ Storage Group 1 │ │
│ │ │ ┌─────────┐ ┌─────────┐ │ │
│ │ │ │ Storage │ │ Storage │ │ │
│ │ │ │ (主) │ │ (从) │ │ │
│ │ │ └─────────┘ └─────────┘ │ │
│ │ └─────────────────────────────┘ │
└─────────────────────────────────────────────────────────────┘

核心组件

  • Tracker Server:跟踪服务器,管理 Storage Server(类似注册中心)
  • Storage Server:存储服务器,存储文件和文件元数据
  • Group:组,一组 Storage Server 互为主从(文件副本)

3. FastDFS 文件上传流程

1
2
3
4
5
6
1. Client 询问 Tracker Server:哪个 Storage Server 可以上传文件?
2. Tracker Server 返回一个 Storage Server 地址
3. Client 上传文件到 Storage Server
4. Storage Server 生成文件 ID(组名 + 虚拟磁盘路径 + 两级目录 + 文件名)
5. Storage Server 同步文件到同组的其他 Storage Server(副本)
6. Storage Server 返回文件 ID 给 Client

文件 ID 示例

1
2
3
4
5
6
group1/M00/00/00/wKgZhWuCXBOAUw7_AAAw0dKE5R8070.txt

- group1:组名
- M00:虚拟磁盘路径(对应 Storage Server 的 store_path0)
- 00/00:两级目录(避免单个目录下文件过多)
- wKgZhWuCXBOAUw7_AAAw0dKE5R8070.txt:文件名(由 Storage Server 生成)

4. MinIO 架构设计

MinIO 是对象存储(类似 AWS S3),适合存储海量小文件(图片、视频、文档)。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
┌─────────────────────────────────────────────────────────────┐
│ MinIO 架构 │
├─────────────────────────────────────────────────────────────┤
│ │
│ ┌─────────┐ ┌─────────┐ ┌─────────┐ │
│ │ Client │───▶│ Load │───▶│ MinIO │ │
│ │ (客户端) │ │ Balancer│ │ Server │ │
│ └─────────┘ └─────────┘ └─────────┘ │
│ │ │
│ ▼ │
│ ┌─────────────────┐ │
│ │ Erasure Code │ │
│ │ (纠删码) │ │
│ └─────────────────┘ │
└─────────────────────────────────────────────────────────────┘

核心特性

  • 纠删码(Erasure Code):将文件分成 N 个数据块和 M 个校验块,允许最多 M 个块损坏
  • Bitrot 保护:自动检测数据损坏(基于哈希校验)
  • S3 兼容:API 兼容 AWS S3

5. 实战:Spring Boot 集成 MinIO

1
2
3
4
5
6
<!-- pom.xml -->
<dependency>
<groupId>io.minio</groupId>
<artifactId>minio</artifactId>
<version>8.5.2</version>
</dependency>
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
import io.minio.MinioClient;
import io.minio.PutObjectArgs;
import org.springframework.web.multipart.MultipartFile;

@Service
public class MinIOService {

private final MinioClient minioClient;

public MinIOService() {
this.minioClient = MinioClient.builder()
.endpoint("http://localhost:9000") // MinIO 地址
.credentials("admin", "password") // 账号密码
.build();
}

// 上传文件
public String uploadFile(MultipartFile file, String bucketName) throws Exception {
// 1. 创建 Bucket(如果不存在)
boolean found = minioClient.bucketExists(b -> b.bucket(bucketName));
if (!found) {
minioClient.makeBucket(b -> b.bucket(bucketName));
}

// 2. 上传文件
String fileName = System.currentTimeMillis() + "_" + file.getOriginalFilename();
minioClient.putObject(
PutObjectArgs.builder()
.bucket(bucketName)
.object(fileName)
.stream(file.getInputStream(), file.getSize(), -1)
.contentType(file.getContentType())
.build()
);

// 3. 返回文件 URL
return "http://localhost:9000/" + bucketName + "/" + fileName;
}
}

面试加分回答

实际项目经验

“在实际项目中,我们使用 MinIO 存储用户上传的文件(头像、文档、视频):

  1. 文件上传:前端上传文件到后端,后端转发到 MinIO
  2. 文件访问:MinIO 生成文件 URL,返回给前端
  3. 文件备份:MinIO 使用纠删码(Erasure Code),允许最多 4 个节点挂掉
  4. 文件权限:MinIO 支持预签名 URL(过期时间 1 小时),防止文件被盗链

对比 FastDFS:FastDFS 适合小文件存储(< 1MB),MinIO 适合任意大小文件存储(兼容 S3 API)。”

面试高频追问

  • Q: 如何保证文件不丢失?
    • A: FastDFS 有多副本(同组 Storage Server 互为主从);MinIO 有纠删码(允许最多 M 个块损坏)。
  • Q: 如何防止文件被盗链?
    • A: MinIO 支持预签名 URL(过期时间 1 小时),只有合法用户才能访问文件。

Q20: 面试实战:如何回答系统设计问题?

一句话总结:回答系统设计问题的核心是先问清楚需求,再给出高层设计,最后深入讨论细节

深度解析

1. 系统设计问题的回答框架

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
┌─────────────────────────────────────────────────────────────┐
│ 系统设计回答框架 │
├─────────────────────────────────────────────────────────────┤
│ │
│ 第 1 步:澄清需求(5 分钟) │
│ - 功能需求:系统要支持哪些功能? │
│ - 非功能需求:QPS、延迟、数据量、一致性要求? │
│ - 约束条件:开发成本、运维成本、技术栈? │
│ │
│ 第 2 步:高层设计(10 分钟) │
│ - 画出系统架构图(负载均衡 → API 服务 → 数据库) │
│ - 说明各组件的职责 │
│ - 说明数据流向 │
│ │
│ 第 3 步:深入讨论细节(10 分钟) │
│ - 数据库 Schema 设计 │
│ - 缓存策略(缓存什么、缓存多久) │
│ - 消息队列选型(为什么选 Kafka 不选 RabbitMQ) │
│ - 分库分表策略(按什么分片、分片算法) │
│ │
│ 第 4 步:扩展讨论(5 分钟) │
│ - 如何支持更高的 QPS?(加缓存、加机器、异步处理) │
│ - 如何保证高可用?(集群部署、副本机制、熔断降级) │
│ - 如何监控和告警?(Prometheus + Grafana) │
│ │
└─────────────────────────────────────────────────────────────┘

2. 实战:设计一个短链接系统

第 1 步:澄清需求

面试官:设计一个短链接系统。

:好的,我先澄清一下需求:

  1. 功能需求
    • 输入长链接,返回短链接
    • 访问短链接,重定向到长链接
    • 短链接有有效期(可选)
  2. 非功能需求
    • QPS:100k(读多写少)
    • 延迟:< 100ms
    • 数据量:1 亿条短链接
    • 一致性:最终一致性(短链接生成后可以容忍 1 秒的延迟)
  3. 约束条件
    • 开发成本:小团队(3 人)
    • 运维成本:尽量简单(用托管服务)
    • 技术栈:Java + Spring Boot

第 2 步:高层设计

:我画一下系统架构图(边画边解释):

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
┌─────────────────────────────────────────────────────────────┐
│ 短链接系统架构 │
├─────────────────────────────────────────────────────────────┤
│ │
│ ┌─────────┐ ┌─────────┐ ┌─────────┐ │
│ │ User │───▶│ LB │───▶│ API │ │
│ │ (用户) │ │ (负载均衡)│ │ Service │ │
│ └─────────┘ └─────────┘ └─────────┘ │
│ │ │
│ ▼ │
│ ┌─────────────────┐ │
│ │ Redis │ │
│ │ (缓存短链接) │ │
│ └─────────────────┘ │
│ │ │
│ ▼ │
│ ┌─────────────────┐ │
│ │ MySQL │ │
│ │ (存储映射关系) │ │
│ └─────────────────┘ │
└─────────────────────────────────────────────────────────────┘

:系统架构说明:

  1. 负载均衡:Nginx 或云负载均衡器(分流请求)
  2. API Service:生成短链接、重定向短链接
  3. Redis:缓存热点短链接(提高读取性能)
  4. MySQL:存储长链接和短链接的映射关系

第 3 步:深入讨论细节

面试官:短链接如何生成?

:短链接生成有两种方案:

  1. 方案 1:自增 ID + Base62 编码

    • 使用分布式 ID 生成器(如雪花算法)生成自增 ID
    • 将 ID 转换为 Base62 编码(0-9、a-z、A-Z,共 62 个字符)
    • 优点:短链接长度固定(如 ID=1000,Base62 编码为 G8
    • 缺点:需要分布式 ID 生成器
  2. 方案 2:长链接 Hash + 碰撞检测

    • 对长链接进行 Hash(如 MD5),取前 6 个字符作为短链接
    • 如果短链接已存在(碰撞),在长链接后面加随机字符串,重新 Hash
    • 优点:不需要分布式 ID 生成器
    • 缺点:短链接长度不固定,有碰撞概率

我选择方案 1(分布式 ID 生成器 + Base62 编码)。

面试官:数据库如何设计?

1
2
3
4
5
6
7
8
CREATE TABLE `short_link` (
`id` BIGINT PRIMARY KEY AUTO_INCREMENT,
`short_key` VARCHAR(10) NOT NULL UNIQUE, -- 短链接 Key(如 `G8`)
`long_url` TEXT NOT NULL, -- 长链接
`created_at` TIMESTAMP DEFAULT CURRENT_TIMESTAMP,
`expire_at` TIMESTAMP, -- 过期时间(可选)
INDEX `idx_short_key` (`short_key`)
) ENGINE=InnoDB;

面试官:如何保证高并发读取?

  1. 缓存优先:访问短链接时,先查 Redis 缓存,缓存没有才查数据库
  2. 缓存预热:热点短链接在系统启动时提前加载到 Redis
  3. 缓存过期:短链接缓存过期时间设置为 24 小时

第 4 步:扩展讨论

面试官:如果 QPS 从 100k 涨到 1M,怎么办?

  1. 加缓存:Redis 集群部署(主从 + 分片)
  2. 加机器:API Service 水平扩展(无状态设计)
  3. 数据库读写分离:写主库,读从库
  4. 分库分表:按 short_key 进行一致性哈希分片

面试官:如何保证高可用?

  1. API Service 高可用:多实例部署 + 负载均衡
  2. Redis 高可用:主从 + 哨兵
  3. MySQL 高可用:主从切换(MHA 或 Orchestrator)

面试加分回答

实际面试经验

“在实际面试中,回答系统设计问题的经验:

  1. 先问清楚需求:不要急于给出方案,先问清楚功能需求和非功能需求
  2. 画图辅助解释:边画架构图边解释,让面试官更容易理解
  3. 权衡方案:不要只给一个方案,要给出多个方案并说明优缺点(如短链接生成的两种方案)
  4. 深入细节:不要只停留在高层设计,要深入讨论数据库 Schema、缓存策略、消息队列选型
  5. 扩展讨论:主动讨论如何支持更高的 QPS、如何保证高可用

技巧:如果某个技术点不熟悉(如一致性哈希),可以主动说’这个我不太熟悉,但我的理解是…’,不要装懂。”

面试高频追问

  • Q: 如果面试官追问一个你不会的技术点,怎么办?
    • A: 不要装懂,可以说’这个我不太熟悉,但我的理解是…’,或者’这个我可以回去研究一下’。面试官更看重你的思考过程,而不是你知道多少。
  • Q: 系统设计问题有没有标准答案?
    • A: 没有标准答案,面试官更看重你的思考过程(如何分析问题、如何权衡方案、如何深入细节)。

🎉 总结

本文详细讲解了 20 个系统设计核心知识点,从基础架构(负载均衡、缓存、消息队列)到高级设计(短链接、秒杀、分布式锁),再到实战技巧(如何回答系统设计问题)。

核心要点回顾

  1. 负载均衡:分层负载均衡(硬件 LB → 软件 LB → 应用 LB)
  2. 缓存:缓存穿透/击穿/雪崩的解决方案
  3. 消息队列:RabbitMQ、Kafka、RocketMQ 的选型
  4. 短链接系统:分布式 ID 生成器 + Base62 编码
  5. 限流器:令牌桶算法(允许突发流量)
  6. 唯一 ID 生成:雪花算法(趋势递增、不依赖数据库)
  7. 秒杀系统:流量分层过滤、库存预扣减、异步下单
  8. 分布式锁:Redis SETNX + 过期时间 + Redlock
  9. 分布式事务:2PC、3PC、TCC、Saga 的优缺点
  10. 高并发系统:缓存优先、异步处理、限流降级

下一步学习建议

  • 如果你对基础架构还不熟悉,先回头把负载均衡、缓存、消息队列搞清楚
  • 如果你对高级设计感兴趣,可以深入研究分布式锁、分布式事务、一致性哈希
  • 如果你准备面试,重点看 Q20(如何回答系统设计问题)

📚 扩展学习资源

官方文档

书籍推荐

  • 📚 《设计数据密集型应用》(DDIA)
  • 📚 《System Design Interview》(Alex Xu)
  • 📚 《高性能网站建设指南》

博客推荐


🎉 恭喜你!学完本文后,你已经掌握了系统设计的 进阶知识

下一步建议:

  1. 实战练习:自己设计一个聊天系统或视频网站架构
  2. 深入研究:选一个方向(如分布式事务、一致性哈希)深入研究
  3. 关注社区:订阅 AWS、Google SRE 博客,学习大厂架构经验
  4. 准备面试:刷 LeetCode 数据库题 + 系统设计题

系统设计面试八股文(20题)
https://whyalwaysme.lol/2026/06/15/2026-06-15-system-design-interview-deep/
作者
Cassiur
发布于
2026年6月15日
许可协议