Skip to content

Commit

Permalink
remove redundant spaces
Browse files Browse the repository at this point in the history
  • Loading branch information
yingang committed Sep 23, 2023
1 parent ae1e797 commit fcd2b77
Show file tree
Hide file tree
Showing 30 changed files with 457 additions and 457 deletions.
2 changes: 1 addition & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -34,7 +34,7 @@
---------

> 计算是一种流行文化,流行文化鄙视历史。 流行文化关乎个体身份和参与感,但与合作无关。流行文化活在当下,也与过去和未来无关。 我认为大部分(为了钱)编写代码的人就是这样的, 他们不知道自己的文化来自哪里。
> 计算是一种流行文化,流行文化鄙视历史。流行文化关乎个体身份和参与感,但与合作无关。流行文化活在当下,也与过去和未来无关。我认为大部分(为了钱)编写代码的人就是这样的,他们不知道自己的文化来自哪里。
>
> —— 阿兰・凯接受 Dobb 博士的杂志采访时(2012 年)
Expand Down
24 changes: 12 additions & 12 deletions ch1.md
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@

![](img/ch1.png)

> 互联网做得太棒了,以至于大多数人将它看作像太平洋这样的自然资源,而不是什么人工产物。上一次出现这种大规模且无差错的技术, 你还记得是什么时候吗?
> 互联网做得太棒了,以至于大多数人将它看作像太平洋这样的自然资源,而不是什么人工产物。上一次出现这种大规模且无差错的技术,你还记得是什么时候吗?
>
> —— [艾伦・凯](http://www.drdobbs.com/architecture-and-design/interview-with-alan-kay/240003442) 在接受 Dobb 博士杂志采访时说(2012 年)
Expand Down Expand Up @@ -127,8 +127,8 @@
* 以最小化犯错机会的方式设计系统。例如,精心设计的抽象、API 和管理后台使做对事情更容易,搞砸事情更困难。但如果接口限制太多,人们就会忽略它们的好处而想办法绕开。很难正确把握这种微妙的平衡。
* 将人们最容易犯错的地方与可能导致失效的地方 **解耦(decouple)**。特别是提供一个功能齐全的非生产环境 **沙箱(sandbox)**,使人们可以在不影响真实用户的情况下,使用真实数据安全地探索和实验。
* 在各个层次进行彻底的测试【3】,从单元测试、全系统集成测试到手动测试。自动化测试易于理解,已经被广泛使用,特别适合用来覆盖正常情况中少见的 **边缘场景(corner case)**
* 允许从人为错误中简单快速地恢复,以最大限度地减少失效情况带来的影响。 例如,快速回滚配置变更,分批发布新代码(以便任何意外错误只影响一小部分用户),并提供数据重算工具(以备旧的计算出错)。
* 配置详细和明确的监控,比如性能指标和错误率。 在其他工程学科中这指的是 **遥测(telemetry)**(一旦火箭离开了地面,遥测技术对于跟踪发生的事情和理解失败是至关重要的)。监控可以向我们发出预警信号,并允许我们检查是否有任何地方违反了假设和约束。当出现问题时,指标数据对于问题诊断是非常宝贵的。
* 允许从人为错误中简单快速地恢复,以最大限度地减少失效情况带来的影响。例如,快速回滚配置变更,分批发布新代码(以便任何意外错误只影响一小部分用户),并提供数据重算工具(以备旧的计算出错)。
* 配置详细和明确的监控,比如性能指标和错误率。在其他工程学科中这指的是 **遥测(telemetry)**(一旦火箭离开了地面,遥测技术对于跟踪发生的事情和理解失败是至关重要的)。监控可以向我们发出预警信号,并允许我们检查是否有任何地方违反了假设和约束。当出现问题时,指标数据对于问题诊断是非常宝贵的。
* 良好的管理实践与充分的培训 —— 一个复杂而重要的方面,但超出了本书的范围。

### 可靠性有多重要?
Expand Down Expand Up @@ -162,7 +162,7 @@

处理每秒 12,000 次写入(发推文的速率峰值)还是很简单的。然而推特的伸缩性挑战并不是主要来自推特量,而是来自 **扇出(fan-out)**[^ii]—— 每个用户关注了很多人,也被很多人关注。

[^ii]: 扇出:从电子工程学中借用的术语,它描述了输入连接到另一个门输出的逻辑门数量。 输出需要提供足够的电流来驱动所有连接的输入。 在事务处理系统中,我们使用它来描述为了服务一个传入请求而需要执行其他服务的请求数量。
[^ii]: 扇出:从电子工程学中借用的术语,它描述了输入连接到另一个门输出的逻辑门数量。输出需要提供足够的电流来驱动所有连接的输入。在事务处理系统中,我们使用它来描述为了服务一个传入请求而需要执行其他服务的请求数量。

大体上讲,这一对操作有两种实现方式。

Expand All @@ -180,7 +180,7 @@

**图 1-2 推特主页时间线的关系型模式简单实现**

2. 为每个用户的主页时间线维护一个缓存,就像每个用户的推文收件箱([图 1-3](img/fig1-3.png))。 当一个用户发布推文时,查找所有关注该用户的人,并将新的推文插入到每个主页时间线缓存中。 因此读取主页时间线的请求开销很小,因为结果已经提前计算好了。
2. 为每个用户的主页时间线维护一个缓存,就像每个用户的推文收件箱([图 1-3](img/fig1-3.png))。当一个用户发布推文时,查找所有关注该用户的人,并将新的推文插入到每个主页时间线缓存中。因此读取主页时间线的请求开销很小,因为结果已经提前计算好了。

![](img/fig1-3.png)

Expand All @@ -205,7 +205,7 @@

对于 Hadoop 这样的批处理系统,通常关心的是 **吞吐量(throughput)**,即每秒可以处理的记录数量,或者在特定规模数据集上运行作业的总时间 [^iii]。对于在线系统,通常更重要的是服务的 **响应时间(response time)**,即客户端发送请求到接收响应之间的时间。

[^iii]: 理想情况下,批量作业的运行时间是数据集的大小除以吞吐量。 在实践中由于数据倾斜(数据不是均匀分布在每个工作进程中),需要等待最慢的任务完成,所以运行时间往往更长。
[^iii]: 理想情况下,批量作业的运行时间是数据集的大小除以吞吐量。在实践中由于数据倾斜(数据不是均匀分布在每个工作进程中),需要等待最慢的任务完成,所以运行时间往往更长。

> #### 延迟和响应时间
>
Expand All @@ -219,7 +219,7 @@

**图 1-4 展示了一个服务 100 次请求响应时间的均值与百分位数**

通常报表都会展示服务的平均响应时间。 (严格来讲 “平均” 一词并不指代任何特定公式,但实际上它通常被理解为 **算术平均值(arithmetic mean)**:给定 n 个值,加起来除以 n )。然而如果你想知道 “**典型(typical)**” 响应时间,那么平均值并不是一个非常好的指标,因为它不能告诉你有多少用户实际上经历了这个延迟。
通常报表都会展示服务的平均响应时间。(严格来讲 “平均” 一词并不指代任何特定公式,但实际上它通常被理解为 **算术平均值(arithmetic mean)**:给定 n 个值,加起来除以 n )。然而如果你想知道 “**典型(typical)**” 响应时间,那么平均值并不是一个非常好的指标,因为它不能告诉你有多少用户实际上经历了这个延迟。

通常使用 **百分位点(percentiles)** 会更好。如果将响应时间列表按最快到最慢排序,那么 **中位数(median)** 就在正中间:举个例子,如果你的响应时间中位数是 200 毫秒,这意味着一半请求的返回时间少于 200 毫秒,另一半比这个要长。

Expand All @@ -231,7 +231,7 @@

另一方面,优化第 99.99 百分位点(一万个请求中最慢的一个)被认为太昂贵了,不能为亚马逊的目标带来足够好处。减小高百分位点处的响应时间相当困难,因为它很容易受到随机事件的影响,这超出了控制范围,而且效益也很小。

百分位点通常用于 **服务级别目标(SLO, service level objectives)****服务级别协议(SLA, service level agreements)**,即定义服务预期性能和可用性的合同。 SLA 可能会声明,如果服务响应时间的中位数小于 200 毫秒,且 99.9 百分位点低于 1 秒,则认为服务工作正常(如果响应时间更长,就认为服务不达标)。这些指标为客户设定了期望值,并允许客户在 SLA 未达标的情况下要求退款。
百分位点通常用于 **服务级别目标(SLO, service level objectives)****服务级别协议(SLA, service level agreements)**,即定义服务预期性能和可用性的合同。SLA 可能会声明,如果服务响应时间的中位数小于 200 毫秒,且 99.9 百分位点低于 1 秒,则认为服务工作正常(如果响应时间更长,就认为服务不达标)。这些指标为客户设定了期望值,并允许客户在 SLA 未达标的情况下要求退款。

**排队延迟(queueing delay)** 通常占了高百分位点处响应时间的很大一部分。由于服务器只能并行处理少量的事务(如受其 CPU 核数的限制),所以只要有少量缓慢的请求就能阻碍后续请求的处理,这种效应有时被称为 **头部阻塞(head-of-line blocking)** 。即使后续请求在服务器上处理的非常迅速,由于需要等待先前请求完成,客户端最终看到的是缓慢的总体响应时间。因为存在这种效应,测量客户端的响应时间非常重要。

Expand Down Expand Up @@ -330,11 +330,11 @@

因为复杂度导致维护困难时,预算和时间安排通常会超支。在复杂的软件中进行变更,引入错误的风险也更大:当开发人员难以理解系统时,隐藏的假设、无意的后果和意外的交互就更容易被忽略。相反,降低复杂度能极大地提高软件的可维护性,因此简单性应该是构建系统的一个关键目标。

简化系统并不一定意味着减少功能;它也可以意味着消除 **额外的(accidental)** 的复杂度。 Moseley 和 Marks【32】把 **额外复杂度** 定义为:由具体实现中涌现,而非(从用户视角看,系统所解决的)问题本身固有的复杂度。
简化系统并不一定意味着减少功能;它也可以意味着消除 **额外的(accidental)** 的复杂度。Moseley 和 Marks【32】把 **额外复杂度** 定义为:由具体实现中涌现,而非(从用户视角看,系统所解决的)问题本身固有的复杂度。

用于消除 **额外复杂度** 的最好工具之一是 **抽象(abstraction)**。一个好的抽象可以将大量实现细节隐藏在一个干净,简单易懂的外观下面。一个好的抽象也可以广泛用于各类不同应用。比起重复造很多轮子,重用抽象不仅更有效率,而且有助于开发高质量的软件。抽象组件的质量改进将使所有使用它的应用受益。

例如,高级编程语言是一种抽象,隐藏了机器码、CPU 寄存器和系统调用。 SQL 也是一种抽象,隐藏了复杂的磁盘 / 内存数据结构、来自其他客户端的并发请求、崩溃后的不一致性。当然在用高级语言编程时,我们仍然用到了机器码;只不过没有 **直接(directly)** 使用罢了,正是因为编程语言的抽象,我们才不必去考虑这些实现细节。
例如,高级编程语言是一种抽象,隐藏了机器码、CPU 寄存器和系统调用。SQL 也是一种抽象,隐藏了复杂的磁盘 / 内存数据结构、来自其他客户端的并发请求、崩溃后的不一致性。当然在用高级语言编程时,我们仍然用到了机器码;只不过没有 **直接(directly)** 使用罢了,正是因为编程语言的抽象,我们才不必去考虑这些实现细节。

抽象可以帮助我们将系统的复杂度控制在可管理的水平,不过,找到好的抽象是非常困难的。在分布式系统领域虽然有许多好的算法,但我们并不清楚它们应该打包成什么样抽象。

Expand All @@ -344,7 +344,7 @@

系统的需求永远不变,基本是不可能的。更可能的情况是,它们处于常态的变化中,例如:你了解了新的事实、出现意想不到的应用场景、业务优先级发生变化、用户要求新功能、新平台取代旧平台、法律或监管要求发生变化、系统增长迫使架构变化等。

在组织流程方面, **敏捷(agile)** 工作模式为适应变化提供了一个框架。敏捷社区还开发了对在频繁变化的环境中开发软件很有帮助的技术工具和模式,如 **测试驱动开发(TDD, test-driven development)****重构(refactoring)**
在组织流程方面,**敏捷(agile)** 工作模式为适应变化提供了一个框架。敏捷社区还开发了对在频繁变化的环境中开发软件很有帮助的技术工具和模式,如 **测试驱动开发(TDD, test-driven development)****重构(refactoring)**

这些敏捷技术的大部分讨论都集中在相当小的规模(同一个应用中的几个代码文件)。本书将探索在更大数据系统层面上提高敏捷性的方法,可能由几个不同的应用或服务组成。例如,为了将装配主页时间线的方法从方法 1 变为方法 2,你会如何 “重构” 推特的架构 ?

Expand All @@ -358,7 +358,7 @@
一个应用必须满足各种需求才称得上有用。有一些 **功能需求**(functional requirements,即它应该做什么,比如允许以各种方式存储,检索,搜索和处理数据)以及一些 **非功能性需求**(nonfunctional,即通用属性,例如安全性、可靠性、合规性、可伸缩性、兼容性和可维护性)。在本章详细讨论了可靠性,可伸缩性和可维护性。


**可靠性(Reliability)** 意味着即使发生故障,系统也能正常工作。故障可能发生在硬件(通常是随机的和不相关的)、软件(通常是系统性的 Bug,很难处理)和人类(不可避免地时不时出错)。 **容错技术** 可以对终端用户隐藏某些类型的故障。
**可靠性(Reliability)** 意味着即使发生故障,系统也能正常工作。故障可能发生在硬件(通常是随机的和不相关的)、软件(通常是系统性的 Bug,很难处理)和人类(不可避免地时不时出错)。**容错技术** 可以对终端用户隐藏某些类型的故障。

**可伸缩性(Scalability)** 意味着即使在负载增加的情况下也有保持性能的策略。为了讨论可伸缩性,我们首先需要定量描述负载和性能的方法。我们简要了解了推特主页时间线的例子,介绍描述负载的方法,并将响应时间百分位点作为衡量性能的一种方式。在可伸缩的系统中可以添加 **处理容量(processing capacity)** 以在高负载下保持可靠。

Expand Down
Loading

0 comments on commit fcd2b77

Please sign in to comment.