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

Created at: 2017-02-27 00:15:28
开发语言: Python
授权协议: NOASSERTION

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

帮助翻译本指南!

系统设计入门


动机

了解如何设计大型系统。

为系统设计面试做准备。

了解如何设计大型系统

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

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

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

向开源社区学习

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

欢迎投稿

准备系统设计面试

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

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

面试准备的其他主题:

安琪抽认卡


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

非常适合在旅途中使用。

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

寻找资源来帮助你为编程面试做准备?


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

贡献

向社区学习。

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

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

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

查看贡献指南

系统设计主题索引

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

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


学习指南

根据你的面试时间表(短,中,长)推荐要审查的主题。

伊姆古尔

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

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

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

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

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

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

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

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

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

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

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

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

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

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

步骤 2:创建高级设计

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

  • 草绘主要组件和连接
  • 证明你的想法

步骤 3:设计核心组件

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

  • 生成和存储完整网址的哈希值
    • MD5Base62
    • 哈希冲突
    • 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服务器管理可能很复杂,通常由政府,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 时产生的额外费用一起权衡。
  • 如果在 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 调优

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 表)。超级列系列进一步分组列系列。你可以使用行键独立访问每列,具有相同行键的列形成一行。每个值都包含一个用于版本控制和解决冲突的时间戳。

谷歌推出了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

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

数据库查询级别的缓存

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

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

对象级别的缓存

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

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

有关要缓存的内容的建议:

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

何时更新缓存

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

缓存端


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

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

  • 在缓存中查找条目,导致缓存未命中
  • 从数据库加载条目
  • 将条目添加到缓存
  • 退货
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是一种应用层协议,依赖于较低级别的协议,如TCPUDP

来源和延伸阅读: HTTP

传输控制协议 (TCP)


来源:如何制作多人游戏

TCP 是通过 IP 网络实现的面向连接的协议。使用握手建立并终止连接。发送的所有数据包都保证以原始顺序到达目的地,并且不会通过以下方式损坏:

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

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

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

在以下情况下,通过 UDP 使用 TCP:

  • 你需要所有数据完好无损地到达
  • 你希望自动对网络吞吐量进行最佳估计

用户数据报协议 (UDP)


来源:如何制作多人游戏

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

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

UDP 不太可靠,但在实时用例(如 VoIP、视频聊天、流式传输和实时多人游戏)中运行良好。

在以下情况下,通过 TCP 使用 UDP:

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

来源和延伸阅读: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 可能很困难。
  • 你可能无法开箱即用地利用现有技术。例如,可能需要额外的工作来确保在缓存服务器(如 Squid)上正确缓存 RPC 调用

具象状态传输 (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 调用比较

操作 断续器 休息
注册 发布/注册 邮政/人员
辞职 POST /resign
{
“personid”: “1234”
}
删除 /人/1234
阅读一个人 GET /readPerson?personid=1234 获取/人/1234
读取人员的项目列表 GET /readUsersItemsList?personid=1234 获取 /人/1234/项
将项目添加到人员的项目 POST /addItemToUsersItemsList
{
“personid”: “1234”;
”itemid“: ”456”
}
POST /persons/1234/items
{
“itemid”: “456”
}
更新项目 POST /modifyItem
{
“itemid”: “456”;
”键“: ”值”
}
PUT /items/456
{
“key”: “value”
}
删除项目 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 的速度按顺序从 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
设计谷歌文档
code.google.com neil.fraser.name
设计像 Redis 这样的键值存储 slideshare.net
设计一个像 Memcached 这样的缓存系统 slideshare.net
设计一个像亚马逊这样的推荐系统
hulu.com ijcai13.org
设计一个像Bitly这样的小网址系统 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/
设计一个证券交易所(如纳斯达克或币安) 简街
戈朗实施
Go 实施
添加系统设计问题 贡献

现实世界的架构

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


资料来源:Twitter Timeline in scales

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

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

公司架构

公司 参考资料
亚马逊河 亚马逊架构
辛奇卡斯特 每天产生 1,500 小时的音频
DataSift 实时数据挖掘 每秒 120,000 条推文
投递箱 我们如何扩展 Dropbox
ESPN 以每秒 100,000 嘟努努斯的速度运行
谷歌 谷歌架构
新浪微博 1400万用户,TB级照片
是什么为Instagram提供动力
Justin.tv Justin.Tv的直播视频广播架构
脸书 在 Facebook
TAO 上扩展 memcached:Facebook 的社交图谱
分布式数据存储 Facebook 的照片存储
Facebook Live Streams to 800,000 个同时观看者
Flickr Flickr 架构
邮箱 在 6 周内从 0 到 100 万用户
网飞 整个 Netflix 堆栈 Netflix 的 360 度全景视图:当你按“播放”时会发生什么?
普特利 从 0 到 100 亿每月 100 亿次页面浏览量
,1800 万访问者,10 倍增长,12 名员工
游鱼 每月 5000 万用户,并且还在不断增长
充足的鱼 PlentyOfFish建筑
销售团队 他们每天如何处理 13 亿笔交易
堆栈溢出 堆栈溢出体系结构
猫途鹰 4000万访问者,2亿动态页面浏览量,30TB数据
Tumblr 每月 150 亿次页面浏览量
使 Twitter 速度提高 10000%使用 MySQL 每天存储 2.5 亿条推文1.5 亿活跃用户、300K QPS、22 MB/S 的消防水管
时间线 在
Twitter 运营 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/