系统设计是什么? - maheshba


在我研究生涯的早期,我曾有机会与世界上一些最优秀的系统研究人员一起研究一些非常有趣的系统设计。

研究工作的乐趣之一在于研究人员(尤其是 SOSP/OSDI 社区的研究人员)在提出新颖而实用的设计方案时所采用的特殊过程。
这一设计过程的特点可以概括为 "以抽象对抗复杂":在任何复杂的环境中,如何将复杂性归纳为定义明确的方框(或更严格地说,抽象),然后在这些方框中划分功能?

后来,当我转到工业领域(从关键任务生产服务到应用研发)从事 "真正 "的工作时,我发现同样的设计流程在解决生产环境中的实际问题时非常有效。
在这些环境上下文中,复杂性的来源多种多样(硬件、软件、分布式协议、组织边界、部署周期、客户......),最终目标也各不相同(可靠性、规模、代码速度、性能、美元成本);但抽象驱动设计仍能使我的团队快速、安全地实现生产目标。

这篇文章介绍了在这个特殊的设计过程中需要遵循的一些规则。

[1] 过时绑定设计。
设计流程的目标不是生成一个单点解决方案,而是描述指定问题的设计空间特征:然后,在问题约束条件下,单点应自然地从该空间(上下文)中产生。

过早趋同于一个单一的设计是有害的;团队应该有能力从空间的一部分((上下文))跳到另一部分(上下文),直到选出一个解决方案。

[2] 每个点解决方案都是对设计过程的 DoS 攻击。
孤立地讨论单个设计会减慢设计速度。而在设计空间的上下文中谈论设计,则会加速设计

应根据设计空间来描述新设计,这样你就能立即传达它们与其他点方案相比的相对位置。

  • 希望能有很多这样的表述:
  • "所有解决方案都必须执行 X";
  • "解决方案 Y 就是 X,只需进行一次更改";
  • "任何满足 X 的解决方案也必须满足 Y";等等。

讨论设计空间(上下文)而非某个点的设计,这样能降低讨论中任意点切换设计带来的成本,从而有效地让设计能扩展后期延展。

[3] 并行思考;共同设计;并行实施;共同审查。
设计和开发流程的某些部分是创造性的,应并行化/碎片化,而其他部分则需要规范,应集中化/广播化。

  • 思考/头脑风暴是一个创造性的过程,应平行进行,无需协调。
  • 设计应集中进行。设计空间是团队成员之间的(强一致性)共享状态;新创意应在同步协调的情况下进入该空间。
  • 实施可以并行进行。集中设计阶段结束后,任何人都可以实现设计的任何部分。与开发人员的后期绑定至关重要;通常情况下(最好),实施创意的人与提出创意的人是不同的。如果开发人员知道他们能实现这个想法,他们往往会对这个想法情有独钟。
  • 审查应集中进行。代码库是共享状态。尤其是应用程序接口的更改,必须由多人仔细审核,以确保它们不是单向的。在一个健康的设计流程中,设计和审核最终会成为集中的瓶颈,这一点没有问题(在研究中,也有同样的四个步骤;但经过仔细审核的成果通常是一篇论文,而不是代码库)。

[4]谈论问题,而不是现有系统。
人们很容易通过查看类似的系统来开始设计过程。这会带来两种类型的风险:

  • 解决方案的复杂性 》问题的复杂性:问题具有一定的基本复杂性(例如,有一定空间的解决方案可以解决原子提交问题);然而,单个解决方案的复杂性可能是无限的,仅受限于人类的创造力(例如,"两阶段提交 "协议的第 5 阶段到底是做什么的?了解现有设计往往比从第一性原理 解决问题花费更多的时间。
  • 解决方案偏差:即使是好的解决方案,也会使你的思维偏向设计空间的某一部分。例如,阅读 Raft 论文的人可能会认为将学习者和接受者放在一起是最基本的(而这对 Paxos 而言并非如此);阅读 Paxos 的人可能会认为法定人数必须占多数(而这对灵活的 Paxos 而言并非如此)。在设计阶段之后,是研究其他系统的大好时机,看看能否将这些解决方案映射到您的空间中。更妙的是,只需了解解决方案在您的设计空间上下文中的位置,您就可以逆向设计解决方案的细节。

[6] 对于每个抽象,构建一个实现;计划第二个实现;希望第三个实现。
与此相反,您不希望抽象的语义依赖于其实现细节。确保这一点的方法之一就是在设计过程中讨论多个实现。例如,如果你的复制层是基于 TCP 的(但你也计划有一个基于 UDP 的变体;而且你希望它也能在信鸽上工作),那么在你的头脑中保留 UDP 变体将防止你用 TCP/IP 信道来定义语义。

[7] 抽象不是免费的
每个抽象层都会引入新的语义,开发人员必须精确地定义这些语义,然后以通用的方式进行推理(例如,新的文件系统必须与块设备的每一种可能的正确实现协同工作)。

因此,抽象是两种复杂性之间的平衡行为:具体性的复杂性(你必须理解无关紧要的细节,例如,文件系统开发人员对 FTL 实现的推理)和抽象性的复杂性(你必须理解一系列可能性,例如,文件系统开发人员对块设备修剪 API 的所有可能实现的思考)。

每次添加抽象层时,都要精确说明其存在的原因,以及该抽象层与周围抽象层之间的功能划分。

[8] 要有批判精神(但要批判正确的事情)。
研究人员习惯于看到新想法从原始沼泽中涌现出来,他们往往过于乐观(博士生培训的一部分就是让学生对自己的想法进行更多的批判性思考)。

与此相反,开发人员通常与成熟的系统打交道,因此对新创意的批判性更强。

新项目往往看起来不够成熟、孱弱、漏洞百出。

但是,每一个成熟的系统在某些时候都只是两三个人在折腾一些半生不熟的想法。

设计的一种方法是不断降低真正未知部分的风险,同时推迟那些困难但已知部分的工作。
(相反,研究人员需要更加注重细节和实用性,但这在工业环境中会自然而然地发生)。