@anurag_gharat: 系统设计中所有构建模块的完整指南

X AI KOLs Timeline 新闻

摘要

全面介绍核心系统设计模块,涵盖客户端-服务器架构、可扩展性、数据库等内容,助力系统设计问题解决与面试准备。

系统设计中所有构建模块的完整指南。 https://t.co/Y1yHWxEdKf
查看原文
查看缓存全文

缓存时间: 2026/09/23 01:58

系统设计完整构件指南

https://t.co/Y1yHWxEdKf


系统设计核心要素 - 1

本文是关于软件系统设计必备概念三部曲系列的第一部分。一旦你清晰理解每个核心概念,便能将它们组合起来解决几乎所有问题。这里的每个主题都是系统设计的核心构件,均包含简短说明、简洁示意图、所解决的问题及其背后的权衡考量。通读全文并理解每个构件后,无论是从零起步还是准备面试,系统设计问题都将变得简单许多。

1. 客户端-服务器架构

客户端-服务器架构是几乎所有系统的基础。客户端发送请求,服务器在与数据库交互的同时处理这些请求。当客户端直接连接数据库时,称为两层架构。若在客户端与数据库之间加入专用应用服务器,则形成三层架构——这正是现代应用普遍采用的模式。缓存、扩展等概念都建立在这一基础架构之上。

2. 垂直扩展 vs 水平扩展

扩展系统意味着提升其处理更多负载的能力,使其在压力下仍能稳定运行。系统负载可能表现为更多请求、更多数据库访问等。扩展系统主要有两种方式:

垂直扩展 通过增强现有机器的性能实现扩展,包括:

  • 增加内存
  • 提升计算能力
  • 扩展存储容量

垂直扩展在初期效果显著,但很快会触及硬件极限,无法无限提升。

水平扩展 通过增加更多机器来分担负载,也称为扇出模式。多台机器协同完成任务。

3. 数据库

每个应用都需要存储数据的地方。例如电商平台需要存储用户、商品、订单和消息;聊天应用需要存储用户、群组和消息。这就是数据库的用途。

数据库是经过组织的数据集合,即使服务器重启或崩溃,仍能可靠地存储、检索、更新和删除数据。服务器本身不存储数据,仅负责从数据库读取/更新/删除数据。

数据库支持四种基本操作:增删改查(CRUD)。

数据库类型包括:

  • 关系型数据库
  • 非关系型数据库
  • 图数据库
  • 面向对象数据库
  • 层次型数据库
  • 向量数据库

4. ACID vs BASE

数据库采用不同模型管理事务、一致性、可用性和可扩展性。ACID和BASE是数据库系统的两种设计思路,分别针对不同的应用需求。

ACID(SQL数据库) 代表原子性、一致性、隔离性和持久性:

  • 原子性:事务要么完全成功,要么完全回滚。例如转账操作:若扣款成功但存款失败,扣款必须回滚。
  • 一致性:事务始终将数据库从一个有效状态转换到另一个有效状态,且不违反既定规则。
  • 隔离性:并发事务互不干扰。
  • 持久性:事务提交后立即永久保存。

BASE(NoSQL数据库) 代表基本可用、软状态、最终一致性:

  • 基本可用:系统始终可响应读写请求
  • 软状态:状态可因同步操作自动改变
  • 最终一致性:数据随时间推移最终达成一致,而非实时同步

5. CAP定理

CAP定理指出,在分布式系统中,以下三项特性最多只能同时满足两项:

  • 一致性:所有节点看到的数据相同
  • 可用性:每个请求都能得到响应
  • 分区容错性:网络分区发生时系统仍能运行

为何不能三者兼得? 网络分区必然会发生。一旦节点间通信中断,必须做出选择:

  • CP系统:在网络分区时选择一致性而非可用性
  • AP系统:在网络分区时选择可用性而非一致性
  • CA系统:放弃分区容错性

ACID更倾向于CP(为保持一致性可能拒绝请求),BASE更倾向于AP(优先保证可用性)。

6. 关系型数据库

关系型数据库(SQL数据库)将数据存储在行列结构的表格中,遵循严格的预定义模式。通过外键建立表间关联(如用户与订单的关系),支持复杂的多表联接查询。

关系型数据库遵循ACID原则,适用于银行、订单管理等对准确性要求高的场景。常见代表:PostgreSQL、MySQL、Oracle。

7. 非关系型数据库

非关系型数据库(NoSQL数据库)无需固定表格结构,数据以文档、键值对或宽列等形式灵活存储。每条记录可具有不同结构,无需预先定义统一模式。

这种灵活性使其特别适合处理非结构化或快速变化的数据,以及需要水平扩展的应用。多数NoSQL数据库遵循BASE原则,优先保证可用性和速度。常见代表:MongoDB、Redis、Cassandra。

7. 数据库复制

创建和维护同一数据库的多个同步副本称为数据库复制。

核心模式:主从架构

  • 主节点:处理所有写操作
  • 从节点:处理读操作,并持续与主节点同步数据

大多数应用读多写少(如浏览商品的用户远多于下单用户)。将读操作分流到从节点,主节点可专注于写操作。通过增加从节点可轻松扩展读取能力。

复制类型:

  • 同步复制:主节点等待从节点确认写入后才响应客户端
  • 异步复制:主节点立即响应客户端,后台异步同步到从节点

8. 数据库分区

数据库分区是将主数据库拆分为多个较小数据库进行处理和存储的技术。

垂直分区:按列拆分,同一行的不同列存储在不同表中。

水平分区:按行拆分,相同列但不同行存储在不同分区中。

分区优势:

  • 小规模数据更易管理和扩展
  • 查询速度更快
  • 可将不再需要的数据归档到独立数据库

9. 数据库分片

数据库分片是通过将数据库拆分为多个独立片段(分片)来扩展数据库的方法,每个分片仅存储部分数据。负载分散到多个分片服务器,每个分片拥有独立数据库。

分片是水平分区的一种形式,通过分片键(基于范围、哈希或地理位置策略)决定数据归属。当单个数据库无法承载写入负载或数据总量时(仅靠复制无法解决),分片是有效方案。代价是跨分片查询复杂化,且跨分片事务难以保证原子性。

10. HTTP

HTTP(超文本传输协议)是客户端与服务器通信的数据传输协议,包含通信建立、请求格式化和响应发送的一系列规则。HTTP是无状态协议,基于TCP实现。

HTTP请求包含:

  • 方法(操作类型)
  • URL(资源地址)
  • 头部(请求元数据)
  • 体(客户端发送的数据)

HTTP响应包含:

  • 状态码(请求结果)
  • 头部(响应元数据)
  • 体(返回的数据)

常用HTTP方法: GET(获取数据)、POST(创建数据)、PUT(更新/替换数据)、PATCH(部分更新)、DELETE(删除数据)

常见状态码: 200(成功)、201(已创建)、301(重定向)、304(未修改)、400(错误请求)、401(未授权)、404(未找到)、500(服务器错误)、503(服务不可用)

11. 单体架构

单体架构是将应用所有功能集成在一个代码库中的统一架构,作为单个单元运行部署。

类型包括:

  • 传统单体:UI、业务层、数据访问层和数据库全部位于同一代码库(如Java/Spring应用)
  • 模块化单体:仅服务层保持单体,UI和数据库分离

优势:易搭建、开发、测试和部署;执行速度快;适合小团队和有限范围。

劣势:扩展后维护困难;层间耦合紧密;多团队协作困难;技术栈锁定。

12. 微服务架构

微服务架构将系统拆分为多个小型独立服务,每个服务负责单一业务功能,拥有独立的代码库、部署流程甚至数据库。

电商应用微服务示例:

  • 用户服务:认证与个人资料
  • 商品服务:目录与库存管理
  • 订单服务:订单创建与跟踪
  • 支付服务:交易处理

优势:独立部署、可扩展性强、故障隔离、技术灵活、开发周期短。

劣势:通信复杂、数据管理复杂、运维开销大、测试复杂、存在延迟。

13. API网关

API网关位于客户端与服务器之间,仅暴露客户端所需功能,隐藏系统复杂性。作为所有客户端访问微服务的统一入口。

职责包括:

  • 处理客户端请求的认证与授权
  • 请求路由至正确微服务
  • 日志记录与监控
  • 负载均衡
  • 流量控制
  • 缓存
  • 协议转换(如HTTP转gRPC)

常见服务:Amazon API Gateway、NGINX、Kong。

14. REST API

REST(表述性状态转移)是基于HTTP构建的API设计规范,为客户端与服务器交互提供可预测的规则契约。

六大原则:

  1. 统一接口:统一的命名、结构和HTTP方法/状态码使用
  2. 无状态:每个请求包含服务端所需全部信息
  3. 客户端-服务器分离:接口与关注点分离
  4. 可缓存:响应可标记为可缓存/不可缓存
  5. 分层系统:客户端仅与直接交互层通信
  6. 按需代码:服务器可向客户端发送可执行代码扩展功能

15. SOAP API

SOAP(简单对象访问协议)是系统间交换结构化信息的协议,严格规定XML格式的消息结构。每个请求/响应都包裹在名为“信封“的XML结构中,头部包含元数据,主体包含实际数据及错误详情。

16. GraphQL

REST API存在两个问题:

  • 过度获取:返回比所需更多的数据
  • 获取不足:单个API响应不够,需多次调用

GraphQL作为API查询语言,允许客户端在单次请求中精确指定所需数据,不多不少。与REST的多端点固定响应不同,GraphQL仅暴露单个端点(POST /graphql),由客户端定义响应结构。

示例:获取用户资料页

  • REST需两次调用:

    • GET /users/12
    • GET /users/12/orders?limit=3 (每次返回完整对象,包含不必要的字段)
  • GraphQL单次调用:

    query {
      user(id: 12) {
        name
        email
        recentOrders(limit: 3) {
          id
          total
        }
      }
    }
    

    (精确获取所需字段,无冗余数据)

相似文章

donnemartin/system-design-primer

GitHub Trending (daily)

一个开源的入门指南,整理了系统设计概念,提供学习指南、Anki 闪卡和练习面试题,帮助工程师构建大规模系统并准备系统设计面试。