English ∙ 日本語 ∙ 简体中文 ∙ 繁體中文 |العَرَبِيَّة ∙ বাংলা ∙ Português do Brasil ∙ Deutsch ∙ ελληνικά ∙ עברית ∙ Italiano ∙ 한국어 ∙ فارسی ∙ Polski ∙ русский язык ∙ Español ∙ ภาษาไทย ∙ Türkçe ∙ tiếng Việt ∙ Français |添加翻译
帮助翻译本指南!
了解如何设计大型系统。
准备系统设计面试。
学习如何设计可扩展的系统将帮助你成为一名更好的工程师。
系统设计是一个广泛的话题。关于系统设计原则的大量资源散布在整个网络上。
此存储库是有组织的资源集合,可帮助你了解如何大规模构建系统。
这是一个不断更新的开源项目。
欢迎投稿!
除了编码面试外,系统设计是许多科技公司技术面试过程的必要组成部分。
练习常见的系统设计面试问题,并将结果与示例解决方案(讨论、代码和图表)进行比较。
面试准备的其他主题:
提供的 Anki 抽认卡组使用间隔重复来帮助你保留关键的系统设计概念。
非常适合在旅途中使用。
正在寻找资源来帮助你准备编码面试?
查看姊妹存储库 Interactive Coding Challenges,其中包含一个额外的 Anki 套牌:
向社区学习。
请随时提交拉取请求以帮助:
需要打磨的内容正在开发中。
查看贡献指南。
各种系统设计主题的摘要,包括优点和缺点。 一切都是权衡取舍。
每个部分都包含指向更深入资源的链接。
根据你的面试时间表(短、中、长)建议要审查的主题。
问:对于面试,我需要知道这里的一切吗?
答:不,你不需要知道这里的一切来准备面试。
面试中会问到什么取决于以下变量:
更有经验的考生通常应该更多地了解系统设计。架构师或团队领导可能比个人贡献者知道的更多。顶级科技公司可能会进行一轮或多轮设计面试。
从广义开始,在几个领域深入。它有助于了解一些关键系统设计主题。根据你的时间表、经验、你正在面试的职位以及你正在面试的公司调整以下指南。
短 | 中等 | 长 | |
---|---|---|---|
通读系统设计主题,全面了解系统的工作原理 | 👍 | 👍 | 👍 |
通读公司工程博客中的几篇文章,了解你正在面试的公司 | 👍 | 👍 | 👍 |
通读一些真实世界的架构 | 👍 | 👍 | 👍 |
复习如何处理系统设计面试问题 | 👍 | 👍 | 👍 |
通过系统设计面试问题和解决方案进行工作 | 一些 | 多 | 最 |
通过面向对象的设计面试问题和解决方案进行工作 | 一些 | 多 | 最 |
查看其他系统设计面试问题 | 一些 | 多 | 最 |
如何解决系统设计面试问题。
系统设计面试是一个开放式的对话。你应该领导它。
你可以使用以下步骤来指导讨论。为了帮助巩固此过程,请使用以下步骤完成系统设计面试问题和解决方案部分。
收集需求并确定问题范围。提出问题以阐明用例和约束。讨论假设。
概述包含所有重要组件的高级设计。
深入了解每个核心组件的详细信息。例如,如果你被要求设计一个网址缩短服务,请讨论:
在给定约束的情况下,识别并解决瓶颈。例如,是否需要以下内容来解决可伸缩性问题?
讨论潜在的解决方案和权衡。一切都是权衡取舍。使用可扩展系统设计原则解决瓶颈问题。
你可能会被要求手动进行一些估算。有关以下资源,请参阅附录:
请查看以下链接,以更好地了解预期内容:
常见的系统设计面试问题,包括示例讨论、代码和图表。
链接到文件夹中内容的解决方案。
solutions/
问题 | |
---|---|
设计 Pastebin.com(或 Bit.ly) | 溶液 |
设计 Twitter 时间线和搜索(或 Facebook 提要和搜索) | 溶液 |
设计网络爬虫 | 溶液 |
设计 Mint.com | 溶液 |
设计社交网络的数据结构 | 溶液 |
为搜索引擎设计键值存储 | 溶液 |
按类别功能设计亚马逊的销售排名 | 溶液 |
在 AWS 上设计可扩展到数百万用户的系统 | 溶液 |
添加系统设计问题 | 贡献 |
常见的面向对象设计面试问题,包括示例讨论、代码和图表。
链接到文件夹中内容的解决方案。
solutions/
注意:此部分正在开发中
问题 | |
---|---|
设计哈希映射 | 溶液 |
设计最近最少使用的缓存 | 溶液 |
设计呼叫中心 | 溶液 |
设计一副纸牌 | 溶液 |
设计停车场 | 溶液 |
设计聊天服务器 | 溶液 |
设计圆形阵列 | 贡献 |
添加面向对象的设计问题 | 贡献 |
刚接触系统设计?
首先,你需要对常见原则有一个基本的了解,了解它们是什么、如何使用它们以及它们的优缺点。
接下来,我们将了解高级权衡:
请记住,一切都是权衡取舍。
然后,我们将深入探讨更具体的主题,例如 DNS、CDN 和负载均衡器。
如果服务以与添加的资源成正比的方式提高性能,则该服务是可伸缩的。通常,提高性能意味着为更多的工作单元提供服务,但也可能是处理更大的工作单元,例如当数据集增长时。1
查看性能与可伸缩性的另一种方式:
延迟是执行某些操作或产生某些结果的时间。
吞吐量是每单位时间内此类操作或结果的数量。
通常,应以可接受的延迟实现最大吞吐量为目标。
在分布式计算机系统中,只能支持以下两项保证:
网络不可靠,因此需要支持分区容错。你需要在一致性和可用性之间进行软件权衡。
等待分区节点的响应可能会导致超时错误。如果你的业务需求需要原子读取和写入,CP 是一个不错的选择。
响应返回任何节点上可用数据的最容易获得的版本,这可能不是最新的。解析分区时,写入可能需要一些时间才能传播。
如果业务需要允许最终一致性,或者当系统需要在外部错误的情况下继续工作时,AP 是一个不错的选择。
对于同一数据的多个副本,我们面临着如何同步它们的选项,以便客户对数据有一个一致的视图。回想一下 CAP 定理中一致性的定义 - 每次读取都会收到最近的写入或错误。
写入后,读取者可能会或可能不会看到它。采取尽力而为的方法。
这种方法在 memcached 等系统中可见。弱一致性在实时用例(如 VoIP、视频聊天和实时多人游戏)中效果很好。例如,如果你在通话中失去接收几秒钟,当你重新获得连接时,你不会听到连接丢失期间所说的内容。
写入后,读取者最终会看到它(通常在几毫秒内)。数据是异步复制的。
这种方法在 DNS 和电子邮件等系统中可见。最终一致性在高可用性系统中效果很好。
写入后,读取者将看到它。数据是同步复制的。
这种方法在文件系统和 RDBMS 中可见。强一致性在需要事务的系统中效果很好。
有两种互补模式可以支持高可用性:故障转移和复制。
通过主动-被动故障转移,检测信号在备用服务器和无源服务器之间发送。如果检测信号中断,无源服务器将接管主用服务器的 IP 地址并恢复服务。
停机时间的长短取决于无源服务器是否已经在“热”备用状态下运行,或者是否需要从“冷”备用状态启动。只有活动服务器处理流量。
主动-被动故障切换也称为主-从故障切换。
在主动-主动模式下,两台服务器都在管理流量,在它们之间分散负载。
如果服务器是面向公众的,则 DNS 需要了解两台服务器的公共 IP。如果服务器面向内部,则应用程序逻辑需要了解这两个服务器。
主动-主动故障切换也称为主-主故障切换。
本主题将在“数据库”部分中进一步讨论:
可用性通常通过正常运行时间(或停机时间)来量化,作为服务可用时间的百分比。可用性通常以 9 的数量来衡量,可用性为 99.99% 的服务被描述为具有四个 9。
期间 | 可接受的停机时间 |
---|---|
每年停机时间 | 8小时 45分 57秒 |
每月停机时间 | 43 分 49.7 秒 |
每周停机时间 | 10 分 4.8 秒 |
每天停机时间 | 1 分 26.4 秒 |
期间 | 可接受的停机时间 |
---|---|
每年停机时间 | 52分 35.7秒 |
每月停机时间 | 4 分 23 秒 |
每周停机时间 | 1 分 5 秒 |
每天停机时间 | 8.6秒 |
如果服务由多个容易发生故障的组件组成,则服务的整体可用性取决于这些组件是按顺序还是并行。
当两个可用性< 100% 的组件依次排列时,总体可用性会降低:
Availability (Total) = Availability (Foo) * Availability (Bar)
如果两者和每个都有 99.9% 的可用性,则它们的总可用性依次为 99.8%。
Foo
Bar
当两个可用性< 100% 的组件并行时,总体可用性会提高:
Availability (Total) = 1 - (1 - Availability (Foo)) * (1 - Availability (Bar))
如果两者和每个都有 99.9% 的可用性,则它们的并行总可用性将为 99.9999%。
Foo
Bar
域名系统 (DNS) 将域名(如 www.example.com)转换为 IP 地址。
DNS 是分层的,在顶层有一些权威服务器。你的路由器或 ISP 提供有关在执行查找时要联系的 DNS 服务器的信息。较低级别的 DNS 服务器缓存映射,由于 DNS 传播延迟,这些映射可能会过时。你的浏览器或操作系统也可以将 DNS 结果缓存一段时间,由生存时间 (TTL) 决定。
CNAME
A
CloudFlare 和 Route 53 等服务提供托管 DNS 服务。某些 DNS 服务可以通过各种方法路由流量:
内容分发网络 (CDN) 是一个全球分布的代理服务器网络,从离用户更近的位置提供内容。通常,HTML/CSS/JS、照片和视频等静态文件由 CDN 提供,尽管某些 CDN(如 Amazon 的 CloudFront)支持动态内容。站点的 DNS 解析将告诉客户端要联系哪个服务器。
从 CDN 提供内容可以通过两种方式显著提高性能:
每当服务器上发生更改时,推送 CDN 都会接收新内容。你全权负责提供内容、直接上传到 CDN 以及重写 URL 以指向 CDN。你可以配置内容何时过期以及何时更新内容。仅当内容是新的或更改的内容时才上传,从而最大限度地减少流量,但最大化存储空间。
流量较小的网站或内容不经常更新的网站可以很好地与推送 CDN 配合使用。 内容在 CDN 上放置一次,而不是定期重新拉取。
拉取 CDN 在第一个用户请求内容时从你的服务器获取新内容。将内容保留在服务器上,并重写 URL 以指向 CDN。这会导致请求速度变慢,直到内容缓存到 CDN 上。
生存时间 (TTL) 决定了缓存内容的时间。拉取 CDN 可最大程度地减少 CDN 上的存储空间,但如果文件过期并在实际更改之前拉取,则可能会产生冗余流量。
流量大的网站与拉式 CDN 配合得很好,因为流量分布得更均匀,CDN 上只保留最近请求的内容。
负载均衡器将传入的客户端请求分发到计算资源,例如应用程序服务器和数据库。在每种情况下,负载均衡器都会将响应从计算资源返回到相应的客户端。负载均衡器在以下方面有效:
负载均衡器可以使用硬件(昂贵)或软件(如 HAProxy)来实现。
其他好处包括:
为了防止故障,通常在主动-被动或主动-主动模式下设置多个负载均衡器。
负载均衡器可以根据各种指标路由流量,包括:
第 4 层负载均衡器查看传输层的信息,以决定如何分发请求。通常,这涉及标头中的源、目标 IP 地址和端口,但不涉及数据包的内容。第 4 层负载均衡器将网络数据包转发到上游服务器或从上游服务器转发网络数据包,执行网络地址转换 (NAT)。
第 7 层负载均衡器查看应用程序层以决定如何分发请求。这可能涉及标头、消息和 Cookie 的内容。第 7 层负载平衡器终止网络流量,读取消息,做出负载平衡决策,然后打开与所选服务器的连接。例如,第 7 层负载均衡器可以将视频流量定向到托管视频的服务器,同时将更敏感的用户计费流量定向到安全强化的服务器。
以灵活性为代价,第 4 层负载均衡比第 7 层需要更少的时间和计算资源,尽管对现代商用硬件的性能影响可能很小。
负载均衡器还可以帮助进行水平扩展,从而提高性能和可用性。与在更昂贵的硬件上纵向扩展单个服务器(称为垂直缩放)相比,使用商用计算机进行横向扩展更具成本效益,并且可以提高可用性。与专业企业系统相比,雇用从事商用硬件工作的人才也更容易。
反向代理是一种 Web 服务器,它集中了内部服务并向公众提供统一的接口。在反向代理将服务器的响应返回给客户端之前,来自客户端的请求将转发到可以完成该请求的服务器。
其他好处包括:
来源:Intro to Architecting Systems for Scale
通过将 Web 层与应用层(也称为平台层)分离出来,你可以独立扩展和配置这两个层。添加新的 API 会导致添加应用程序服务器,而不必添加其他 Web 服务器。单一责任原则提倡协同工作的小型和自主服务。拥有小型服务的小型团队可以更积极地规划快速增长。
应用层的工作线程还有助于实现异步。
与此讨论相关的是微服务,它可以被描述为一套可独立部署的小型模块化服务。每个服务都运行一个独特的流程,并通过定义明确的轻量级机制进行通信,以实现业务目标。1
例如,Pinterest 可以有以下微服务:用户个人资料、关注者、提要、搜索、照片上传等。
Consul、Etcd 和 Zookeeper 等系统可以通过跟踪注册的名称、地址和端口来帮助服务找到彼此。运行状况检查有助于验证服务完整性,通常使用 HTTP 终结点完成。Consul 和 Etcd 都有一个内置的键值存储,可用于存储配置值和其他共享数据。
像 SQL 这样的关系数据库是以表形式组织的数据项的集合。
ACID 是关系数据库事务的一组属性。
有许多技术可以扩展关系数据库:主从复制、主-主复制、联合、分片、非规范化和 SQL 优化。
主服务器提供读取和写入服务,将写入复制到一个或多个仅提供读取服务的从服务器。从属服务器还可以以树状的方式复制到其他从属服务器。如果主设备脱机,系统可以继续以只读模式运行,直到从设备升级为主设备或配置新的主设备。
两个主服务器都提供读取和写入,并在写入时相互协调。如果任一主设备出现故障,系统可以继续进行读取和写入操作。
联合(或功能分区)按功能拆分数据库。例如,你可以拥有三个数据库:论坛、用户和产品,而不是单个整体式数据库,从而减少每个数据库的读取和写入流量,从而减少复制滞后。数据库越小,内存中可以容纳的数据就越多,这反过来又会由于缓存局部性的改进而导致更多的缓存命中。由于没有单个中央主序列化写入,因此你可以并行写入,从而提高吞吐量。
分片将数据分布在不同的数据库之间,因此每个数据库只能管理数据的子集。以用户数据库为例,随着用户数量的增加,集群中加入的分片也越来越多。
与联合的优点类似,分片可以减少读取和写入流量、减少复制和增加缓存命中。索引大小也会减小,这通常会通过更快的查询来提高性能。如果一个分片出现故障,其他分片仍可运行,但你需要添加某种形式的复制以避免数据丢失。与联合一样,没有单个中央主序列化写入,允许你在增加吞吐量的同时并行写入。
对用户表进行分片的常见方法是通过用户的姓氏首字母或用户的地理位置。
非规范化想以牺牲某些写入性能为代价来提高读取性能。数据的冗余副本写入多个表中,以避免成本高昂的联接。一些 RDBMS(如 PostgreSQL 和 Oracle)支持物化视图,这些视图处理存储冗余信息和保持冗余副本一致性的工作。
一旦数据通过联合和分片等技术进行分布式处理,跨数据中心管理联接将进一步增加复杂性。非规范化可能会规避对这种复杂连接的需求。
在大多数系统中,读取次数可能远远超过写入次数 100:1 甚至 1000:1。导致复杂数据库联接的读取可能非常昂贵,在磁盘操作上花费大量时间。
SQL调优是一个广泛的话题,已经写了许多书籍作为参考。
对基准测试和分析进行建模以模拟和发现瓶颈非常重要。
基准测试和分析可能会指向以下优化。
CHAR
VARCHAR
CHAR有效地允许快速、随机的访问,而使用 ,你必须先找到一个字符串的末尾,然后才能进入下一个字符串。
VARCHAR
TEXT
TEXT
TEXT
INT
DECIMAL
BLOBS
VARCHAR(255)是可以用 8 位数字计数的最大字符数,通常在某些 RDBMS 中最大化使用一个字节。
NOT NULL
SELECT
GROUP BY
ORDER BY
JOIN
NoSQL 是以键值存储、文档存储、宽列存储或图形数据库表示的数据项的集合。数据是非规范化的,联接通常在应用程序代码中完成。大多数 NoSQL 存储缺乏真正的 ACID 事务,并且有利于最终一致性。
BASE 通常用于描述 NoSQL 数据库的属性。与 CAP 定理相比,BASE 选择可用性而不是一致性。
除了在 SQL 或 NoSQL 之间进行选择之外,了解哪种类型的 NoSQL 数据库最适合你的用例也很有帮助。我们将在下一节中介绍键值存储、文档存储、宽列存储和图形数据库。
抽象:哈希表
键值存储通常允许 O(1) 读取和写入,并且通常由内存或 SSD 提供支持。数据存储可以按字典顺序维护密钥,从而可以有效地检索密钥范围。键值存储可以允许存储具有值的元数据。
键值存储提供高性能,通常用于简单的数据模型或快速变化的数据,例如内存中缓存层。由于它们仅提供一组有限的操作,因此如果需要其他操作,复杂性会转移到应用层。
键值存储是更复杂系统(如文档存储)的基础,在某些情况下,还有图形数据库。
抽象:键值存储,文档存储为值
文档存储以文档(XML、JSON、二进制等)为中心,其中文档存储给定对象的所有信息。文档存储提供 API 或查询语言,用于根据文档本身的内部结构进行查询。请注意,许多键值存储都包含用于处理值元数据的功能,从而模糊了这两种存储类型之间的界限。
根据基础实现,文档按集合、标记、元数据或目录进行组织。尽管文档可以组织或组合在一起,但文档可能具有彼此完全不同的字段。
一些文档存储(如 MongoDB 和 CouchDB)也提供类似 SQL 的语言来执行复杂的查询。DynamoDB 支持键值对和文档。
文档存储提供了高度的灵活性,通常用于处理偶尔更改的数据。
抽象:嵌套映射
ColumnFamily<RowKey, Columns<ColKey, Value, Timestamp>>
宽列存储的基本数据单位是列(名称/值对)。列可以按列系列进行分组(类似于 SQL 表)。超级色谱柱族进一步对色谱柱族进行分组。你可以使用行键独立访问每一列,具有相同行键的列构成一行。每个值都包含用于版本控制和冲突解决的时间戳。
Google 引入了 Bigtable 作为第一个宽列存储,这影响了 Hadoop 生态系统中经常使用的开源 HBase,以及 Facebook 的 Cassandra。BigTable、HBase 和 Cassandra 等存储按字典顺序维护密钥,从而可以高效检索选择性密钥范围。
宽列存储提供高可用性和高可伸缩性。它们通常用于非常大的数据集。
抽象:图形
在图形数据库中,每个节点都是一条记录,每个弧是两个节点之间的关系。图形数据库经过优化,可以表示具有许多外键或多对多关系的复杂关系。
图形数据库为具有复杂关系的数据模型(例如社交网络)提供高性能。它们相对较新,尚未广泛使用;查找开发工具和资源可能更加困难。许多图形只能使用 REST API 访问。
使用 SQL 的原因:
使用 NoSQL 的原因:
非常适合 NoSQL 的示例数据:
缓存可缩短页面加载时间,并可减少服务器和数据库的负载。在此模型中,调度程序将首先查找之前是否发出过请求,并尝试查找要返回的先前结果,以保存实际执行。
数据库通常受益于跨分区的读取和写入的均匀分布。热门项目可能会扭曲分布,从而导致瓶颈。将缓存放在数据库的前面有助于吸收不均匀的负载和流量峰值。
缓存可以位于客户端(操作系统或浏览器)、服务器端或不同的缓存层中。
CDN 被视为一种缓存。
反向代理和缓存(如 Varnish)可以直接提供静态和动态内容。Web 服务器还可以缓存请求,返回响应,而无需联系应用程序服务器。
你的数据库通常在默认配置中包含某种级别的缓存,并针对通用用例进行了优化。针对特定使用模式调整这些设置可以进一步提高性能。
Memcached 和 Redis 等内存缓存是应用程序和数据存储之间的键值存储。由于数据保存在 RAM 中,因此它比数据存储在磁盘上的典型数据库快得多。RAM 比磁盘更受限制,因此缓存失效算法(如最近最少使用过 (LRU))可以帮助使“冷”条目失效,并将“热”数据保留在 RAM 中。
Redis 具有以下附加功能:
可以缓存多个级别,这些级别分为两个常规类别:数据库查询和对象:
通常,应尽量避免基于文件的缓存,因为它会使克隆和自动缩放更加困难。
每当查询数据库时,请将查询作为键进行哈希处理,并将结果存储到缓存中。此方法存在过期问题:
将数据视为对象,类似于对应用程序代码执行的操作。让应用程序将数据库中的数据集组合到类实例或数据结构中:
缓存内容的建议:
由于你只能在缓存中存储有限数量的数据,因此你需要确定哪种缓存更新策略最适合你的用例。
该应用程序负责从存储中读取和写入。缓存不直接与存储交互。该应用程序执行以下操作:
def get_user(self, user_id):
user = cache.get("user.{0}", user_id)
if user is None:
user = db.query("SELECT * FROM users WHERE user_id = {0}", user_id)
if user is not None:
key = "user.{0}".format(user_id)
cache.set(key, json.dumps(user))
return user
Memcached 通常以这种方式使用。
对添加到缓存中的数据的后续读取速度很快。缓存端也称为延迟加载。仅缓存请求的数据,从而避免使用未请求的数据填满缓存。
The application uses the cache as the main data store, reading and writing data to it, while the cache is responsible for reading and writing to the database:
Application code:
set_user(12345, {"foo":"bar"})
Cache code:
def set_user(user_id, values):
user = db.query("UPDATE Users WHERE id = {0}", user_id, values)
cache.set(user_id, user)
Write-through is a slow overall operation due to the write operation, but subsequent reads of just written data are fast. Users are generally more tolerant of latency when updating data than reading data. Data in the cache is not stale.
In write-behind, the application does the following:
You can configure the cache to automatically refresh any recently accessed cache entry prior to its expiration.
Refresh-ahead can result in reduced latency vs read-through if the cache can accurately predict which items are likely to be needed in the future.
Source: Intro to architecting systems for scale
Asynchronous workflows help reduce request times for expensive operations that would otherwise be performed in-line. They can also help by doing time-consuming work in advance, such as periodic aggregation of data.
Message queues receive, hold, and deliver messages. If an operation is too slow to perform inline, you can use a message queue with the following workflow:
The user is not blocked and the job is processed in the background. During this time, the client might optionally do a small amount of processing to make it seem like the task has completed. For example, if posting a tweet, the tweet could be instantly posted to your timeline, but it could take some time before your tweet is actually delivered to all of your followers.
Redis is useful as a simple message broker but messages can be lost.
RabbitMQ is popular but requires you to adapt to the 'AMQP' protocol and manage your own nodes.
Amazon SQS is hosted but can have high latency and has the possibility of messages being delivered twice.
Tasks queues receive tasks and their related data, runs them, then delivers their results. They can support scheduling and can be used to run computationally-intensive jobs in the background.
Celery has support for scheduling and primarily has python support.
If queues start to grow significantly, the queue size can become larger than memory, resulting in cache misses, disk reads, and even slower performance. Back pressure can help by limiting the queue size, thereby maintaining a high throughput rate and good response times for jobs already in the queue. Once the queue fills up, clients get a server busy or HTTP 503 status code to try again later. Clients can retry the request at a later time, perhaps with exponential backoff.
HTTP is a method for encoding and transporting data between a client and a server. It is a request/response protocol: clients issue requests and servers issue responses with relevant content and completion status info about the request. HTTP is self-contained, allowing requests and responses to flow through many intermediate routers and servers that perform load balancing, caching, encryption, and compression.
A basic HTTP request consists of a verb (method) and a resource (endpoint). Below are common HTTP verbs:
Verb | Description | Idempotent* | Safe | Cacheable |
---|---|---|---|---|
GET | Reads a resource | Yes | Yes | Yes |
POST | Creates a resource or trigger a process that handles data | No | No | Yes if response contains freshness info |
PUT | Creates or replace a resource | Yes | No | No |
PATCH | Partially updates a resource | No | No | Yes if response contains freshness info |
DELETE | Deletes a resource | Yes | No | No |
*Can be called many times without different outcomes.
HTTP is an application layer protocol relying on lower-level protocols such as TCP and UDP.
Source: How to make a multiplayer game
TCP is a connection-oriented protocol over an IP network. Connection is established and terminated using a handshake. All packets sent are guaranteed to reach the destination in the original order and without corruption through:
If the sender does not receive a correct response, it will resend the packets. If there are multiple timeouts, the connection is dropped. TCP also implements flow control and congestion control. These guarantees cause delays and generally result in less efficient transmission than UDP.
To ensure high throughput, web servers can keep a large number of TCP connections open, resulting in high memory usage. It can be expensive to have a large number of open connections between web server threads and say, a memcached server. Connection pooling can help in addition to switching to UDP where applicable.
TCP is useful for applications that require high reliability but are less time critical. Some examples include web servers, database info, SMTP, FTP, and SSH.
Use TCP over UDP when:
Source: How to make a multiplayer game
UDP is connectionless. Datagrams (analogous to packets) are guaranteed only at the datagram level. Datagrams might reach their destination out of order or not at all. UDP does not support congestion control. Without the guarantees that TCP support, UDP is generally more efficient.
UDP can broadcast, sending datagrams to all devices on the subnet. This is useful with DHCP because the client has not yet received an IP address, thus preventing a way for TCP to stream without the IP address.
UDP is less reliable but works well in real time use cases such as VoIP, video chat, streaming, and realtime multiplayer games.
Use UDP over TCP when:
Source: Crack the system design interview
In an RPC, a client causes a procedure to execute on a different address space, usually a remote server. The procedure is coded as if it were a local procedure call, abstracting away the details of how to communicate with the server from the client program. Remote calls are usually slower and less reliable than local calls so it is helpful to distinguish RPC calls from local calls. Popular RPC frameworks include Protobuf, Thrift, and Avro.
RPC is a request-response protocol:
Sample RPC calls:
GET /someoperation?data=anId POST /anotheroperation { "data":"anId"; "anotherdata": "another value" }
RPC is focused on exposing behaviors. RPCs are often used for performance reasons with internal communications, as you can hand-craft native calls to better fit your use cases.
Choose a native library (aka SDK) when:
HTTP APIs following REST tend to be used more often for public APIs.
REST is an architectural style enforcing a client/server model where the client acts on a set of resources managed by the server. The server provides a representation of resources and actions that can either manipulate or get a new representation of resources. All communication must be stateless and cacheable.
There are four qualities of a RESTful interface:
Sample REST calls:
GET /someresources/anId PUT /someresources/anId {"anotherdata": "another value"}
REST is focused on exposing data. It minimizes the coupling between client/server and is often used for public HTTP APIs. REST uses a more generic and uniform method of exposing resources through URIs, representation through headers, and actions through verbs such as GET, POST, PUT, DELETE, and PATCH. Being stateless, REST is great for horizontal scaling and partitioning.
Operation | RPC | REST |
---|---|---|
Signup | POST /signup | POST /persons |
Resign |
POST /resign { "personid": "1234" } |
DELETE /persons/1234 |
Read a person | GET /readPerson?personid=1234 | GET /persons/1234 |
Read a person’s items list | GET /readUsersItemsList?personid=1234 | GET /persons/1234/items |
Add an item to a person’s items |
POST /addItemToUsersItemsList { "personid": "1234"; "itemid": "456" } |
POST /persons/1234/items { "itemid": "456" } |
Update an item |
POST /modifyItem { "itemid": "456"; "key": "value" } |
PUT /items/456 { "key": "value" } |
Delete an item |
POST /removeItem { "itemid": "456" } |
DELETE /items/456 |
Source: Do you really know why you prefer REST over RPC
This section could use some updates. Consider contributing!
Security is a broad topic. Unless you have considerable experience, a security background, or are applying for a position that requires knowledge of security, you probably won't need to know more than the basics:
You'll sometimes be asked to do 'back-of-the-envelope' estimates. For example, you might need to determine how long it will take to generate 100 image thumbnails from disk or how much memory a data structure will take. The Powers of two table and Latency numbers every programmer should know are handy references.
Power Exact Value Approx Value Bytes --------------------------------------------------------------- 7 128 8 256 10 1024 1 thousand 1 KB 16 65,536 64 KB 20 1,048,576 1 million 1 MB 30 1,073,741,824 1 billion 1 GB 32 4,294,967,296 4 GB 40 1,099,511,627,776 1 trillion 1 TB
Latency Comparison Numbers -------------------------- L1 cache reference 0.5 ns Branch mispredict 5 ns L2 cache reference 7 ns 14x L1 cache Mutex lock/unlock 25 ns Main memory reference 100 ns 20x L2 cache, 200x L1 cache Compress 1K bytes with Zippy 10,000 ns 10 us Send 1 KB bytes over 1 Gbps network 10,000 ns 10 us Read 4 KB randomly from SSD* 150,000 ns 150 us ~1GB/sec SSD Read 1 MB sequentially from memory 250,000 ns 250 us Round trip within same datacenter 500,000 ns 500 us Read 1 MB sequentially from SSD* 1,000,000 ns 1,000 us 1 ms ~1GB/sec SSD, 4X memory HDD seek 10,000,000 ns 10,000 us 10 ms 20x datacenter roundtrip Read 1 MB sequentially from 1 Gbps 10,000,000 ns 10,000 us 10 ms 40x memory, 10X SSD Read 1 MB sequentially from HDD 30,000,000 ns 30,000 us 30 ms 120x memory, 30X SSD Send packet CA->Netherlands->CA 150,000,000 ns 150,000 us 150 ms Notes ----- 1 ns = 10^-9 seconds 1 us = 10^-6 seconds = 1,000 ns 1 ms = 10^-3 seconds = 1,000 us = 1,000,000 ns
Handy metrics based on numbers above:
Common system design interview questions, with links to resources on how to solve each.
Question | Reference(s) |
---|---|
Design a file sync service like Dropbox | youtube.com |
Design a search engine like Google |
queue.acm.org stackexchange.com ardendertat.com stanford.edu |
Design a scalable web crawler like Google | quora.com |
Design Google docs |
code.google.com neil.fraser.name |
Design a key-value store like Redis | slideshare.net |
Design a cache system like Memcached | slideshare.net |
Design a recommendation system like Amazon's |
hulu.com ijcai13.org |
Design a tinyurl system like Bitly | n00tc0d3r.blogspot.com |
Design a chat app like WhatsApp | highscalability.com |
Design a picture sharing system like Instagram |
highscalability.com highscalability.com |
Design the Facebook news feed function |
quora.com quora.com slideshare.net |
Design the Facebook timeline function |
facebook.com highscalability.com |
Design the Facebook chat function |
erlang-factory.com facebook.com |
Design a graph search function like Facebook's |
facebook.com facebook.com facebook.com |
Design a content delivery network like CloudFlare | figshare.com |
Design a trending topic system like Twitter's |
michael-noll.com snikolov .wordpress.com |
Design a random ID generation system |
blog.twitter.com github.com |
Return the top k requests during a time interval |
cs.ucsb.edu wpi.edu |
Design a system that serves data from multiple data centers | highscalability.com |
Design an online multiplayer card game |
indieflashblog.com buildnewgames.com |
Design a garbage collection system |
stuffwithstuff.com washington.edu |
Design an API rate limiter | https://stripe.com/blog/ |
Design a Stock Exchange (like NASDAQ or Binance) |
Jane Street Golang Implementation Go Implementation |
Add a system design question | Contribute |
Articles on how real world systems are designed.
Source: Twitter timelines at scale
Don't focus on nitty gritty details for the following articles, instead:
Type | System | Reference(s) |
---|---|---|
Data processing | MapReduce - Distributed data processing from Google | research.google.com |
Data processing | Spark - Distributed data processing from Databricks | slideshare.net |
Data processing | Storm - Distributed data processing from Twitter | slideshare.net |
Data store | Bigtable - Distributed column-oriented database from Google | harvard.edu |
Data store | HBase - Open source implementation of Bigtable | slideshare.net |
Data store | Cassandra - Distributed column-oriented database from Facebook | slideshare.net |
Data store | DynamoDB - Document-oriented database from Amazon | harvard.edu |
Data store | MongoDB - Document-oriented database | slideshare.net |
Data store | Spanner - Globally-distributed database from Google | research.google.com |
Data store | Memcached - Distributed memory caching system | slideshare.net |
Data store | Redis - Distributed memory caching system with persistence and value types | slideshare.net |
File system | Google File System (GFS) - Distributed file system | research.google.com |
File system | Hadoop File System (HDFS) - Open source implementation of GFS | apache.org |
Misc | Chubby - Lock service for loosely-coupled distributed systems from Google | research.google.com |
Misc | Dapper - Distributed systems tracing infrastructure | research.google.com |
Misc | Kafka - Pub/sub message queue from LinkedIn | slideshare.net |
Misc | Zookeeper - Centralized infrastructure and services enabling synchronization | slideshare.net |
Add an architecture | Contribute |
Architectures for companies you are interviewing with.
Questions you encounter might be from the same domain.
Looking to add a blog? To avoid duplicating work, consider adding your company blog to the following repo:
Interested in adding a section or helping complete one in-progress? Contribute!
捐赠 and sources are provided throughout this repo.
Special thanks to:
Feel free to contact me to discuss any issues, questions, or comments.
My contact info can be found on my GitHub page.
I am providing code and resources in this repository to you under an open source license. Because this is my personal repository, the license you receive to my code and resources is from me and not my employer (Facebook).
Copyright 2017 Donne Martin Creative Commons Attribution 4.0 International License (CC BY 4.0) http://creativecommons.org/licenses/by/4.0/