Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

translation updates (chapter 9, TOC in readme, glossary, etc.) #123

Merged
merged 8 commits into from
Aug 19, 2021
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
78 changes: 66 additions & 12 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -44,24 +44,78 @@

### [第一部分:数据系统的基石](part-i.md)

* [第一章:可靠性、可伸缩性、可维护性](ch1.md)
* [第一章:可靠性、可伸缩性、可维护性](ch1.md)
* [关于数据系统的思考](ch1.md#关于数据系统的思考)
* [可靠性](ch1.md#可靠性)
* [可伸缩性](ch1.md#可伸缩性)
* [可维护性](ch1.md#可维护性)
* [本章小结](ch1.md#本章小结)
* [第二章:数据模型与查询语言](ch2.md)
* [第三章:存储与检索](ch3.md)
* [关系模型与文档模型](ch2.md#关系模型与文档模型)
* [数据查询语言](ch2.md#数据查询语言)
* [图数据模型](ch2.md#图数据模型)
* [本章小结](ch2.md#本章小结)
* [第三章:存储与检索](ch3.md)
* [驱动数据库的数据结构](ch3.md#驱动数据库的数据结构)
* [事务处理还是分析?](ch3.md#事务处理还是分析?)
* [列存储](ch3.md#列存储)
* [本章小结](ch3.md#本章小结)
* [第四章:编码与演化](ch4.md)
* [编码数据的格式](ch4.md#编码数据的格式)
* [数据流的类型](ch4.md#数据流的类型)
* [本章小结](ch4.md#本章小结)

### [第二部分:分布式数据](part-ii.md)

* [第五章:复制](ch5.md)
* [第六章:分区](ch6.md)
* [第七章:事务](ch7.md)
* [第八章:分布式系统的麻烦](ch8.md)
* [第九章:一致性与共识](ch9.md)
* [第五章:复制](ch5.md)
* [领导者与追随者](ch5.md#领导者与追随者)
* [复制延迟问题](ch5.md#复制延迟问题)
* [多主复制](ch5.md#多主复制)
* [无主复制](ch5.md#无主复制)
* [本章小结](ch5.md#本章小结)
* [第六章:分区](ch6.md)
* [分区与复制](ch6.md#分区与复制)
* [键值数据的分区](ch6.md#键值数据的分区)
* [分区与次级索引](ch6.md#分区与次级索引)
* [分区再平衡](ch6.md#分区再平衡)
* [请求路由](ch6.md#请求路由)
* [本章小结](ch6.md#本章小结)
* [第七章:事务](ch7.md)
* [事务的棘手概念](ch7.md#事务的棘手概念)
* [弱隔离级别](ch7.md#弱隔离级别)
* [可串行化](ch7.md#可串行化)
* [本章小结](ch7.md#本章小结)
* [第八章:分布式系统的麻烦](ch8.md)
* [故障与部分失效](ch8.md#故障与部分失效)
* [不可靠的网络](ch8.md#不可靠的网络)
* [不可靠的时钟](ch8.md#不可靠的时钟)
* [知识、真相与谎言](ch8.md#知识、真相与谎言)
* [本章小结](ch8.md#本章小结)
* [第九章:一致性与共识](ch9.md)
* [一致性保证](ch9.md#一致性保证)
* [线性一致性](ch9.md#线性一致性)
* [顺序保证](ch9.md#顺序保证)
* [分布式事务与共识](ch9.md#分布式事务与共识)
* [本章小结](ch9.md#本章小结)

### [第三部分:衍生数据](part-iii.md)

* [第十章:批处理](ch10.md)
* [第十一章:流处理](ch11.md)
* [第十二章:数据系统的未来](ch12.md)
* [第十章:批处理](ch10.md)
* [使用Unix工具的批处理](ch10.md#使用Unix工具的批处理)
* [MapReduce和分布式文件系统](ch10.md#MapReduce和分布式文件系统)
* [MapReduce之后](ch10.md#MapReduce之后)
* [本章小结](ch10.md#本章小结)
* [第十一章:流处理](ch11.md)
* [传递事件流](ch11.md#传递事件流)
* [流与数据库](ch11.md#流与数据库)
* [流处理](ch11.md#流处理)
* [本章小结](ch11.md#本章小结)
* [第十二章:数据系统的未来](ch12.md)
* [数据集成](ch12.md#数据集成)
* [分拆数据库](ch12.md#分拆数据库)
* [将事情做正确](ch12.md#将事情做正确)
* [做正确的事情](ch12.md#做正确的事情)
* [本章小结](ch12.md#本章小结)

### [术语表](glossary.md)

Expand All @@ -88,7 +142,7 @@
4. [第一部分](part-i.md)前言,[ch2](ch2.md)校正 by [@jiajiadebug](https://github.com/Vonng/ddia/commits?author=jiajiadebug)
5. [词汇表](glossary.md)、[后记]()关于野猪的部分 by @[Chowss](https://github.com/Vonng/ddia/commits?author=Chowss)
6. [繁體中文](https://github.com/Vonng/ddia/pulls)版本与转换脚本 by [@afunTW](https://github.com/afunTW)
7. [对第各章进行大量翻译更正润色](https://github.com/Vonng/ddia/pull/118) by [@yingang](https://github.com/yingang)
7. [对各章进行大量翻译更正润色](https://github.com/Vonng/ddia/pull/118) by [@yingang](https://github.com/yingang)
8. 感谢所有作出贡献,提出意见的朋友们:

<details>
Expand All @@ -99,7 +153,7 @@
| [121](https://github.com/Vonng/ddia/pull/121) | [@yingang](https://github.com/yingang) | translation updates (chapter 5 to chapter 8) |
| [120](https://github.com/Vonng/ddia/pull/120) | [@jiong-han](https://github.com/jiong-han) | Typo fix: 呲之以鼻 -> 嗤之以鼻 |
| [119](https://github.com/Vonng/ddia/pull/119) | [@cclauss](https://github.com/cclauss) | Streamline file operations in convert() |
| [118](https://github.com/Vonng/ddia/pull/118) | [@yingang](https://github.com/yingang) | translation updates (chapter 2 and 3) |
| [118](https://github.com/Vonng/ddia/pull/118) | [@yingang](https://github.com/yingang) | translation updates (chapter 2 and 4) |
| [117](https://github.com/Vonng/ddia/pull/117) | [@feeeei](https://github.com/feeeei) | 统一每章的标题格式 |
| [115](https://github.com/Vonng/ddia/pull/115) | [@NageNalock](https://github.com/NageNalock) | 第七章病句修改: 重复词语 |
| [114](https://github.com/Vonng/ddia/pull/114) | [@Sunt-ing](https://github.com/Sunt-ing) | Update README.md: correct the book name |
Expand Down
2 changes: 1 addition & 1 deletion ch10.md
Original file line number Diff line number Diff line change
Expand Up @@ -347,7 +347,7 @@ top5.each{|count, url| puts "#{count} #{url}" } # 5

​ 如果你有多个Web服务器处理用户请求,则特定用户的活动事件很可能分散在各个不同的服务器的日志文件中。你可以通过使用会话cookie,用户ID或类似的标识符作为分组键,以将特定用户的所有活动事件放在一起来实现会话化,与此同时,不同用户的事件仍然散步在不同的分区中。

#### 处理倾斜
#### 处理偏斜

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

Expand Down
6 changes: 3 additions & 3 deletions ch11.md
Original file line number Diff line number Diff line change
Expand Up @@ -333,9 +333,9 @@

​ 事件流的消费者不允许拒绝事件:当消费者看到事件时,它已经成为日志中不可变的一部分,并且可能已经被其他消费者看到了。因此任何对命令的验证,都需要在它成为事件之前同步完成。例如,通过使用一个可自动验证命令的可序列化事务来发布事件。

​ 或者,预订座位的用户请求可以拆分为两个事件:第一个是暂时预约,第二个是验证预约后的独立的确认事件(如“[使用全序广播实现线性一致存储](ch9.md#使用全序广播实现线性一致存储)”中所述) 。这种分割方式允许验证发生在一个异步的过程中。
​ 或者,预订座位的用户请求可以拆分为两个事件:第一个是暂时预约,第二个是验证预约后的独立的确认事件(如“[使用全序广播实现线性一致的存储](ch9.md#使用全序广播实现线性一致的存储)”中所述) 。这种分割方式允许验证发生在一个异步的过程中。

#### 状态,流和不变性
### 状态,流和不变性

​ 我们在[第10章](ch10.md)中看到,批处理因其输入文件不变性而受益良多,你可以在现有输入文件上运行实验性处理作业,而不用担心损坏它们。这种不变性原则也是使得事件溯源与变更数据捕获如此强大的原因。

Expand Down Expand Up @@ -386,7 +386,7 @@ $$

​ 事件溯源和变更数据捕获的最大缺点是,事件日志的消费者通常是异步的,所以可能会出现这样的情况:用户会写入日志,然后从日志衍生视图中读取,结果发现他的写入还没有反映在读取视图中。我们之前在在“[读己之写](ch5.md#读己之写)”中讨论了这个问题以及可能的解决方案。

​ 一种解决方案是将事件附加到日志时同步执行读取视图的更新。而将这些写入操作合并为一个原子单元需要**事务**,所以要么将事件日志和读取视图保存在同一个存储系统中,要么就需要跨不同系统进行分布式事务。或者,你也可以使用在“[使用全序广播实现线性化存储](ch9.md#使用全序广播实现线性化存储)”中讨论的方法。
​ 一种解决方案是将事件附加到日志时同步执行读取视图的更新。而将这些写入操作合并为一个原子单元需要**事务**,所以要么将事件日志和读取视图保存在同一个存储系统中,要么就需要跨不同系统进行分布式事务。或者,你也可以使用在“[使用全序广播实现线性一致的存储](ch9.md#使用全序广播实现线性一致的存储)”中讨论的方法。

​ 另一方面,从事件日志导出当前状态也简化了并发控制的某些部分。许多对于多对象事务的需求(参阅“[单对象和多对象操作](ch7.md#单对象和多对象操作)”)源于单个用户操作需要在多个不同的位置更改数据。通过事件溯源,你可以设计一个自包含的事件以表示一个用户操作。然后用户操作就只需要在一个地方进行单次写入操作 —— 即将事件附加到日志中 —— 这个还是很容易使原子化的。

Expand Down
4 changes: 2 additions & 2 deletions ch12.md
Original file line number Diff line number Diff line change
Expand Up @@ -491,7 +491,7 @@ BEGIN TRANSACTION;
COMMIT;
```

​ [例12-2]()依赖于`request_id`列上的唯一约束。如果一个事务尝试插入一个已经存在的ID,那么`INSERT`失败,事务被中止,使其无法生效两次。即使在较弱的隔离级别下,关系数据库也能正确地维护唯一性约束(而在“[写入偏差与幻读](ch7.md#写入偏差与幻读)”中讨论过,应用级别的**检查-然后-插入**可能会在不可序列化的隔离下失败)。
​ [例12-2]()依赖于`request_id`列上的唯一约束。如果一个事务尝试插入一个已经存在的ID,那么`INSERT`失败,事务被中止,使其无法生效两次。即使在较弱的隔离级别下,关系数据库也能正确地维护唯一性约束(而在“[写入偏斜与幻读](ch7.md#写入偏斜与幻读)”中讨论过,应用级别的**检查-然后-插入**可能会在不可序列化的隔离下失败)。

​ 除了抑制重复的请求之外,[例12-2]()中的请求表表现得就像一种事件日志,提示向着事件溯源的方向(参阅“[事件溯源](ch11.md#事件溯源)”)。更新账户余额事实上不必与插入事件发生在同一个事务中,因为它们是冗余的,而能由下游消费者从请求事件中衍生出来 —— 只要该事件被恰好处理一次,这又一次可以使用请求ID来强制执行。

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

该算法基本上与“[使用全序广播实现线性一致的存储](ch9.md#使用全序广播实现线性一致的存储)”中的算法相同。它可以简单地通过增加分区数伸缩至较大的请求吞吐量,因为每个分区可以被独立处理。

​ 该方法不仅适用于唯一性约束,而且适用于许多其他类型的约束。其基本原理是,任何可能冲突的写入都会路由到相同的分区并按顺序处理。正如“[什么是冲突?](ch5.md#什么是冲突?)”与“[写入偏差与幻读](ch7.md#写入偏差与幻读)”中所述,冲突的定义可能取决于应用,但流处理器可以使用任意逻辑来验证请求。这个想法与Bayou在90年代开创的方法类似【58】。
​ 该方法不仅适用于唯一性约束,而且适用于许多其他类型的约束。其基本原理是,任何可能冲突的写入都会路由到相同的分区并按顺序处理。正如“[什么是冲突?](ch5.md#什么是冲突?)”与“[写入偏斜与幻读](ch7.md#写入偏斜与幻读)”中所述,冲突的定义可能取决于应用,但流处理器可以使用任意逻辑来验证请求。这个想法与Bayou在90年代开创的方法类似【58】。

#### 多分区请求处理

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

![](img/fig3-4.png)

##### 图3-4 合并几个SSTable段,只保留每个键的最新值
**图3-4 合并几个SSTable段,只保留每个键的最新值**

如果在几个输入段中出现相同的键,该怎么办?请记住,每个段都包含在一段时间内写入数据库的所有值。这意味着一个输入段中的所有值必须比另一个段中的所有值更新(假设我们总是合并相邻的段)。当多个段包含相同的键时,我们可以保留最近段的值,并丢弃旧段中的值。

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

这些OLTP系统往往对业务运作至关重要,因而通常会要求 **高可用** 与 **低延迟**。所以DBA会密切关注他们的OLTP数据库,他们通常不愿意让业务分析人员在OLTP数据库上运行临时分析查询,因为这些查询通常开销巨大,会扫描大部分数据集,这会损害同时执行的事务的性能。

相比之下,数据仓库是一个独立的数据库,分析人员可以查询他们想要的内容而不影响OLTP操作【48】。数据仓库包含公司各种OLTP系统中所有的只读数据副本。从OLTP数据库中提取数据(使用定期的数据转储或连续的更新流),转换成适合分析的模式,清理并加载到数据仓库中。将数据存入仓库的过程称为“**抽取-转换-加载(ETL)**”,如[图3-8](img/fig3-8)所示。
相比之下,数据仓库是一个独立的数据库,分析人员可以查询他们想要的内容而不影响OLTP操作【48】。数据仓库包含公司各种OLTP系统中所有的只读数据副本。从OLTP数据库中提取数据(使用定期的数据转储或连续的更新流),转换成适合分析的模式,清理并加载到数据仓库中。将数据存入仓库的过程称为“**抽取-转换-加载(ETL)**”,如[图3-8](img/fig3-8.png)所示。

![](img/fig3-8.png)

Expand Down
2 changes: 1 addition & 1 deletion ch4.md
Original file line number Diff line number Diff line change
Expand Up @@ -258,7 +258,7 @@ Avro的关键思想是Writer模式和Reader模式不必是相同的 - 他们只

只要Avro可以支持相应的类型转换,就可以改变字段的数据类型。更改字段的名称也是可能的,但有点棘手:Reader模式可以包含字段名称的别名,所以它可以匹配旧Writer的模式字段名称与别名。这意味着更改字段名称是向后兼容的,但不能向前兼容。同样,向联合类型添加分支也是向后兼容的,但不能向前兼容。

##### 但Writer模式到底是什么?
#### 但Writer模式到底是什么?

到目前为止,我们一直跳过了一个重要的问题:对于一段特定的编码数据,Reader如何知道其Writer模式?我们不能只将整个模式包括在每个记录中,因为模式可能比编码的数据大得多,从而使二进制编码节省的所有空间都是徒劳的。

Expand Down
4 changes: 2 additions & 2 deletions ch5.md
Original file line number Diff line number Diff line change
Expand Up @@ -52,7 +52,7 @@
![](img/fig5-2.png)
**图5-2 基于领导者的复制:一个同步从库和一个异步从库**

​ 在[图5-2]()的示例中,从库1的复制是同步的:在向用户报告写入成功,并使结果对其他用户可见之前,主库需要等待从库1的确认,确保从库1已经收到写入操作。以及在使写入对其他客户端可见之前接收到写入。跟随者2的复制是异步的:主库发送消息,但不等待从库的响应。
​ 在[图5-2](img/fig5-2.png)的示例中,从库1的复制是同步的:在向用户报告写入成功,并使结果对其他用户可见之前,主库需要等待从库1的确认,确保从库1已经收到写入操作。以及在使写入对其他客户端可见之前接收到写入。跟随者2的复制是异步的:主库发送消息,但不等待从库的响应。

​ 在这幅图中,从库2处理消息前存在一个显著的延迟。通常情况下,复制的速度相当快:大多数数据库系统能在一秒向从库应用变更,但它们不能提供复制用时的保证。有些情况下,从库可能落后主库几分钟或更久;例如:从库正在从故障中恢复,系统在最大容量附近运行,或者如果节点间存在网络问题。

Expand Down Expand Up @@ -277,7 +277,7 @@

​ 防止这种异常,需要另一种类型的保证:**一致前缀读(consistent prefix reads)**【23】。 这个保证说:如果一系列写入按某个顺序发生,那么任何人读取这些写入时,也会看见它们以同样的顺序出现。

​ 这是**分区(partitioned)**(**分片(sharded)**)数据库中的一个特殊问题,将在第6章中讨论。如果数据库总是以相同的顺序应用写入,则读取总是会看到一致的前缀,所以这种异常不会发生。但是在许多分布式数据库中,不同的分区独立运行,因此不存在**全局写入顺序**:当用户从数据库中读取数据时,可能会看到数据库的某些部分处于较旧的状态,而某些处于较新的状态。
​ 这是**分区(partitioned)**(**分片(sharded)**)数据库中的一个特殊问题,将在[第6章](ch6.md)中讨论。如果数据库总是以相同的顺序应用写入,则读取总是会看到一致的前缀,所以这种异常不会发生。但是在许多分布式数据库中,不同的分区独立运行,因此不存在**全局写入顺序**:当用户从数据库中读取数据时,可能会看到数据库的某些部分处于较旧的状态,而某些处于较新的状态。

​ 一种解决方案是,确保任何因果相关的写入都写入相同的分区。对于某些无法高效完成这种操作的应用,还有一些显式跟踪因果依赖关系的算法,本书将在“[“此前发生”的关系和并发](#“此前发生”的关系和并发)”一节中返回这个主题。

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

[^i]: 正如本章所讨论的,分区是一种有意将大型数据库分解成小型数据库的方式。它与 **网络分区(network partitions, netsplits)** 无关,这是节点之间网络故障的一种。我们将在[第8章](ch8.md)讨论这些错误。

> ##### 术语澄清
> #### 术语澄清
>
> ​ 上文中的**分区(partition)**,在MongoDB,Elasticsearch和Solr Cloud中被称为**分片(shard)**,在HBase中称之为**区域(Region)**,Bigtable中则是 **表块(tablet)**,Cassandra和Riak中是**虚节点(vnode)**,Couchbase中叫做**虚桶(vBucket)**。但是**分区(partitioning)** 是最约定俗成的叫法。
>
Expand Down Expand Up @@ -55,7 +55,7 @@

### 根据键的范围分区

​ 一种分区的方法是为每个分区指定一块连续的键范围(从最小值到最大值),如纸质百科全书的卷([图6-2]())。如果知道范围之间的边界,则可以轻松确定哪个分区包含某个值。如果您还知道分区所在的节点,那么可以直接向相应的节点发出请求(对于百科全书而言,就像从书架上选取正确的书籍)。
​ 一种分区的方法是为每个分区指定一块连续的键范围(从最小值到最大值),如纸质百科全书的卷([图6-2](img/fig6-2.png))。如果知道范围之间的边界,则可以轻松确定哪个分区包含某个值。如果您还知道分区所在的节点,那么可以直接向相应的节点发出请求(对于百科全书而言,就像从书架上选取正确的书籍)。

![](img/fig6-2.png)

Expand Down
Loading