@Lenciel

如何写好系统架构文档

软件开发实际上是一个学习的过程,架构和代码只是它的副产品。

所以方案应该主要体现两个部分:

  1. 你对用户需求、关键路径等「领域知识」有了什么样的了解。
  2. 你因为这些了解,在:
  • 系统的核心模块准备采取什么样的设计
  • 模块之间通过什么方式通信或者暴露什么 API
  • 数据怎么进行读写和持久化

等关键选择上做了什么样的选择和权衡。

本文面向所有需要编写系统设计方案或者系统架构方案的工程师。

目录

一、基本步骤

1. 梳理和澄清系统

维基百科对「系统」的定义是:

A system is a group of interacting or interrelated entities that form a unified whole. A system, surrounded and influenced by its environment, is described by its boundaries, structure and purpose and expressed in its functioning.

因此,一个系统的定义主要有几个方面:

  • 目的
  • 边界
  • 模块(or 子系统)
  • 模块(or 子系统)间的协同关系

1.1 目的

系统的目的主要通过「用户故事」来表达。书写用户故事是产品经理的基本功,但同时,也是所有进行系统设计和分析的人的基本功。

用户故事的结构是三部分:

  • 角色(谁要使用,为谁而设计?)
  • 功能(这个功能有什么作用,怎么获得)
  • 价值(为什么用户需要这个功能)

在实际书写过程里面,「用户故事」可以是文本的,也可以是表格,甚至可以是用 UML 的用例图或者序列图。

以我们的镜子为例,下面是一个完整的用户故事:

成都天府软件园的一家中型互联网公司,有300人的规模。这家公司的CEO大凡在软件园CEO群里面得知,FITURE魔镜开始给企业提供三个月试用,于是安排公司中的HR同事小凡来负责跟进。小凡根据大凡提供的联系方式,联系到了FITURE的BD,在提交了必要的公司证明材料后,预约了3台FITURE魔镜产品,并和行政的同事商议,决定将FITURE魔镜分别摆放在公司的两个茶水间和一个专门的小型会议室。

第二天,FITURE的BD带着安装人员上门安装调试,并且给小凡介绍了如何试用,以及试用期间的运营手段。第二周开始,小凡每周四下午3点都会组织大家一起做工间操,感兴趣的同事聚集在茶水间的魔镜前面,花15分钟的时间跟着岳岳老师进行肩颈放松与背部拉伸,有效缓解了工作疲劳。上午上班前、午休时、下班后,也有部分同事通过会议室的魔镜进行单人锻炼。甚至由于想用的人太多,还需要通过公司的会议预约系统提前进行预约。

在两个月后,FITURE的BD再次和小凡交流,小凡和CEO大凡商量后,决定正式付费使用FITURE魔镜产品,作为公司给员工提供的福利之一。而且,考虑到员工排队的情况,找了另外一间大的会议室,又新增了一台FITURE魔镜。

1.2 边界

中文里系统的「边界」,有两个维度:scope 和 constraints。其中「scope」主要是通过用户故事来抽象得到的,所以梳理完用户故事之后,我们一般还需要梳理的「边界」是系统的 「contraints」,正是这些约束条件会决定系统的一些关键特性:

  • Performance Efficiency
  • Compatibility
  • Availability & Reliability
  • Security
  • Maintainability
  • Portability

由于类似于 CAP 约束的原因,一个系统只能支持我们列出的体系结构特征里面的几个。因为每个架构特性通常会成为其他架构特性的约束。例如,如果一个架构师想要提高安全性,它几乎肯定会对性能产生负面影响:应用程序必须执行更多的加解密等降低性能的活动。

一般来说,在早期最主要需要梳理的约束条件,一般是跟流量/数据相关的,比如系统承接的 rps/bps,数据一致性要求的等等,这些会决定系统设计的时候,对可靠性、可扩展性、弹性等系统特性的决定。

在我很喜欢的《Designing Data-Intensive Applications》里,它提到的应用系统主要追求的三个方面就直接没有「可用性」,而是:

  • Reliability
  • Scalability
  • Maintainability

我觉得这里的原因,主要是「可用」更多是用户纬度的一个感受(系统在运行的过程中有多少时间是可以被用户使用的)。它本身是以「可靠性」(系统在出故障的情况十分能够完成工作)和「可维护性」(系统进行定期维护和故障处理十分方便)等其他工程纬度的指标为基础的。

2. 顶层设计

经过第一步的梳理,第二步就是进行顶层设计。一个系统在最顶层基本都可以划分为:

  • 应用层(App、小程序、Web Application 等等形式)
  • 接入层(一般会有流量管理,比如 AG 的设计)
  • 拆分出来的服务(有时候用户、商品、交易等等服务会在业务较多的时候为了复用成为一个 platform service,也就是常常看到的所谓「平台」或者「中台」或者「公共服务」)
  • 数据存储/持久化层(一开始通常主从数据库加上基本的缓存就够了)

3. 核心组件设计

前面我们讲系统的定义时说过,系统是由模块组成,通过模块间的协作完成功能的。

模块之间怎么协作呢?一般通过消息或者 API 调用来进行。

所以模块的设计一般是几个方面:

  • 根据功能使用 OOD(面向对象设计)来设计模块
  • 设计模块 的数据库 schema
  • 设计模块的 API 或者消息

可以说,模块边界的划分,API 或者消息的设计、schema 的设计等等,是架构师能力的主要体现。

4. 考虑系统的瓶颈和如何扩展当前的设计

当前架构是不是有性能或者安全的方面的瓶颈?什么时候应该使用什么方法解决这些瓶颈?比如数据库会变慢,需要做主从库做读写分离?需要分库分表?需要加缓存体系?

一个好的方案,一定是对当前业务情况最适用,投入产出比最高的方案。这也往往意味着,这个方案代表的系统,多半会在一年左右大规模重构:因为一个健康的互联网业务一般一年流量就应该翻很多倍了

二、核心命题

方案需要体现对以下问题的思考:

  1. 系统的价值、构成、边界和约束条件
  2. 系统有哪些角色,关键用户路径的流程是什么,有怎样的 SLA/SLI/SLO
  3. 有什么样的假设,有什么样的依赖条件
  4. 如何保障可用性和可靠性的细节
    • a. 包括但不限于流量怎么切分
    • b. 缓存怎么设计
      • i. Application caching
      • ii. Database caching
      • iii. Object caching(KV 存储如 Reids 或 Memchache)
      • iv. …
    • c. 数据怎么放怎么取
    • d. 系统的弹性怎么保障
  5. 系统在安全性等方面的考虑
  6. 有什么外部依赖和风险

这里就不一一展开了。

欢迎留言