system-design-primer - 学习如何设计大型系统

Created at: 2017-02-27 00:15:28
Language: Python
License: NOASSERTION

简体中文 ∙ 日本語简体中文 ∙ 繁體中文 |العَرَبِيَّةবাংলা葡萄牙做巴西德语 ∙ ελληνικάעבריתItaliano한국어فارسیPolskiрусский язык西班牙语ภาษาไทย土耳其tiếng 越南法国|添加翻译

帮助翻译本指南!

系统设计入门


赋予动机

了解如何设计大型系统。

准备系统设计面试。

了解如何设计大型系统

学习如何设计可扩展的系统将帮助你成为一名更好的工程师。

系统设计是一个广泛的主题。网络上有大量关于系统设计原则的资源

此存储库是有组织的资源集合,可帮助你了解如何大规模构建系统。

向开源社区学习

这是一个不断更新的开源项目。

欢迎投稿

准备系统设计面试

除了编码面试之外,系统设计是许多科技公司技术面试流程的必要组成部分

练习常见的系统设计面试问题,并将你的结果示例解决方案进行比较:讨论、代码和图表。

面试准备的其他主题:

安基抽认卡


提供的 Anki 抽认卡组使用间隔重复来帮助你保留关键的系统设计概念。

非常适合在旅途中使用。

编码资源:交互式编码挑战

寻找资源来帮助你准备编码面试


查看姊妹存储库交互式编码挑战,其中包含一个额外的 Anki 甲板:

贡献

向社区学习。

请随时提交拉取请求以帮助:

  • 修复错误
  • 改进部分
  • 添加新部分
  • 翻译

需要一些润色的内容正在开发中

查看贡献指南

系统设计主题索引

各种系统设计主题的摘要,包括优缺点。 一切都是权衡。

每个部分都包含指向更深入资源的链接。


学习指南

根据你的面试时间表(短、中、长)建议审查的主题。

伊姆古尔

问:对于面试,我需要知道这里的一切吗?

答:不,你不需要知道这里的一切来准备面试

你在面试中被问到的问题取决于以下变量:

  • 你有多少经验
  • 你的技术背景是什么
  • 你正在面试什么职位
  • 你正在面试哪些公司
  • 运气

通常期望更有经验的候选人更多地了解系统设计。架构师或团队主管可能比个人贡献者更了解。顶级科技公司可能会有一轮或多轮设计面试。

从广泛开始,在几个领域更深入。了解一些关键系统设计主题会有所帮助。根据你的时间表、经验、面试职位以及面试的公司调整以下指南。

  • 时间短 - 以系统设计主题的广度为目标。通过解决一些面试问题来练习。
  • 中等时间线 - 以系统设计主题的广度深度为目标。通过解决许多面试问题来练习。
  • 长时间表 - 以系统设计主题的广度深度为目标。通过解决大多数面试问题来练习。
中等
通读系统设计主题,广泛了解系统的工作原理 👍 👍 👍
通读公司工程博客中的几篇文章,了解你正在面试的公司 👍 👍 👍
通读一些真实世界的架构 👍 👍 👍
复习如何处理系统设计面试问题 👍 👍 👍
通过解决方案解决系统设计面试问题 一些
通过面向对象设计面试问题与解决方案一起工作 一些
查看其他系统设计面试问题 一些

如何处理系统设计面试问题

如何解决系统设计面试问题。

系统设计面试是一个开放式的对话。你应该领导它。

你可以使用以下步骤来指导讨论。为了帮助巩固此过程,请使用以下步骤完成系统设计面试问题与解决方案部分。

步骤 1:概述用例、约束和假设

收集需求并确定问题的范围。提出问题以阐明用例和约束。讨论假设。

  • 谁会使用它?
  • 他们将如何使用它?
  • 有多少用户?
  • 系统有什么作用?
  • 系统的输入和输出是什么?
  • 我们期望处理多少数据?
  • 我们预计每秒有多少请求?
  • 预期的读写比率是多少?

步骤 2:创建高级设计

勾勒出包含所有重要组件的高级设计。

  • 绘制主要组件和连接的草图
  • 证明你的想法是合理的

步骤 3:设计核心组件

深入了解每个核心组件的详细信息。例如,如果要求你设计 url 缩短服务,请讨论:

  • 生成和存储完整 url 的哈希
    • MD5 和底座 62
    • 哈希冲突
    • SQL 或 NoSQL
    • 数据库架构
  • 将经过哈希处理的网址转换为完整网址
    • 数据库查找
  • API 和面向对象设计

步骤 4:缩放设计

根据限制因素,识别并解决瓶颈问题。例如,是否需要以下内容来解决可伸缩性问题?

  • 负载均衡器
  • 水平缩放
  • 缓存
  • 数据库分片

讨论潜在的解决方案和权衡。一切都是权衡。使用可扩展系统设计原则解决瓶颈。

粗略计算

可能会要求你手动进行一些估算。有关以下资源,请参阅附录

来源和延伸阅读

查看以下链接以更好地了解预期内容:

系统设计面试问题及解决方案

常见的系统设计面试问题,包括示例讨论、代码和图表。

链接到文件夹中内容的解决方案。

solutions/

问题
设计 Pastebin.com(或 Bit.ly) 溶液
设计Twitter时间线和搜索(或Facebook提要和搜索) 溶液
设计网络爬虫 溶液
设计 Mint.com 溶液
设计社交网络的数据结构 溶液
为搜索引擎设计键值存储 溶液
按类别功能设计亚马逊的销售排名 溶液
设计一个可扩展到 AWS 上数百万用户的系统 溶液
添加系统设计问题 贡献

设计 Pastebin.com(或 Bit.ly)

查看练习和解决方案

伊姆古尔

设计Twitter时间线和搜索(或Facebook提要和搜索)

查看练习和解决方案

伊姆古尔

设计网络爬虫

查看练习和解决方案

伊姆古尔

设计 Mint.com

查看练习和解决方案

伊姆古尔

设计社交网络的数据结构

查看练习和解决方案

伊姆古尔

为搜索引擎设计键值存储

查看练习和解决方案

伊姆古尔

按类别功能设计亚马逊的销售排名

查看练习和解决方案

伊姆古尔

设计一个可扩展到 AWS 上数百万用户的系统

查看练习和解决方案

伊姆古尔

面向对象设计面试问题及解决方案

常见的面向对象设计面试问题,包括示例讨论、代码和图表。

链接到文件夹中内容的解决方案。

solutions/

注意:此部分正在开发中

问题
设计哈希映射 溶液
设计最近最少使用的缓存 溶液
设计呼叫中心 溶液
设计一副纸牌 溶液
设计停车场 溶液
设计聊天服务器 溶液
设计圆形阵列 贡献
添加面向对象的设计问题 贡献

系统设计主题:从这里开始

系统设计新手?

首先,你需要对共同原则有基本的了解,了解它们是什么、如何使用它们以及它们的优缺点。

步骤 1:查看可伸缩性视频讲座

哈佛大学可扩展性讲座

  • 主题:
    • 垂直缩放
    • 水平缩放
    • 缓存
    • 负载平衡
    • 数据库复制
    • 数据库分区

步骤 2:查看可伸缩性一文

可扩展性

后续步骤

接下来,我们将研究高级权衡:

  • 性能可扩展性
  • 延迟吞吐量
  • 可用性一致性

请记住,一切都是权衡

然后,我们将深入探讨更具体的主题,例如 DNS、CDN 和负载均衡器。

性能与可扩展性

如果服务以与添加的资源成比例的方式提高性能,则该服务是可缩放的。通常,提高性能意味着为更多的工作单元提供服务,但也可以是处理更大的工作单元,例如当数据集增长时。1

查看性能与可伸缩性的另一种方法:

  • 如果遇到性能问题,则系统对于单个用户来说速度很慢。
  • 如果遇到可伸缩性问题,则系统对于单个用户来说速度很快,但在负载较重的情况下速度较慢。

来源和延伸阅读

延迟与吞吐量

延迟是执行某些操作或产生某些结果的时间。

吞吐量是每单位时间内此类操作或结果的数量。

通常,应以可接受的延迟实现最大吞吐量为目标。

来源和延伸阅读

可用性与一致性

CAP定理


来源:重新审视CAP定理

在分布式计算机系统中,只能支持以下两种保证:

  • 一致性 - 每次读取都会收到最近的写入或错误
  • 可用性 - 每个请求都会收到响应,但不保证它包含最新版本的信息
  • 分区容错 - 尽管由于网络故障而进行了任意分区,系统仍继续运行

网络不可靠,因此需要支持分区容错。你需要在一致性和可用性之间进行软件权衡。

CP - 一致性和分区容错

等待分区节点的响应可能会导致超时错误。如果你的业务需求需要原子读取和写入,CP 是一个不错的选择。

AP - 可用性和分区容错

响应返回任何节点上最容易获得的数据版本,这可能不是最新版本。解析分区时,写入可能需要一些时间才能传播。

如果业务需要允许最终一致性,或者系统需要继续工作,尽管存在外部错误,则 AP 是一个不错的选择。

来源和延伸阅读

一致性模式

对于相同数据的多个副本,我们面临着如何同步它们的选项,以便客户对数据有一个一致的视图。回想一下 CAP 定理中一致性的定义 - 每次读取都会收到最近的写入或错误。

一致性弱

写入后,读取可能会也可能看不到它。采取尽力而为的方法。

这种方法在诸如memcached之类的系统中可以看到。弱一致性在 VoIP、视频聊天和实时多人游戏等实时用例中效果很好。例如,如果你正在打电话并失去接收几秒钟,则当你重新获得连接时,你将听不到连接丢失期间所说的内容。

最终一致性

写入后,读取最终将看到它(通常在毫秒内)。数据以异步方式复制。

这种方法在 DNS 和电子邮件等系统中可见。最终一致性在高可用性系统中运行良好。

一致性强

写入后,读取将看到它。数据同步复制。

这种方法在文件系统和RDBMS中可见。强一致性在需要事务的系统中效果很好。

来源和延伸阅读

可用性模式

有两种互补的模式可以支持高可用性:故障转移复制

故障转移

主动-被动

使用主动-被动故障转移时,检测信号在备用服务器的主动服务器和无源服务器之间发送。如果检测信号中断,无源服务器将接管活动的 IP 地址并恢复服务。

停机时间的长短取决于无源服务器是否已在“热”备用中运行,还是需要从“冷”备用服务器启动。只有活动服务器处理流量。

主动-被动故障转移也可以称为主从故障转移。

主动-主动

在主动-主动模式下,两台服务器都在管理流量,在它们之间分散负载。

如果服务器面向公众,则 DNS 需要了解两台服务器的公共 IP。如果服务器面向内部,则应用程序逻辑需要了解两台服务器。

主动-主动故障转移也称为主-主故障转移。

缺点:故障转移

  • 故障转移会增加更多硬件和复杂性。
  • 如果主动系统在任何新写入的数据复制到被动系统之前发生故障,则可能会丢失数据。

复制

主从和主主

本主题将在数据库部分中进一步讨论:

可用性(数字)

可用性通常通过正常运行时间(或停机时间)来量化,即服务可用时间的百分比。可用性通常以 9 的数量来衡量 - 具有 99.99% 可用性的服务被描述为具有四个 9。

99.9% 可用性 - 三个 9

期间 可接受的停机时间
每年停机时间 8小时 45分钟 57秒
每月停机时间 43分钟 49.7秒
每周停机时间 10分钟4.8秒
每日停机时间 1 分钟 26.4 秒

99.99% 可用性 - 四个 9

期间 可接受的停机时间
每年停机时间 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 安全演示文稿

域名系统 (DNS) 将域名(如 www.example.com)转换为 IP 地址。

DNS 是分层的,在顶层有一些权威服务器。你的路由器或 ISP 提供有关在执行查找时要联系的 DNS 服务器的信息。较低级别的 DNS 服务器缓存映射,由于 DNS 传播延迟,这些映射可能会过时。DNS 结果也可以由你的浏览器或操作系统缓存一段时间,由生存时间 (TTL) 决定。

  • NS 记录(名称服务器) - 指定域/子域的 DNS 服务器。
  • MX 记录(邮件交换) - 指定用于接受邮件的邮件服务器。
  • 记录(地址) - 将名称指向 IP 地址。
  • CNAME(规范) - 将名称指向另一个名称或(example.com 指向 www.example.com)或记录。
    CNAME
    A

CloudFlareRoute 53 等服务提供托管 DNS 服务。某些 DNS 服务可以通过各种方法路由流量:

缺点: DNS

  • 访问 DNS 服务器会带来轻微的延迟,但通过上述缓存可以缓解。
  • DNS 服务器管理可能很复杂,通常由政府、ISP 和大公司管理。
  • DNS服务最近受到DDoS攻击,阻止用户在不知道Twitter的IP地址的情况下访问Twitter等网站。

来源和延伸阅读

内容交付网络


来源:为什么要使用 CDN

内容分发网络 (CDN) 是全球分布的代理服务器网络,从离用户更近的位置提供内容。通常,静态文件(如 HTML/CSS/JS、照片和视频)由 CDN 提供,尽管某些 CDN(如 Amazon 的 CloudFront)支持动态内容。站点的 DNS 解析将告诉客户端要联系哪个服务器。

从 CDN 提供内容可以通过两种方式显著提高性能:

  • 用户从他们附近的数据中心接收内容
  • 你的服务器不必为 CDN 满足的请求提供服务

推送 CDN

每当服务器上发生更改时,推送 CDN 都会接收新内容。你全权负责提供内容、直接上传到 CDN 以及重写 URL 以指向 CDN。你可以配置内容何时过期以及何时更新。仅当内容是新的或更改的内容时,才会上传内容,从而最大限度地减少流量,但最大化存储。

流量较小的网站或内容不经常更新的网站非常适合推送 CDN。 内容在 CDN 上放置一次,而不是定期重新拉取。

拉取 CDN

当第一个用户请求内容时,拉取 CDN 从你的服务器中获取新内容。将内容保留在服务器上,并重写 URL 以指向 CDN。这会导致请求速度变慢,直到内容缓存在 CDN 上。

生存时间 (TTL) 确定内容的缓存时间。拉取 CDN 可最大程度地减少 CDN 上的存储空间,但如果文件过期并在实际更改之前拉取,则可能会创建冗余流量。

流量较大的网站与拉取 CDN 配合得很好,因为流量分布得更均匀,只有最近请求的内容保留在 CDN 上。

缺点: CDN

  • CDN 成本可能很大,具体取决于流量,尽管这应该与不使用 CDN 会产生的额外费用进行权衡。
  • 如果在 TTL 过期之前更新内容,则内容可能会过时。
  • CDN 需要更改静态内容的 URL 才能指向 CDN。

来源和延伸阅读

负载均衡器


来源:可扩展的系统设计模式

负载均衡器将传入的客户端请求分发到计算资源,例如应用程序服务器和数据库。在每种情况下,负载均衡器都会将来自计算资源的响应返回到相应的客户端。负载均衡器在以下方面有效:

  • 防止请求进入不正常的服务器
  • 防止资源过载
  • 帮助消除单点故障

负载均衡器可以通过硬件(昂贵)或HAProxy等软件来实现。

其他好处包括:

  • SSL 终止 - 解密传入请求并加密服务器响应,以便后端服务器不必执行这些可能代价高昂的操作
  • 会话持久性 - 如果 Web 应用未跟踪会话,则发出 Cookie 并将特定客户端的请求路由到同一实例

为了防止故障,通常设置多个负载均衡器,无论是在主动-被动模式下还是在主动-主动模式下

负载均衡器可以根据各种指标路由流量,包括:

第 4 层负载平衡

第 4 层负载均衡器查看传输层的信息,以决定如何分发请求。通常,这涉及标头中的源、目标 IP 地址和端口,但不涉及数据包的内容。第 4 层负载均衡器将网络数据包转发到上游服务器或从上游服务器转发网络数据包,执行网络地址转换 (NAT)。

第 7 层负载平衡

第 7 层负载均衡器查看应用程序层以决定如何分发请求。这可能涉及标头、消息和 Cookie 的内容。第 7 层负载均衡器终止网络流量,读取消息,做出负载平衡决策,然后打开与所选服务器的连接。例如,第 7 层负载均衡器可以将视频流量定向到托管视频的服务器,同时将更敏感的用户计费流量定向到安全强化的服务器。

以牺牲灵活性为代价,第 4 层负载平衡比第 7 层需要更少的时间和计算资源,尽管对现代商用硬件的性能影响可能很小。

水平缩放

负载均衡器还可以帮助水平扩展,从而提高性能和可用性。与在更昂贵的硬件(称为垂直扩展)上纵向扩展单个服务器相比,使用商用计算机横向扩展更具成本效益,并且具有更高的可用性。与专业企业系统相比,雇用从事商品硬件工作的人才也更容易。

缺点:水平缩放

  • 水平扩展会带来复杂性,并涉及克隆服务器
    • 服务器应该是无状态的:它们不应包含任何与用户相关的数据,如会话或个人资料图片
    • 会话可以存储在集中式数据存储中,例如数据库(SQL,NoSQL)或持久缓存(Redis,Memcached)
  • 随着上游服务器的横向扩展,缓存和数据库等下游服务器需要处理更多的同时连接

缺点:负载均衡器

  • 如果负载均衡器没有足够的资源或配置不正确,则可能会成为性能瓶颈。
  • 引入负载均衡器来帮助消除单点故障会导致复杂性增加。
  • 单个负载均衡器是单点故障,配置多个负载均衡器会进一步增加复杂性。

来源和延伸阅读

反向代理(网络服务器)


来源:维基百科

反向代理是一种 Web 服务器,它集中内部服务并向公众提供统一的接口。在反向代理将服务器的响应返回给客户端之前,来自客户端的请求将转发到可以满足该请求的服务器。

其他好处包括:

  • 提高安全性 - 隐藏有关后端服务器的信息,将IP列入黑名单,限制每个客户端的连接数
  • 提高可扩展性和灵活性 - 客户端只能看到反向代理的 IP,允许你扩展服务器或更改其配置
  • SSL 终止 - 解密传入请求并加密服务器响应,以便后端服务器不必执行这些可能代价高昂的操作
  • 压缩 - 压缩服务器响应
  • 缓存 - 返回缓存请求的响应
  • 静态内容 - 直接提供静态内容
    • HTML/CSS/JS
    • 照片
    • 视频

负载均衡器与反向代理

  • 当你有多个服务器时,部署负载平衡器非常有用。通常,负载均衡器将流量路由到一组提供相同功能的服务器。
  • 即使只有一个 Web 服务器或应用程序服务器,反向代理也很有用,从而打开了上一节中描述的好处。
  • NGINX和HAProxy等解决方案可以支持第7层反向代理和负载平衡。

缺点:反向代理

  • 引入反向代理会导致复杂性增加。
  • 单个反向代理是单点故障,配置多个反向代理(即故障转移)会进一步增加复杂性。

来源和延伸阅读

应用层


来源:规模架构系统简介

通过将 Web 层与应用程序层(也称为平台层)分离,你可以独立扩展和配置这两个层。添加新的 API 会导致添加应用程序服务器,而不必添加额外的 Web 服务器。单一责任原则倡导协同工作的小型和自治服务。具有小型服务的小型团队可以更积极地规划快速增长。

应用程序层中的工作线程还有助于启用异步性

微服务

与此讨论相关的是微服务,它可以被描述为一套可独立部署的小型模块化服务。每个服务都运行一个独特的流程,并通过定义明确的轻量级机制进行通信,以实现业务目标。1

例如,Pinterest可以具有以下微服务:用户个人资料,关注者,提要,搜索,照片上传等。

服务发现

ConsulEtcdZookeeper等系统可以通过跟踪注册的名称,地址和端口来帮助服务找到彼此。运行状况检查有助于验证服务完整性,通常使用 HTTP 终结点完成。Consul 和 Etcd 都有一个内置的键值存储,可用于存储配置值和其他共享数据。

缺点:应用层

  • 添加具有松散耦合服务的应用程序层需要从体系结构、操作和流程角度(与整体系统)不同的方法。
  • 微服务可能会增加部署和操作方面的复杂性。

来源和延伸阅读

数据库


来源:扩展到前 1000 万用户

关系数据库管理系统

像 SQL 这样的关系数据库是组织在表中的数据项的集合。

ACID 是关系数据库事务的一组属性。

  • 原子性 - 每笔交易全有或全无
  • 一致性 - 任何事务都将使数据库从一个有效状态进入另一个有效状态
  • 隔离 - 并发执行事务的结果与串行执行事务的结果相同
  • 持久性 - 一旦事务提交,它将保持如此

有许多技术可以扩展关系数据库:主从复制、主-主复制联合分片非规范化SQL 调优

主从复制

主站提供读取和写入服务,将写入复制到一个或多个仅提供读取服务的从属服务器。从属也可以以树状方式复制到其他从属。如果主站脱机,系统可以继续以只读模式运行,直到从站提升为主站或配置新的主站。


来源:可伸缩性、可用性、稳定性、模式

缺点:主从复制
  • 需要额外的逻辑才能将从属服务器提升为主服务器。
  • 请参阅缺点:复制,了解与主从和主主相关的点。

主-主复制

两个主节点都提供读取和写入服务,并在写入时相互协调。如果任一主设备出现故障,系统可以继续读取和写入操作。


来源:可伸缩性、可用性、稳定性、模式

缺点:主-主复制
  • 你将需要一个负载均衡器,或者需要对应用程序逻辑进行更改以确定写入位置。
  • 大多数主-主系统要么松散一致(违反 ACID),要么由于同步而增加了写入延迟。
  • 随着更多写入节点的添加和延迟的增加,冲突解决的作用越来越大。
  • 请参阅缺点:复制,了解与主从和主主相关的点。
缺点:复制
  • 如果主节点在任何新写入的数据复制到其他节点之前发生故障,则可能会丢失数据。
  • 写入将重放到只读副本。如果有很多写入,只读副本可能会因重播写入而陷入困境,并且无法执行尽可能多的读取。
  • 读取从站越多,需要复制的就越多,这会导致更大的复制滞后。
  • 在某些系统上,写入主服务器可以生成多个线程进行并行写入,而只读副本仅支持使用单个线程按顺序写入。
  • 复制增加了更多的硬件和复杂性。
来源和延伸阅读:复制

联邦


来源:扩展到前 10 万用户

联合(或功能分区)按功能拆分数据库。例如,你可以拥有三个数据库,而不是单个整体式数据库:论坛用户产品,从而减少每个数据库的读写流量,从而减少复制延迟。较小的数据库会产生更多的数据可以容纳在内存中,这反过来又会导致更多的缓存命中,因为改进了缓存局部性。由于没有单个中央主序列化写入,因此你可以并行写入,从而提高吞吐量。

缺点:联合
  • 如果架构需要大型函数或表,则联合无效。
  • 需要更新应用程序逻辑以确定要读取和写入的数据库。
  • 使用服务器链接联接来自两个数据库的数据更为复杂。
  • 联合增加了更多的硬件和额外的复杂性。
来源和延伸阅读:联邦

分片


来源:可伸缩性、可用性、稳定性、模式

分片将数据分布在不同的数据库之间,以便每个数据库只能管理数据的一个子集。以用户数据库为例,随着用户数量的增加,集群中加入的分片也越来越多。

联合的优势类似,分片会导致更少的读写流量、更少的复制和更多的缓存命中。索引大小也会减小,这通常会通过更快的查询提高性能。如果一个分片出现故障,其他分片仍可运行,但你需要添加某种形式的复制以避免数据丢失。与联合一样,没有单个中央主序列化写入,允许你在增加吞吐量的情况下并行写入。

对用户表进行分片的常见方法是通过用户的姓氏首字母或用户的地理位置。

缺点:分片
  • 你需要更新应用程序逻辑以使用分片,这可能会导致复杂的 SQL 查询。
  • 数据分布在分片中可能会变得不平衡。例如,与其他分片相比,分片上的一组高级用户可能会导致该分片的负载增加。
    • 重新平衡增加了额外的复杂性。基于一致哈希的分片函数可以减少传输的数据量。
  • 联接来自多个分片的数据更为复杂。
  • 分片增加了更多的硬件和额外的复杂性。
来源和延伸阅读:分片

非规范化

非规范化尝试以牺牲某些写入性能为代价来提高读取性能。数据的冗余副本写入多个表中,以避免昂贵的联接。一些RDBMS,如PostgreSQL和Oracle支持物化视图,这些视图处理存储冗余信息并保持冗余副本一致的工作。

一旦数据使用联合分片等技术进行分布式处理,跨数据中心管理联接就会进一步增加复杂性。非规范化可能会避免对此类复杂联接的需求。

在大多数系统中,读取次数可能远远超过写入次数 100:1 甚至 1000:1。导致复杂数据库联接的读取可能非常昂贵,会在磁盘操作上花费大量时间。

缺点:非规范化
  • 数据重复。
  • 约束可以帮助信息的冗余副本保持同步,这增加了数据库设计的复杂性。
  • 写入负载较重的非规范化数据库的性能可能比规范化数据库的性能差。
来源和延伸阅读:非规范化

数据库调优

SQL调优是一个广泛的主题,已经写了许多作为参考。

进行基准测试和剖析以模拟和发现瓶颈非常重要。

  • 基准测试 - 使用 ab 等工具模拟高负载情况。
  • 配置文件 - 启用慢查询日志等工具以帮助跟踪性能问题。

基准测试和分析可能会指向以下优化。

收紧架构
  • MySQL 以连续块转储到磁盘,以便快速访问。
  • 用于 而不是固定长度的字段。
    CHAR
    VARCHAR
    • CHAR
      有效地允许快速、随机的访问,而使用 ,你必须在移动到下一个字符串之前找到字符串的末尾。
      VARCHAR
  • 用于大型文本块,例如博客文章。 还允许布尔搜索。使用字段会导致在磁盘上存储用于查找文本块的指针。
    TEXT
    TEXT
    TEXT
  • 用于高达 2^32 或 40 亿的较大数字。
    INT
  • 用于货币以避免浮点表示错误。
    DECIMAL
  • 避免存储大型,而是存储获取对象的位置。
    BLOBS
  • VARCHAR(255)
    是 8 位数字中可以计数的最大字符数,在某些 RDBMS 中通常最大化使用字节。
  • 在适用的情况下设置约束以提高搜索性能
    NOT NULL
使用良好的索引
  • 查询的列 (、、、) 使用索引可能会更快。
    SELECT
    GROUP BY
    ORDER BY
    JOIN
  • 索引通常表示为自平衡 B 树,它保持数据排序并允许在对数时间内进行搜索、顺序访问、插入和删除。
  • 放置索引可以将数据保留在内存中,需要更多空间。
  • 写入也可能更慢,因为索引也需要更新。
  • 加载大量数据时,禁用索引、加载数据,然后重建索引可能会更快。
避免昂贵的联接
分区表
  • 通过将热点放在单独的表中来帮助将其保留在内存中来分解表。
调整查询缓存
来源和进一步阅读:SQL 调优

NoSQL

NoSQL 是在键值存储、文档存储、宽列存储图形数据库中表示的数据项的集合。数据是非规范化的,联接通常在应用程序代码中完成。大多数NoSQL存储缺乏真正的ACID事务,并且倾向于最终一致性

BASE通常用于描述NoSQL数据库的属性。与CAP定理相比,BASE选择可用性而不是一致性。

  • 基本可用 - 系统保证可用性。
  • 软状态 - 即使没有输入,系统的状态也可能随时间而变化。
  • 最终一致性 - 系统将在一段时间内保持一致,前提是系统在此期间未收到输入。

除了在SQL或NoSQL之间进行选择之外,了解哪种类型的NoSQL数据库最适合你的用例也很有帮助。我们将在下一节中回顾键值存储、文档存储、宽列存储图形数据库

键值存储

抽象:哈希表

键值存储通常允许 O(1) 读取和写入,并且通常由内存或 SSD 支持。数据存储可以按字典顺序维护键,从而可以高效检索键范围。键值存储可以允许存储具有值的元数据。

键值存储提供高性能,通常用于简单的数据模型或快速变化的数据,例如内存中的缓存层。由于它们仅提供一组有限的操作,因此如果需要其他操作,复杂性将转移到应用程序层。

键值存储是更复杂的系统(如文档存储)的基础,在某些情况下,是图形数据库。

来源和延伸阅读:键值存储

文档存储

抽象:键值存储,文档存储为值

文档存储以文档(XML、JSON、二进制等)为中心,其中文档存储给定对象的所有信息。文档存储提供 API 或查询语言,以根据文档本身的内部结构进行查询。请注意,许多键值存储都包含用于处理值元数据的功能,模糊了这两种存储类型之间的界限。

基于基础实现,文档按集合、标记、元数据或目录进行组织。尽管文档可以组织或组合在一起,但文档的字段可能彼此完全不同。

一些文档存储(如MongoDBCouchDB)也提供类似SQL的语言来执行复杂的查询。DynamoDB 同时支持键值和文档。

文档存储提供了高度的灵活性,通常用于处理偶尔更改的数据。

来源和延伸阅读:文档存储

宽色谱柱存储


资料来源:SQL & NoSQL,简史

抽象:嵌套映射

ColumnFamily<RowKey, Columns<ColKey, Value, Timestamp>>

宽列存储的基本数据单位是列(名称/值对)。列可以按列系列进行分组(类似于 SQL 表)。超级列族进一步分组列族。你可以使用行键独立访问每一列,具有相同行键的列构成一行。每个值都包含用于版本控制和冲突解决的时间戳。

Google将Bigtable作为第一个宽列存储,这影响了Hadoop生态系统中经常使用的开源HBase,以及Facebook的Cassandra。BigTable、HBase 和 Cassandra 等存储按字典顺序维护键,允许有效地检索选择性键范围。

宽列存储提供高可用性和高可扩展性。它们通常用于非常大的数据集。

来源和延伸阅读:宽列存储

图形数据库


来源:图形数据库

抽象:图

在图形数据库中,每个节点都是一条记录,每个弧是两个节点之间的关系。图形数据库经过优化,可以表示具有许多外键或多对多关系的复杂关系。

图形数据库为具有复杂关系的数据模型(如社交网络)提供高性能。它们相对较新,尚未广泛使用;找到开发工具和资源可能更加困难。许多图形只能通过 REST API 访问。

来源和进一步阅读:图表

来源和延伸阅读:NoSQL

SQL 或 NoSQL


来源:从RDBMS过渡到NoSQL

使用 SQL 的原因:

  • 结构化数据
  • 严格架构
  • 关系数据
  • 需要复杂的连接
  • 交易
  • 清晰的缩放模式
  • 更成熟:开发人员、社区、代码、工具等
  • 按索引查找非常快

NoSQL的原因:

  • 半结构化数据
  • 动态或灵活架构
  • 非关系数据
  • 无需复杂的连接
  • 存储许多 TB(或 PB)的数据
  • 非常数据密集型的工作负载
  • IOPS 的吞吐量非常高

非常适合 NoSQL 的示例数据:

  • 快速摄取点击流和日志数据
  • 排行榜或评分数据
  • 临时数据,例如购物车
  • 经常访问(“热”)表
  • 元数据/查找表
来源和进一步阅读:SQL或NoSQL

缓存


来源:可扩展的系统设计模式

缓存可缩短页面加载时间,并可以减少服务器和数据库上的负载。在这个模型中,调度程序将首先查找请求之前是否已经发出,并尝试找到要返回的先前结果,以保存实际执行。

数据库通常受益于跨其分区的读取和写入的均匀分布。热门项目可能会扭曲分布,从而导致瓶颈。将缓存放在数据库前面有助于吸收不均匀的负载和流量峰值。

客户端缓存

缓存可以位于客户端(操作系统或浏览器)、服务器端或不同的缓存层中。

CDN 缓存

CDN 被视为一种缓存类型。

网络服务器缓存

反向代理和缓存(如 Varnish)可以直接提供静态和动态内容。Web 服务器还可以缓存请求,返回响应,而无需联系应用程序服务器。

数据库缓存

你的数据库通常在默认配置中包含某种级别的缓存,并针对通用用例进行了优化。针对特定使用模式调整这些设置可以进一步提高性能。

应用程序缓存

内存中缓存(如 Memcached 和 Redis)是应用程序和数据存储之间的键值存储。由于数据保存在RAM中,因此它比数据存储在磁盘上的典型数据库快得多。RAM 比磁盘更受限制,因此缓存失效算法(如最近最少使用 (LRU))可以帮助使“冷”条目无效并将“热”数据保留在 RAM 中。

Redis 具有以下附加功能:

  • 持久性选项
  • 内置数据结构,如排序集和列表

你可以缓存多个级别,这些级别分为两个常规类别:数据库查询对象

  • 行级别
  • 查询级
  • 完全格式的可序列化对象
  • 完全呈现的 HTML

通常,应尽量避免基于文件的缓存,因为这会使克隆和自动缩放更加困难。

数据库查询级别的缓存

每当查询数据库时,请将查询哈希为键并将结果存储到缓存中。此方法存在过期问题:

  • 使用复杂查询很难删除缓存结果
  • 如果一段数据(如表单元格)发生更改,则需要删除可能包含已更改单元格的所有缓存查询

对象级别的缓存

将数据视为对象,类似于处理应用程序代码的操作。让应用程序将数据库中的数据集组装成类实例或数据结构:

  • 如果对象的基础数据已更改,则从缓存中删除该对象
  • 允许异步处理:worker通过使用最新的缓存对象来组装对象

关于缓存内容的建议:

  • 用户会话
  • 完全呈现的网页
  • 活动流
  • 用户图形数据

何时更新缓存

由于你只能在缓存中存储有限数量的数据,因此你需要确定哪种缓存更新策略最适合你的使用案例。

缓存端


源:从缓存到内存中数据网格

应用程序负责从存储中读取和写入。缓存不直接与存储交互。应用程序执行以下操作:

  • 在缓存中查找条目,导致缓存未命中
  • 从数据库加载条目
  • 将条目添加到缓存
  • 退货条目
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 通常以这种方式使用。

对添加到缓存的数据的后续读取速度很快。缓存端也称为延迟加载。仅缓存请求的数据,从而避免使用未请求的数据填充缓存。

缺点:缓存旁
  • 每次缓存未命中会导致三次行程,这可能会导致明显的延迟。
  • 如果在数据库中更新数据,则数据可能会过时。通过设置强制更新缓存条目的生存时间 (TTL) 或使用直写来缓解此问题。
  • 当一个节点发生故障时,它会被一个新的空节点取代,从而增加延迟。

直写


来源:可伸缩性、可用性、稳定性、模式

应用程序使用缓存作为主数据存储,读取和写入数据,而缓存负责读取和写入数据库:

  • 应用程序在缓存中添加/更新条目
  • 缓存同步将条目写入数据存储
  • 返回

应用程序代码:

set_user(12345, {"foo":"bar"})

缓存代码:

def set_user(user_id, values):
    user = db.query("UPDATE Users WHERE id = {0}", user_id, values)
    cache.set(user_id, user)

由于写入操作,直写是一个缓慢的整体操作,但仅写入数据的后续读取速度很快。用户在更新数据时通常比读取数据时更容忍延迟。缓存中的数据不会过时。

缺点:直写
  • 当由于失败或缩放而创建新节点时,新节点将不会缓存条目,直到数据库中的条目更新为止。缓存端与直写结合使用可以缓解此问题。
  • 写入的大多数数据可能永远不会被读取,这可以通过 TTL 最小化。

后写(回写)


来源:可伸缩性、可用性、稳定性、模式

在后写中,应用程序执行以下操作:

  • 在缓存中添加/更新条目
  • 异步写入数据存储条目,提高写入性能
缺点:后写
  • 如果缓存在其内容到达数据存储之前关闭,则可能会丢失数据。
  • 实现后写比实现缓存端或直写更复杂。

提前刷新


源:从缓存到内存中数据网格

你可以将缓存配置为在过期之前自动刷新任何最近访问的缓存条目。

如果缓存可以准确预测将来可能需要哪些项目,则与直读相比,预刷新可以减少延迟。

缺点:提前刷新
  • 与不提前刷新相比,不准确预测将来可能需要哪些项目可能会导致性能降低。

缺点:缓存

  • 需要通过缓存失效来维护缓存与事实来源(如数据库)之间的一致性。
  • 缓存失效是一个难题,与何时更新缓存相关的额外复杂性。
  • 需要进行应用程序更改,例如添加 Redis 或 memcached。

来源和延伸阅读

异步


来源:规模架构系统简介

异步工作流有助于减少原本以内联方式执行的昂贵操作的请求时间。他们还可以通过提前完成耗时的工作来提供帮助,例如定期汇总数据。

消息队列

消息队列接收、保留和传递消息。如果操作太慢而无法以内联方式执行,则可以将消息队列与以下工作流一起使用:

  • 应用程序将作业发布到队列,然后通知用户作业状态
  • 工作人员从队列中选取作业,对其进行处理,然后发出作业完成的信号

用户不会被阻止,作业在后台处理。在此期间,客户端可能会选择性地执行少量处理,以使其看起来像任务已完成。例如,如果发布一条推文,该推文可以立即发布到你的时间线,但可能需要一些时间才能将你的推文实际发送给所有关注者。

Redis 作为简单的消息代理很有用,但消息可能会丢失。

RabbitMQ 很流行,但需要你适应“AMQP”协议并管理自己的节点。

Amazon SQS 是托管的,但可能具有高延迟,并且消息可能会被传送两次。

任务队列

任务队列接收任务及其相关数据,运行它们,然后交付其结果。它们可以支持调度,并可用于在后台运行计算密集型作业。

Celery 支持调度,主要支持 python。

背压

如果队列开始显著增长,队列大小可能会大于内存,从而导致缓存未命中、磁盘读取甚至性能降低。背压可以通过限制队列大小来提供帮助,从而为队列中已有的作业保持高吞吐率和良好的响应时间。队列填满后,客户端将获得服务器繁忙或 HTTP 503 状态代码,以便稍后重试。客户端可以在以后重试请求,可能会使用指数退避

缺点:异步性

  • 廉价计算和实时工作流等用例可能更适合同步操作,因为引入队列会增加延迟和复杂性。

来源和延伸阅读

通信


来源:OSI 7 层模型

超文本传输协议 (HTTP)

HTTP 是一种在客户端和服务器之间编码和传输数据的方法。它是一种请求/响应协议:客户端发出请求,服务器发出响应,其中包含有关请求的相关内容和完成状态信息。HTTP 是独立的,允许请求和响应流经许多执行负载平衡、缓存、加密和压缩的中间路由器和服务器。

基本 HTTP 请求由谓词(方法)和资源(终结点)组成。以下是常见的 HTTP 动词:

动词 描述 幂等* 安全 可缓存
获取 读取资源 是的 是的 是的
发布 创建资源或触发处理数据的进程 如果响应包含新鲜度信息,则为是
创建或替换资源 是的
补丁 部分更新资源 如果响应包含新鲜度信息,则为是
删除 删除资源 是的

*可以多次调用,没有不同的结果。

HTTP是一种依赖于TCPUDP等较低级别协议的应用层协议。

来源和进一步阅读:HTTP

传输控制协议 (TCP)


来源:如何制作多人游戏

TCP 是 IP 网络上面向连接的协议。使用握手建立和终止连接。通过以下途径,保证发送的所有数据包都能按原始顺序到达目的地,而不会损坏:

如果发送方未收到正确的响应,它将重新发送数据包。如果有多个超时,连接将断开。TCP 还实现了流量控制和拥塞控制。这些保证会导致延迟,并且通常会导致传输效率低于UDP。

为了确保高吞吐量,Web 服务器可以保持大量 TCP 连接打开,从而导致高内存使用率。在 Web 服务器线程和 memcached 服务器之间拥有大量打开的连接可能会很昂贵。除了在适用的情况下切换到 UDP 之外,连接池还可以提供帮助。

TCP 对于需要高可靠性但时间要求较低的应用程序非常有用。一些示例包括 Web 服务器、数据库信息、SMTP、FTP 和 SSH。

在以下情况下,使用 TCP over UDP:

  • 你需要所有数据才能完好无损地到达
  • 你希望自动估算网络吞吐量的最佳利用率

用户数据报协议 (UDP)


来源:如何制作多人游戏

UDP 是无连接的。数据报(类似于数据包)仅在数据报级别得到保证。数据报可能会无序到达目的地,或者根本不到达目的地。UDP 不支持拥塞控制。如果没有TCP支持的保证,UDP通常更有效率。

UDP 可以广播,将数据报发送到子网上的所有设备。这对于 DHCP 很有用,因为客户端尚未收到 IP 地址,从而阻止了 TCP 在没有 IP 地址的情况下进行流式传输的方式。

UDP 不太可靠,但在 VoIP、视频聊天、流媒体和实时多人游戏等实时用例中效果很好。

在以下情况下使用 UDP over TCP:

  • 你需要最低的延迟
  • 延迟数据比数据丢失更糟糕
  • 你想实现自己的纠错

来源和延伸阅读:TCP和UDP

远程过程调用 (RPC)


来源:破解系统设计专访

在 RPC 中,客户端会导致过程在不同的地址空间(通常是远程服务器)上执行。该过程的编码就像本地过程调用一样,从客户端程序中抽象出如何与服务器通信的详细信息。远程调用通常比本地调用慢且可靠性低,因此区分 RPC 调用和本地调用很有帮助。流行的RPC框架包括ProtobufThriftAvro

RPC 是一种请求-响应协议:

  • 客户端程序 - 调用客户端存根过程。参数像本地过程调用一样推送到堆栈上。
  • 客户端存根过程 - 封送(打包)过程 ID 和参数到请求消息中。
  • 客户端通信模块 - 操作系统将消息从客户端发送到服务器。
  • 服务器通信模块 - 操作系统将传入数据包传递到服务器存根过程。
  • 服务器存根过程 - 解组结果,调用与过程 ID 匹配的服务器过程并传递给定的参数。
  • 服务器响应以相反的顺序重复上述步骤。

示例 RPC 调用:

GET /someoperation?data=anId

POST /anotheroperation
{
  "data":"anId";
  "anotherdata": "another value"
}

RPC 专注于公开行为。出于性能原因,RPC 通常用于内部通信,因为你可以手动制作本机调用以更好地适应你的用例。

在以下情况下选择本机库(又名 SDK):

  • 你知道你的目标平台。
  • 你想控制你的“逻辑”是如何被访问的。
  • 你希望控制错误控制在库外发生的方式。
  • 性能和最终用户体验是你最关心的问题。

遵循 REST 的 HTTP API 往往更常用于公共 API。

缺点: RPC

  • RPC 客户端与服务实现紧密耦合。
  • 必须为每个新操作或用例定义一个新的 API。
  • 调试 RPC 可能很困难。
  • 你可能无法利用开箱即用的现有技术。例如,可能需要额外的工作来确保 RPC 调用正确缓存在缓存服务器(如 Squid)上。

具象状态转移 (REST)

REST 是一种强制实施客户端/服务器模型的体系结构样式,其中客户端作用于服务器管理的一组资源。服务器提供资源和操作的表示形式,这些表示形式可以操作或获取资源的新表示形式。所有通信都必须是无状态且可缓存的。

RESTful 接口有四种特性:

  • 标识资源(HTTP 中的 URI) - 无论任何操作如何,都使用相同的 URI。
  • 使用表示形式进行更改(HTTP 中的动词) - 使用动词、标头和正文。
  • 自我描述的错误消息(HTTP 中的状态响应) - 使用状态代码,不要重新发明轮子。
  • HATEOAS(HTTP的HTML界面) - 你的Web服务应该可以在浏览器中完全访问。

示例 REST 调用:

GET /someresources/anId

PUT /someresources/anId
{"anotherdata": "another value"}

REST 专注于公开数据。它最大限度地减少了客户端/服务器之间的耦合,通常用于公共 HTTP API。REST 使用更通用和统一的方法,通过 URI 公开资源,通过标头表示,并通过谓词(如 GET、POST、PUT、DELETE 和 PATCH)公开操作。由于是无状态的,REST 非常适合水平扩展和分区。

缺点:休息

  • 由于 REST 专注于公开数据,如果资源不是在简单的层次结构中自然组织或访问的,它可能不太合适。例如,返回过去一小时与一组特定事件匹配的所有更新记录不容易表示为路径。使用 REST,它很可能使用 URI 路径、查询参数和可能的请求正文的组合来实现。
  • REST 通常依赖于一些动词(GET、POST、PUT、DELETE 和 PATCH),这些动词有时不适合你的用例。例如,将过期的文档移动到存档文件夹可能不适合这些谓词。
  • 获取具有嵌套层次结构的复杂资源需要在客户端和服务器之间多次往返以呈现单个视图,例如获取博客条目的内容和对该条目的评论。对于在可变网络条件下运行的移动应用程序,这些多次往返是非常不可取的。
  • 随着时间的推移,可能会将更多字段添加到 API 响应中,并且较旧的客户端将收到所有新数据字段,甚至是它们不需要的数据字段,因此,它会膨胀有效负载大小并导致更大的延迟。

RPC 和 REST 调用比较

操作 RPC 休息
注册 发布/注册 职位/人
辞职 POST /resign
{
“personid”: “1234”
}
删除 /人/1234
读人 GET /readPerson?personid=1234 获取 /人/1234
读取人员的项目列表 GET /readUsersItemsList?personid=1234 获取 /人/1234/项
将项目添加到人员的项目 POST /addItemToUsersItemsList
{
“personid”: “1234”;
”项“: ”456”
}
POST /persons/1234/items
{
“itemid”: “456”
}
更新项目 POST /modifyItem
{
“itemid”: “456”;
”键“:”值”
}
PUT /items/456
{
“键”: “值”
}
删除项目 POST /removeItem
{“itemid”
: “456”
}
删除 /项目/456

来源:你真的知道为什么你更喜欢REST而不是RPC吗?

来源和延伸阅读:REST 和 RPC

安全

本部分可以使用一些更新。考虑贡献

安全性是一个广泛的话题。除非你有丰富的经验、安全背景或正在申请需要安全知识的职位,否则你可能只需要了解基础知识:

  • 在传输中和静态加密。
  • 清理所有用户输入或向用户公开的任何输入参数,以防止 XSSSQL 注入
  • 使用参数化查询来防止 SQL 注入。
  • 使用最小特权原则。

来源和延伸阅读

附录

你有时会被要求进行“粗略”估算。例如,你可能需要确定从磁盘生成 100 个图像缩略图需要多长时间,或者数据结构需要多少内存。每个程序员都应该知道的两个表的幂和延迟数字是方便的参考。

两个表的幂

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

基于上述数字的便捷指标:

  • 以 30 MB/s 的速度从硬盘按顺序读取
  • 以 100 MB/s 的速度从 1 Gbps 以太网按顺序读取
  • 以 1 GB/s 的速度从固态硬盘按顺序读取
  • 以 4 GB/s 的速度从主内存按顺序读取
  • 每秒 6-7 次全球往返
  • 数据中心内每秒 2,000 次往返

可视化延迟数字

来源和延伸阅读

其他系统设计面试问题

常见的系统设计面试问题,并提供有关如何解决每个问题的资源链接。

问题 参考资料
设计像 Dropbox 这样的文件同步服务 youtube.com
设计一个像谷歌一样的搜索引擎
queue.acm.org stackexchange.com
ardendertat.com
stanford.edu
设计一个可扩展的网络爬虫,如谷歌 quora.com
设计谷歌文档
code.google.com neil.fraser.name
设计一个像 Redis 这样的键值存储 slideshare.net
设计一个像Memcached这样的缓存系统 slideshare.net
设计一个像亚马逊一样的推荐系统
hulu.com ijcai13.org
设计一个像Bitly这样的tinyurl系统 n00tc0d3r.blogspot.com
设计一个像WhatsApp这样的聊天应用程序 highscalability.com
设计一个像Instagram这样的图片共享系统
highscalability.com highscalability.com
设计脸书新闻提要功能
quora.com quora.com
slideshare.net
设计脸书时间轴功能
facebook.com highscalability.com
设计脸书聊天功能
erlang-factory.com facebook.com
设计一个像Facebook一样的图形搜索函数
facebook.com facebook.com
facebook.com
设计像CloudFlare这样的内容交付网络 figshare.com
设计一个像Twitter这样的热门话题系统
michael-noll.com 斯尼科洛夫 .wordpress.com
设计随机 ID 生成系统
blog.twitter.com github.com
返回时间间隔内排名前 k 的请求
cs.ucsb.edu wpi.edu
设计一个为来自多个数据中心的数据提供服务的系统 highscalability.com
设计在线多人纸牌游戏
indieflashblog.com buildnewgames.com
设计垃圾回收系统
stuffwithstuff.com washington.edu
设计 API 速率限制器 https://stripe.com/blog/
设计证券交易所(如纳斯达克或币安) 简街
戈朗实施
实现
添加系统设计问题 贡献

真实世界的架构

关于如何设计现实世界系统的文章。


资料来源:推特时间表

不要关注以下文章的细节,而是:

  • 确定这些文章中的共享原则、通用技术和模式
  • 研究每个组件解决了哪些问题,在哪里工作,在哪里不工作
  • 回顾经验教训
类型 系统 参考资料
数据处理 MapReduce - 来自谷歌的分布式数据处理 research.google.com
数据处理 Spark - 来自Databricks的分布式数据处理 slideshare.net
数据处理 Storm - 来自Twitter的分布式数据处理 slideshare.net
数据存储 Bigtable - 来自谷歌的分布式面向列的数据库 harvard.edu
数据存储 HBase - Bigtable 的开源实现 slideshare.net
数据存储 Cassandra - 来自Facebook的分布式面向列的数据库 slideshare.net
数据存储 DynamoDB - 来自 Amazon 的面向文档的数据库 harvard.edu
数据存储 MongoDB - 面向文档的数据库 slideshare.net
数据存储 Spanner - 来自谷歌的全球分布式数据库 research.google.com
数据存储 Memcached - 分布式内存缓存系统 slideshare.net
数据存储 Redis - 具有持久性和值类型的分布式内存缓存系统 slideshare.net
文件系统 谷歌文件系统 (GFS) - 分布式文件系统 research.google.com
文件系统 Hadoop File System (HDFS) - GFS 的开源实现 apache.org
杂项 - 谷歌松散耦合分布式系统的锁定服务 research.google.com
杂项 Dapper - 分布式系统跟踪基础结构 research.google.com
杂项 Kafka - 来自LinkedIn的发布/订阅消息队列 slideshare.net
杂项 Zookeeper - 支持同步的集中式基础架构和服务 slideshare.net
添加体系结构 贡献

公司架构

公司 参考资料
亚马逊河 亚马逊架构
辛奇卡斯特 每天制作 1,500 小时的音频
数据筛 实时数据挖掘 每秒 120,000 条推文
嘶�� 我们如何扩展 Dropbox
ESPN 以每秒 100,000 duh nuh nuhs 的速度运行
谷歌 谷歌架构
Instagram 1400 万用户,TB 级照片
是什么为Instagram提供动力
Justin.tv 贾斯汀电视的直播视频广播架构
脸书 在Facebook TAO上扩展memcached:Facebook用于社交图谱
的分布式数据存储 Facebook的照片存储
Facebook Live如何同时向800,000名观众进行流式传输
Flickr Flickr 架构
邮箱 6 周内从 0 到 100 万用户
网飞 整个 Netflix 堆栈
的 360 度视图 Netflix:按下播放时会发生什么?
Pinterest 从 0 到 10 每月数十亿次页面浏览
1800 万访问者,10 倍增长,12 名员工
玩鱼 每月 5000 万用户,并且还在不断增长
丰富的鱼 丰富的鱼类架构
销售队伍 他们每天如何处理 13 亿笔交易
堆栈溢出 堆栈溢出架构
猫途鹰 40M访问者,200M动态页面浏览量,30TB数据
Tumblr 每月 150 亿次页面浏览量
让 Twitter 速度提高
10000% 使用 MySQL
每天存储 2.5 亿条推文 150M 活跃用户,300K QPS,22 MB/s 消防水带
大规模
时间表 Twitter 的大数据大小数据 Twitter 运营:扩展到 1 亿
用户以上 Twitter 如何每秒处理 3,000 张图像
优步 Uber 如何扩展其实时市场平台
将 Uber 扩展到 2000 名工程师、1000 项服务和 8000 个 Git 存储库的经验教训
微信 Facebook以190亿美元收购的WhatsApp架构
优酷 YouTube 可扩展性
YouTube 架构

公司工程博客

你正在面试的公司的架构。

你遇到的问题可能来自同一域。

来源和延伸阅读

想要添加博客?若要避免重复工作,请考虑将公司博客添加到以下存储库:

开发中

有兴趣添加部分或帮助完成正在进行的部分吗?贡献

  • 使用MapReduce进行分布式计算
  • 一致的哈希
  • 分散聚集
  • 贡献

捐赠

此存储库中提供了信用和来源。

特别鸣谢:

联系方式

请随时与我联系以讨论任何问题、问题或意见。

我的联系信息可以在我的 GitHub 页面上找到。

许可证

我根据开源许可证在此存储库中为你提供代码和资源。因为这是我的个人仓库,所以你收到的我的代码和资源的许可证来自我,而不是我的雇主(Facebook)。

Copyright 2017 Donne Martin

Creative Commons Attribution 4.0 International License (CC BY 4.0)

http://creativecommons.org/licenses/by/4.0/