Skip to content

Commit

Permalink
Merge pull request Vonng#121 from yingang/master
Browse files Browse the repository at this point in the history
translation updates (chapter 5 to chapter 8)
  • Loading branch information
Vonng authored Aug 9, 2021
2 parents 3f89e91 + 2fff204 commit 8eb7de1
Show file tree
Hide file tree
Showing 12 changed files with 350 additions and 362 deletions.
2 changes: 1 addition & 1 deletion ch1.md
Original file line number Diff line number Diff line change
Expand Up @@ -264,7 +264,7 @@

​ 人们经常讨论**纵向伸缩(scaling up)****垂直伸缩(vertical scaling)**,转向更强大的机器)和**横向伸缩(scaling out)****水平伸缩(horizontal scaling)**,将负载分布到多台小机器上)之间的对立。跨多台机器分配负载也称为“**无共享(shared-nothing)**”架构。可以在单台机器上运行的系统通常更简单,但高端机器可能非常贵,所以非常密集的负载通常无法避免地需要横向伸缩。现实世界中的优秀架构需要将这两种方法务实地结合,因为使用几台足够强大的机器可能比使用大量的小型虚拟机更简单也更便宜。

​ 有些系统是 **弹性(elastic)** 的,这意味着可以在检测到负载增加时自动增加计算资源,而其他系统则是手动伸缩(人工分析容量并决定向系统添加更多的机器)。如果负载**极难预测(highly unpredictable)**,则弹性系统可能很有用,但手动伸缩系统更简单,并且意外操作可能会更少(参阅“[重新平衡分区](ch6.md#分区再平衡)”)。
​ 有些系统是 **弹性(elastic)** 的,这意味着可以在检测到负载增加时自动增加计算资源,而其他系统则是手动伸缩(人工分析容量并决定向系统添加更多的机器)。如果负载**极难预测(highly unpredictable)**,则弹性系统可能很有用,但手动伸缩系统更简单,并且意外操作可能会更少(参阅“[分区再平衡](ch6.md#分区再平衡)”)。

​ 跨多台机器部署 **无状态服务(stateless services)** 非常简单,但将带状态的数据系统从单节点变为分布式配置则可能引入许多额外复杂度。出于这个原因,常识告诉我们应该将数据库放在单个节点上(纵向伸缩),直到伸缩成本或可用性需求迫使其改为分布式。

Expand Down
4 changes: 2 additions & 2 deletions ch10.md
Original file line number Diff line number Diff line change
Expand Up @@ -351,11 +351,11 @@ top5.each{|count, url| puts "#{count} #{url}" } # 5

​ 如果存在与单个键关联的大量数据,则“将具有相同键的所有记录放到相同的位置”这种模式就被破坏了。例如在社交网络中,大多数用户可能会与几百人有连接,但少数名人可能有数百万的追随者。这种不成比例的活动数据库记录被称为**关键对象(linchpin object)**【38】或**热键(hot key)**

​ 在单个Reducer中收集与某个名流相关的所有活动(例如他们发布内容的回复)可能导致严重的倾斜(也称为**热点(hot spot)**)—— 也就是说,一个Reducer必须比其他Reducer处理更多的记录(参见“[负载倾斜与消除热点](ch6.md#负载倾斜与消除热点)“)。由于MapReduce作业只有在所有Mapper和Reducer都完成时才完成,所有后续作业必须等待最慢的Reducer才能启动。
​ 在单个Reducer中收集与某个名流相关的所有活动(例如他们发布内容的回复)可能导致严重的倾斜(也称为**热点(hot spot)**)—— 也就是说,一个Reducer必须比其他Reducer处理更多的记录(参见“[负载偏斜与热点消除](ch6.md#负载偏斜与热点消除)“)。由于MapReduce作业只有在所有Mapper和Reducer都完成时才完成,所有后续作业必须等待最慢的Reducer才能启动。

​ 如果连接的输入存在热点键,可以使用一些算法进行补偿。例如,Pig中的**倾斜连接(skewed join)**方法首先运行一个抽样作业来确定哪些键是热键【39】。连接实际执行时,Mapper会将热键的关联记录**随机**(相对于传统MapReduce基于键散列的确定性方法)发送到几个Reducer之一。对于另外一侧的连接输入,与热键相关的记录需要被复制到所有处理该键的Reducer上【40】。

​ 这种技术将处理热键的工作分散到多个Reducer上,这样可以使其更好地并行化,代价是需要将连接另一侧的输入记录复制到多个Reducer上。 Crunch中的**分片连接(sharded join)**方法与之类似,但需要显式指定热键而不是使用采样作业。这种技术也非常类似于我们在“[负载倾斜与消除热点](ch6.md#负载倾斜与消除热点)”中讨论的技术,使用随机化来缓解分区数据库中的热点。
​ 这种技术将处理热键的工作分散到多个Reducer上,这样可以使其更好地并行化,代价是需要将连接另一侧的输入记录复制到多个Reducer上。 Crunch中的**分片连接(sharded join)**方法与之类似,但需要显式指定热键而不是使用采样作业。这种技术也非常类似于我们在“[负载偏斜与热点消除](ch6.md#负载偏斜与热点消除)”中讨论的技术,使用随机化来缓解分区数据库中的热点。

​ Hive的偏斜连接优化采取了另一种方法。它需要在表格元数据中显式指定热键,并将与这些键相关的记录单独存放,与其它文件分开。当在该表上执行连接时,对于热键,它会使用Map端连接(参阅[下一节](#Map端连接))。

Expand Down
4 changes: 2 additions & 2 deletions ch12.md
Original file line number Diff line number Diff line change
Expand Up @@ -434,7 +434,7 @@

​ 虽然传统的事务方法并没有走远,但我也相信在使应用正确而灵活地处理错误方面上,事务并不是最后的遗言。在本节中,我将提出一些在数据流架构中考量正确性的方式。

### 为数据库使用端到端的参数
### 数据库端到端的争论

​ 应用仅仅是使用具有相对较强安全属性的数据系统(例如可序列化的事务),并不意味着就可以保证没有数据丢失或损坏。例如,如果某个应用有个Bug,导致它写入不正确的数据,或者从数据库中删除数据,那么可序列化的事务也救不了你。

Expand Down Expand Up @@ -710,7 +710,7 @@ COMMIT;

​ 如果我们不能完全相信系统的每个组件都不会损坏 —— 每一个硬件都没缺陷,每一个软件都没有Bug —— 那我们至少必须定期检查数据的完整性。如果我们不检查,我们就不能发现损坏,直到无可挽回地导致对下游的破坏时,那时候再去追踪问题就要难得多,且代价也要高的多。

​ 检查数据系统的完整性,最好是以端到端的方式进行(参阅“[数据库的端到端争论](#数据库的端到端争论)”):我们能在完整性检查中涵盖的系统越多,某些处理阶中出现不被察觉损坏的几率就越小。如果我们能检查整个衍生数据管道端到端的正确性,那么沿着这一路径的任何磁盘,网络,服务,以及算法的正确性检查都隐含在其中了。
​ 检查数据系统的完整性,最好是以端到端的方式进行(参阅“[数据库的端到端 ](#数据库的端到端争论)”):我们能在完整性检查中涵盖的系统越多,某些处理阶中出现不被察觉损坏的几率就越小。如果我们能检查整个衍生数据管道端到端的正确性,那么沿着这一路径的任何磁盘,网络,服务,以及算法的正确性检查都隐含在其中了。

​ 持续的端到端完整性检查可以不断提高你对系统正确性的信心,从而使你能更快地进步【70】。与自动化测试一样,审计提高了快速发现错误的可能性,从而降低了系统变更或新存储技术可能导致损失的风险。如果你不害怕进行变更,就可以更好地充分演化一个应用,使其满足不断变化的需求。

Expand Down
4 changes: 2 additions & 2 deletions ch2.md
Original file line number Diff line number Diff line change
Expand Up @@ -208,13 +208,13 @@ CODASYL中的查询是通过利用遍历记录列和跟随访问路径表在数

在关系数据库中,查询优化器自动决定查询的哪些部分以哪个顺序执行,以及使用哪些索引。这些选择实际上是“访问路径”,但最大的区别在于它们是由查询优化器自动生成的,而不是由程序员生成,所以我们很少需要考虑它们。

如果想按新的方式查询数据,你可以声明一个新的索引,查询会自动使用最合适的那些索引。无需更改查询来利用新的索引。(请参阅“[用于数据的查询语言](#用于数据的查询语言)”。)关系模型因此使添加应用程序新功能变得更加容易。
如果想按新的方式查询数据,你可以声明一个新的索引,查询会自动使用最合适的那些索引。无需更改查询来利用新的索引。(请参阅“[数据查询语言](#数据查询语言)”。)关系模型因此使添加应用程序新功能变得更加容易。

关系数据库的查询优化器是复杂的,已耗费了多年的研究和开发精力【18】。关系模型的一个关键洞察是:只需构建一次查询优化器,随后使用该数据库的所有应用程序都可以从中受益。如果你没有查询优化器的话,那么为特定查询手动编写访问路径比编写通用优化器更容易——不过从长期看通用解决方案更好。

#### 与文档数据库相比

在一个方面,文档数据库还原为层次模型:在其父记录中存储嵌套记录([图2-1]()中的一对多关系,如`positions``education``contact_info`),而不是在单独的表中。
在一个方面,文档数据库还原为层次模型:在其父记录中存储嵌套记录([图2-1](img/fig2-1.png)中的一对多关系,如`positions``education``contact_info`),而不是在单独的表中。

但是,在表示多对一和多对多的关系时,关系数据库和文档数据库并没有根本的不同:在这两种情况下,相关项目都被一个唯一的标识符引用,这个标识符在关系模型中被称为**外键**,在文档模型中称为**文档引用**【9】。该标识符在读取时通过连接或后续查询来解析。迄今为止,文档数据库没有走CODASYL的老路。

Expand Down
4 changes: 2 additions & 2 deletions ch3.md
Original file line number Diff line number Diff line change
Expand Up @@ -130,7 +130,7 @@ $ cat database

乍一看,只有追加日志看起来很浪费:为什么不更新文件,用新值覆盖旧值?但是只能追加设计的原因有几个:

* 追加和分段合并是顺序写入操作,通常比随机写入快得多,尤其是在磁盘旋转硬盘上。在某种程度上,顺序写入在基于闪存的 **固态硬盘(SSD)** 上也是优选的【4】。我们将在第83页的“[比较B-树和LSM-树](#比较B-树和LSM-树)”中进一步讨论这个问题。
* 追加和分段合并是顺序写入操作,通常比随机写入快得多,尤其是在磁盘旋转硬盘上。在某种程度上,顺序写入在基于闪存的 **固态硬盘(SSD)** 上也是优选的【4】。我们将在第83页的“[比较B树和LSM树](#比较B树和LSM树)”中进一步讨论这个问题。
* 如果段文件是附加的或不可变的,并发和崩溃恢复就简单多了。例如,您不必担心在覆盖值时发生崩溃的情况,而将包含旧值和新值的一部分的文件保留在一起。
* 合并旧段可以避免数据文件随着时间的推移而分散的问题。

Expand Down Expand Up @@ -339,7 +339,7 @@ SELECT * FROM restaurants WHERE latitude > 51.4946 AND latitude < 51.5079

例如,全文搜索引擎通常允许搜索一个单词以扩展为包括该单词的同义词,忽略单词的语法变体,并且搜索在相同文档中彼此靠近的单词的出现,并且支持各种其他功能取决于文本的语言分析。为了处理文档或查询中的拼写错误,Lucene能够在一定的编辑距离内搜索文本(编辑距离1意味着添加,删除或替换了一个字母)【37】。

正如“[在SSTables中创建LSM树](#在SSTables中创建LSM树)”中所提到的,Lucene为其词典使用了一个类似于SSTable的结构。这个结构需要一个小的内存索引,告诉查询需要在排序文件中哪个偏移量查找键。在LevelDB中,这个内存中的索引是一些键的稀疏集合,但在Lucene中,内存中的索引是键中字符的有限状态自动机,类似于trie 【38】。这个自动机可以转换成Levenshtein自动机,它支持在给定的编辑距离内有效地搜索单词【39】。
正如“[用SSTables制作LSM树](#用SSTables制作LSM树)”中所提到的,Lucene为其词典使用了一个类似于SSTable的结构。这个结构需要一个小的内存索引,告诉查询需要在排序文件中哪个偏移量查找键。在LevelDB中,这个内存中的索引是一些键的稀疏集合,但在Lucene中,内存中的索引是键中字符的有限状态自动机,类似于trie 【38】。这个自动机可以转换成Levenshtein自动机,它支持在给定的编辑距离内有效地搜索单词【39】。

其他的模糊搜索技术正朝着文档分类和机器学习的方向发展。有关更多详细信息,请参阅信息检索教科书,例如【40】。

Expand Down
6 changes: 3 additions & 3 deletions ch4.md
Original file line number Diff line number Diff line change
Expand Up @@ -274,7 +274,7 @@ Avro的关键思想是Writer模式和Reader模式不必是相同的 - 他们只

* 通过网络连接发送记录

当两个进程通过双向网络连接进行通信时,他们可以在连接设置上协商模式版本,然后在连接的生命周期中使用该模式。 Avro RPC协议(参阅“[通过服务的数据流:REST和RPC](#通过服务的数据流:REST和RPC)”)就是这样工作的。
当两个进程通过双向网络连接进行通信时,他们可以在连接设置上协商模式版本,然后在连接的生命周期中使用该模式。 Avro RPC协议(参阅“[服务中的数据流:REST与RPC](#服务中的数据流:REST与RPC)”)就是这样工作的。

具有模式版本的数据库在任何情况下都是非常有用的,因为它充当文档并为您提供了检查模式兼容性的机会【24】。作为版本号,你可以使用一个简单的递增整数,或者你可以使用模式的散列。

Expand Down Expand Up @@ -326,7 +326,7 @@ Avro为静态类型编程语言提供了可选的代码生成功能,但是它
这是一个相当抽象的概念 - 数据可以通过多种方式从一个流程流向另一个流程。谁编码数据,谁解码?在本章的其余部分中,我们将探讨数据如何在流程之间流动的一些最常见的方式:

* 通过数据库(参阅“[数据库中的数据流](#数据库中的数据流)”)
* 通过服务调用(参阅“[服务中的数据流:REST和RPC](#服务中的数据流:REST和RPC)”)
* 通过服务调用(参阅“[服务中的数据流:REST与RPC](#服务中的数据流:REST与RPC)”)
* 通过异步消息传递(参阅“[消息传递中的数据流](#消息传递中的数据流)”)


Expand Down Expand Up @@ -383,7 +383,7 @@ Web浏览器不是唯一的客户端类型。例如,在移动设备或桌面

此外,服务器本身可以是另一个服务的客户端(例如,典型的Web应用服务器充当数据库的客户端)。这种方法通常用于将大型应用程序按照功能区域分解为较小的服务,这样当一个服务需要来自另一个服务的某些功能或数据时,就会向另一个服务发出请求。这种构建应用程序的方式传统上被称为**面向服务的体系结构(service-oriented architecture,SOA)**,最近被改进和更名为**微服务架构**【31,32】。

在某些方面,服务类似于数据库:它们通常允许客户端提交和查询数据。但是,虽然数据库允许使用我们在[第2章](./ch2.md)中讨论的查询语言进行任意查询,但是服务公开了一个特定于应用程序的API,它只允许由服务的业务逻辑(应用程序代码)预定的输入和输出【33】。这种限制提供了一定程度的封装:服务能够对客户可以做什么和不可以做什么施加细粒度的限制。
在某些方面,服务类似于数据库:它们通常允许客户端提交和查询数据。但是,虽然数据库允许使用我们在[第2章](ch2.md)中讨论的查询语言进行任意查询,但是服务公开了一个特定于应用程序的API,它只允许由服务的业务逻辑(应用程序代码)预定的输入和输出【33】。这种限制提供了一定程度的封装:服务能够对客户可以做什么和不可以做什么施加细粒度的限制。

面向服务/微服务架构的一个关键设计目标是通过使服务独立部署和演化来使应用程序更易于更改和维护。例如,每个服务应该由一个团队拥有,并且该团队应该能够经常发布新版本的服务,而不必与其他团队协调。换句话说,我们应该期望服务器和客户端的旧版本和新版本同时运行,因此服务器和客户端使用的数据编码必须在不同版本的服务API之间兼容——这正是我们在本章所一直在谈论的。

Expand Down
Loading

0 comments on commit 8eb7de1

Please sign in to comment.