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

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

English日本語简体中文 ∙ 繁體中文 |العَرَبِيَّةবাংলাPortuguês do BrasilDeutschελληνικάעבריתItaliano한국어فارسیPolskiрусский языкEspañolภาษาไทยTürkçetiếng ViệtFrançais |添加翻译

帮助翻译本指南!

系统设计入门


赋予动机

了解如何设计大型系统。

准备系统设计面试。

了解如何设计大型系统

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

系统设计是一个广泛的话题。关于系统设计原则,网络上散布着大量资源

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

向开源社区学习

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

欢迎投稿

系统设计面试准备

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

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

面试准备的其他主题:

Anki 抽认卡


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

非常适合在旅途中使用。

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

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


查看姊妹存储库 Interactive Coding Challenges,其中包含一个额外的 Anki 套牌:

贡献

向社区学习。

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

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

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

查看贡献指南

系统设计主题索引

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

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


学习指南

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

伊姆古尔

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

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

面试中会问到什么取决于以下变量:

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

更有经验的考生通常应该更多地了解系统设计。架构师或团队领导可能比个人贡献者知道的更多。顶级科技公司可能会进行一轮或多轮设计面试。

从广义开始,在几个领域深入。它有助于了解一些关于各种关键系统设计主题的知识。根据你的时间表、经验、你正在面试的职位以及你正在面试的公司调整以下指南。

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

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

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

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

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

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

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

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

第 2 步:创建高级设计

概述包含所有重要组件的高级设计。

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

第 3 步:设计核心组件

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

  • 生成和存储完整 url 的哈希值
    • MD5Base62
    • 哈希冲突
    • SQL 或 NoSQL
    • 数据库架构
  • 将经过哈希处理的 URL 转换为完整 URL
    • 数据库查找
  • 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 (canonical) - 将一个名称指向另一个名称或(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 服务器)


资料来源:维基百科

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

其他好处包括:

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

负载均衡器与反向代理

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

缺点:反向代理

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

来源和延伸阅读

应用层


来源:Intro to Architecting Systems for Scale

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

应用层的工作线程还有助于实现异步。

微服务

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

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

服务发现

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

缺点:应用层

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

来源和延伸阅读

数据库


来源:扩展到前 1000 万用户

关系数据库管理系统 (RDBMS)

像 SQL 这样的关系数据库是以表形式组织的数据项的集合。

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

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

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

主从复制

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


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

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

主-主复制

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


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

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

联邦


来源:扩展到前 1000 万用户

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

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

分片


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

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

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

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

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

非规范化

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

一旦数据通过联合分片等技术进行分布式处理,跨数据中心管理联接将进一步增加复杂性。非规范化可能会规避对这种复杂连接的需求。

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

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

SQL 调优

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 被视为一种缓存。

Web 服务器缓存

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

数据库缓存

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

应用程序缓存

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

Redis 具有以下附加功能:

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

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

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

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

数据库查询级别的缓存

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

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

对象级别的缓存

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

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

缓存内容的建议:

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

何时更新缓存

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

缓存端


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

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

  • 在缓存中查找条目,导致缓存未命中
  • 从数据库加载条目
  • 将条目添加到缓存
  • 回程入场
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 最小化。

后写(write-back)


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

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

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

提前刷新


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

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

如果缓存可以准确预测将来可能需要哪些项目,则提前刷新可以减少延迟而不是读取。

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

缺点:缓存

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

来源和延伸阅读

异步


来源:Intro to Architecting Systems for Scale

异步工作流有助于减少成本高昂的操作的请求时间,否则这些操作将在线执行。他们还可以通过提前完成耗时的工作来提供帮助,例如定期聚合数据。

消息队列

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

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

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

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

RPC 和 REST 调用比较

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

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

来源和延伸阅读:REST 和 RPC

安全

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

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

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

来源和延伸阅读

附录

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

二表的幂

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 的速度从 HDD 按顺序读取
  • 以 100 MB/s 的速度从 1 Gbps 以太网按顺序读取
  • 以 1 GB/s 的速度从 SSD 按顺序读取
  • 以 4 GB/s 的速度从主内存顺序读取
  • 每秒 6-7 次全球往返
  • 数据中心内每秒 2,000 次往返

可视化的延迟数字

来源和延伸阅读

其他系统设计面试问题

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

问题 参考资料
设计像 Dropbox 这样的文件同步服务 youtube.com
设计一个像谷歌这样的搜索引擎
queue.acm.org stackexchange.com
ardendertat.com
stanford.edu
设计一个可扩展的网络爬虫,如谷歌 quora.com
设计 Google 文档
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
设计 Facebook 新闻提要功能
quora.com quora.com
slideshare.net
设计 Facebook 时间轴功能
facebook.com highscalability.com
设计 Facebook 聊天功能
erlang-factory.com facebook.com
设计一个像 Facebook 一样的图形搜索功能
facebook.com facebook.com
facebook.com
设计像CloudFlare这样的内容分发网络 figshare.com
设计一个像 Twitter 这样的热门话题系统
michael-noll.com snikolov .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/
设计证券交易所(如纳斯达克或币安) Jane Street
Golang 实现 Go 实现
添加系统设计问题 贡献

真实世界的架构

有关如何设计真实世界系统的文章。


资料来源:Twitter 大规模时间线

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

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

公司架构

公司 参考资料
亚马逊河 Amazon 架构
辛奇卡斯特 每天制作 1,500 小时的音频
数据筛 实时数据挖掘 每秒 120,000 条推文
Dropbox的 我们如何扩展 Dropbox
ESPN电视台 以每秒 100,000 duh nuh nuhs 的速度运行
谷歌 Google 架构
Instagram的 1400 万用户,数 TB 的照片
是什么为 Instagram 提供动力
Justin.tv Justin.Tv 的视频直播架构
脸书 在 Facebook 上扩展 memcachedTAO:Facebook 用于社交图
谱的分布式数据存储 Facebook 的照片存储
Facebook 如何向 800,000 名同时观看者直播
Flickr的 Flickr 架构
邮箱 在 6 周内从 0 到 100 万用户
Netflix公司 整个 Netflix 堆栈
的 360 度视图 Netflix:按下播放键时会发生什么?
Pinterest的 每月
0到10数十亿页面浏览量,1800万访问者,10倍增长,12名员工
戏鱼 每月 5000 万用户,并且还在不断增长
PlentyOfFish(丰盛的鱼) PlentyOfFish 架构
Salesforce的 他们每天如何处理 13 亿笔交易
堆栈溢出 Stack Overflow 架构
猫途鹰 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 存储库的经验教训
WhatsApp的 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/