init commit

This commit is contained in:
Vonng 2018-02-08 14:07:06 +08:00
commit d05529b73c
141 changed files with 12574 additions and 0 deletions

90
README.md Normal file
View File

@ -0,0 +1,90 @@
# db
> 不懂数据库的全栈工程师不是好架构师
>
> —— Vonng
## Data System
数据系统"学习笔记"[DDIA](ddia/README.md)
#### [I. 数据系统基础](ddia/part-i.md)
1. [可靠性、可扩展性、可维护性](ddia/ch1.md)
2. [数据模型与查询语言](ddia/ch2.md)
3. [存储与检索](ddia/ch3.md)
4. [编码与演化](ddia/ch4.md)
#### [II. 分布式数据](ddia/part-ii.md)
5. [复制](ddia/ch5.md)
6. [分片](ddia/ch6.md)
7. [事务](ddia/ch7.md)
8. [分布式系统的麻烦](ddia/ch8.md)
9. [一致性与共识](ddia/ch9.md)
#### [III. 派生数据](ddia/part-iii.md)
10. [批处理](ddia/ch10.md)
11. [流处理](ddia/ch11.md)
12. [数据系统的未来](ddia/ch12.md)
## [PostgreSQL](pg/)
PostgreSQL是世界上最先进的开源关系型数据库
### SQL
* [PostgreSQL中的锁](note/pg-sql-lock.md)
### GIS
* PostGIS教程
### Adminstration
- [Installation](pg/pg-admin-install.md)
- [Setup](pg/pg-admin-setup.md)
- [Configuration](pg/pg-admin-config.md)
- [Authentication](pg/pg-admin-auth.md)
- [PostgreSQL 监控](pg/pg-admin-monitor.md)
- [PostgreSQL备份与恢复](pg/pg-admin-backup.md)
- [PostgreSQL WAL与检查点](pg/pg-admin-wal.md)
- [PostgreSQL 高可用](pg/pg-admin-ha.md)
### Tunning
* [Memory Tunning](pg/pg-tune-memory.md)
* [Checkpoint Tuning Basic](pg/pg-tune-checkpoint)
* [Autovacuum Tuning Basics](pg/pg-tune-autovacuum.md)
### Extension
* [PostGIS Installation](pg/ext-postgis-install.md)
* [FileFDW Usage](pg/ext-file_fdw-intro.md)
* [RedisFDW Installation](pg/ext-redis_fdw-install.md)
* [MongoFDW Installation](pg/ext-mongo_fdw-install.md)
* [PgAdmin Installation](pg/ext-pgadmin-install.md)
### Reference
* [PostgreSQL 9.6 中文文档](http://www.postgres.cn/docs/9.6/)
* [PostgreSQL 10.1 官方文档](https://www.postgresql.org/docs/10/static/index.html)
* [PostGIS 2.4 官方文档](https://postgis.net/docs/manual-2.4/)
* [Introduction to PostGIS](http://workshops.boundlessgeo.com/postgis-intro/index.html)
## License
闷声发大财才是坠吼地。

117
ddia/README.md Normal file
View File

@ -0,0 +1,117 @@
# 《设计数据密集应用》
* 作者: Martin Kleppmann
* 原书名称《Designing Data-Intensive Application》
* 译者:冯若航 fengruohang@outlook.com , http://vonng.com/about
## 前言
> 在我们的社会中,技术是一种强大的力量。数据、软件、通信可以用于坏的方面:不公平的阶级固化,损害公民权利,保护既得利益集团。但也可以用于好的方面:让底层人民发出自己的声音,让每个人都拥有机会,避免灾难。本书献给所有将技术用于善途的人们。
> 计算是一种流行文化,流行文化鄙视历史。 流行文化关乎个体身份和参与感,与合作无关。它活在当下,也与过去和未来无关。 我认为大部分(为钱)写代码的人就是这样, 他们不知道他们的文化来自哪里。
>
> ——阿兰·凯接受Dobb博士的杂志采访时2012年
## 目录
### [序言](preface.md) [机翻]
### 第一部分: [数据系统的基石](part-i.md)
1. [可靠性、可扩展性、可维护性](ch1.md) [初翻30%]
* 关于数据系统的思考
* 可靠性
* 可扩展性
* 可维护性
2. [数据模型与查询语言](ch2.md) [初翻]
* 关系模型与文档模型
* 数据查询语言
* 图数据模型
3. [存储与检索](ch3.md) [初翻]
* 支撑数据库的数据结构
* 分析还是事务处理?
* 列存储
4. [编码与演化](ch4.md) [初翻]
* 编码数据的格式
* 数据流的模型
### 第二部分: [分布式数据](part-ii.md)
5. [复制](ch5.md) [机翻]
* 主从
* 复制延迟带来的问题
* 多主复制
* 无主复制
6. [分片](ch6.md) [机翻]
* 分片与复制
* 键值对数据的分片
* 分片与次级索引
* 分片再平衡
* 请求路由
7. [事务](ch7.md) [机翻]
* 事务的棘手概念
* ACID的含义
* 弱隔离级别
* 序列化能力
8. [分布式系统的麻烦](ch8.md) [待翻]
* 故障与部分失效
* 不可靠的网络
* 不可靠的时钟
* 知识、真相与谎言
9. [一致性与共识](ch9.md) [待翻]
* 一致性保证
* 线性一致性
* 顺序保证
* 分布式事务与共识
### 第三部分:[衍生数据](part-iii.md)
10. [批处理](ch10.md) [未翻]
* 使用Unix工具的批处理
* MapReduce和分布式文件系统
* 后MapReduce时代
11. [流处理](ch11.md) [未翻]
* 传递事件流
* 流与数据库
* 流处理
12. [数据系统的未来](ch12.md) [未翻]
* 数据集成
* 拆分数据库
* 目标是正确性
* 做正确的事情
## 翻译计划
机翻:程序翻译,基本保留原书的组织结构,也是阅读原文,学习本书的过程。
初翻:人工修复格式错误和显著翻译错误,重新组织语言,保障基本的可读性。
精翻:确定一些术语的最终译法,保证可以流畅阅读,着力信达雅。
翻译完全看心情,但通常每周至少会完成一章的初翻。
阅读建议使用Typora可以获得最好的阅览体验。
## 译者声明
纯粹出于学习目的与个人兴趣翻译,仅供交流讨论与个人学习使用,闷声发大财自己看就行,严禁用于商业目的与公开传播发行。侵删。目前尚无中文译本,有能力阅读英文书籍者请购买原版支持。
```
《中华人民共和国著作权法》
第四节 权利的限制
第二十二条 在下列情况下使用作品,可以不经著作权人许可,不向其支付报酬,但应当指明作者姓名、作品名称,并且不得侵犯著作权人依照本法享有的其他权利:
(六)为学校课堂教学或者科学研究,翻译或者少量复制已经发表的作品,供教学或者科研人员使用,但不得出版发行;
```
![](img/title.png)

519
ddia/ch1.md Normal file
View File

@ -0,0 +1,519 @@
# 1.可靠性,可扩展性,可维护性
![](img/ch1.png)
> 互联网做得太棒了,以至于多数人将它看作像海洋这样的天然资源,而不是什么人工产物。 这种规模的技术没出问题,上一次是什么时候了?
>
> ——阿兰·凯在接受Dobb博士杂志采访时2012年
-----------------------
[TOC]
现今很多应用程序都是**数据密集型data-intensive**,而非**计算密集型compute-intensive**的。CPU很少成为这类应用的瓶颈更大的问题通常来自数据量数据的复杂性、以及数据的变更速度。
数据密集型应用通常由标准组件构建而成,标准组件提供了很多通用的功能:例如,许多应用程序需要:
* 存储数据,以便自己或其他应用程序之后能再次找到。(数据库 database
* 记住开销昂贵操作的结果,加快读取速度。(缓存 cache
* 允许用户按关键字搜索数据,或以各种方式对数据进行过滤。(搜索索引 search indexes
* 发送消息至其他进程,进行异步处理(流处理 stream processing
* 定期压缩积累的大批量数据(批处理 batch processing
如果这些功能听上去平淡无奇,那真让人心酸……。因为这些*数据系统data system*是如此成功的抽象,我们一直用着它们,却没有想太多。绝大多数工程师不会想从零开始编写存储引擎,开发应用时,数据库已经是足够完美工具了。
但事实并没有这么简单。不同的应用有不同的需求,所以数据库系统也是百花齐放,有着各式各样的特性。有很多不同的手段可以实现缓存,也有好几种方法可以搞定搜索索引,诸如此类。所以开发应用时,我们仍然需要弄清楚什么样的工具和方法最适合手头的工作。而当单个工具解决不了你的问题时,你会发现组合使用这些工具还是有难度的。
本书将是一趟关于数据系统原理、实践与应用的旅途,并讲述了设计数据密集型应用的方法。我们将探索不同工具之间的共性与特性,以及各自的实现原理。
本章将从探索我们所要实现的基础目标开始:可靠,可扩展、可维护的数据系统。我们将澄清这些词语的含义,概述考量这些目标的方法。并回顾一些后续章节所需的基础知识。在接下来的章节中我们将抽丝剥茧,研究设计数据密集型应用时可能遇到的设计决策。
## 关于数据系统的思考
通常认为,数据库,消息队列,缓存这些,是差异显著的工具分类。虽然数据库和消息队列表面上有一些相似性—— 都会存一段时间的数据。——但它们有迥然的访问模式,这意味着迥然的性能特征和迥然的实现。
那么为什么要把它们混为一谈,放在一个 **数据系统data system**的总称之下呢?
近些年来出现了许多新的数据存储工具与数据处理工具。它们针对各种不同应用场景进行优化,不再适用于传统的类别[【1】][1]。类别之间的界限越来越模糊例如数据存储也被当成消息队列用Redis消息队列带有类似数据库的持久保证Apache Kafka
其次,越来越多的应用程序有各式各样苛刻广泛的要求,单个工具不足以满足所有的数据处理和存储需求。取而代之的是,工作被拆分成一系列能被单个工具能高效完成的任务。并通过应用代码将这些工具缝合起来。
例如如果把缓存和全文搜索功能从主数据库分离出来多了一个应用管理的缓存Memcached或类似品和一个全文搜索服务器例如Elasticsearch或Solr那么使缓存/索引与主数据库保证同步通常是应用代码的责任。[图1-1]() 给出了这种架构可能的样子(细节将在后面的章节中详细介绍)。
![](img/fig1-1.png)
**图1-1 组合使用多个组件的数据系统,一种可能的架构**
当你将多个工具组合在一起提供服务时,服务的接口,或*应用程序编程接口API, Application Programming Interface*通常向客户端隐藏这些实现细节。现在,你基本上已经使用较小的通用组件创建了一个全新的,专用的数据系统。这个新的复合数据系统可能会提供特定的保证:例如,缓存在写入时作废或更新,以便外部客户端获取一致的结果。现在你不仅是应用程序开发人员,还是数据系统设计人员了。
设计数据系统或服务时可能会遇到很多棘手的问题。当系统出问题时如何确保数据的正确性和完整性当部分系统退化降级时如何为客户提供始终如一的良好性能当负载增加时如何扩容应对什么样的API才是好的API
影响数据系统设计的因素很多,包括参与人员的技能和经验,历史遗留问题,系统路径依赖,交付时限,单位对各种风险的容忍度,监管约束等。这些因素都需要具体问题具体分析。
本书着重讨论三个在大多数软件系统中都很重要的问题:
***可靠性Reliability***
系统在困境(硬件故障、软件故障、人为错误)中仍可正常工作(正确完成功能,能并达到期望性能水准)。
***可扩展性Scalability***
有合理的办法应对系统的增长(数据量,流量、复杂性)(参阅“可伸缩性”)
***可维护性Maintainability***
许多不同的人(工程师、运维)在不同的生命周期,都能在高效地在系统上工作(使系统保持现有行为,适应新的应用场景)。(参阅”可维护性“)
人们经常追求这些词汇,却并没有清楚理解它们到底意味着什么。为了工程的严谨性,本章的剩余部分将探讨可靠性、可扩展性、可维护性的含义。为实现这些目标而使用的各种技术,架构和算法,将在后续的章节中研究。
## 可靠性
人们对于一个东西是否可靠,都有一个直观的想法。对于可靠的软件,典型的期望包括:
* 应用程序表现出用户所期望的功能。
* 它可以允许用户犯错或以出乎意料的方式使用软件。
* 在预期的负载和数据量下,性能满足应用场景的要求。
* 系统可以防止未经授权的访问和滥用。
如果所有这些在一起意味着“正确工作”,那么我们可以把可靠性粗略理解为”即使出现问题,也能继续正确工作”。
可能出问题的东西叫做***故障fault***,能预料并应对故障的系统特性可称为***容错fault-tolerant***或***韧性resilient***。第一个术语可能会产生误导:它暗示可以让系统容忍所有可能的错误,实际中这是不可能的。如果整个地球(及其上的所有服务器)都被黑洞吞噬,容忍这种错误需要将网络托管到宇宙中。能不能通过这种预算就祝你好运了。所以在讲容错时,只有谈论*特定类型*的错误才有意义。
注意***故障fault***不同于***失效failure***[【2】][2]。**故障**通常定义为系统的一部分偏离其标准,而**失效**则是系统作为一个整体停止向用户提供服务。故障的概率不可能降到零,因此最好设计容错机制,以防止**故障**导致**失效**。本书们将介绍几种用不可靠的部件构建可靠系统的技术。
反直觉的是,在这类容错系统中,通过故意触发来**提高**故障率是有意义的。例如在没有警告的情况下随机地杀死单个进程。许多高危漏洞实际上由糟糕的错误处理导致的[【3】][3]通过故意引发故障来确保容错机制不断运行并接受考验从而提高故障自然发生时系统能正确处理的信心。Netflix *Chaos Monkey*[【4】][]就是这种方法的一个例子。
尽管比起**阻止错误Prevent error**,我们更倾向于容忍错误。但也有**预防胜于治疗**的情况(比如不存在治疗方法时)。安全问题就属于这种情况。例如,如果攻击者破坏了系统,并获取了敏感数据,这种事是撤销不了的。但是本书主要讨论的是可以恢复的故障类型,如下所述。
### 硬件故障
当我们想到系统失效的原因时,硬件故障总是第一个进入脑海。硬盘崩溃,内存出错,机房断电,有人拔错网线。任何与大型数据中心打交道的人都会告诉你,当拥有很多机器时,这些事情**总是**会发生的。
硬盘的平均无故障时间MTTF, mean time to failure据报道称约为10到50年[【5】][] [【6】][]。因此,在一个有一万个磁盘的存储集群上,期望上每天平均会有一个磁盘挂掉。
为了减少系统的故障率第一反应通常是增加单个硬件的冗余度。磁盘可以组RAID服务器可能有双路电源和热插拔CPU数据中心可能有电池和柴油发电机作为后备电源。当某个组件挂掉时换下来并由冗余组件取而代之。这种方法并不能完全防止因为硬件问题导致的系统失效但它简单易懂通常也足以让机器不间断运行多年。
直到最近,硬件冗余对于大多数应用来说已经足够了,它使单台机器完全失效变得相当罕见。只要你能快速地把备份恢复到新机器上,故障停机时间对于大多数应用程序都不算灾难性的。少部分需要高可用的应用会采用多个冗余副本。
但是随着数据量和应用程序的计算需求的增加越来越多的应用程序开始使用大量的机器这会相应地增加硬件故障率。此外在一些云平台如亚马逊网络服务AWS虚拟机实例在没有警告的情况下变得不可用[7],这是因为平台旨在优先考虑单机可靠性的灵活性和弹性。
因此,通过优先使用软件容错技术或除了硬件冗余之外,还有一种趋向于可以容忍整个机器损失的系统。这样的系统还具有操作优势:如果需要重启机器(例如应用操作系统安全补丁),则单服务器系统需要计划的停机时间,而可以容忍机器故障的系统可以一次修补一个节点没有整个系统的停机时间(滚动升级;参见第4章
### 软件错误
我们通常认为硬件故障是随机的,相互独立的:一台机器的磁盘失败并不意味着另一台机器的磁盘将会失败。可能存在较弱的相关性(例如,由于常见原因,例如服务器机架中的温度),否则大量硬件组件不可能同时发生故障。
另一类错误是系统内部的系统错误[8]。这样的错误很难预测,而且由于它们在节点间相互关联,所以往往比不相关的硬件故障造成更多的系统故障[5]。例子包括:
* 给定特定的错误输入时导致应用程序服务器的每个实例崩溃的软件错误。例如考虑到2012年6月30日的闰秒由于Linux内核中的一个错误导致许多应用程序同时挂起。
* 失控进程会占用一些共享资源 - CPU时间内存磁盘空间或网络带宽。
* 系统依赖的服务变慢,变为无响应,或者开始返回损坏的响应。
* 级联故障,其中一个组件中的小故障触发另一个组件中的故障,进而触发进一步的故障[10]。
导致这类软件故障的错误通常会长时间处于休眠状态,直到被不寻常的情况触发为止。在这种情况下,显示出软件正在对其环境做出某种假设 - 虽然这种假设通常是正确的,但由于某种原因它最终会被否定[11]。
软件中的系统故障问题没有快速的解决方案。许多小事情可以帮助:仔细考虑系统中的假设和交互;彻底的测试;过程隔离;允许进程崩溃并重新启动;测量,监控和分析生产中的系统行为。如果一个系统需要提供一些保证(例如在一个消息队列中,输入消息的数量等于输出消息的数量),它可以在运行时不断检查自己,并在出现差异时发出警报被发现[12]。
### 人为错误
人类设计和建造软件系统保持系统运行的操作人员也是人。即使他们有最好的意图人类也是不可靠的。例如一项关于大型互联网服务的研究发现运营商的配置错误是导致中断的主要原因而硬件故障服务器或网络仅在10-25的中断中发挥作用[13]。
尽管人类不可靠,我们如何使我们的系统可靠?最好的系统结合了几种方法:
* 以最大限度地减少错误机会的方式设计系统。例如精心设计的抽象API和管理界面使得“做正确的事情”变得容易并且阻止“错误的事情”。然而如果接口过于严格人们会绕过它们否定它们的好处。这是一个棘手的平衡得到正确的。
* 将人们犯最多错误的地方与可能导致失败的地方分开。特别是提供功能齐全的非生产性沙箱环境,使用户可以在不影响真实用户的情况下使用真实数据安全地探索和实验。
* 从单元测试到全系统集成测试和手动测试,在各个层面进行彻底测试[3]。自动化测试广泛使用,易于理解,特别适用于覆盖在正常运行中很少出现的角落案例。
* 允许从人为错误中快速轻松地恢复,以最大限度地减少故障情况下的影响。 例如,快速回滚配置更改,逐渐推出新代码(以便任何意外的错误只影响一小部分用户),并提供重新计算数据的工具(万一事实证明旧计算 是不正确的)。
* 设置详细和明确的监控,如性能指标和错误率。 在其他工程学科中,这被称为遥测。 (一旦火箭离开了地面,遥测技术对于追踪发生的事情和理解失败是必不可少的。)监测可以向我们展示预警信号,并让我们检查是否有任何假设或限制是违反的。迟来。 发生问题时,度量标准对于诊断问题是非常有价值的。
* 实施良好的管理实践和培训 - 一个复杂而重要的方面,超出了本书的范围。
### 可靠性有多重要?
可靠性不仅仅针对核电站和空中交通管制软件,更多的普通应用也预计可靠运行。商业应用程序中的错误会导致生产力的损失(如果数据报告不完整,则会面临法律风险),而且电子商务网站的中断可能会导致收入损失和声誉受损。
即使在“非关键”应用中,我们也对用户负有责任。考虑一个父母,他们的所有照片和他们的孩子的视频存储在您的照片应用程序[15]。如果数据库突然被破坏,他们会感觉如何?他们会知道如何从备份恢复它?
在某些情况下,我们可能选择牺牲可靠性来降低开发成本(例如,为未经证实的市场开发原型产品)或运营成本(例如,利润率极低的服务),但是我们应该非常清楚我们什么时候偷工减料。
## 可扩展性
即使系统今天运行稳定但这并不意味着未来一定能够可靠运行。降级的一个常见原因是负载增加或许系统已经从10,000个并发用户增加到100000个并发用户或者从100万增加到1000万。也许正在处理的数据量比以前大得多。
可伸缩性Scalability是我们用来描述系统应对负载增加的能力的术语。但是请注意这不是我们可以附加到系统上的一维标签说“X可伸缩”或“Y不能缩放”是没有意义的。相反讨论可扩展性意味着考虑如“如果系统以特定方式增长我们有什么选择来应对增长”和“我们如何增加计算资源来处理额外的负载”等问题。
### 描述负载
首先我们需要简洁地描述系统的当前负载。只有这样我们才能讨论增长问题如果我们的负荷加倍会发生什么。负载可以用一些我们称之为负载参数的数字来描述。参数的最佳选择取决于系统的体系结构它可能是每秒向Web服务器发出的请求数据库中的读写比率聊天室中同时活动的用户数量缓存或其他东西。也许平均情况对你来说很重要或者你的瓶颈主要是少数极端情况。
为了使这个想法更加具体我们以2012年11月发布的数据[16]为例以Twitter为例。 Twitter的两个主要业务是
* 发布推文用户可以向其追随者发布新消息平均每秒4.6k个请求/秒峰值超过12k个请求/秒)。
* 主页时间线用户可以查看他们关注的人发布的推文300k请求/秒)。
简单地处理每秒12,000次写入发布推文的最高速率将是相当容易的。然而Twitter的扩张挑战并不是主要由于推特量而是由扇出fan-out从电子工程中借用的一个术语它描述了连接到另一个门输出的逻辑门输入的数量。 输出需要提供足够的电流来驱动所有连接的输入。 在事务处理系统中,我们使用它来描述为了服务一个传入请求而需要做的其他服务的请求数量。), 每个用户跟随很多人,每个用户跟着很多人。大致有两种方法来实现这两个操作:
1. 发布推文只需将新推文插入推文的全局集合即可。当用户请求他们的主页时间线时查找他们关注的所有人为每个用户查找所有推文并合并按时间排序。在如图1-2所示的关系数据库中可以编写如下查询
```sql
SELECT tweets.*, users.*
FROM tweets
JOIN users ON tweets.sender_id = users.id
JOIN follows ON follows.followee_id = users.id
WHERE follows.follower_id = current_user
```
为每个用户的主页时间线维护一个缓存例如每个收件人用户的推文信箱见图1-3。 当用户发布tweet时查找所有关注该用户的人并将新的tweet插入到每个主页时间线缓存中。 阅读主页时间表的请求便宜,因为其结果是提前计算的。
![](img/fig1-2.png)
**图1-2 推特主页时间线的关系型模式简单实现**
![](img/fig1-3.png)
**图1-2 用于分发推特至关注者的数据流水线带有负载参数2012年11月**
Twitter的第一个版本使用了方法1但系统努力跟上主页时间线查询的负载所以公司转向了方法2.这更好地发挥作用,因为发布的推文的平均比率几乎比主页时间线查询频率低了两个数量级,所以在这种情况下,最好在写入时间做更多的工作,而在读取时间做更少的工作。
然而方法2的缺点是发布推文现在需要大量的额外工作。平均来说一条推特被发送到约75个追随者所以每秒4.6k的推文变成主页时间线缓存每秒345k的写入。但是这个平均值隐藏了每个用户的关注者数量与一些用户差异很大的事实
有超过三千万的追随者。这意味着一个推特可能会导致超过3000万的写入时间表及时做到这一点 - Twitter试图在5秒内向粉丝发送推文 - 是一个重大的挑战。
在Twitter的例子中每个用户的关注者分布可能是这些用户发微博的频率是讨论可伸缩性的关键负载参数因为它决定了扇出负载。您的应用程序可能具有非常不同的特征但您可以应用相似的原则来推理其负载。
推特轶事的最后一个转折现在方法2 健壮的实施了Twitter正在转向两种方法的混合。大多数用户的推文在发布的时候仍然是在主页时间线上但是很少有粉丝即名人的用户被排除在外。用户可能关注的任何名人的推文都会单独提取并在阅读时与用户的家庭时间线合并如方法1所示。这种混合方法能够持续提供良好的性能。我们将在第12章重新讨论这个例子因为我们已经覆盖了更多的技术层面。
### 描述性能
一旦描述了系统的负载,就可以调查负载增加时发生的情况。你可以用两种方法来看它:
* 增加负载参数并保持系统资源CPU内存网络带宽等不变时系统性能如何受影响
* 当您增加一个负载参数时,如果要保持性能不变,您需要增加多少资源?
这两个问题都需要性能数字,所以让我们简单地看一下系统的性能。
在像Hadoop这样的批处理系统中我们通常关心吞吐量 - 每秒处理的记录数量,或者在一定数量的数据集上运行作业的总时间.(理想情况下,批量作业的运行时间是数据集的大小除以吞吐量。 在实践中,由于歪斜(数据不是均匀分布在工作进程中),而且需要等待最慢的任务完成,所以运行时间往往更长)在在线系统中,通常是什么更重要的是服务的响应时间 - 也就是客户端发送请求和接收响应之间的时间。
#### 延迟和响应时间
延迟Latency和响应时间Response Time通常用作同义词但它们并不相同。响应时间是**客户看到的**:除了处理请求的实际时间(服务时间)之外,还包括网络延迟和排队延迟。**延迟是一个请求等待处理的时间** - 在这个时间内,它是潜在的,等待服务[17]。
即使你只是一次又一次地提出相同的请求,每次尝试都会得到一个稍微不同的响应时间。实际上,在处理各种请求的系统中,响应时间可能会有很大差异。因此,我们需要将响应时间视为一个单一的数字,而不是一个可以衡量的价值分布。
在图1-4中每个灰色条表示对服务的请求其高度表示请求花了多长时间。大多数请求是相当快的但是偶尔出现的异常值需要更长的时间。也许缓慢的请求本质上更昂贵例如因为它们处理更多的数据。但是即使在你认为所有的请求都要花费同样的时间的情况下你也会得到一些变化上下文切换到后台进程可能引入随机的附加延迟网络数据包丢失和TCP重传垃圾收集暂停强制从磁盘读取的页面错误服务器机架[18]中的机械振动或许多其他原因。
![](img/fig1-4.png)
**图1-4 展示了一个服务100次请求响应时间的均值与百分位数**
通常看到报告的服务的平均响应时间。 严格地说“平均”一词并不是指任何特定的公式但实际上它通常被理解为算术平均值给定n 个值加起来所有的值除以n。然而平均值如果你想知道你的“典型”响应时间那么它不是一个很好的指标因为它不能告诉你有多少用户实际上经历了这个延迟。
通常使用百分比更好。如果将响应时间列表从最快到最慢排序那么中值是中间值例如如果您的中值响应时间是200毫秒这意味着一半请求的返回时间少于200毫秒一半你的要求比这个要长。
如果您想知道用户通常需要等待多长时间那么这使中间值成为一个好的度量标准用户请求的一半服务时间少于中间响应时间另一半服务时间比中间值长。中位数也被称为第50百分位有时缩写为p50。请注意中位数是指单个请求;如果用户提出了几个请求在一个会话过程中或者由于多个资源被包含在一个页面中至少其中一个请求比中间值慢的可能性远远大于50
为了弄清楚你的异常值有多糟糕你可以看看更高的百分位数第95,99和99.9百分位数是常见的缩写p95p99和p999。它们是9599或99.9的请求比特定阈值更快的响应时间阈值。例如如果第95百分位响应时间是1.5秒则意味着100个请求中的95个占用少于1.5秒并且100个请求中的5个占用1.5秒或更多。如图1-4所示。
响应时间的高百分比(也称为尾部延迟 Tail Percentil非常重要因为它们直接影响用户的服务体验。例如亚马逊描述了内部服务的响应时间要求**以百分之九十九为单位,即使只影响一千个请求中的一个**。这是因为要求最慢的客户往往是那些账户数据最多的客户,因为他们进行了大量的采购 - 也就是说,他们是最有价值的客户[19]。通过确保网站快速发展让客户满意是非常重要的亚马逊还观察到响应时间增加了100毫秒销售量减少了1[20]而另一些人则报告说1秒钟的减速会减少客户 - 收敛度为16[21,22]。
另一方面优化第99.99个百分点10000个请求中最慢的1个被认为太昂贵并且不能为亚马逊的目的带来足够的好处。以非常高的百分比来减少响应时间是困难的因为它们很容易受到您控制之外的随机事件的影响并且好处正在减少。
例如百分比通常用于服务级别目标SLO和服务级别协议SLA即定义服务的预期性能和可用性的合同。 SLA可能会声明如果服务的响应时间中位数小于200毫秒并且在1秒内响应时间较长如果响应时间较长则可能会下降则认为该服务已启动。可能需要至少99.9的时间。这些指标为服务客户设定了期望值并允许客户在SLA未达到的情况下要求退款。
排队延迟通常占高百分比响应时间的很大一部分。由于服务器只能并行处理少量的事务例如受其CPU核数量的限制所以只需要少量缓慢的请求来阻止后续请求的处理这种效果有时被称为头部阻塞。即使这些后续请求在服务器上快速处理由于等待事先请求完成的时间客户端将看到总体响应时间缓慢。由于这种影响测量客户端的响应时间非常重要。
当为了测试系统的可扩展性而人为地产生负载时,产生负载的客户端需要不受响应时间的影响而不断发送请求。如果客户端在发送下一个请求之前等待先前的请求完成,那么这种行为会在测试中人为地保持队列的长度,而不是在实际中保持队列的长度,这会影响测量结果[23]。
> #### 实践中的百分位点
>
> 在多重调用的后端服务里高百分位数变得特别重要。即使并行调用最终用户请求仍然需要等待最慢的并行呼叫完成。如图1-5所示只需要一个缓慢的呼叫就可以使整个最终用户请求变慢。即使只有一小部分后端呼叫速度较慢如果最终用户请求需要多个后端调用则获得较慢调用的机会也会增加因此较高比例的最终用户请求速度会变慢效果称为尾部延迟放大[24])。
>
> 如果您想将响应时间百分点添加到您的服务的监视仪表板则需要持续有效地计算它们。例如您可能希望在最近10分钟内保持请求响应时间的滚动窗口。每一分钟您都会计算出该窗口中的中值和各种百分数并将这些度量值绘制在图上。
>
> 简单的实现是在时间窗口内保存所有请求的响应时间列表并且每分钟对列表进行排序。如果对你来说效率太低那么有一些算法能够以最小的CPU和内存成本如正向衰减[25]t-digest [26]或HdrHistogram [27])来计算百分位数的近似值。请注意,平均百分比(例如,减少时间分辨率或合并来自多台机器的数据)在数学上没有意义 - 聚合响应时间数据的正确方法是添加直方图[28]。
![](img/fig1-5.png)
**图1-5 当一个请求需要多个后端请求时,单个慢后端请求就会拖慢整个终端用请求**
### 应对负荷的方法
现在我们已经讨论了用于描述测量性能的负载和度量的参数,我们可以开始认真讨论可伸缩性:即使当我们的负载参数增加一些时,我们如何保持良好的性能呢?
适合于一个级别的负载的体系结构不太可能应付10倍的负载。如果您正在开发一个快速增长的服务那么您可能需要重新考虑每个数量级负载增长的架构 - 或者甚至更多。
人们经常谈到 scale-up垂直扩展转向更强大的机器和scale-out水平扩展将负载分配到多个小型机器之间的矛盾。在多台机器上分配负载也称为“无共享(shared-nothing)”体系结构。可以在一台机器上运行的系统通常更简单,但是高端机器可能变得非常昂贵,所以非常密集的工作量通常无法避免向外扩展。实际上,优秀的体系结构通常包含一些实用的方法:例如,使用几个功能相当强大的机器可能比大量的小型虚拟机更简单,更便宜。
有些系统是弹性的这意味着他们可以在检测到负载增加时自动添加计算资源而其他系统则是手动扩展人工分析容量并决定向系统添加更多计算机。如果负载高度不可预测则弹性系统可能非常有用但手动缩放系统更简单并且可能具有更少的操作意外请参阅“重新平衡分区”第195页
在多台机器上分发无状态服务非常简单,从单一节点到分布式设置的状态数据系统可能会带来很多额外的复杂性。出于这个原因,直到最近,人们普遍认为将数据库保持在单个节点上(扩展),直到缩放成本或高可用性要求迫使您将其改为分布式的。
随着分布式系统的工具和抽象变得越来越好,这种常识可能会改变,至少对于某些类型的应用来说。可以想象,分布式数据系统将成为未来的默认设置,即使对于不处理大量数据或流量的用例也是如此。在本书的其余部分中,我们将介绍多种分布式数据系统,并讨论它们不仅在可伸缩性方面的表现,还包括易用性和可维护性。
大规模运行的系统体系结构通常对应用程序具有高度的特定性 - 没有像通用的一刀切的可扩展体系结构非正式地称为魔力缩放magic scaling sauce )这样的事物。问题可能是读取量,写入量,要存储的数据量,数据的复杂程度,响应时间要求,访问模式,或者(通常)所有这些的混合物以及更多的问题。
例如设计用于处理每秒100,000个请求每个大小为1 kB的系统与为每分钟3个请求每个大小为2 GB设计的系统看起来非常不同即使两个系统的大小相同数据吞吐量。
一个适合特定应用的体系结构是围绕着哪些操作是常见的,哪些是负载参数是罕见的。如果这些假设结果是错误的,那么缩放的工程努力至多是浪费的,最糟糕的是适得其反。在早期阶段的初创公司或非正式的产品中,能够快速迭代产品特征比扩展到假设的未来负载更重要。
尽管它们是特定于特定应用程序的,但可扩展架构通常是从通用构建模块构建而成,并以熟悉的模式排列。在本书中,我们将讨论这些构件和模式。
## 可维护性
众所周知,软件的大部分成本并没不在最初的开发阶段,而是在于持续的维护修复漏洞:保持系统正常运行,调查故障,适应新的平台,修改新的用例,偿还技术债务,增加新的功能。
然而不幸的是,许多从事软件系统工作的人不喜欢维护所谓的遗留系统 - 也许涉及修复其他人的错误或处理已经过时的平台,或者被迫做从未有意为之的系统。每一个遗留系统都是以自己的方式让人不爽,所以很难给出一个一般的建议来处理它们。
但是,我们可以也应该设计软件,以便在维护期间尽可能减少痛苦,从而避免自己创建传统软件。为此,我们将特别关注软件系统的三个设计原则:
* 可操作性
方便运营团队保持系统平稳运行。
* 简单
通过从系统中消除尽可能多的复杂性,使新工程师能够轻松理解系统。 (注意这与用户界面的简单性不一样。)
可进化
使工程师能够轻松地对将来的系统进行更改,并根据需求变化将其适用于意外的用例。也被称为可扩展性,可修改性或可塑性。
正如以前的可靠性和可扩展性一样,实现这些目标也没有简单的解决方案。相反,我们会考虑可操作性,简单性和可演化性的系统。
### 可操作性:关爱运维
有人认为,“良好的运维经常可以解决不好的(或不完整的)软件的局限性,再好的系统也架不住垃圾运维。尽管运维的某些方面可以而且应该是自动化的,但首先要确保自动化的正确性,然后由人来完成。
运维团队对于保持软件系统顺利运行至关重要。一个优秀的运维团队通常负责以下内容,以及更多[29]
* 监控系统的运行状况,并在服务状况不佳时快速恢复服务
* 追踪问题的原因,例如系统故障或性能下降
* 保持软件和平台保持最新状态,包括安全补丁
* 了解不同的系统如何相互影响,以便在造成损害之前避免有问题的更改
* 预测未来的问题并在问题出现之前加以解决(例如扩容计划)
* 建立部署,配置管理等方面的良好实践和工具
* 执行复杂的维护任务,例如将应用程序从一个平台移动到另一个平台
* 随着配置更改,维护系统的安全性
* 定义使操作可预测的流程,并帮助保持生产环境稳定
* 保持组织对系统的了解,即使是个人来来去去
良好的可操作性意味着使日常工作变得简单,使运营团队能够专注于高价值的活动。数据系统可以做各种事情,使日常任务变得简单,包括:
* 提供对系统的运行时行为和内部的可视性,并具有良好的监控能力
* 为自动化和与标准工具的集成提供良好的支持
* 避免依赖个别机器(在整个系统继续不间断运行的情况下允许机器停机维护)
* 提供良好的文档和易于理解的操作模型“如果我做XY会发生”
* 提供良好的默认行为,还可以让管理员在需要时自由覆盖默认值
* 在适当的情况下进行自我修复,并在需要时让管理员手动控制系统状态
* 展现可预见的行为,最大限度地减少惊喜
### 简单性:管理复杂性
小型软件项目可以有简单而富有表现力的代码,但随着项目越来越大,它们往往变得非常复杂,难以理解。这种复杂性拖慢了每个需要在系统上工作的人员,进一步增加了维护成本。一个陷入复杂的软件项目有时被描述为一个大泥潭[30]。
复杂性有各种可能的症状:状态空间的爆炸,模块的紧密耦合,纠结的依赖关系,不一致的命名和术语,旨在解决性能问题的黑客攻击,解决其他问题的特殊框架等等。已经有很多关于这个话题的说法[31,32,33]。
当复杂性使维护困难时,预算和时间安排通常会超支。在复杂的软件中,当发生变化时,引入错误的风险也更大:系统开发人员难以理解和推理时,隐藏的假设,意想不到的后果和意外的交互更容易被忽略。相反,降低复杂性大大提高了软件的可维护性,因此简单性应该是我们构建系统的关键目标。
简化系统并不一定意味着减少其功能;它也意味着消除意外的复杂性。 Moseley和Marks [32]把复杂性定义为偶然的,如果软件解决的问题不是固有的(用户看到的),而只是由实现产生的。
我们用来消除意外复杂性的最好工具之一是抽象。一个好的抽象可以隐藏大量的实现细节在一个干净,简单易懂的外观背后。一个好的抽象也可以用于各种不同的应用程序。这不仅是重复使用效率比多次重复实现类似的东西更高效,而且还会导致更高质量的软件,因为抽象组件中的质量改进将有利于所有使用它的应用程序。
例如高级编程语言是隐藏机器代码CPU寄存器和系统调用的抽象。 SQL是隐藏复杂的磁盘和内存数据结构
来自其他客户端的并发请求以及崩溃之后的不一致的抽象。当然,在用高级语言编程时,我们仍然使用机器码;我们只是不直接使用它,因为编程语言抽象使我们不必考虑它。
但是,找到好的抽象是非常困难的。在分布式系统领域,虽然有许多好的算法,但是我们应该如何将它们打包成抽象,这样就不那么清楚了,这些抽象可以帮助我们将系统的复杂性保持在可管理的水平。
在整本书中,我们将继续睁大眼睛来看好抽象,从而使我们能够将大型系统的一部分抽象成定义明确,可重用的组件。
### 可演化性:易于改变
你的系统的需求不会永远保持不变。他们更有可能处于不断变化的状态:您学习新的事实,之前出现意想不到的用例,业务优先级发生变化,用户请求新功能,新平台取代旧平台,法律或监管要求发生变化,系统增长强迫架构发生变化等
在组织流程方面敏捷工作模式为适应变化提供了一个框架。敏捷社区还开发了技术工具和模式这些工具和模式在频繁变化的环境中开发软件时很有帮助如测试驱动开发TDD和重构。
这些敏捷技术的大部分讨论都集中在相当小的本地规模同一个应用程序中的源代码文件。在本书中我们将探索在更大的数据系统层面上提高敏捷性的方法可能由几个不同特性的应用程序或服务组成。例如您将如何“重构”Twitter的架构来将Home Time从方法1重构为方法2
您可以轻松修改数据系统并使其适应不断变化的需求,这与其简单性和抽象性密切相关:简单易懂的系统通常比复杂系统更容易修改。但是由于这是一个非常重要的想法,我们将用一个不同的词来指代数据系统层面的敏捷性:可进化性[34]。
## 本章小结
在本章中,我们探讨了一些关于数据密集型应用程序的基本思路。这些原则将指导我们阅读本书的其余部分,在这里我们深入技术细节。
一个应用程序必须满足各种要求才能有用。有一些功能需求(它应该做什么,比如允许以各种方式存储,检索,搜索和处理数据)以及一些非功能性需求(一般属性如安全性,可靠性,合规性,可伸缩性,兼容性和可维护性)。在本章中,我们详细讨论了可靠性,可扩展性和可维护性。
**可靠性**意味着即使发生故障,也能使系统正常工作。故障可以是硬件(通常是随机的和不相关的),软件(缺陷通常是系统的,难以处理的),以及人类(不可避免地会不时出错)。容错技术可以隐藏最终用户的某些类型的故障。
**可扩展性**意味着即使在负载增加的情况下也有保持性能的策略。为了讨论可扩展性我们首先需要定量描述负载和性能的方法。我们简单地将Twitter的家庭时间表作为描述负载的一个例子并将响应时间百分比作为衡量每个时间段的一种方式。在可扩展的系统中您可以添加处理能力以在高负载下保持可靠。
**可维护性**有许多方面,但实质上是为需要使用该系统的工程和运营团队提供更好的生活。良好的抽象可以帮助降低复杂性,并使系统更易于修改和适应新的用例。良好的可操作性意味着对系统的健康具有良好的可见性,并具有有效的管理方式。
不幸的是,为了使应用程序可靠,可扩展或可持续,并不容易。但是,某些模式和技术会不断出现在不同的应用程序中。在接下来的几章中,我们将看看数据系统的一些例子,并分析它们如何实现这些目标。
在本书后面的第三部分中我们将看看由几个组件组成的系统的模式比如图1-1中的组件。
## 参考文献
[1]: http://citeseerx.ist.psu.edu/viewdoc/download?doi=10.1.1.68.9136&rep=rep1&type=pdf "Michael Stonebraker and Uğur Çetintemel: “'One Size Fits All': An Idea Whose Time Has Come and Gone,” at *21st International Conference on Data Engineering* (ICDE), April 2005."
[2]: http://www.sei.cmu.edu/reports/92tr033.pdf "Walter L. Heimerdinger and Charles B. Weinstock: “A Conceptual Framework for System Fault Tolerance,” Technical Report CMU/SEI-92-TR-033, Software Engineering Institute, Carnegie Mellon University, October 1992."
[3]: https://www.usenix.org/system/files/conference/osdi14/osdi14-paper-yuan.pdf "Ding Yuan, Yu Luo, Xin Zhuang, et al.: “Simple Testing Can Prevent Most Critical Failures: An Analysis of Production Failures in Distributed Data-Intensive Systems,” at 11th USENIX Symposium on Operating Systems Design and Implementation (OSDI), October 2014."
[4]: http://techblog.netflix.com/2011/07/netflix-simian-army.html "Yury Izrailevsky and Ariel Tseitlin: “The Netflix Simian Army,” techblog.netflix.com, July 19, 2011."
1. Walter L. Heimerdinger and Charles B. Weinstock:
“[A Conceptual Framework for System Fault Tolerance](http://www.sei.cmu.edu/reports/92tr033.pdf),” Technical Report CMU/SEI-92-TR-033, Software Engineering Institute, Carnegie
Mellon University, October 1992.
2. Ding Yuan, Yu Luo, Xin Zhuang, et al.:
“[Simple Testing Can Prevent Most Critical Failures: An Analysis of Production Failures in Distributed Data-Intensive Systems](https://www.usenix.org/system/files/conference/osdi14/osdi14-paper-yuan.pdf),” at *11th USENIX Symposium on Operating Systems Design
and Implementation* (OSDI), October 2014.
3. Yury Izrailevsky and Ariel Tseitlin:
“[The Netflix Simian Army](http://techblog.netflix.com/2011/07/netflix-simian-army.html),”
*techblog.netflix.com*, July 19, 2011.
4. Daniel Ford, François Labelle, Florentina I. Popovici, et al.:
“[Availability in Globally Distributed Storage Systems](http://research.google.com/pubs/archive/36737.pdf),”
at *9th USENIX Symposium on Operating Systems Design and Implementation* (OSDI),
October 2010.
5. Brian Beach:
“[Hard Drive Reliability Update Sep 2014](https://www.backblaze.com/blog/hard-drive-reliability-update-september-2014/),” *backblaze.com*, September 23, 2014.
6. Laurie Voss:
“[AWS: The Good, the Bad and the Ugly](https://web.archive.org/web/20160429075023/http://blog.awe.sm/2012/12/18/aws-the-good-the-bad-and-the-ugly/),” *blog.awe.sm*, December 18, 2012.
7. Haryadi S. Gunawi, Mingzhe Hao, Tanakorn
Leesatapornwongsa, et al.: “[What Bugs Live in the Cloud?](http://ucare.cs.uchicago.edu/pdf/socc14-cbs.pdf),” at *5th ACM Symposium on Cloud Computing* (SoCC), November 2014.
[doi:10.1145/2670979.2670986](http://dx.doi.org/10.1145/2670979.2670986)
8. Nelson Minar:
“[Leap Second Crashes Half the Internet](http://www.somebits.com/weblog/tech/bad/leap-second-2012.html),” *somebits.com*, July 3, 2012.
9. Amazon Web Services:
“[Summary of the Amazon EC2 and Amazon RDS Service Disruption in the US East Region](http://aws.amazon.com/message/65648/),” *aws.amazon.com*, April 29, 2011.
10. Richard I. Cook:
“[How Complex Systems Fail](http://web.mit.edu/2.75/resources/random/How%20Complex%20Systems%20Fail.pdf),” Cognitive Technologies Laboratory, April 2000.
11. Jay Kreps:
“[Getting Real About Distributed System Reliability](http://blog.empathybox.com/post/19574936361/getting-real-about-distributed-system-reliability),” *blog.empathybox.com*, March 19, 2012.
12. David Oppenheimer, Archana Ganapathi, and David A. Patterson:
“[Why Do Internet Services Fail, and What Can Be Done About It?](http://static.usenix.org/legacy/events/usits03/tech/full_papers/oppenheimer/oppenheimer.pdf),” at *4th USENIX Symposium on
Internet Technologies and Systems* (USITS), March 2003.
13. Nathan Marz:
“[Principles of Software Engineering, Part 1](http://nathanmarz.com/blog/principles-of-software-engineering-part-1.html),” *nathanmarz.com*, April 2, 2013.
14. Michael Jurewitz:
“[The Human Impact of Bugs](http://jury.me/blog/2013/3/14/the-human-impact-of-bugs),”
*jury.me*, March 15, 2013.
15. Raffi Krikorian:
“[Timelines at Scale](http://www.infoq.com/presentations/Twitter-Timeline-Scalability),”
at *QCon San Francisco*, November 2012.
16. Martin Fowler:
*Patterns of Enterprise Application Architecture*. Addison Wesley, 2002.
ISBN: 978-0-321-12742-6
17. Kelly Sommers:
“[After all that run around, what caused 500ms disk latency even when we replaced physical server?](https://twitter.com/kellabyte/status/532930540777635840)” *twitter.com*, November 13, 2014.
18. Giuseppe DeCandia, Deniz Hastorun, Madan Jampani, et al.:
“[Dynamo: Amazon's Highly Available Key-Value Store](http://www.allthingsdistributed.com/files/amazon-dynamo-sosp2007.pdf),” at *21st ACM Symposium on Operating
Systems Principles* (SOSP), October 2007.
19. Greg Linden:
“[Make Data Useful](http://glinden.blogspot.co.uk/2006/12/slides-from-my-talk-at-stanford.html),” slides from presentation at Stanford University Data Mining class (CS345), December 2006.
20. Tammy Everts:
“[The Real Cost of Slow Time vs Downtime](http://www.webperformancetoday.com/2014/11/12/real-cost-slow-time-vs-downtime-slides/),” *webperformancetoday.com*, November 12, 2014.
21. Jake Brutlag:
“[Speed Matters for Google Web Search](http://googleresearch.blogspot.co.uk/2009/06/speed-matters.html),” *googleresearch.blogspot.co.uk*, June 22, 2009.
22. Tyler Treat:
“[Everything You Know About Latency Is Wrong](http://bravenewgeek.com/everything-you-know-about-latency-is-wrong/),” *bravenewgeek.com*, December 12, 2015.
23. Jeffrey Dean and Luiz André Barroso:
“[The Tail at Scale](http://cacm.acm.org/magazines/2013/2/160173-the-tail-at-scale/fulltext),”
*Communications of the ACM*, volume 56, number 2, pages 7480, February 2013.
[doi:10.1145/2408776.2408794](http://dx.doi.org/10.1145/2408776.2408794)
24. Graham Cormode, Vladislav
Shkapenyuk, Divesh Srivastava, and Bojian Xu:
“[Forward Decay: A Practical Time Decay Model for Streaming Systems](http://dimacs.rutgers.edu/~graham/pubs/papers/fwddecay.pdf),” at *25th IEEE International Conference on Data
Engineering* (ICDE), March 2009.
25. Ted Dunning and Otmar Ertl:
“[Computing Extremely Accurate Quantiles Using t-Digests](https://github.com/tdunning/t-digest),” *github.com*, March 2014.
26. Gil Tene:
“[HdrHistogram](http://www.hdrhistogram.org/),” *hdrhistogram.org*.
27. Baron Schwartz:
“[Why Percentiles Dont Work the Way You Think](https://www.vividcortex.com/blog/why-percentiles-dont-work-the-way-you-think),” *vividcortex.com*, December 7, 2015.
28. James Hamilton:
“[On Designing and Deploying Internet-Scale Services](https://www.usenix.org/legacy/events/lisa07/tech/full_papers/hamilton/hamilton.pdf),” at *21st Large Installation
System Administration Conference* (LISA), November 2007.
29. Brian Foote and Joseph Yoder:
“[Big Ball of Mud](http://www.laputan.org/pub/foote/mud.pdf),” at
*4th Conference on Pattern Languages of Programs* (PLoP),
September 1997.
30. Frederick P Brooks: “No Silver Bullet Essence and
Accident in Software Engineering,” in *The Mythical Man-Month*, Anniversary
edition, Addison-Wesley, 1995. ISBN: 978-0-201-83595-3
31. Ben Moseley and Peter Marks:
“[Out of the Tar Pit](http://citeseerx.ist.psu.edu/viewdoc/summary?doi=10.1.1.93.8928),”
at *BCS Software Practice Advancement* (SPA), 2006.
32. Rich Hickey:
“[Simple Made Easy](http://www.infoq.com/presentations/Simple-Made-Easy),”
at *Strange Loop*, September 2011.
33. Hongyu Pei Breivold, Ivica Crnkovic, and Peter J. Eriksson:
“[Analyzing Software Evolvability](http://www.mrtc.mdh.se/publications/1478.pdf),”
at *32nd Annual IEEE International Computer Software and Applications Conference*
(COMPSAC), July 2008.
[doi:10.1109/COMPSAC.2008.50](http://dx.doi.org/10.1109/COMPSAC.2008.50)

362
ddia/ch10.md Normal file
View File

@ -0,0 +1,362 @@
# 10. 批处理
![](img/ch10.png)
带有太强个人色彩的系统无法成功。当第一版健壮的设计完成时,真正的考验才开始:许多不同观点的人会以他们自己的方式来测试。
——高德纳
---------------
[TOC]
## 使用Unix工具的批处理
### 分析简单日志
### Unix哲学
## MapReduce和分布式文件系统
### MapReduce任务执行
![](img/fig10-1.png)
**图10-1 具有三个Mapper和三个Reducer的MapReduce任务**
### Reduce端连接与分组
![](img/fig10-2.png)
**图10-2 用户行为日志与用户档案的连接**
### Map端连接
![](img/fig10-3.png)
**图10-3 Reduce端在user ID上进行归并排序连接如果输入数据集分片成多个文件则每个都会被多个Mapper并行处理**
### 工作流的输出
## 后MapReduce时代
### 内部状态表示
### 图与迭代处理
### 高级API和语言
## 本章小结
## 参考文献
1. Jeffrey Dean and Sanjay Ghemawat:
“[MapReduce: Simplified Data Processing on Large Clusters](http://research.google.com/archive/mapreduce.html),” at *6th USENIX Symposium on Operating System Design
and Implementation* (OSDI), December 2004.
1. Joel Spolsky:
“[The Perils of JavaSchools](http://www.joelonsoftware.com/articles/ThePerilsofJavaSchools.html),” *joelonsoftware.com*, December 25, 2005.
1. Shivnath Babu and Herodotos Herodotou:
“[Massively Parallel Databases and MapReduce Systems](http://research.microsoft.com/pubs/206464/db-mr-survey-final.pdf),” *Foundations and Trends in Databases*,
volume 5, number 1, pages 1104, November 2013.
[doi:10.1561/1900000036](http://dx.doi.org/10.1561/1900000036)
1. David J. DeWitt and Michael Stonebraker:
“[MapReduce: A Major Step Backwards](https://homes.cs.washington.edu/~billhowe/mapreduce_a_major_step_backwards.html),” originally published at *databasecolumn.vertica.com*, January 17, 2008.
1. Henry Robinson:
“[The Elephant Was a Trojan Horse: On the Death of Map-Reduce at Google](http://the-paper-trail.org/blog/the-elephant-was-a-trojan-horse-on-the-death-of-map-reduce-at-google/),”
*the-paper-trail.org*, June 25, 2014.
1. “[The Hollerith Machine](https://www.census.gov/history/www/innovations/technology/the_hollerith_tabulator.html),” United States Census Bureau, *census.gov*.
1. “[IBM 82, 83, and 84 Sorters Reference Manual](http://www.textfiles.com/bitsavers/pdf/ibm/punchedCard/Sorter/A24-1034-1_82-83-84_sorters.pdf),” Edition A24-1034-1, International Business
Machines Corporation, July 1962.
1. Adam Drake:
“[Command-Line Tools Can Be 235x Faster than Your Hadoop Cluster](http://aadrake.com/command-line-tools-can-be-235x-faster-than-your-hadoop-cluster.html),” *aadrake.com*, January 25, 2014.
1. “[GNU Coreutils 8.23 Documentation](http://www.gnu.org/software/coreutils/manual/html_node/index.html),” Free Software Foundation, Inc., 2014.
1. Martin Kleppmann:
“[Kafka, Samza, and the Unix Philosophy of Distributed Data](http://martin.kleppmann.com/2015/08/05/kafka-samza-unix-philosophy-distributed-data.html),” *martin.kleppmann.com*, August 5, 2015.
1. Doug McIlroy:
[Internal Bell Labs memo](http://cm.bell-labs.com/cm/cs/who/dmr/mdmpipe.pdf),
October 1964. Cited in: Dennis M. Richie:
“[Advice from Doug McIlroy](https://www.bell-labs.com/usr/dmr/www/mdmpipe.html),”
*cm.bell-labs.com*.
1. M. D. McIlroy, E. N. Pinson, and B. A. Tague:
“[UNIX Time-Sharing System: Foreword](https://archive.org/details/bstj57-6-1899),”
*The Bell System Technical Journal*, volume 57, number 6, pages 18991904,
July 1978.
1. Eric S. Raymond:
<a href="http://www.catb.org/~esr/writings/taoup/html/">*The Art of UNIX Programming*</a>.
Addison-Wesley, 2003. ISBN: 978-0-13-142901-7
1. Ronald Duncan:
“[Text File Formats ASCII Delimited Text Not CSV or TAB Delimited Text](https://ronaldduncan.wordpress.com/2009/10/31/text-file-formats-ascii-delimited-text-not-csv-or-tab-delimited-text/),”
*ronaldduncan.wordpress.com*, October 31, 2009.
1. Alan Kay:
“[Is 'Software Engineering' an Oxymoron?](http://tinlizzie.org/~takashi/IsSoftwareEngineeringAnOxymoron.pdf),” *tinlizzie.org*.
1. Martin Fowler:
“[InversionOfControl](http://martinfowler.com/bliki/InversionOfControl.html),”
*martinfowler.com*, June 26, 2005.
1. Daniel J. Bernstein:
“[Two File Descriptors for Sockets](http://cr.yp.to/tcpip/twofd.html),” *cr.yp.to*.
1. Rob Pike and Dennis M. Ritchie:
“[The Styx Architecture for Distributed Systems](http://doc.cat-v.org/inferno/4th_edition/styx),” *Bell Labs Technical Journal*, volume 4, number 2, pages
146152, April 1999.
1. Sanjay Ghemawat, Howard Gobioff, and Shun-Tak
Leung: “[The Google File System](http://research.google.com/archive/gfs-sosp2003.pdf),”
at *19th ACM Symposium on Operating Systems Principles* (SOSP), October 2003.
[doi:10.1145/945445.945450](http://dx.doi.org/10.1145/945445.945450)
1. Michael Ovsiannikov, Silvius Rus, Damian Reeves, et al.:
“[The Quantcast File System](http://db.disi.unitn.eu/pages/VLDBProgram/pdf/industry/p808-ovsiannikov.pdf),” *Proceedings of the VLDB Endowment*, volume 6, number 11, pages 10921101, August 2013.
[doi:10.14778/2536222.2536234](http://dx.doi.org/10.14778/2536222.2536234)
1. “[OpenStack Swift 2.6.1 Developer Documentation](http://docs.openstack.org/developer/swift/),” OpenStack Foundation, *docs.openstack.org*, March 2016.
1. Zhe Zhang, Andrew Wang, Kai Zheng, et al.:
“[Introduction to HDFS Erasure Coding in Apache Hadoop](http://blog.cloudera.com/blog/2015/09/introduction-to-hdfs-erasure-coding-in-apache-hadoop/),” *blog.cloudera.com*, September 23, 2015.
1. Peter Cnudde:
“[Hadoop Turns 10](http://yahoohadoop.tumblr.com/post/138739227316/hadoop-turns-10),”
*yahoohadoop.tumblr.com*, February 5, 2016.
1. Eric Baldeschwieler:
“[Thinking About the HDFS vs. Other Storage Technologies](http://hortonworks.com/blog/thinking-about-the-hdfs-vs-other-storage-technologies/),” *hortonworks.com*, July 25, 2012.
1. Brendan Gregg:
“[Manta: Unix Meets Map Reduce](http://dtrace.org/blogs/brendan/2013/06/25/manta-unix-meets-map-reduce/),” *dtrace.org*, June 25, 2013.
1. Tom White: *Hadoop: The Definitive Guide*,
4th edition. O'Reilly Media, 2015. ISBN: 978-1-491-90163-2
1. Jim N. Gray:
“[Distributed Computing Economics](http://arxiv.org/pdf/cs/0403019.pdf),” Microsoft
Research Tech Report MSR-TR-2003-24, March 2003.
1. Márton Trencséni:
“[Luigi vs Airflow vs Pinball](http://bytepawn.com/luigi-airflow-pinball.html),”
*bytepawn.com*, February 6, 2016.
1. Roshan Sumbaly, Jay Kreps, and Sam Shah:
“[The 'Big Data' Ecosystem at LinkedIn](http://www.slideshare.net/s_shah/the-big-data-ecosystem-at-linkedin-23512853),” at *ACM International Conference on Management of Data*
(SIGMOD), July 2013.
[doi:10.1145/2463676.2463707](http://dx.doi.org/10.1145/2463676.2463707)
1. Alan F. Gates, Olga Natkovich, Shubham Chopra, et al.:
“[Building a High-Level Dataflow System on Top of Map-Reduce: The Pig Experience](http://www.vldb.org/pvldb/2/vldb09-1074.pdf),” at *35th International Conference on Very Large Data
Bases* (VLDB), August 2009.
1. Ashish Thusoo, Joydeep Sen Sarma, Namit Jain, et al.:
“[Hive A Petabyte Scale Data Warehouse Using Hadoop](http://i.stanford.edu/~ragho/hive-icde2010.pdf),” at *26th IEEE International Conference on Data Engineering* (ICDE), March 2010.
[doi:10.1109/ICDE.2010.5447738](http://dx.doi.org/10.1109/ICDE.2010.5447738)
1. “[Cascading 3.0 User Guide](http://docs.cascading.org/cascading/3.0/userguide/),” Concurrent, Inc., *docs.cascading.org*, January 2016.
1. “[Apache Crunch User Guide](https://crunch.apache.org/user-guide.html),” Apache Software Foundation, *crunch.apache.org*.
1. Craig Chambers, Ashish Raniwala, Frances
Perry, et al.: “[FlumeJava: Easy, Efficient Data-Parallel Pipelines](https://research.google.com/pubs/archive/35650.pdf),” at *31st ACM SIGPLAN Conference on Programming Language
Design and Implementation* (PLDI), June 2010.
[doi:10.1145/1806596.1806638](http://dx.doi.org/10.1145/1806596.1806638)
1. Jay Kreps:
“[Why Local State is a Fundamental Primitive in Stream Processing](https://www.oreilly.com/ideas/why-local-state-is-a-fundamental-primitive-in-stream-processing),” *oreilly.com*, July 31, 2014.
1. Martin Kleppmann:
“[Rethinking Caching in Web Apps](http://martin.kleppmann.com/2012/10/01/rethinking-caching-in-web-apps.html),” *martin.kleppmann.com*, October 1, 2012.
1. Mark Grover, Ted Malaska, Jonathan
Seidman, and Gwen Shapira: *[Hadoop Application Architectures](http://shop.oreilly.com/product/0636920033196.do)*. O'Reilly Media, 2015. ISBN: 978-1-491-90004-8
1. Philippe Ajoux, Nathan Bronson,
Sanjeev Kumar, et al.:
“[Challenges to Adopting Stronger Consistency at Scale](https://www.usenix.org/system/files/conference/hotos15/hotos15-paper-ajoux.pdf),” at *15th USENIX Workshop on Hot Topics in
Operating Systems* (HotOS), May 2015.
1. Sriranjan Manjunath:
“[Skewed Join](https://wiki.apache.org/pig/PigSkewedJoinSpec),” *wiki.apache.org*,
2009.
1. David J. DeWitt, Jeffrey F. Naughton, Donovan A.
Schneider, and S. Seshadri: “[Practical Skew Handling in Parallel Joins](http://www.vldb.org/conf/1992/P027.PDF),” at *18th International Conference on Very Large Data Bases* (VLDB), August 1992.
1. Marcel Kornacker, Alexander Behm, Victor
Bittorf, et al.: “[Impala: A Modern, Open-Source SQL Engine for Hadoop](http://pandis.net/resources/cidr15impala.pdf),” at *7th Biennial Conference on Innovative Data Systems
Research* (CIDR), January 2015.
1. Matthieu Monsch:
“[Open-Sourcing PalDB, a Lightweight Companion for Storing Side Data](https://engineering.linkedin.com/blog/2015/10/open-sourcing-paldb--a-lightweight-companion-for-storing-side-da),” *engineering.linkedin.com*, October 26, 2015.
1. Daniel Peng and Frank Dabek:
“[Large-Scale Incremental Processing Using Distributed Transactions and Notifications](https://www.usenix.org/legacy/event/osdi10/tech/full_papers/Peng.pdf),” at *9th USENIX
conference on Operating Systems Design and Implementation* (OSDI), October 2010.
1. “["Cloudera Search User Guide,"](http://www.cloudera.com/documentation/cdh/5-1-x/Search/Cloudera-Search-User-Guide/Cloudera-Search-User-Guide.html) Cloudera, Inc., September 2015.
1. Lili Wu, Sam Shah, Sean Choi, et al.:
“[The Browsemaps: Collaborative Filtering at LinkedIn](http://ls13-www.cs.uni-dortmund.de/homepage/rsweb2014/papers/rsweb2014_submission_3.pdf),” at *6th Workshop on Recommender Systems and
the Social Web* (RSWeb), October 2014.
1. Roshan Sumbaly, Jay Kreps, Lei Gao, et al.:
“[Serving Large-Scale Batch Computed Data with Project Voldemort](http://static.usenix.org/events/fast12/tech/full_papers/Sumbaly.pdf),” at *10th USENIX Conference on File and Storage
Technologies* (FAST), February 2012.
1. Varun Sharma:
“[Open-Sourcing Terrapin: A Serving System for Batch Generated Data](https://engineering.pinterest.com/blog/open-sourcing-terrapin-serving-system-batch-generated-data-0),” *engineering.pinterest.com*, September 14, 2015.
1. Nathan Marz:
“[ElephantDB](http://www.slideshare.net/nathanmarz/elephantdb),” *slideshare.net*, May 30, 2011.
1. Jean-Daniel (JD) Cryans:
“[How-to: Use HBase Bulk Loading, and Why](http://blog.cloudera.com/blog/2013/09/how-to-use-hbase-bulk-loading-and-why/),” *blog.cloudera.com*, September 27, 2013.
1. Nathan Marz:
“[How to Beat the CAP Theorem](http://nathanmarz.com/blog/how-to-beat-the-cap-theorem.html),” *nathanmarz.com*, October 13, 2011.
1. Molly Bartlett Dishman and Martin Fowler:
“[Agile Architecture](http://conferences.oreilly.com/software-architecture/sa2015/public/schedule/detail/40388),” at *O'Reilly Software Architecture Conference*, March 2015.
1. David J. DeWitt and Jim N. Gray:
“[Parallel Database Systems: The Future of High Performance Database Systems](http://www.cs.cmu.edu/~pavlo/courses/fall2013/static/papers/dewittgray92.pdf),”
*Communications of the ACM*, volume 35, number 6, pages 8598, June 1992.
[doi:10.1145/129888.129894](http://dx.doi.org/10.1145/129888.129894)
1. Jay Kreps:
“[But the multi-tenancy thing is actually really really hard](https://twitter.com/jaykreps/status/528235702480142336),” tweetstorm, *twitter.com*, October 31, 2014.
1. Jeffrey Cohen, Brian Dolan, Mark Dunlap, et al.: “[MAD Skills: New Analysis Practices for Big Data](http://www.vldb.org/pvldb/2/vldb09-219.pdf),” *Proceedings of the VLDB Endowment*, volume 2, number
2, pages 14811492, August 2009.
[doi:10.14778/1687553.1687576](http://dx.doi.org/10.14778/1687553.1687576)
1. Ignacio
Terrizzano, Peter Schwarz, Mary Roth, and John E. Colino:
“[Data Wrangling: The Challenging Journey from the Wild to the Lake](http://cidrdb.org/cidr2015/Papers/CIDR15_Paper2.pdf),” at *7th Biennial Conference on Innovative Data Systems
Research* (CIDR), January 2015.
1. Paige Roberts:
“[To Schema on Read or to Schema on Write, That Is the Hadoop Data Lake Question](http://adaptivesystemsinc.com/blog/to-schema-on-read-or-to-schema-on-write-that-is-the-hadoop-data-lake-question/),” *adaptivesystemsinc.com*, July 2, 2015.
1. Bobby Johnson and Joseph Adler:
“[The Sushi Principle: Raw Data Is Better](https://vimeo.com/123985284),” at
*Strata+Hadoop World*, February 2015.
1. Vinod Kumar Vavilapalli, Arun C. Murthy, Chris Douglas, et al.:
“[Apache Hadoop YARN: Yet Another Resource Negotiator](http://www.socc2013.org/home/program/a5-vavilapalli.pdf),” at *4th ACM Symposium on Cloud Computing* (SoCC), October 2013.
[doi:10.1145/2523616.2523633](http://dx.doi.org/10.1145/2523616.2523633)
1. Abhishek Verma, Luis Pedrosa, Madhukar Korupolu, et al.:
“[Large-Scale Cluster Management at Google with Borg](http://research.google.com/pubs/pub43438.html),” at *10th European Conference on Computer Systems* (EuroSys), April 2015.
[doi:10.1145/2741948.2741964](http://dx.doi.org/10.1145/2741948.2741964)
1. Malte Schwarzkopf:
“[The Evolution of Cluster Scheduler Architectures](http://www.firmament.io/blog/scheduler-architectures.html),” *firmament.io*, March 9, 2016.
1. Matei Zaharia, Mosharaf Chowdhury, Tathagata Das, et al.:
“[Resilient Distributed Datasets: A Fault-Tolerant Abstraction for In-Memory Cluster Computing](https://www.usenix.org/system/files/conference/nsdi12/nsdi12-final138.pdf),” at *9th
USENIX Symposium on Networked Systems Design and Implementation* (NSDI), April 2012.
1. Holden Karau, Andy Konwinski, Patrick Wendell, and Matei
Zaharia: *Learning Spark*. O'Reilly Media, 2015. ISBN: 978-1-449-35904-1
1. Bikas Saha and Hitesh Shah:
“[Apache Tez: Accelerating Hadoop Query Processing](http://www.slideshare.net/Hadoop_Summit/w-1205phall1saha),” at *Hadoop Summit*, June 2014.
1. Bikas Saha, Hitesh Shah, Siddharth Seth, et al.:
“[Apache Tez: A Unifying Framework for Modeling and Building Data Processing Applications](http://home.cse.ust.hk/~weiwa/teaching/Fall15-COMP6611B/reading_list/Tez.pdf),” at *ACM
International Conference on Management of Data* (SIGMOD), June 2015.
[doi:10.1145/2723372.2742790](http://dx.doi.org/10.1145/2723372.2742790)
1. Kostas Tzoumas:
“[Apache Flink: API, Runtime, and Project Roadmap](http://www.slideshare.net/KostasTzoumas/apache-flink-api-runtime-and-project-roadmap),” *slideshare.net*, January 14, 2015.
1. Alexander Alexandrov, Rico Bergmann, Stephan Ewen, et al.:
“[The Stratosphere Platform for Big Data Analytics](https://ssc.io/pdf/2014-VLDBJ_Stratosphere_Overview.pdf),” *The VLDB Journal*, volume 23, number 6, pages 939964, May 2014.
[doi:10.1007/s00778-014-0357-y](http://dx.doi.org/10.1007/s00778-014-0357-y)
1. Michael Isard, Mihai Budiu, Yuan Yu, et al.:
“[Dryad: Distributed Data-Parallel Programs from Sequential Building Blocks](http://research.microsoft.com/en-us/projects/dryad/eurosys07.pdf),” at *European Conference on Computer
Systems* (EuroSys), March 2007.
[doi:10.1145/1272996.1273005](http://dx.doi.org/10.1145/1272996.1273005)
1. Daniel Warneke and Odej Kao:
“[Nephele: Efficient Parallel Data Processing in the Cloud](https://stratosphere2.dima.tu-berlin.de/assets/papers/Nephele_09.pdf),” at *2nd Workshop on Many-Task Computing on Grids and
Supercomputers* (MTAGS), November 2009.
[doi:10.1145/1646468.1646476](http://dx.doi.org/10.1145/1646468.1646476)
1. Lawrence Page, Sergey Brin, Rajeev
Motwani, and Terry Winograd: “<a href="http://ilpubs.stanford.edu:8090/422/">The <span class="keep-together">PageRank
1. Leslie G. Valiant:
“[A Bridging Model for Parallel Computation](http://dl.acm.org/citation.cfm?id=79181),”
*Communications of the ACM*, volume 33, number 8, pages 103111, August 1990.
[doi:10.1145/79173.79181](http://dx.doi.org/10.1145/79173.79181)
1. Stephan Ewen, Kostas Tzoumas, Moritz Kaufmann, and Volker Markl:
“[Spinning Fast Iterative Data Flows](http://vldb.org/pvldb/vol5/p1268_stephanewen_vldb2012.pdf),” *Proceedings of the VLDB Endowment*, volume 5, number 11, pages 1268-1279, July 2012.
[doi:10.14778/2350229.2350245](http://dx.doi.org/10.14778/2350229.2350245)
1. Grzegorz Malewicz, Matthew H.
Austern, Aart J. C. Bik, et al.: “[Pregel: A System for Large-Scale Graph Processing](https://kowshik.github.io/JPregel/pregel_paper.pdf),” at *ACM International Conference on Management of
Data* (SIGMOD), June 2010.
[doi:10.1145/1807167.1807184](http://dx.doi.org/10.1145/1807167.1807184)
1. Frank McSherry, Michael Isard, and Derek G. Murray:
“[Scalability! But at What COST?](http://www.frankmcsherry.org/assets/COST.pdf),” at
*15th USENIX Workshop on Hot Topics in Operating Systems* (HotOS), May 2015.
1. Ionel Gog, Malte Schwarzkopf, Natacha Crooks, et al.:
“[Musketeer: All for One, One for All in Data Processing Systems](http://www.cl.cam.ac.uk/research/srg/netos/camsas/pubs/eurosys15-musketeer.pdf),” at *10th European Conference on
Computer Systems* (EuroSys), April 2015.
[doi:10.1145/2741948.2741968](http://dx.doi.org/10.1145/2741948.2741968)
1. Aapo Kyrola, Guy Blelloch, and Carlos Guestrin:
“[GraphChi: Large-Scale Graph Computation on Just a PC](https://www.usenix.org/system/files/conference/osdi12/osdi12-final-126.pdf),” at *10th USENIX Symposium on Operating Systems
Design and Implementation* (OSDI), October 2012.
1. Andrew Lenharth, Donald Nguyen, and Keshav Pingali:
“[Parallel Graph Analytics](http://cacm.acm.org/magazines/2016/5/201591-parallel-graph-analytics/fulltext),” *Communications of the ACM*, volume 59, number 5, pages 7887, May
2016. [doi:10.1145/2901919](http://dx.doi.org/10.1145/2901919)
1. Fabian Hüske:
“[Peeking into Apache Flink's Engine Room](http://flink.apache.org/news/2015/03/13/peeking-into-Apache-Flinks-Engine-Room.html),” *flink.apache.org*, March 13, 2015.
1. Mostafa Mokhtar:
“[Hive 0.14 Cost Based Optimizer (CBO) Technical Overview](http://hortonworks.com/blog/hive-0-14-cost-based-optimizer-cbo-technical-overview/),” *hortonworks.com*, March 2, 2015.
1. Michael Armbrust, Reynold S Xin, Cheng Lian, et al.:
“[Spark SQL: Relational Data Processing in Spark](http://people.csail.mit.edu/matei/papers/2015/sigmod_spark_sql.pdf),” at *ACM International Conference on Management of Data* (SIGMOD), June 2015.
[doi:10.1145/2723372.2742797](http://dx.doi.org/10.1145/2723372.2742797)
1. Daniel Blazevski:
“[Planting Quadtrees for Apache Flink](http://insightdataengineering.com/blog/flink-knn/),” *insightdataengineering.com*, March 25, 2016.
1. Tom White:
“[Genome Analysis Toolkit: Now Using Apache Spark for Data Processing](http://blog.cloudera.com/blog/2016/04/genome-analysis-toolkit-now-using-apache-spark-for-data-processing/),” *blog.cloudera.com*, April 6, 2016.

407
ddia/ch11.md Normal file
View File

@ -0,0 +1,407 @@
# 11. 流处理
![](img/ch11.png)
> 有效的复杂系统总是从简单的系统演化而来。 反之亦然:从零开始设计的复杂系统没一个能有效工作的。
>
> ——约翰·加尔Systemantics1975
---------------
[TOC]
## 传递事件流
### 消息系统
### 分区日志
## 流与数据库
### 保持系统同步
### 改变数据捕获
### 事件源
### 状态,流,不可变性
## 流处理
### 流处理的应用
### 与时间讲理
### 流式连接
### 容错
## 本章小结
![](img/fig11-1.png)
**图11-1**
![](img/fig11-2.png)
**图11-2**
![](img/fig11-3.png)
**图11-3**
## 参考文献
1. Tyler Akidau, Robert Bradshaw, Craig Chambers, et al.:
“[The Dataflow Model: A Practical Approach to Balancing Correctness, Latency, and Cost in Massive-Scale, Unbounded, Out-of-Order Data Processing](http://www.vldb.org/pvldb/vol8/p1792-Akidau.pdf),”
*Proceedings of the VLDB Endowment*, volume 8, number 12, pages 17921803, August 2015.
[doi:10.14778/2824032.2824076](http://dx.doi.org/10.14778/2824032.2824076)
1. Harold Abelson, Gerald Jay Sussman, and Julie Sussman:
<a href="https://mitpress.mit.edu/sicp/">*Structure and Interpretation of Computer Programs*</a>,
2nd edition. MIT Press, 1996. ISBN: 978-0-262-51087-5, available online at *mitpress.mit.edu*
1. Patrick Th. Eugster, Pascal A. Felber,
Rachid Guerraoui, and Anne-Marie Kermarrec:
“[The Many Faces of Publish/Subscribe](http://www.cs.ru.nl/~pieter/oss/manyfaces.pdf),”
*ACM Computing Surveys*, volume 35, number 2, pages 114131, June 2003.
[doi:10.1145/857076.857078](http://dx.doi.org/10.1145/857076.857078)
1. Joseph M. Hellerstein and Michael Stonebraker:
<a href="http://redbook.cs.berkeley.edu/">*Readings in Database Systems*</a>, 4th edition.
MIT Press, 2005. ISBN: 978-0-262-69314-1, available online at *redbook.cs.berkeley.edu*
1. Don Carney, Uğur Çetintemel, Mitch Cherniack, et al.:
“[Monitoring Streams A New Class of Data Management Applications](http://www.vldb.org/conf/2002/S07P02.pdf),” at *28th International Conference on Very Large Data Bases*
(VLDB), August 2002.
1. Matthew Sackman:
“[Pushing Back](http://www.lshift.net/blog/2016/05/05/pushing-back/),”
*lshift.net*, May 5, 2016.
1. Vicent Martí:
“[Brubeck, a statsd-Compatible Metrics Aggregator](http://githubengineering.com/brubeck/),” *githubengineering.com*, June 15, 2015.
1. Seth Lowenberger:
“[MoldUDP64 Protocol Specification V 1.00](http://www.nasdaqtrader.com/content/technicalsupport/specifications/dataproducts/moldudp64.pdf),” *nasdaqtrader.com*, July 2009.
1. Pieter Hintjens:
<a href="http://zguide.zeromq.org/page:all">*ZeroMQ The Guide*</a>. O'Reilly Media, 2013.
ISBN: 978-1-449-33404-8
1. Ian Malpass:
“[Measure Anything, Measure Everything](https://codeascraft.com/2011/02/15/measure-anything-measure-everything/),” *codeascraft.com*, February 15, 2011.
1. Dieter Plaetinck:
“[25 Graphite, Grafana and statsd Gotchas](https://blog.raintank.io/25-graphite-grafana-and-statsd-gotchas/),” *blog.raintank.io*, March 3, 2016.
1. Jeff Lindsay:
“[Web Hooks to Revolutionize the Web](http://progrium.com/blog/2007/05/03/web-hooks-to-revolutionize-the-web/),” *progrium.com*, May 3, 2007.
1. Jim N. Gray:
“[Queues Are Databases](http://research.microsoft.com/pubs/69641/tr-95-56.pdf),”
Microsoft Research Technical Report MSR-TR-95-56, December 1995.
1. Mark Hapner, Rich Burridge, Rahul Sharma, et al.:
“[JSR-343 Java Message Service (JMS) 2.0 Specification](https://jcp.org/en/jsr/detail?id=343),” *jms-spec.java.net*, March 2013.
1. Sanjay Aiyagari, Matthew Arrott, Mark Atwell, et al.:
“[AMQP: Advanced Message Queuing Protocol Specification](http://www.rabbitmq.com/resources/specs/amqp0-9-1.pdf),” Version 0-9-1, November 2008.
1. “[Google Cloud Pub/Sub: A Google-Scale Messaging Service](https://cloud.google.com/pubsub/architecture),” *cloud.google.com*, 2016.
1. “[Apache Kafka 0.9 Documentation](http://kafka.apache.org/documentation.html),” *kafka.apache.org*, November 2015.
1. Jay Kreps, Neha Narkhede, and Jun Rao:
“[Kafka: A Distributed Messaging System for Log Processing](http://www.longyu23.com/doc/Kafka.pdf),” at *6th International Workshop on
Networking Meets Databases* (NetDB), June 2011.
1. “[Amazon Kinesis Streams Developer Guide](http://docs.aws.amazon.com/streams/latest/dev/introduction.html),” *docs.aws.amazon.com*, April 2016.
1. Leigh Stewart and Sijie Guo:
“[Building DistributedLog: Twitters High-Performance Replicated Log Service](https://blog.twitter.com/2015/building-distributedlog-twitter-s-high-performance-replicated-log-service),” *blog.twitter.com*,
September 16, 2015.
1. “[DistributedLog Documentation](http://distributedlog.incubator.apache.org/docs/latest/),” Twitter, Inc., *distributedlog.io*, May 2016.
1. Jay Kreps:
“[Benchmarking Apache Kafka: 2 Million Writes Per Second (On Three Cheap Machines)](https://engineering.linkedin.com/kafka/benchmarking-apache-kafka-2-million-writes-second-three-cheap-machines),” *engineering.linkedin.com*,
April 27, 2014.
1. Kartik Paramasivam:
“[How Were Improving and Advancing Kafka at LinkedIn](https://engineering.linkedin.com/apache-kafka/how-we_re-improving-and-advancing-kafka-linkedin),” *engineering.linkedin.com*, September 2, 2015.
1. Jay Kreps:
“[The Log: What Every Software Engineer Should Know About Real-Time Data's Unifying Abstraction](http://engineering.linkedin.com/distributed-systems/log-what-every-software-engineer-should-know-about-real-time-datas-unifying),”
*engineering.linkedin.com*, December 16, 2013.
1. Shirshanka Das, Chavdar Botev, Kapil Surlaker,
et al.: “[All Aboard the Databus!](http://www.socc2012.org/s18-das.pdf),” at *3rd ACM
Symposium on Cloud Computing* (SoCC), October 2012.
1. Yogeshwer Sharma, Philippe Ajoux, Petchean Ang, et al.:
“[Wormhole: Reliable Pub-Sub to Support Geo-Replicated Internet Services](https://www.usenix.org/system/files/conference/nsdi15/nsdi15-paper-sharma.pdf),” at *12th USENIX Symposium on
Networked Systems Design and Implementation* (NSDI), May 2015.
1. P. P. S. Narayan:
“[Sherpa Update](http://web.archive.org/web/20160801221400/https://developer.yahoo.com/blogs/ydn/sherpa-7992.html),”
*developer.yahoo.com*, June 8, .
1. Martin Kleppmann:
“[Bottled Water: Real-Time Integration of PostgreSQL and Kafka](http://martin.kleppmann.com/2015/04/23/bottled-water-real-time-postgresql-kafka.html),” *martin.kleppmann.com*, April 23, 2015.
1. Ben Osheroff:
“[Introducing Maxwell, a mysql-to-kafka Binlog Processor](https://developer.zendesk.com/blog/introducing-maxwell-a-mysql-to-kafka-binlog-processor),” *developer.zendesk.com*, August 20, 2015.
1. Randall Hauch:
“[Debezium 0.2.1 Released](http://debezium.io/blog/2016/06/10/Debezium-0/),” *debezium.io*,
June 10, 2016.
1. Prem Santosh Udaya Shankar:
“[Streaming MySQL Tables in Real-Time to Kafka](https://engineeringblog.yelp.com/2016/08/streaming-mysql-tables-in-real-time-to-kafka.html),” *engineeringblog.yelp.com*, August 1, 2016.
1. “[Mongoriver](https://github.com/stripe/mongoriver),”
Stripe, Inc., *github.com*, September 2014.
1. Dan Harvey:
“[Change Data Capture with Mongo + Kafka](http://www.slideshare.net/danharvey/change-data-capture-with-mongodb-and-kafka),” at *Hadoop Users Group UK*, August 2015.
1. “[Oracle GoldenGate 12c: Real-Time Access to Real-Time Information](http://www.oracle.com/us/products/middleware/data-integration/oracle-goldengate-realtime-access-2031152.pdf),” Oracle White Paper, March 2015.
1. “[Oracle GoldenGate Fundamentals: How Oracle GoldenGate Works](https://www.youtube.com/watch?v=6H9NibIiPQE),” Oracle Corporation, *youtube.com*, November 2012.
1. Slava Akhmechet:
“[Advancing the Realtime Web](http://rethinkdb.com/blog/realtime-web/),” *rethinkdb.com*,
January 27, 2015.
1. “[Firebase Realtime Database Documentation](https://firebase.google.com/docs/database/),” Google, Inc., *firebase.google.com*, May 2016.
1. “[Apache CouchDB 1.6 Documentation](http://docs.couchdb.org/en/latest/),” *docs.couchdb.org*, 2014.
1. Matt DeBergalis:
“[Meteor 0.7.0: Scalable Database Queries Using MongoDB Oplog Instead of Poll-and-Diff](http://info.meteor.com/blog/meteor-070-scalable-database-queries-using-mongodb-oplog-instead-of-poll-and-diff),” *info.meteor.com*,
December 17, 2013.
1. “[Chapter 15. Importing and Exporting Live Data](https://docs.voltdb.com/UsingVoltDB/ChapExport.php),” VoltDB 6.4 User Manual, *docs.voltdb.com*, June 2016.
1. Neha Narkhede:
“[Announcing Kafka Connect: Building Large-Scale Low-Latency Data Pipelines](http://www.confluent.io/blog/announcing-kafka-connect-building-large-scale-low-latency-data-pipelines),” *confluent.io*,
February 18, 2016.
1. Greg Young:
“[CQRS and Event Sourcing](https://www.youtube.com/watch?v=JHGkaShoyNs),” at *Code on
the Beach*, August 2014.
1. Martin Fowler:
“[Event Sourcing](http://martinfowler.com/eaaDev/EventSourcing.html),” *martinfowler.com*,
December 12, 2005.
1. Vaughn Vernon:
<a href="https://vaughnvernon.co/?page_id=168">*Implementing Domain-Driven Design*</a>.
Addison-Wesley Professional, 2013. ISBN: 978-0-321-83457-7
1. H. V. Jagadish, Inderpal Singh Mumick, and Abraham Silberschatz:
“[View Maintenance Issues for the Chronicle Data Model](http://www.mathcs.emory.edu/~cheung/papers/StreamDB/Histogram/1995-Jagadish-Histo.pdf),” at *14th ACM SIGACT-SIGMOD-SIGART Symposium
on Principles of Database Systems* (PODS), May 1995.
[doi:10.1145/212433.220201](http://dx.doi.org/10.1145/212433.220201)
1. “[Event Store 3.5.0 Documentation](http://docs.geteventstore.com/),” Event Store LLP, *docs.geteventstore.com*, February 2016.
1. Martin Kleppmann:
<a href="http://www.oreilly.com/data/free/stream-processing.csp">*Making Sense of Stream
Processing*</a>. Report, O'Reilly Media, May 2016.
1. Sander Mak:
“[Event-Sourced Architectures with Akka](http://www.slideshare.net/SanderMak/eventsourced-architectures-with-akka),” at *JavaOne*, September 2014.
1. Julian Hyde:
[personal communication](https://twitter.com/julianhyde/status/743374145006641153),
June 2016.
1. Ashish Gupta and Inderpal Singh Mumick:
*Materialized Views: Techniques, Implementations, and Applications*. MIT Press, 1999.
ISBN: 978-0-262-57122-7
1. Timothy Griffin and Leonid Libkin:
“[Incremental Maintenance of Views with Duplicates](http://homepages.inf.ed.ac.uk/libkin/papers/sigmod95.pdf),” at *ACM International Conference on Management of
Data* (SIGMOD), May 1995.
[doi:10.1145/223784.223849](http://dx.doi.org/10.1145/223784.223849)
1. Pat Helland:
“[Immutability Changes Everything](http://www.cidrdb.org/cidr2015/Papers/CIDR15_Paper16.pdf),” at *7th Biennial Conference on Innovative Data Systems Research* (CIDR),
January 2015.
1. Martin Kleppmann:
“[Accounting for Computer Scientists](http://martin.kleppmann.com/2011/03/07/accounting-for-computer-scientists.html),” *martin.kleppmann.com*, March 7, 2011.
1. Pat Helland:
“[Accountants Don't Use Erasers](https://blogs.msdn.microsoft.com/pathelland/2007/06/14/accountants-dont-use-erasers/),” *blogs.msdn.com*, June 14, 2007.
1. Fangjin Yang:
“[Dogfooding with Druid, Samza, and Kafka: Metametrics at Metamarkets](https://metamarkets.com/2015/dogfooding-with-druid-samza-and-kafka-metametrics-at-metamarkets/),” *metamarkets.com*, June 3, 2015.
1. Gavin Li, Jianqiu Lv, and Hang Qi:
“[Pistachio: Co-Locate the Data and Compute for Fastest Cloud Compute](http://yahoohadoop.tumblr.com/post/116365275781/pistachio-co-locate-the-data-and-compute-for),” *yahoohadoop.tumblr.com*, April 13, 2015.
1. Kartik Paramasivam:
“[Stream Processing Hard Problems Part 1: Killing Lambda](https://engineering.linkedin.com/blog/2016/06/stream-processing-hard-problems-part-1-killing-lambda),” *engineering.linkedin.com*, June 27, 2016.
1. Martin Fowler:
“[CQRS](http://martinfowler.com/bliki/CQRS.html),” *martinfowler.com*, July 14, 2011.
1. Greg Young:
“[CQRS Documents](https://cqrs.files.wordpress.com/2010/11/cqrs_documents.pdf),”
*cqrs.files.wordpress.com*, November 2010.
1. Baron Schwartz:
“[Immutability, MVCC, and Garbage Collection](http://www.xaprb.com/blog/2013/12/28/immutability-mvcc-and-garbage-collection/),” *xaprb.com*, December 28, 2013.
1. Daniel Eloff, Slava Akhmechet, Jay Kreps, et al.:
["Re: Turning the Database Inside-out with Apache Samza](https://news.ycombinator.com/item?id=9145197)," Hacker News discussion, *news.ycombinator.com*, March 4, 2015.
1. “[Datomic Development Resources: Excision](http://docs.datomic.com/excision.html),” Cognitect, Inc., *docs.datomic.com*.
1. “[Fossil Documentation: Deleting Content from Fossil](http://fossil-scm.org/index.html/doc/trunk/www/shunning.wiki),” *fossil-scm.org*, 2016.
1. Jay Kreps:
“[The irony of distributed systems is that data loss is really easy but deleting data is surprisingly hard,](https://twitter.com/jaykreps/status/582580836425330688)” *twitter.com*, March 30,
2015.
1. David C. Luckham:
“[Whats the Difference Between ESP and CEP?](http://www.complexevents.com/2006/08/01/what%E2%80%99s-the-difference-between-esp-and-cep/),” *complexevents.com*, August 1, 2006.
1. Srinath Perera:
“[How Is Stream Processing and Complex Event Processing (CEP) Different?](https://www.quora.com/How-is-stream-processing-and-complex-event-processing-CEP-different),” *quora.com*, December 3, 2015.
1. Arvind Arasu, Shivnath Babu, and Jennifer Widom:
“[The CQL Continuous Query Language: Semantic Foundations and Query Execution](http://research.microsoft.com/pubs/77607/cql.pdf),” *The VLDB Journal*, volume 15, number 2, pages
121142, June 2006.
[doi:10.1007/s00778-004-0147-z](http://dx.doi.org/10.1007/s00778-004-0147-z)
1. Julian Hyde:
“[Data in Flight: How Streaming SQL Technology Can Help Solve the Web 2.0 Data Crunch](http://queue.acm.org/detail.cfm?id=1667562),” *ACM Queue*, volume 7, number 11, December 2009.
[doi:10.1145/1661785.1667562](http://dx.doi.org/10.1145/1661785.1667562)
1. “[Esper Reference, Version 5.4.0](http://www.espertech.com/esper/release-5.4.0/esper-reference/html_single/index.html),” EsperTech, Inc., *espertech.com*, April 2016.
1. Zubair Nabi, Eric Bouillet, Andrew Bainbridge, and Chris Thomas:
“[Of Streams and Storms](https://developer.ibm.com/streamsdev/wp-content/uploads/sites/15/2014/04/Streams-and-Storm-April-2014-Final.pdf),” IBM technical report, *developer.ibm.com*, April 2014.
1. Milinda Pathirage, Julian Hyde, Yi Pan, and Beth Plale:
“[SamzaSQL: Scalable Fast Data Management with Streaming SQL](https://github.com/milinda/samzasql-hpbdc2016/blob/master/samzasql-hpbdc2016.pdf),” at *IEEE International Workshop on
High-Performance Big Data Computing* (HPBDC), May 2016.
[doi:10.1109/IPDPSW.2016.141](http://dx.doi.org/10.1109/IPDPSW.2016.141)
1. Philippe Flajolet, Éric Fusy, Olivier
Gandouet, and Frédéric Meunier:
“[HyperLo&#x2060;g&#x200b;Log: The Analysis of a Near-Optimal Cardinality Estimation Algorithm](http://algo.inria.fr/flajolet/Publications/FlFuGaMe07.pdf),” at *Conference on Analysis of
Algorithms* (AofA), June 2007.
1. Jay Kreps:
“[Questioning the Lambda Architecture](https://www.oreilly.com/ideas/questioning-the-lambda-architecture),” *oreilly.com*, July 2, 2014.
1. Ian Hellström:
“[An Overview of Apache Streaming Technologies](https://databaseline.wordpress.com/2016/03/12/an-overview-of-apache-streaming-technologies/),” *databaseline.wordpress.com*, March 12, 2016.
1. Jay Kreps:
“[Why Local State Is a Fundamental Primitive in Stream Processing](https://www.oreilly.com/ideas/why-local-state-is-a-fundamental-primitive-in-stream-processing),” *oreilly.com*, July 31, 2014.
1. Shay Banon:
“[Percolator](https://www.elastic.co/blog/percolator),” *elastic.co*, February 8,
2011.
1. Alan Woodward and Martin Kleppmann:
“[Real-Time Full-Text Search with Luwak and Samza](http://martin.kleppmann.com/2015/04/13/real-time-full-text-search-luwak-samza.html),” *martin.kleppmann.com*, April 13, 2015.
1. “[Apache Storm 1.0.1 Documentation](https://storm.apache.org/releases/1.0.1/index.html),” *storm.apache.org*, May 2016.
1. Tyler Akidau:
“[The World Beyond Batch: Streaming 102](https://www.oreilly.com/ideas/the-world-beyond-batch-streaming-102),” *oreilly.com*, January 20, 2016.
1. Stephan Ewen:
“[Streaming Analytics with Apache Flink](http://www.confluent.io/kafka-summit-2016-systems-advanced-streaming-analytics-with-apache-flink-and-apache-kafka),” at *Kafka Summit*, April
2016.
1. Tyler Akidau, Alex Balikov, Kaya Bekiroğlu, et al.:
“[MillWheel: Fault-Tolerant Stream Processing at Internet Scale](http://research.google.com/pubs/pub41378.html),” at *39th International Conference on Very Large Data Bases* (VLDB),
August 2013.
1. Alex Dean:
“[Improving Snowplow's Understanding of Time](http://snowplowanalytics.com/blog/2015/09/15/improving-snowplows-understanding-of-time/),” *snowplowanalytics.com*, September 15, 2015.
1. “[Windowing (Azure Stream Analytics)](https://msdn.microsoft.com/en-us/library/azure/dn835019.aspx),” Microsoft Azure Reference, *msdn.microsoft.com*, April 2016.
1. “[State Management](http://samza.apache.org/learn/documentation/0.10/container/state-management.html),” Apache Samza 0.10 Documentation, *samza.apache.org*, December 2015.
1. Rajagopal Ananthanarayanan,
Venkatesh Basker, Sumit Das, et al.:
“[Photon: Fault-Tolerant and Scalable Joining of Continuous Data Streams](http://research.google.com/pubs/pub41318.html),” at *ACM International Conference on Management of
Data* (SIGMOD), June 2013.
[doi:10.1145/2463676.2465272](http://dx.doi.org/10.1145/2463676.2465272)
1. Martin Kleppmann:
“[Samza Newsfeed Demo](https://github.com/ept/newsfeed),” *github.com*,
September 2014.
1. Ben Kirwin:
“[Doing the Impossible: Exactly-Once Messaging Patterns in Kafka](http://ben.kirw.in/2014/11/28/kafka-patterns/),” *ben.kirw.in*, November 28, 2014.
1. Pat Helland:
“[Data on the Outside Versus Data on the Inside](http://cidrdb.org/cidr2005/papers/P12.pdf),” at *2nd Biennial Conference on Innovative Data Systems Research* (CIDR), January
2005.
1. Ralph Kimball and Margy Ross:
*The Data Warehouse Toolkit: The Definitive Guide to Dimensional Modeling*,
3rd edition. John Wiley & Sons, 2013. ISBN: 978-1-118-53080-1
1. Viktor Klang:
“[I'm coining the phrase 'effectively-once' for message processing with at-least-once + idempotent operations](https://twitter.com/viktorklang/status/789036133434978304),”
*twitter.com*, October 20, 2016.
1. Matei Zaharia, Tathagata Das, Haoyuan Li, et al.:
“[Discretized Streams: An Efficient and Fault-Tolerant Model for Stream Processing on Large Clusters](https://www.usenix.org/system/files/conference/hotcloud12/hotcloud12-final28.pdf),” at
*4th USENIX Conference in Hot Topics in Cloud Computing* (HotCloud), June 2012.
1. Kostas Tzoumas, Stephan Ewen, and Robert Metzger:
“[High-Throughput, Low-Latency, and Exactly-Once Stream Processing with Apache Flink](http://data-artisans.com/high-throughput-low-latency-and-exactly-once-stream-processing-with-apache-flink/),” *data-artisans.com*, August 5, 2015.
1. Paris Carbone, Gyula Fóra, Stephan Ewen, et al.:
“[Lightweight Asynchronous Snapshots for Distributed Dataflows](http://arxiv.org/abs/1506.08603),” arXiv:1506.08603 &#91;cs.DC&#93;, June 29, 2015.
1. Ryan Betts and John Hugg:
<a href="http://www.oreilly.com/data/free/fast-data-smart-and-at-scale.csp">*Fast Data: Smart and
at Scale*</a>. Report, O'Reilly Media, October 2015.
1. Flavio Junqueira:
“[Making Sense of Exactly-Once Semantics](http://conferences.oreilly.com/strata/hadoop-big-data-eu/public/schedule/detail/49690),” at *Strata+Hadoop World London*, June 2016.
1. Jason Gustafson, Flavio Junqueira, Apurva Mehta, Sriram Subramanian, and Guozhang Wang: “[KIP-98 Exactly Once Delivery and Transactional Messaging](https://cwiki.apache.org/confluence/display/KAFKA/KIP-98+-+Exactly+Once+Delivery+and+Transactional+Messaging),” *cwiki.apache.org*, November 2016.
1. Pat Helland:
“[Idempotence Is Not a Medical Condition](http://citeseerx.ist.psu.edu/viewdoc/download?doi=10.1.1.401.1539&rep=rep1&type=pdf),” *Communications of the ACM*, volume 55, number 5, page 56, May 2012.
[doi:10.1145/2160718.2160734](http://dx.doi.org/10.1145/2160718.2160734)
1. Jay Kreps:
“[Re: Trying to Achieve Deterministic Behavior on Recovery/Rewind](http://mail-archives.apache.org/mod_mbox/samza-dev/201409.mbox/%3CCAOeJiJg%2Bc7Ei%3DgzCuOz30DD3G5Hm9yFY%3DUJ6SafdNUFbvRgorg%40mail.gmail.com%3E),” email to *samza-dev* mailing list,
September 9, 2014.
1. E. N. (Mootaz) Elnozahy,
Lorenzo Alvisi, Yi-Min Wang, and David B. Johnson:
“[A Survey of Rollback-Recovery Protocols in Message-Passing Systems](http://www.cs.utexas.edu/~lorenzo/papers/SurveyFinal.pdf),” *ACM Computing Surveys*, volume 34, number 3,
pages 375408, September 2002.
[doi:10.1145/568522.568525](http://dx.doi.org/10.1145/568522.568525)
1. Adam Warski:
“[Kafka Streams How Does It Fit the Stream Processing Landscape?](https://softwaremill.com/kafka-streams-how-does-it-fit-stream-landscape/),” *softwaremill.com*, June 1, 2016.

487
ddia/ch12.md Normal file
View File

@ -0,0 +1,487 @@
# 12. 数据系统的未来
![](img/ch12.png)
> 如果船长的最高目标是保护他的船,他应该永远待在港口。
>
> ——圣托马斯·阿奎那《神学大全》1265-1274
---------------
[TOC]
## 数据集成
### 组合使用派生数据的工具
### 批量处理与流处理
## 拆分数据库
### 组合使用数据存储技术
### 围绕数据流设计应用
### 观察派生数据状态
## 目标是正确性
### 数据库端到端的争论
### 强制实施约束
### 时间线与完整性
### 信任,但需要验证
## 做正确的事情
### 预测性的分析
### 隐私与跟踪
## 本章小结
## 参考文献
1. Rachid Belaid:
“[Postgres Full-Text Search is Good Enough!](http://rachbelaid.com/postgres-full-text-search-is-good-enough/),” *rachbelaid.com*, July 13, 2015.
1. Philippe Ajoux, Nathan Bronson, Sanjeev Kumar, et al.:
“[Challenges to Adopting Stronger Consistency at Scale](https://www.usenix.org/system/files/conference/hotos15/hotos15-paper-ajoux.pdf),” at *15th USENIX Workshop on Hot Topics
in Operating Systems* (HotOS), May 2015.
1. Pat Helland and Dave Campbell:
“[Building on Quicksand](https://database.cs.wisc.edu/cidr/cidr2009/Paper_133.pdf),” at
*4th Biennial Conference on Innovative Data Systems Research* (CIDR), January 2009.
1. Jessica Kerr:
“[Provenance and Causality in Distributed Systems](http://blog.jessitron.com/2016/09/provenance-and-causality-in-distributed.html),” *blog.jessitron.com*, September 25, 2016.
1. Kostas Tzoumas:
“[Batch Is a Special Case of Streaming](http://data-artisans.com/batch-is-a-special-case-of-streaming/),” *data-artisans.com*, September 15, 2015.
1. Shinji Kim and Robert Blafford:
“[Stream Windowing Performance Analysis: Concord and Spark Streaming](http://concord.io/posts/windowing_performance_analysis_w_spark_streaming),” *concord.io*, July 6, 2016.
1. Jay Kreps:
“[The Log: What Every Software Engineer Should Know About Real-Time Data's Unifying Abstraction](http://engineering.linkedin.com/distributed-systems/log-what-every-software-engineer-should-know-about-real-time-datas-unifying),”
*engineering.linkedin.com*, December 16, 2013.
1. Pat Helland:
“[Life Beyond Distributed Transactions: An Apostates Opinion](http://www-db.cs.wisc.edu/cidr/cidr2007/papers/cidr07p15.pdf),” at *3rd Biennial Conference on Innovative Data
Systems Research* (CIDR), January 2007.
1. “[Great Western Railway (18351948)](https://www.networkrail.co.uk/VirtualArchive/great-western/),” Network Rail Virtual Archive, *networkrail.co.uk*.
1. Jacqueline Xu:
“[Online Migrations at Scale](https://stripe.com/blog/online-migrations),”
*stripe.com*, February 2, 2017.
1. Molly Bartlett Dishman and Martin Fowler:
“[Agile Architecture](http://conferences.oreilly.com/software-architecture/sa2015/public/schedule/detail/40388),” at *O'Reilly Software Architecture Conference*, March 2015.
1. Nathan Marz and James Warren:
<a href="https://www.manning.com/books/big-data">*Big Data: Principles and Best Practices of
Scalable Real-Time Data Systems*</a>. Manning, 2015. ISBN: 978-1-617-29034-3
1. Oscar Boykin, Sam Ritchie, Ian O'Connell, and
Jimmy Lin: “[Summingbird: A Framework for Integrating Batch and Online MapReduce Computations](http://www.vldb.org/pvldb/vol7/p1441-boykin.pdf),” at *40th International Conference on
Very Large Data Bases* (VLDB), September 2014.
1. Jay Kreps:
“[Questioning the Lambda Architecture](https://www.oreilly.com/ideas/questioning-the-lambda-architecture),” *oreilly.com*, July 2, 2014.
1. Raul Castro Fernandez, Peter Pietzuch,
Jay Kreps, et al.: “[Liquid: Unifying Nearline and Offline Big Data Integration](http://www.cidrdb.org/cidr2015/Papers/CIDR15_Paper25u.pdf),” at *7th Biennial Conference on
Innovative Data Systems Research* (CIDR), January 2015.
1. Dennis M. Ritchie and Ken Thompson:
“[The UNIX Time-Sharing System](http://www.cs.virginia.edu/~zaher/classes/CS656/p365-ritchie.pdf),” *Communications of the ACM*, volume 17, number 7, pages 365375, July 1974.
[doi:10.1145/361011.361061](http://dx.doi.org/10.1145/361011.361061)
1. Eric A. Brewer and Joseph M. Hellerstein:
“[CS262a: Advanced Topics in Computer Systems](http://people.eecs.berkeley.edu/~brewer/cs262/systemr.html),” lecture notes, University of California, Berkeley, *cs.berkeley.edu*,
August 2011.
1. Michael Stonebraker:
“[The Case for Polystores](http://wp.sigmod.org/?p=1629),” *wp.sigmod.org*,
July 13, 2015.
1. Jennie Duggan,
Aaron J. Elmore, Michael Stonebraker, et al.:
“[The BigDAWG Polystore System](http://dspace.mit.edu/openaccess-disseminate/1721.1/100936),” *ACM SIGMOD Record*, volume 44, number 2, pages 1116, June 2015.
[doi:10.1145/2814710.2814713](http://dx.doi.org/10.1145/2814710.2814713)
1. Patrycja Dybka:
“[Foreign Data Wrappers for PostgreSQL](http://www.vertabelo.com/blog/technical-articles/foreign-data-wrappers-for-postgresql),” *vertabelo.com*, March 24, 2015.
1. David B. Lomet, Alan Fekete, Gerhard Weikum, and Mike Zwilling:
“[Unbundling Transaction Services in the Cloud](https://www.microsoft.com/en-us/research/publication/unbundling-transaction-services-in-the-cloud/),” at *4th Biennial Conference on Innovative Data Systems
Research* (CIDR), January 2009.
1. Martin Kleppmann and Jay Kreps:
“[Kafka, Samza and the Unix Philosophy of Distributed Data](http://martin.kleppmann.com/papers/kafka-debull15.pdf),” *IEEE Data Engineering Bulletin*, volume 38, number 4, pages 414,
December 2015.
1. John Hugg:
“[Winning Now and in the Future: Where VoltDB Shines](https://voltdb.com/blog/winning-now-and-future-where-voltdb-shines),” *voltdb.com*, March 23, 2016.
1. Frank McSherry, Derek G. Murray, Rebecca Isaacs, and Michael Isard:
“[Differential Dataflow](http://cidrdb.org/cidr2013/Papers/CIDR13_Paper111.pdf),”
at *6th Biennial Conference on Innovative Data Systems Research* (CIDR), January 2013.
1. Derek G Murray, Frank McSherry, Rebecca Isaacs, et al.:
“[Naiad: A Timely Dataflow System](http://research.microsoft.com/pubs/201100/naiad_sosp2013.pdf),”
at *24th ACM Symposium on Operating Systems Principles* (SOSP), pages 439455, November 2013.
[doi:10.1145/2517349.2522738](http://dx.doi.org/10.1145/2517349.2522738)
1. Gwen Shapira:
“[We have a bunch of customers who are implementing database inside-out concept and they all ask is anyone else doing it? are we crazy?](https://twitter.com/gwenshap/status/758800071110430720)” *twitter.com*, July 28, 2016.
1. Martin Kleppmann:
“[Turning the Database Inside-out with Apache Samza,](http://martin.kleppmann.com/2015/03/04/turning-the-database-inside-out.html)” at *Strange Loop*, September 2014.
1. Peter Van Roy and Seif Haridi:
<a href="http://www.epsa.org/forms/uploadFiles/3B6300000000.filename.booksingle.pdf">*Concepts,
Techniques, and Models of Computer Programming*</a>. MIT Press, 2004.
ISBN: 978-0-262-22069-9
1. “[Juttle Documentation](http://juttle.github.io/juttle/),” *juttle.github.io*, 2016.
1. Evan Czaplicki and Stephen Chong:
“[Asynchronous Functional Reactive Programming for GUIs](http://people.seas.harvard.edu/~chong/pubs/pldi13-elm.pdf),” at *34th ACM SIGPLAN Conference on Programming Language
Design and Implementation* (PLDI), June 2013.
[doi:10.1145/2491956.2462161](http://dx.doi.org/10.1145/2491956.2462161)
1. Engineer Bainomugisha, Andoni Lombide Carreton,
Tom van Cutsem, Stijn Mostinckx, and Wolfgang de Meuter:
“[A Survey on Reactive Programming](http://soft.vub.ac.be/Publications/2012/vub-soft-tr-12-13.pdf),” *ACM Computing Surveys*, volume 45, number 4, pages 134, August 2013.
[doi:10.1145/2501654.2501666](http://dx.doi.org/10.1145/2501654.2501666)
1. Peter
Alvaro, Neil Conway, Joseph M. Hellerstein, and William R. Marczak:
“[Consistency Analysis in Bloom: A CALM and Collected Approach](http://www.eecs.berkeley.edu/~palvaro/cidr11.pdf),” at *5th Biennial Conference on Innovative Data Systems Research*
(CIDR), January 2011.
1. Felienne Hermans:
“[Spreadsheets Are Code](https://vimeo.com/145492419),” at *Code Mesh*, November
2015.
1. Dan Bricklin and Bob
Frankston: “[VisiCalc: Information from Its Creators](http://danbricklin.com/visicalc.htm),” *danbricklin.com*.
1. D. Sculley, Gary Holt, Daniel Golovin, et al.:
“[Machine Learning: The High-Interest Credit Card of Technical Debt](http://research.google.com/pubs/pub43146.html),” at *NIPS Workshop on Software Engineering for Machine Learning*
(SE4ML), December 2014.
1. Peter Bailis, Alan Fekete, Michael J Franklin,
et al.: “[Feral Concurrency Control: An Empirical Investigation of Modern Application Integrity](http://www.bailis.org/papers/feral-sigmod2015.pdf),” at *ACM International Conference on
Management of Data* (SIGMOD), June 2015.
[doi:10.1145/2723372.2737784](http://dx.doi.org/10.1145/2723372.2737784)
1. Guy Steele:
“[Re: Need for Macros (Was Re: Icon)](https://people.csail.mit.edu/gregs/ll1-discuss-archive-html/msg01134.html),” email to *ll1-discuss* mailing list, *people.csail.mit.edu*, December 24,
2001.
1. David Gelernter:
“[Generative Communication in Linda](http://cseweb.ucsd.edu/groups/csag/html/teaching/cse291s03/Readings/p80-gelernter.pdf),” *ACM Transactions on Programming Languages and Systems*
(TOPLAS), volume 7, number 1, pages 80112, January 1985.
[doi:10.1145/2363.2433](http://dx.doi.org/10.1145/2363.2433)
1. Patrick Th. Eugster, Pascal A. Felber,
Rachid Guerraoui, and Anne-Marie Kermarrec:
“[The Many Faces of Publish/Subscribe](http://www.cs.ru.nl/~pieter/oss/manyfaces.pdf),”
*ACM Computing Surveys*, volume 35, number 2, pages 114131, June 2003.
[doi:10.1145/857076.857078](http://dx.doi.org/10.1145/857076.857078)
1. Ben Stopford:
“[Microservices in a Streaming World](https://www.infoq.com/presentations/microservices-streaming),” at *QCon London*, March 2016.
1. Christian Posta:
“[Why Microservices Should Be Event Driven: Autonomy vs Authority](http://blog.christianposta.com/microservices/why-microservices-should-be-event-driven-autonomy-vs-authority/),” *blog.christianposta.com*, May 27, 2016.
1. Alex Feyerke:
“[Say Hello to Offline First](http://hood.ie/blog/say-hello-to-offline-first.html),”
*hood.ie*, November 5, 2013.
1. Sebastian Burckhardt, Daan Leijen, Jonathan
Protzenko, and Manuel Fähndrich:
“[Global Sequence Protocol: A Robust Abstraction for Replicated Shared State](http://drops.dagstuhl.de/opus/volltexte/2015/5238/),” at *29th European Conference on Object-Oriented
Programming* (ECOOP), July 2015.
[doi:10.4230/LIPIcs.ECOOP.2015.568](http://dx.doi.org/10.4230/LIPIcs.ECOOP.2015.568)
1. Mark Soper:
“[Clearing Up React Data Management Confusion with Flux, Redux, and Relay](https://medium.com/@marksoper/clearing-up-react-data-management-confusion-with-flux-redux-and-relay-aad504e63cae),” *medium.com*, December 3, 2015.
1. Eno Thereska, Damian Guy, Michael Noll, and Neha Narkhede:
“[Unifying Stream Processing and Interactive Queries in Apache Kafka](http://www.confluent.io/blog/unifying-stream-processing-and-interactive-queries-in-apache-kafka/),” *confluent.io*, October 26, 2016.
1. Frank McSherry:
“[Dataflow as Database](https://github.com/frankmcsherry/blog/blob/master/posts/2016-07-17.md),” *github.com*, July 17, 2016.
1. Peter Alvaro:
“[I See What You Mean](https://www.youtube.com/watch?v=R2Aa4PivG0g),” at *Strange
Loop*, September 2015.
1. Nathan Marz:
“[Trident: A High-Level Abstraction for Realtime Computation](https://blog.twitter.com/2012/trident-a-high-level-abstraction-for-realtime-computation),” *blog.twitter.com*, August 2, 2012.
1. Edi Bice:
“[Low Latency Web Scale Fraud Prevention with Apache Samza, Kafka and Friends](http://www.slideshare.net/edibice/extremely-low-latency-web-scale-fraud-prevention-with-apache-samza-kafka-and-friends),” at *Merchant Risk
Council MRC Vegas Conference*, March 2016.
1. Charity Majors:
“[The Accidental DBA](https://charity.wtf/2016/10/02/the-accidental-dba/),” *charity.wtf*,
October 2, 2016.
1. Arthur J. Bernstein, Philip M. Lewis, and Shiyong Lu:
“[Semantic Conditions for Correctness at Different Isolation Levels](http://db.cs.berkeley.edu/cs286/papers/isolation-icde2000.pdf),” at *16th International Conference on Data
Engineering* (ICDE), February 2000.
[doi:10.1109/ICDE.2000.839387](http://dx.doi.org/10.1109/ICDE.2000.839387)
1. Sudhir Jorwekar, Alan Fekete, Krithi Ramamritham, and
S. Sudarshan: “[Automating the Detection of Snapshot Isolation Anomalies](http://www.vldb.org/conf/2007/papers/industrial/p1263-jorwekar.pdf),” at *33rd International Conference on Very
Large Data Bases* (VLDB), September 2007.
1. Kyle Kingsbury:
[Jepsen blog post series](https://aphyr.com/tags/jepsen), *aphyr.com*, 20132016.
1. Michael Jouravlev:
“[Redirect After Post](http://www.theserverside.com/news/1365146/Redirect-After-Post),”
*theserverside.com*, August 1, 2004.
1. Jerome H. Saltzer, David P. Reed, and
David D. Clark: “[End-to-End Arguments in System Design](http://www.ece.drexel.edu/courses/ECE-C631-501/SalRee1984.pdf),” *ACM Transactions on Computer Systems*, volume 2, number 4,
pages 277288, November 1984.
[doi:10.1145/357401.357402](http://dx.doi.org/10.1145/357401.357402)
1. Peter Bailis, Alan Fekete, Michael J. Franklin, et al.:
“[Coordination-Avoiding Database Systems](http://arxiv.org/pdf/1402.2237.pdf),”
*Proceedings of the VLDB Endowment*, volume 8, number 3, pages 185196, November 2014.
1. Alex Yarmula:
“[Strong Consistency in Manhattan](https://blog.twitter.com/2016/strong-consistency-in-manhattan),” *blog.twitter.com*, March 17, 2016.
1. Douglas B Terry, Marvin M Theimer, Karin Petersen, et al.:
“[Managing Update Conflicts in Bayou, a Weakly Connected Replicated Storage System](http://css.csail.mit.edu/6.824/2014/papers/bayou-conflicts.pdf),” at *15th ACM Symposium on Operating
Systems Principles* (SOSP), pages 172182, December 1995.
[doi:10.1145/224056.224070](http://dx.doi.org/10.1145/224056.224070)
1. Jim Gray:
“[The Transaction Concept: Virtues and Limitations](http://research.microsoft.com/en-us/um/people/gray/papers/theTransactionConcept.pdf),” at *7th International Conference on
Very Large Data Bases* (VLDB), September 1981.
1. Hector Garcia-Molina and Kenneth Salem:
“[Sagas](http://www.cs.cornell.edu/andru/cs711/2002fa/reading/sagas.pdf),” at
*ACM International Conference on Management of Data* (SIGMOD), May 1987.
[doi:10.1145/38713.38742](http://dx.doi.org/10.1145/38713.38742)
1. Pat Helland:
“[Memories, Guesses, and Apologies](http://blogs.msdn.com/b/pathelland/archive/2007/05/15/memories-guesses-and-apologies.aspx),” *blogs.msdn.com*, May 15, 2007.
1. Yoongu Kim, Ross Daly, Jeremie Kim, et al.:
“[Flipping Bits in Memory Without Accessing Them: An Experimental Study of DRAM Disturbance Errors](https://users.ece.cmu.edu/~yoonguk/papers/kim-isca14.pdf),” at *41st Annual
International Symposium on Computer Architecture* (ISCA), June 2014.
[doi:10.1145/2678373.2665726](http://dx.doi.org/10.1145/2678373.2665726)
1. Mark Seaborn and Thomas Dullien:
“[Exploiting the DRAM Rowhammer Bug to Gain Kernel Privileges](https://googleprojectzero.blogspot.co.uk/2015/03/exploiting-dram-rowhammer-bug-to-gain.html),” *googleprojectzero.blogspot.co.uk*, March 9,
2015.
1. Jim N. Gray and Catharine van Ingen:
“[Empirical Measurements of Disk Failure Rates and Error Rates](https://www.microsoft.com/en-us/research/publication/empirical-measurements-of-disk-failure-rates-and-error-rates/),” Microsoft Research, MSR-TR-2005-166,
December 2005.
1. Annamalai Gurusami and Daniel Price:
“[Bug #73170: Duplicates in Unique Secondary Index Because of Fix of Bug#68021](http://bugs.mysql.com/bug.php?id=73170),” *bugs.mysql.com*, July 2014.
1. Gary Fredericks:
“[Postgres Serializability Bug](https://github.com/gfredericks/pg-serializability-bug),”
*github.com*, September 2015.
1. Xiao Chen:
“[HDFS DataNode Scanners and Disk Checker Explained](http://blog.cloudera.com/blog/2016/12/hdfs-datanode-scanners-and-disk-checker-explained/),” *blog.cloudera.com*, December 20,
2016.
1. Jay Kreps:
“[Getting Real About Distributed System Reliability](http://blog.empathybox.com/post/19574936361/getting-real-about-distributed-system-reliability),” *blog.empathybox.com*, March 19, 2012.
1. Martin Fowler:
“[The LMAX Architecture](http://martinfowler.com/articles/lmax.html),”
*martinfowler.com*, July 12, 2011.
1. Sam Stokes:
“[Move Fast with Confidence](http://blog.samstokes.co.uk/blog/2016/07/11/move-fast-with-confidence/),” *blog.samstokes.co.uk*, July 11, 2016.
1. “[Sawtooth Lake Documentation](http://intelledger.github.io/introduction.html),” Intel Corporation, *intelledger.github.io*, 2016.
1. Richard Gendal Brown:
“[Introducing R3 Corda™: A Distributed Ledger Designed for Financial Services](https://gendal.me/2016/04/05/introducing-r3-corda-a-distributed-ledger-designed-for-financial-services/),” *gendal.me*, April 5, 2016.
1. Trent McConaghy, Rodolphe Marques, Andreas Müller, et al.:
“[BigchainDB: A Scalable Blockchain Database](https://www.bigchaindb.com/whitepaper/bigchaindb-whitepaper.pdf),” *bigchaindb.com*, June 8, 2016.
1. Ralph C. Merkle:
“[A Digital Signature Based on a Conventional Encryption Function](https://people.eecs.berkeley.edu/~raluca/cs261-f15/readings/merkle.pdf),” at *CRYPTO '87*, August 1987.
[doi:10.1007/3-540-48184-2_32](http://dx.doi.org/10.1007/3-540-48184-2_32)
1. Ben Laurie:
“[Certificate Transparency](http://queue.acm.org/detail.cfm?id=2668154),” *ACM
Queue*, volume 12, number 8, pages 10-19, August 2014.
[doi:10.1145/2668152.2668154](http://dx.doi.org/10.1145/2668152.2668154)
1. Mark D. Ryan:
“[Enhanced Certificate Transparency and End-to-End Encrypted Mail](http://www.internetsociety.org/doc/enhanced-certificate-transparency-and-end-end-encrypted-mail),” at *Network and Distributed System
Security Symposium* (NDSS), February 2014.
[doi:10.14722/ndss.2014.23379](http://dx.doi.org/10.14722/ndss.2014.23379)
1. “<a
href="http://www.acm.org/about/se-code">Software Engineering Code of Ethics and Professional
Practice</a>,” Association for Computing Machinery, *acm.org*, 1999.
1. François Chollet:
“[Software development is starting to involve important ethical choices](https://twitter.com/fchollet/status/792958695722201088),” *twitter.com*, October 30, 2016.
1. Igor Perisic:
“[Making Hard Choices: The Quest for Ethics in Machine Learning](https://engineering.linkedin.com/blog/2016/11/making-hard-choices--the-quest-for-ethics-in-machine-learning),” *engineering.linkedin.com*, November
2016.
1. John Naughton:
“[Algorithm Writers Need a Code of Conduct](https://www.theguardian.com/commentisfree/2015/dec/06/algorithm-writers-should-have-code-of-conduct),” *theguardian.com*, December 6, 2015.
1. Logan Kugler:
“[What Happens When Big Data Blunders?](http://cacm.acm.org/magazines/2016/6/202655-what-happens-when-big-data-blunders/fulltext),” *Communications of the ACM*, volume 59, number 6, pages
1516, June 2016. [doi:10.1145/2911975](http://dx.doi.org/10.1145/2911975)
1. Bill Davidow:
“[Welcome to Algorithmic Prison](http://www.theatlantic.com/technology/archive/2014/02/welcome-to-algorithmic-prison/283985/),” *theatlantic.com*, February 20, 2014.
1. Don Peck:
“[They're Watching You at Work](http://www.theatlantic.com/magazine/archive/2013/12/theyre-watching-you-at-work/354681/),” *theatlantic.com*, December 2013.
1. Leigh Alexander:
“[Is an Algorithm Any Less Racist Than a Human?](https://www.theguardian.com/technology/2016/aug/03/algorithm-racist-human-employers-work)” *theguardian.com*, August 3, 2016.
1. Jesse Emspak:
“[How a Machine Learns Prejudice](https://www.scientificamerican.com/article/how-a-machine-learns-prejudice/),” *scientificamerican.com*, December 29, 2016.
1. Maciej Cegłowski:
“[The Moral Economy of Tech](http://idlewords.com/talks/sase_panel.htm),”
*idlewords.com*, June 2016.
1. Cathy O'Neil:
<a href="https://weaponsofmathdestructionbook.com/">*Weapons of Math Destruction: How Big Data
Increases Inequality and Threatens Democracy*</a>. Crown Publishing, 2016.
ISBN: 978-0-553-41881-1
1. Julia Angwin:
“[Make Algorithms Accountable](http://www.nytimes.com/2016/08/01/opinion/make-algorithms-accountable.html),” *nytimes.com*, August 1, 2016.
1. Bryce Goodman and Seth Flaxman:
“[European Union Regulations on Algorithmic Decision-Making and a Right to Explanation](https://arxiv.org/abs/1606.08813),” *arXiv:1606.08813*, August 31,
2016.
1. “[A Review of the Data Broker Industry: Collection, Use, and Sale of Consumer Data for Marketing Purposes](https://www.commerce.senate.gov/public/index.cfm/reports?ID=57C428EC-8F20-44EE-BFB8-A570E9BE0CCC),” Staff Report, *United States Senate Committee on Commerce, Science, and
Transportation*, *commerce.senate.gov*, December 2013.
1. Olivia Solon:
“[Facebooks Failure: Did Fake News and Polarized Politics Get Trump Elected?](https://www.theguardian.com/technology/2016/nov/10/facebook-fake-news-election-conspiracy-theories)” *theguardian.com*, November 10,
2016.
1. Donella H. Meadows and Diana Wright:
*Thinking in Systems: A Primer*. Chelsea Green Publishing, 2008. ISBN: 978-1-603-58055-7
1. Daniel J. Bernstein:
“[Listening to a big data/data science talk](https://twitter.com/hashbreaker/status/598076230437568512),” *twitter.com*, May 12, 2015.
1. Marc Andreessen:
“[Why Software Is Eating the World](http://genius.com/Marc-andreessen-why-software-is-eating-the-world-annotated),” *The Wall Street Journal*, 20 August 2011.
1. J. M. Porup:
“[Internet of Things Security Is Hilariously Broken and Getting Worse](http://arstechnica.com/security/2016/01/how-to-search-the-internet-of-things-for-photos-of-sleeping-babies/),” *arstechnica.com*, January 23, 2016.
1. Bruce Schneier:
<a href="https://www.schneier.com/books/data_and_goliath/">*Data and Goliath: The Hidden Battles
to Collect Your Data and Control Your World*</a>. W. W. Norton, 2015.
ISBN: 978-0-393-35217-7
1. The Grugq:
“[Nothing to Hide](https://grugq.tumblr.com/post/142799983558/nothing-to-hide),”
*grugq.tumblr.com*, April 15, 2016.
1. Tony Beltramelli:
“[Deep-Spying: Spying Using Smartwatch and Deep Learning](https://arxiv.org/abs/1512.05616),” Masters Thesis, IT University of Copenhagen, December 2015. Available at
*arxiv.org/abs/1512.05616*
1. Shoshana Zuboff:
“[Big Other: Surveillance Capitalism and the Prospects of an Information Civilization](http://papers.ssrn.com/sol3/papers.cfm?abstract_id=2594754),” *Journal of Information
Technology*, volume 30, number 1, pages 7589, April 2015.
[doi:10.1057/jit.2015.5](http://dx.doi.org/10.1057/jit.2015.5)
1. Carina C. Zona:
“[Consequences of an Insightful Algorithm](https://www.youtube.com/watch?v=YRI40A4tyWU),”
at *GOTO Berlin*, November 2016.
1. Bruce Schneier:
“[Data Is a Toxic Asset, So Why Not Throw It Out?](https://www.schneier.com/essays/archives/2016/03/data_is_a_toxic_asse.html),” *schneier.com*, March 1, 2016.
1. John E. Dunn:
“[The UKs 15 Most Infamous Data Breaches](http://www.techworld.com/security/uks-most-infamous-data-breaches-2016-3604586/),” *techworld.com*, November 18, 2016.
1. Cory Scott:
“[Data is not toxic - which implies no benefit - but rather hazardous material, where we must balance need vs. want](https://twitter.com/cory_scott/status/706586399483437056),”
*twitter.com*, March 6, 2016.
1. Bruce Schneier:
“[Mission Creep: When Everything Is Terrorism](https://www.schneier.com/essays/archives/2013/07/mission_creep_when_e.html),” *schneier.com*, July 16, 2013.
1. Lena Ulbricht and Maximilian von Grafenstein:
“[Big Data: Big Power Shifts?](http://policyreview.info/articles/analysis/big-data-big-power-shifts),” *Internet Policy Review*, volume 5, number 1, March 2016.
[doi:10.14763/2016.1.406](http://dx.doi.org/10.14763/2016.1.406)
1. Ellen P. Goodman and Julia Powles:
“[Facebook and Google: Most Powerful and Secretive Empires We've Ever Known](https://www.theguardian.com/technology/2016/sep/28/google-facebook-powerful-secretive-empire-transparency),” *theguardian.com*, September 28,
2016.
1. [Directive 95/46/EC on the protection of individuals with regard to the processing of personal data and on the free movement of such data](http://eur-lex.europa.eu/legal-content/EN/TXT/?uri=CELEX:31995L0046), Official Journal of the European Communities No. L 281/31,
*eur-lex.europa.eu*, November 1995.
1. Brendan Van Alsenoy:
“[Regulating Data Protection: The Allocation of Responsibility and Risk Among Actors Involved in Personal Data Processing](https://lirias.kuleuven.be/handle/123456789/545027),”
Thesis, KU Leuven Centre for IT and IP Law, August 2016.
1. Michiel Rhoen:
“[Beyond Consent: Improving Data Protection Through Consumer Protection Law](http://policyreview.info/articles/analysis/beyond-consent-improving-data-protection-through-consumer-protection-law),” *Internet Policy
Review*, volume 5, number 1, March 2016.
[doi:10.14763/2016.1.404](http://dx.doi.org/10.14763/2016.1.404)
1. Jessica Leber:
“[Your Data Footprint Is Affecting Your Life in Ways You Cant Even Imagine](https://www.fastcoexist.com/3057514/your-data-footprint-is-affecting-your-life-in-ways-you-cant-even-imagine),” *fastcoexist.com*, March 15,
2016.
1. Maciej Cegłowski:
“[Haunted by Data](http://idlewords.com/talks/haunted_by_data.htm),” *idlewords.com*,
October 2015.
1. Sam Thielman:
“[You Are Not What You Read: Librarians Purge User Data to Protect Privacy](https://www.theguardian.com/us-news/2016/jan/13/us-library-records-purged-data-privacy),” *theguardian.com*,
January 13, 2016.
1. Conor Friedersdorf:
“[Edward Snowdens Other Motive for Leaking](http://www.theatlantic.com/politics/archive/2014/05/edward-snowdens-other-motive-for-leaking/370068/),” *theatlantic.com*, May 13, 2014.
1. Phillip Rogaway:
“[The Moral Character of Cryptographic Work](http://web.cs.ucdavis.edu/~rogaway/papers/moral-fn.pdf),” Cryptology ePrint 2015/1162, December 2015.

1083
ddia/ch2.md Normal file

File diff suppressed because it is too large Load Diff

856
ddia/ch3.md Normal file
View File

@ -0,0 +1,856 @@
# 3. 存储与检索
![](img/ch3.png)
> 建立秩序,省却搜索
>
> ——德国谚语
>
-------------------
[TOC]
在最基本的层次上,一个数据库需要完成两件事情:当你给它数据时,它应该存储起来,而当你提问时,它应该把数据返回给你。
在第二章中,我们讨论了数据模型和查询语言,即程序员录入数据库的数据格式,以及你可以再次获取它的机制。在本章中,我们讨论一样的问题,但是是从数据库的视角:我们如何存储我们提供的数据,以及如何在需要时重新找到数据。
作为程序员,为什么要关心数据库如何在内部处理存储和检索?您可能不会从头开始实现自己的存储引擎,但是您需要从可用的许多存储引擎中选择适合应用程序的存储引擎。为了调整存储引擎以适应应用的工作负载,你需要大致了解存储引擎在做什么。
特别需要注意针对事务性工作负载优化的存储引擎与针对分析优化的存储引擎之间存在着巨大差异。稍后我们将在第90页的 “事务处理或分析?” 和第91页的 “列存储”中探讨这个区别,那里将讨论针对分析优化的一系列存储引擎。
但是我们将从您最可能熟悉的两大类数据库传统关系型数据库与所谓的“NoSQL”数据库开始通过介绍它们的存储引擎来开始本章的内容。
我们会研究两大类存储引擎日志结构log-structured的存储引擎以及面向页面page-oriented的存储引擎如B树
### 数据库的底层数据结构
世界上最简单的数据库可以用两个Bash函数实现
```bash
#!/bin/bash
db_set () {
echo "$1,$2" >> database
}
db_get () {
grep "^$1," database | sed -e "s/^$1,//" | tail -n 1
}
```
这两个函数实现了键值存储的功能。执行`db_set key value`,会将`key`和`value`存储在数据库中。键和值可以是几乎任何你喜欢的东西例如值可以是JSON文档。然后调用`db_get key`,查找与该键关联的最新值并将其返回。麻雀虽小,五脏俱全:
```bash
$ db_set 123456 '{"name":"London","attractions":["Big Ben","London Eye"]}' $ db_set 42 '{"name":"San Francisco","attractions":["Golden Gate Bridge"]}'
$ db_get 42
{"name":"San Francisco","attractions":["Golden Gate Bridge"]}
```
底层的存储格式非常简单一个文本文件每行包含一条逗号分隔的键值对忽略转义问题的话大致类似于CSV文件。每次对`db_set`的调用都会追加记录到文件末尾,所以更新键的时候旧版本的值不会被覆盖。需要查看文件中最后一次出现的键以查找最新值(因此`db_get`中使用了`tail -n 1 `。)
```bash
$ db_set 42 '{"name":"San Francisco","attractions":["Exploratorium"]}' $ db_get 42
{"name":"San Francisco","attractions":["Exploratorium"]}
$ cat database
123456,{"name":"London","attractions":["Big Ben","London Eye"]} 42,{"name":"San Francisco","attractions":["Golden Gate Bridge"]} 42,{"name":"San Francisco","attractions":["Exploratorium"]}
```
`db_set`函数对于极其简单的场景其实有非常好的性能,因为在文件尾部追加写入通常是非常高效的。与`db_set`做的事情类似许多数据库内部使用日志log也就是一个Append-Only的数据文件。真正的数据库有更多的问题需要处理如并发控制回收磁盘空间以免日志无限增长处理错误和部分写入记录但基本原理是一样的。日志非常有用我们还将在本书的其它部分见到它。
> 日志这个词通常用来指应用程序日志,应用程序输出描述发生事情的文本。本书中,日志用于更一般的含义上:一个只有追加记录的序列。它不一定是人类可读的记录,它可能是只能由其他程序读取的二进制记录。
另一方面,如果这个数据库中有大量记录,则我们的`db_get`函数的性能会非常糟糕。每次你想查找一个键时,`db_get`必须从头到尾扫描整个数据库文件来查找键的出现。在算法方面,查找的成本是`O(n)`如果数据库的记录数量n增加了一倍查找也需要一倍的时间。这就不好了。
为了高效地找到数据库中特定键的值,我们需要一个数据结构:索引。本章将介绍一系列的索引结构并对它们进行对比。索引的通用思路是保存一些额外的元数据作为路标,帮助你找到你想要的数据。如果您想以几种不同的方式在相同的数据中搜索,也许需要在数据的不同部分使用多个不同的索引。
索引是从主数据派生的附加结构。许多数据库允许添加和删除索引,这不会影响数据的内容,它只影响查询的性能。维护额外的结构会产生开销,特别是在写入时。写入性能很难超过简单地追加写入文件,因为这是最简单的写入操作。任何类型的索引通常都会减慢写入速度,因为每次写入数据时都需要更新索引。
这是存储系统中一个重要的权衡精心选取的索引加快了读取查询速度但是每个索引都会减慢写入速度。因此数据库通常不会索引所有内容需要程序员或DBA通过对应用查询模式的了解来手动选择索引。你可以选择能为应用带来最大收益同时又不会引入超必要开销的索引。
### 哈希索引
让我们从键值数据key-value Data的索引开始。这不是您可以索引的唯一一种数据类型但键值数据是非常常见的。对于更复杂的索引来说这是一个有用的构建模块。
键值存储与在大多数编程语言中可以找到的字典类型非常相似,通常字典都是用散列表(哈希表)实现的。哈希映射在许多算法教科书中都有描述[1,2]所以我们不会详细讨论它们工作方式。既然我们已经有内存数据结构——HashMap为什么不使用它们来索引在磁盘上的数据呢
假设我们的数据存储只包含一个文件就像前面的例子一样。然后最简单的索引策略是保留一个内存HashMap其中每个键映射到数据文件中的一个字节偏移量即该值可以被找到的位置。
如图3-1所示。无论何时将新的键值对添加到文件中还要更新散列映射以反映刚刚写入的数据的偏移量这适用于插入新键和更新现有键。查找一个值时使用哈希映射来查找数据文件中的偏移量寻找该位置并读取该值。
![](img/fig3-1.png)
**图3-1 以类CSV格式存储键值对的日志并使用内存哈希映射进行索引。**
听上去简单但这是一个可行的方法。这实际上就是Bitcask做的事情Riak中默认的存储引擎[3]。 Bitcask提供高性能的读取和写入操作但所有键必须能合适地放入在内存因为哈希映射完全保留在内存中。这些值可以使用比可用内存更多的空间因为可以从磁盘上通过一次`seek`加载所需部分如果数据文件的那部分已经在文件系统缓存中则读取根本不需要任何磁盘I/O。
像Bitcask这样的存储引擎非常适合每个键的值经常更新的情况。例如键可能是猫视频的URL值可能是它播放的次数每次有人点击播放按钮时递增。在这种类型的工作负载中有很多写操作但是没有太多不同的键 - 每个键有很多的写操作,但是将所有键保存在内存中是可行的。
直到现在,我们只是追加写一个文件 - 所以我们如何避免最终用完磁盘空间一个好的解决方案是通过在达到一定大小时关闭一个段文件然后将其写入一个新的段文件来将日志分割成特定大小的段。然后我们可以对这些段进行压缩如图3-2所示。压缩意味着在日志中丢弃重复的键只保留每个键的最新更新。
![](img/fig3-2.png)
**图3-2 压缩键值更新日志(统计猫视频的播放次数),只保留每个键的最近值**
而且由于压缩经常会使得段更小假设在一个段内键被平均重写了好几次我们也可以在执行压缩的同时将多个段合并在一起如图3-3所示。段被写入后永远不会被修改所以合并的段被写入一个新的文件。冻结段的合并和压缩可以在后台线程中完成在进行时我们仍然可以继续使用旧的段文件来正常提供读写请求。合并过程完成后我们将读取请求转换为使用新的合并段而不是旧段 - 然后可以简单地删除旧的段文件。
![](img/fig3-3.png)
**图3-3 同时执行压缩和分段合并**
每个段现在都有自己的内存散列表,将键映射到文件偏移量。为了找到一个键的值,我们首先检查最近段的哈希映射;如果键不存在,我们检查第二个最近的段,依此类推。合并过程保持细分的数量,所以查找不需要检查许多哈希映射。
大量的细节进入实践这个简单的想法工作。简而言之,一些真正实施中重要的问题是:
* 文件格式
CSV不是日志的最佳格式。使用二进制格式更快更简单首先以字节为单位对字符串的长度进行编码然后使用原始字符串不需要转义
* 删除记录
如果要删除一个键及其关联的值,则必须在数据文件(有时称为逻辑删除)中附加一个特殊的删除记录。当日志段被合并时,逻辑删除告诉合并过程放弃删除键的任何以前的值。
* 崩溃恢复
如果数据库重新启动,则内存散列映射将丢失。原则上,您可以通过从头到尾读取整个段文件并在每次按键时注意每个键的最近值的偏移量来恢复每个段的哈希映射。但是,如果段文件很大,这可能需要很长时间,这将使服务器重新启动痛苦。 Bitcask通过存储加速恢复磁盘上每个段的哈希映射的快照可以更快地加载到内存中。
* 部分书面记录
数据库可能随时崩溃,包括将记录附加到日志中途。 Bitcask文件包含校验和允许检测和忽略日志的这些损坏部分。
* 并发控制
由于写操作是以严格顺序的顺序附加到日志中的,所以常见的实现选择是只有一个写入器线程。数据文件段是附加的,否则是不可变的,所以它们可以被多个线程同时读取。
乍一看,只有追加日志看起来很浪费:为什么不更新文件,用新值覆盖旧值?但是只能追加设计的原因有几个:
* 追加和分段合并是顺序写入操作通常比随机写入快得多尤其是在磁盘旋转硬盘上。在某种程度上顺序写入在基于闪存的固态硬盘SSD上也是优选的[4]。我们将在第83页的“比较B-树和LSM-树”中进一步讨论这个问题。
* 如果段文件是附加的或不可变的,并发和崩溃恢复就简单多了。例如,您不必担心在覆盖值时发生崩溃的情况,而将包含旧值和新值的一部分的文件保留在一起。
* 合并旧段可以避免数据文件随着时间的推移而分散的问题。
但是,哈希表索引也有局限性:
* 散列表必须能放进内存
如果你有非常多的键那真是倒霉。原则上可以在磁盘上保留一个哈希映射不幸的是磁盘哈希映射很难表现优秀。它需要大量的随机访问I/O当它变满时增长是很昂贵的并且散列冲突需要很多的逻辑[5]。
* 范围查询效率不高。例如您无法轻松扫描kitty00000和kitty99999之间的所有键 - 您必须在散列映射中单独查找每个键。
在下一节中,我们将看看一个没有这些限制的索引结构。
### SSTables和LSM-Trees
在图3-3中每个日志结构存储段都是一系列键值对。这些对按照它们写入的顺序出现日志中稍后的值优先于日志中较早的相同键的值。除此之外文件中键值对的顺序并不重要。
现在我们可以对段文件的格式做一个简单的改变:我们要求键值对的序列按键排序。乍一看,这个要求似乎打破了我们使用顺序写入的能力,但是我们马上就会明白这一点。
我们把这个格式称为Sorted String Table简称SSTable。我们还要求每个键只在每个合并的段文件中出现一次压缩过程已经确保。与使用散列索引的日志段相比SSTable有几个很大的优势
1. 合并段是简单而高效的即使文件大于可用内存。这种方法就像mergesort算法中使用的方法一样如图3-4所示您开始并排读取输入文件查看每个文件中的第一个键复制最低键根据排序顺序到输出文件并重复。这产生一个新的合并段文件也按键排序。
![](img/fig3-4.png)
##### 图3-4 合并几个SSTable段只保留每个键的最新值
如果在几个输入段中出现相同的键,该怎么办?请记住,每个段都包含在一段时间内写入数据库的所有值。这意味着一个输入段中的所有值必须比另一个段中的所有值更新(假设我们总是合并相邻的段)。当多个段包含相同的键时,我们可以保留最近段的值,并丢弃旧段中的值。
2. 为了在文件中找到一个特定的键,你不再需要保存内存中所有键的索引。以[图3-5]()为例:假设你正在内存中寻找键`handiwork`,但是你不知道段文件中该关键字的确切偏移量。然而,你知道`handbag`和`handsome`的偏移,而且由于排序特性,你知道`handiwork`必须出现在这两者之间。这意味着您可以跳到`handbag`的偏移位置并从那里扫描,直到您找到`handiwork`(或没找到,如果该文件中没有该键)。
![](img/fig3-5.png)
**图3-5 具有内存索引的SSTable**
您仍然需要一个内存中索引来告诉您一些键的偏移量,但它可能很稀疏:每几千字节的段文件就有一个键就足够了,因为几千字节可以很快被扫描。
3. 由于读取请求无论如何都需要扫描所请求范围内的多个键值对因此可以将这些记录分组到块中并在将其写入磁盘之前对其进行压缩如图3-5中的阴影区域所示 。稀疏内存中索引的每个条目都指向压缩块的开始处。除了节省磁盘空间之外压缩还可以减少IO带宽的使用。
#### 构建和维护SSTables
到目前为止,但是如何让你的数据首先被按键排序呢?我们的传入写入可以以任何顺序发生。
在磁盘上维护有序结构是可能的参阅“B-Tree”但在内存保存则要容易得多。有许多可以使用的众所周知的树形数据结构例如红黑树或AVL树[2]。使用这些数据结构,您可以按任何顺序插入键,并按排序顺序读取它们。
现在我们可以使我们的存储引擎工作如下:
* 写入时将其添加到内存中的平衡树数据结构for例如红黑树。这个内存树有时被称为memtable。
* 当memtable大于某个阈值通常为几兆字节将其作为SSTable文件写入磁盘。这可以高效地完成因为树已经维护了按键排序的键值对。新的SSTable文件成为数据库的最新部分。当SSTable被写入磁盘时写入可以继续到一个新的memtable实例。
* 为了提供读取请求首先尝试在memtable中找到关键字然后在最近的磁盘段中然后在下一个较旧的段中找到该关键字。
* 有时会在后台运行合并和压缩过程以组合段文件并丢弃覆盖或删除的值。
这个方案效果很好。它只会遇到一个问题如果数据库崩溃则最近的写入在memtable中但尚未写入磁盘将丢失。为了避免这个问题我们可以在磁盘上保存一个单独的日志每个写入都会立即被附加到磁盘上就像在前一节中一样。该日志不是按排序顺序但这并不重要因为它的唯一目的是在崩溃后恢复memtable。每当Memtable写出到SSTable时相应的日志都可以被丢弃。
#### 用SSTables制作LSM树
这里描述的算法本质上是LevelDB [6]和RocksDB [7]中使用的关键值存储引擎库被设计嵌入到其他应用程序中。除此之外LevelDB可以在Riak中用作Bitcask的替代品。在Cassandra和HBase中使用了类似的存储引擎[8]这两种引擎都受到了Google的Bigtable文档[9]引入了SSTable和memtable的启发。
最初这种索引结构是由Patrick O'Neil等人描述的。在Log-Structured Merge-Tree或LSM-Tree[10]的基础上,建立在以前的工作上日志结构的文件系统[11]。基于这种合并和压缩排序文件原理的存储引擎通常被称为LSM存储引擎。
Lucene是Elasticsearch和Solr使用的一种全文搜索的索引引擎它使用类似的方法来存储它的词典[12,13]。全文索引比键值索引复杂得多但是基于类似的想法在搜索查询中给出一个单词找到提及单词的所有文档网页产品描述等。这是通过键值结构实现的其中键是单词术语值是包含单词发布列表的所有文档的ID的列表。在Lucene中从术语到发布列表的这种映射保存在SSTable类的有序文件中根据需要在后台合并[14]。
#### 性能优化
与往常一样大量的细节使得存储引擎在实践中表现良好。例如当查找数据库中不存在的键时LSM树算法可能会很慢您必须检查memtable然后将这些段一直回到最老的可能必须从磁盘读取每一个然后才能确定键不存在。为了优化这种访问存储引擎通常使用额外的Bloom过滤器[15]。 (布隆过滤器是用于近似集合内容的内存高效数据结构,它可以告诉您数据库中是否出现键,从而为不存在的键节省许多不必要的磁盘读取操作。
还有不同的策略来确定SSTables如何被压缩和合并的顺序和时间。最常见的选择是大小分层压实。 LevelDB和RocksDB使用平坦压缩因此Lev-elDB的名称HBase使用大小分层Cassandra同时支持[16]。在规模级别的调整中更新和更小的SSTables先后被合并到更老的和更大的SSTable中。在水平压实中关键范围被拆分成更小的SSTables而较旧的数据被移动到单独的“水平”这使得压缩能够更加递增地进行并且使用更少的磁盘空间。
即使有许多微妙的东西LSM树的基本思想 - 保存一系列在后台合并的SSTables - 简单而有效。即使数据集比可用内存大得多它仍能继续正常工作。由于数据按排序顺序存储因此可以高效地执行范围查询扫描所有高于某些最小值和最高值的所有键并且因为磁盘写入是连续的所以LSM-tree可以支持非常高的写入吞吐量。
### B树
我们迄今为止讨论的日志结构索引正在被接受但它们并不是最常见的索引类型。使用最广泛的索引结构是1970年引入[17]不到10年后又被称为“无处不在”[18]B树经受了时间的考验。在几乎所有的关系数据库中它们仍然是标准的索引实现许多非关系数据库也使用它们。
像SSTables一样B树保持按键排序的键值对这允许高效的键值查找和范围查询。但这就是相似之处的结尾B树有着非常不同的设计理念。
我们前面看到的日志结构索引将数据库分解为可变大小的段通常是几兆字节或更大的大小并且总是按顺序编写段。相比之下B树将数据库分解成固定大小的块或页面传统上大小为4 KB有时会更大并且一次只能读取或写入一个页面。这种设计更接近于底层硬件因为磁盘也被安排在固定大小的块中。
每个页面都可以使用地址或位置来标识,这允许一个页面引用另一个页面 - 类似于指针,但在磁盘而不是在内存中。我们可以使用这些页面引用来构建一个页面树,如[图3-6]()所示。
![](img/fig3-6.png)
**图3-6 使用B树索引查找一个键**
一个页面会被指定为B树的根在索引中查找一个键时就从这里开始。该页面包含几个键和对子页面的引用。每个子页面负责一段连续范围的键引用之间的键指明了引用子页面的键范围。
在[图3-6]()的例子中我们正在寻找关键字251所以我们知道我们需要遵循边界200和300之间的页面引用。这将我们带到一个类似的页面进一步打破了200 -300到子范围。
最后,我们可以看到包含单个键(叶页)的页面,该页面包含每个键的内联值,或者包含对可以找到值的页面的引用。
在B树的一个页面中对子页面的引用的数量称为分支因子。例如在图3-6中分支因子是六。在实践中分支因子取决于存储页面参考和范围边界所需的空间量但通常是几百个。
如果要更新B树中现有键的值则搜索包含该键的叶页更改该页中的值并将该页写回到磁盘对该页的任何引用保持有效 。如果你想添加一个新的键你需要找到其范围包含新键的页面并将其添加到该页面。如果页面中没有足够的可用空间容纳新键则将其分成两个半满页面并更新父页面以解释键范围的新分区如图3-7所示。
![](img/fig3-7.png)
**图3-7 通过分割页面来生长B树**
该算法确保树保持平衡具有n个键的B树总是具有Olog n的深度。大多数数据库可以放入一个三到四层的B树所以你不需要遵循许多页面引用来找到你正在查找的页面。 分支因子为500的4 KB页面的四级树可以存储多达256 TB。
#### 让B树更可靠
B树的基本底层写操作是用新数据覆盖磁盘上的页面。假定覆盖不改变页面的位置;即当页面被覆盖时对该页面的所有引用保持完整。这与日志结构索引如LSM-trees形成鲜明对比后者只附加到文件并最终删除过时的文件但从不修改文件。
您可以考虑将硬盘上的页面覆盖为实际的硬件操作。在磁性硬盘驱动器上这意味着将磁头移动到正确的位置等待旋转盘上的正确位置出现然后用新的数据覆盖适当的扇区。在固态硬盘上由于SSD必须一次擦除和重写相当大的存储芯片块所以会发生更复杂的事情[19]。
而且,一些操作需要覆盖几个不同的页面。例如,如果因为插入导致页面过度而拆分页面,则需要编写已拆分的两个页面,并覆盖其父页面以更新对两个子页面的引用。这是一个危险的操作,因为如果数据库在仅有一些页面被写入后崩溃,那么最终将导致一个损坏的索引(例如,可能有一个孤儿页面不是任何父项的子项) 。
为了使数据库对崩溃具有韧性B树实现通常会带有一个额外的磁盘数据结构预写式日志WAL也称为重做日志。这是一个只能追加的文件每个B树修改都可以应用到树本身的页面上。当数据库在崩溃后恢复时这个日志被用来恢复B树回到一致的状态[5,20]。
更新页面的一个额外的复杂情况是如果多个线程要同时访问B树则需要仔细的并发控制 - 否则线程可能会看到树处于不一致的状态。这通常通过使用***锁存器latches***(轻量级锁)保护树的数据结构来完成。日志结构化的方法在这方面更简单,因为它们在后台进行所有的合并,而不会干扰传入的查询,并且不时地将旧的分段原子交换为新的分段。
#### B树优化
由于B树已经存在了这么久许多优化已经发展了多年这并不奇怪。仅举几例
* 一些数据库如LMDB使用写时复制方案[21]而不是覆盖页面并维护WAL进行崩溃恢复。修改的页面被写入到不同的位置并且树中的父页面的新版本被创建指向新的位置。这种方法对于并发控制也很有用我们将在第237页的“快照隔离和可重复读取”中看到。
* 我们可以通过不存储整个键来节省页面空间,但可以缩小它的大小。特别是在树内部的页面上,键只需要提供足够的信息来充当键范围之间的边界。在页面中包含更多的键允许树具有更高的分支因子,因此更少的层次
* 通常,页面可以放置在磁盘上的任何位置;没有什么要求附近的键范围页面附近的磁盘上。如果查询需要按照排序顺序扫描大部分关键字范围那么每个页面的布局可能会非常不方便因为每个读取的页面都可能需要磁盘查找。因此许多B-树实现尝试布局树使得叶子页面按顺序出现在磁盘上。但是随着树的增长维持这个顺序是很困难的。相比之下由于LSM树在合并过程中一次又一次地重写存储的大部分所以它们更容易使顺序键在磁盘上彼此靠近。
* 额外的指针已添加到树中。例如,每个叶子页面可以在左边和右边具有对其兄弟页面的引用,这允许不跳回父页面就能顺序扫描。
* B树的变体如分形树[22]借用一些日志结构的思想来减少磁盘寻道(而且它们与分形无关)。
### 比较B-树和LSM-树
尽管B树实现通常比LSM树实现更成熟但LSM树由于其性能特点也非常有趣。根据经验LSM树通常写速度更快而B树被认为读取速度更快[23]。 LSM树上的读取通常比较慢因为他们必须在压缩的不同阶段检查几个不同的数据结构和SSTables。
然而,基准通常对工作量的细节不确定和敏感。 您需要测试具有特定工作负载的系统,以便进行有效的比较。 在本节中,我们将简要讨论一些在衡量存储引擎性能时值得考虑的事情。
#### LSM树的优点
B树索引必须至少两次写入每一段数据一次写入预先写入日志一次写入树页面本身也许再次分页。即使在该页面中只有几个字节发生了变化也需要一次编写整个页面的开销。有些存储引擎甚至会覆盖同一个页面两次以免在电源故障的情况下导致页面部分更新[24,25]。
由于反复压缩和合并SSTables日志结构索引也会重写数据。这种影响 - 在数据库的生命周期中写入数据库导致对磁盘的多次写入 - 被称为**写放大Write amplification**。固态硬盘是特别值得关注的,固态硬盘在磨损之前只能覆盖一段时间。
在写入繁重的应用程序中,性能瓶颈可能是数据库可以写入磁盘的速度。在这种情况下,写入放大具有直接的性能成本:存储引擎写入磁盘的次数越多,可用磁盘带宽内的每秒写入次数越少。
而且LSM树通常能够比B-树支持更高的写入吞吐量部分原因是它们有时具有较低的写入放大尽管这取决于存储引擎配置和工作负载部分是因为它们顺序地写入紧凑的SSTable文件而不是必须覆盖树中的几个页面[26]。这种差异在磁性硬盘驱动器上尤其重要,顺序写入比随机写入快得多。
LSM树可以被压缩得更好因此经常比B树在磁盘上产生更小的文件。 B树存储引擎会由于分割而留下一些未使用的磁盘空间当页面被拆分或某行不能放入现有页面时页面中的某些空间仍未被使用。由于LSM树不是面向页面的并且定期重写SSTables以去除碎片所以它们具有较低的存储开销特别是当使用平坦压缩时[27]。
在许多固态硬盘上,固件内部使用日志结构化算法,将随机写入转变为顺序写入底层存储芯片,因此存储引擎写入模式的影响不太明显[19]。但是较低的写入放大率和减少的碎片对SSD仍然有利更紧凑地表示数据可在可用的I/O带宽内提供更多的读取和写入请求。
#### LSM树的缺点
日志结构存储的缺点是压缩过程有时会干扰正在进行的读写操作。尽管存储引擎尝试逐步执行压缩而不影响并发访问但是磁盘资源有限所以很容易发生请求需要等待而磁盘完成昂贵的压缩操作。对吞吐量和平均响应时间的影响通常很小但是在更高百分比的情况下请参阅第13页上的“描述性能”对日志结构化存储引擎的查询响应时间有时会相当长而B树的行为则相对更具可预测性[28]。
压缩的另一个问题出现在高写入吞吐量磁盘的有限写入带宽需要在初始写入记录和刷新memtable到磁盘和在后台运行的压缩线程之间共享。写入空数据库时可以使用全磁盘带宽进行初始写入但数据库越大压缩所需的磁盘带宽就越多。
如果写入吞吐量很高并且压缩没有仔细配置压缩跟不上写入速率。在这种情况下磁盘上未合并段的数量不断增加直到磁盘空间用完读取速度也会减慢因为它们需要检查更多段文件。通常情况下即使压缩无法跟上基于SSTable的存储引擎也不会限制传入写入的速率所以您需要进行明确的监控来检测这种情况[29,30]。
B树的一个优点是每个键只存在于索引中的一个位置而日志结构化的存储引擎可能在不同的段中有相同键的多个副本。这个方面使得B树在想要提供强大的事务语义的数据库中很有吸引力在许多关系数据库中事务隔离是通过在键范围上使用锁来实现的在B树索引中这些锁可以直接连接到树[5]。在第7章中我们将更详细地讨论这一点。
B树在数据库体系结构中是非常根深蒂固的为许多工作负载提供始终如一的良好性能所以它们不可能很快就会消失。在新的数据存储中日志结构化索引变得越来越流行。没有快速和容易的规则来确定哪种类型的存储引擎对你的场景更好所以值得进行一些经验上的测试
### 其他索引结构
到目前为止,我们只讨论了关键值索引,它们就像关系模型中的**主键primary key**索引。主键唯一标识关系表中的一行或文档数据库中的一个文档或图形数据库中的一个顶点。数据库中的其他记录可以通过其主键或ID引用该行/文档/顶点,并且索引用于解析这样的引用。
有二级索引也很常见。在关系数据库中您可以使用CREATE INDEX命令在同一个表上创建多个二级索引而且这些索引通常对于有效地执行联接而言至关重要。例如在第2章中的[图2-1]()中,很可能在`user_id`列上有一个二级索引,以便您可以在每个表中找到属于同一用户的所有行。
一个二级索引可以很容易地从一个键值索引构建。主要的不同是Key不是唯一的。即可能有许多行文档顶点具有相同的键。这可以通过两种方式来解决或者通过使索引中的每个值成为匹配行标识符的列表如全文索引中的发布列表或者通过向每个索引添加行标识符来使每个关键字唯一。无论哪种方式B树和日志结构索引都可以用作辅助索引。
#### 将值存储在索引中
索引中的关键字是查询搜索的内容,但是该值可以是以下两种情况之一:它可以是所讨论的实际行(文档,顶点),也可以是对存储在别处的行的引用。在后一种情况下,行被存储的地方被称为**堆文件heap file**,并且存储的数据没有特定的顺序(它可以是仅附加的,或者可以跟踪被删除的行以便用新数据覆盖它们后来)。堆文件方法很常见,因为它避免了在存在多个二级索引时复制数据:每个索引只引用堆文件中的一个位置,实际的数据保存在一个地方。
在不更改键的情况下更新值时,堆文件方法可以非常高效:只要新值不大于旧值,就可以覆盖该记录。如果新值更大,情况会更复杂,因为它可能需要移到堆中有足够空间的新位置。在这种情况下,要么所有的索引都需要更新,以指向记录的新堆位置,或者在旧堆位置留下一个转发指针[5]。
在某些情况下从索引到堆文件的额外跳跃对读取来说性能损失太大因此可能希望将索引行直接存储在索引中。这被称为聚集索引。例如在MySQL的InnoDB存储引擎中表的主键总是一个聚簇索引二级索引是指主键而不是堆文件的位置[31]。在SQL Server中您可以为每个表指定一个聚簇索引[32]。
在**聚集索引clustered index**(在索引中存储所有行数据)和**非聚集索引nonclustered index**(仅在索引中存储对数据的引用)之间的折衷被称为**包含列的索引index with included columns**或**覆盖索引covering index**,其存储表的一部分在索引内[33]。这允许通过单独使用索引来回答一些查询(这种情况叫做:索引**覆盖了cover**查询)[32]。
与任何类型的数据重复一样,聚簇和覆盖索引可以加快读取速度,但是它们需要额外的存储空间,并且会增加写入开销。数据库还需要额外的努力来执行事务保证,因为应用程序不应该因为重复而导致不一致。
#### 多列索引
目前讨论的索引只将一个键映射到一个值。这是不够的,如果我们需要同时查询一个表(或文档中的多个字段)的多个列。
最常见的多列索引被称为**连接索引concatenated index**,它通过将一列附加到另一列(索引定义指定字段以何种顺序连接)来简单地将多个字段组合成一个键。这就像一个老式的纸质电话簿,它提供了一个从(姓,名)到电话号码的索引。由于排序顺序,索引可以用来查找所有具有特定姓氏的人,或所有具有特定姓氏 - 姓氏组合的人。**然而,如果你想找到所有具有特定名字的人,这个索引是没有用的**。
多维索引是一种查询多个列的更一般的方法,这对于地理空间数据尤为重要。例如,餐馆搜索网站可能有一个数据库,其中包含每个餐厅的经度和纬度。当用户在地图上查看餐馆时,网站需要搜索用户正在查看的矩形地图区域内的所有餐馆。这需要一个二维范围查询,如下所示:
```sql
SELECT * FROM restaurants WHERE latitude > 51.4946 AND latitude < 51.5079
AND longitude > -0.1162 AND longitude < -0.1004;
```
一个标准的B树或者LSM树索引不能够有效地回答这种查询它可以给你一个纬度范围内的所有餐馆但是在任何长度上或者所有餐馆一系列的经度但在北极和南极之间的任何地方但不能同时存在。
一种选择是使用空间填充曲线将二维位置转换为单个数字然后使用常规B树索引[34]。更普遍的是使用特殊化的空间索引例如R树。例如PostGIS使用PostgreSQL的Gist工具[35]将地理空间索引实现为R-树。这里我们没有足够的空间来描述R树但是有大量的文献可供参考。
一个有趣的想法是多维索引不仅仅是地理位置。例如在电子商务网站上您可以使用维度红色绿色蓝色上的三维索引来搜索特定颜色范围内的产品也可以在天气观测数据库中搜索二维日期温度的指数以便有效地搜索2013年的温度在25至30°C之间的所有观测资料。使用一维索引您将不得不扫描2013年的所有记录不管温度如何然后通过温度进行过滤反之亦然。 2D索引可以同时通过时间戳和温度缩小。这个技术被HyperDex使用[36]。
#### 全文搜索和模糊索引
到目前为止所讨论的所有索引都假定您有确切的数据,并允许您查询键的确切值或具有排序顺序的键的值范围。他们不允许你做的是搜索类似的键,如拼写错误的单词。这种模糊的查询需要不同的技术。
例如全文搜索引擎通常允许搜索一个单词以扩展为包括该单词的同义词忽略单词的语法变体并且搜索在相同文档中彼此靠近的单词的出现并且支持各种其他功能取决于文本的语言分析。为了处理文档或查询中的拼写错误Lucene能够在一定的编辑距离内搜索文本编辑距离1意味着添加删除或替换了一个字母[37]。
正如第78页“在SSTables中创建一个LSM-tree”中所提到的Lucene为其词典使用了一个类似于SSTable的结构。这个结构需要一个小的内存索引告诉查询在排序文件中哪个偏移量需要查找关键字。在LevelDB中这个内存中的索引是一些键的稀疏集合但在Lucene中内存中的索引是键中字符的有限状态自动机类似于trie [38]。这个自动机可以转换成Levenshtein自动机它支持在给定的编辑距离内有效地搜索单词[39]。
其他的模糊搜索技术正朝着文档分类和机器学习的方向发展。有关更多详细信息,请参阅信息检索教科书[例如40]。
#### 在内存中存储一切
本章到目前为止讨论的数据结构都是对磁盘限制的回答。与主内存相比磁盘处理起来很尴尬。对于磁盘和SSD如果要在读取和写入时获得良好性能则需要仔细地布置磁盘上的数据。但是我们容忍这种尴尬因为磁盘有两个显着的优点它们是耐用的它们的内容在电源关闭时不会丢失并且每GB的成本比RAM低。
随着RAM变得更便宜每GB的成本价格被侵蚀了。许多数据集不是那么大所以将它们全部保存在内存中是非常可行的可能分布在多个机器上。这导致了内存数据库的发展。
某些内存中的键值存储如Memcached仅用于缓存在重新启动计算机时丢失的数据是可以接受的。但其他内存数据库的目标是持久性可以通过特殊的硬件例如电池供电的RAM将更改日志写入磁盘将定时快照写入磁盘或通过复制内存来实现记忆状态到其他机器。
内存数据库重新启动时,需要从磁盘或通过网络从副本重新加载其状态(除非使用特殊的硬件)。尽管写入磁盘,它仍然是一个内存数据库,因为磁盘仅用作耐久性附加日志,读取完全由内存提供。写入磁盘也具有操作优势:磁盘上的文件可以很容易地由外部实用程序进行备份,检查和分析。
诸如VoltDBMemSQL和Oracle TimesTen等产品是具有关系模型的内存数据库供应商声称通过消除与管理磁盘上的数据结构相关的所有开销他们可以提供巨大的性能改进[41,42]。 RAMCloud是一个开源的内存键值存储器具有持久性对存储器中的数据以及磁盘上的数据使用日志结构化方法[43]。 Redis和Couchbase通过异步写入磁盘提供了较弱的持久性。
**反直觉的是,内存数据库的性能优势并不是因为它们不需要从磁盘读取的事实。即使是基于磁盘的存储引擎也可能永远不需要从磁盘读取,因为操作系统缓存最近在内存中使用了磁盘块。相反,它们更快的原因在于省去了将内存数据结构编码为磁盘数据结构的开销**。[44]。
除了性能内存数据库的另一个有趣的领域是提供难以用基于磁盘的索引实现的数据模型。例如Redis为各种数据结构如优先级队列和集合提供了类似数据库的接口。因为它将所有数据保存在内存中所以它的实现相对简单。
最近的研究表明,内存数据库体系结构可以扩展到支持比可用内存更大的数据集,而不必重新采用以磁盘为中心的体系结构[45]。所谓的**反缓存anti-caching**方法通过在内存不足的情况下将最近最少使用的数据从内存转移到磁盘并在将来再次访问时将其重新加载到内存中。这与操作系统对虚拟内存和交换文件的操作类似但数据库可以比操作系统更有效地管理内存因为它可以按单个记录的粒度工作而不是整个内存页面。尽管如此这种方法仍然需要索引能完全放入内存中就像本章开头的Bitcask例子
如果非易失性存储器NVM技术得到更广泛的应用可能还需要进一步改变存储引擎设计[46]。目前这是一个新的研究领域,值得关注。
## 事务处理还是分析?
在业务数据处理的早期,对数据库的写入通常对应于正在进行的商业交易:进行销售,向供应商下订单,支付员工工资等等。随着数据库扩展到那些没有不涉及钱易手,术语交易仍然卡住,指的是形成一个逻辑单元的一组读写。
事务不一定具有ACID原子性一致性隔离性和持久性属性。事务处理只是意味着允许客户端进行低延迟读取和写入 - 而不是批量处理作业而这些作业只能定期运行例如每天一次。我们在第7章中讨论ACID属性在第10章中讨论批处理。
即使数据库开始被用于许多不同类型的博客文章游戏中的动作地址簿中的联系人等等基本访问模式仍然类似于处理业务事务。应用程序通常使用索引通过某个键查找少量记录。根据用户的输入插入或更新记录。由于这些应用程序是交互式的因此访问模式被称为在线事务处理OLTP
但是,数据库也开始越来越多地用于数据分析,这些数据分析具有非常不同的访问模式。通常,分析查询需要扫描大量记录,每个记录只读取几列,并计算汇总统计信息(如计数,总和或平均值),而不是将原始数据返回给用户。例如,如果您的数据是一个销售交易表,那么分析查询可能是:
* 一月份我们每个商店的总收入是多少?
* 我们在最近的推广活动中销售多少香蕉?
* 哪种品牌的婴儿食品最常与X品牌的尿布一起购买
这些查询通常由业务分析师编写并提供给帮助公司管理层做出更好决策商业智能的报告。为了区分这种使用数据库的事务处理模式它被称为在线分析处理OLAP。[47]。OLTP和OLAP之间的区别并不总是清晰的但是一些典型的特征在表3中列出-1。
**表3-1 比较交易处理和分析系统的特点**
| 属性 | 分析系统 OLAP | 事务处理 OLTP |
| :----: | :------------: | :-----------: |
| 主要读取模式 | 查询少量记录,按键读取 | 在大批量记录上聚合 |
| 主要写入模式 | 随机访问,写入要求低延时 | 批量导入ETL事件流 |
| 主要用户 | 终端用户通过Web应用 | 内部数据分析师,决策支持 |
| 处理的数据 | 数据的最新状态(当前时间点) | 随时间推移的历史事件 |
| 数据集尺寸 | TB ~ PB | GB ~ TB |
起初,相同的数据库用于事务处理和分析查询。 SQL在这方面证明是非常灵活的对于OLTP类型的查询以及OLAP类型的查询来说效果很好。尽管如此在二十世纪八十年代末和九十年代初期公司有停止使用OLTP系统进行分析的趋势而是在单独的数据库上运行分析。这个单独的数据库被称为数据仓库。
### 数据仓库
一个企业可能有几十个不同的交易处理系统系统为面向客户的网站提供动力控制实体商店的销售点checkout系统跟踪仓库中的库存规划车辆路线管理供应商管理员工等。这些系统中的每一个都是复杂的需要一个人员去维护所以系统最终都是自动运行的。
这些OLTP系统通常具有高度的可用性并以低延迟处理事务因为这些系统往往对业务运作至关重要。因此数据库管理员密切关注他们的OLTP数据库他们通常不愿意让业务分析人员在OLTP数据库上运行临时分析查询因为这些查询通常很昂贵扫描大部分数据集这会损害同时执行的事务的性能。
相比之下数据仓库是一个独立的数据库分析人员可以查询他们心中的内容而不影响OLTP操作[48]。数据仓库包含公司所有各种OLTP系统中的只读数据副本。从OLTP数据库中提取数据使用定期的数据转储或连续的更新流转换成适合分析的模式清理并加载到数据仓库中。将数据存入仓库的过程称为“提取 - 转换 - 加载ETL如图3-8所示。
![](img/fig3-8.png)
**图3-8 ETL至数据仓库的简化提纲**
几乎所有的大型企业都有数据仓库但在小型企业中几乎闻所未闻。这可能是因为大多数小公司没有这么多不同的OLTP系统大多数小公司只有少量的数据 - 可以在传统的SQL数据库中查询甚至可以在电子表格中分析。在一家大公司里要做一些在一家小公司很简单的事情需要很多繁重的工作。
使用单独的数据仓库而不是直接查询OLTP系统进行分析的一大优势是数据仓库可针对分析访问模式进行优化。事实证明本章前半部分讨论的索引算法对于OLTP来说工作得很好但对于回答分析查询并不是很好。在本章的其余部分中我们将看看为分析而优化的存储引擎。
### OLTP数据库和数据仓库之间的分歧
数据仓库的数据模型通常是关系型的因为SQL通常很适合分析查询。有许多图形数据分析工具可以生成SQL查询可视化结果并允许分析人员通过下钻切片和切块等操作探索数据。
表面上一个数据仓库和一个关系OLTP数据库看起来很相似因为它们都有一个SQL查询接口。然而系统的内部看起来可能完全不同因为它们针对非常不同的查询模式进行了优化。现在许多数据库供应商都将重点放在支持事务处理或分析工作负载上而不是两者都支持。
一些数据库例如Microsoft SQL Server和SAP HANA支持同一产品中的事务处理和数据仓库。但是它们正在日益成为两个独立的存储和查询引擎这些引擎正好可以通过一个通用的SQL接口访问[49,50,51]。
TeradataVerticaSAP HANA和ParAccel等数据仓库供应商通常使用昂贵的商业许可证销售他们的系统。 Amazon RedShift是ParAccel的托管版本。最近大量的开源SQL-on-Hadoop项目已经出现他们还年轻但是正在与商业数据仓库系统竞争。这些包括Apache HiveSpark SQLCloudera ImpalaFacebook PrestoApache Tajo和Apache Drill [52,53]。其中一些是基于谷歌的Dremel [54]的想法。
### 星型和雪花型:分析的模式
正如第2章所探讨的根据应用程序的需要在事务处理领域中使用了大量不同的数据模型。另一方面在分析中数据模型的多样性则少得多。许多数据仓库都以相当公式化的方式使用被称为星型模式也称为维度建模[55])。
图3-9中的示例模式显示了可能在食品零售商处找到的数据仓库。在模式的中心是一个所谓的事实表在这个例子中它被称为fact_sales。事实表的每一行代表在特定时间发生的事件这里每一行代表客户购买的产品。如果我们分析的是网站流量而不是零售量则每行可能代表一个用户的页面浏览量或点击量。
![](img/fig3-9.png)
**图3-9 用于数据仓库的星型模式的示例**
通常情况下事实被视为单独的事件因为这样可以在以后分析中获得最大的灵活性。但是这意味着事实表可以变得非常大。像苹果沃尔玛或eBay这样的大企业在其数据仓库中可能有几十PB的交易历史其中大部分实际上是表[56]。
事实表中的一些列是属性,例如产品销售的价格和从供应商那里购买的成本(允许计算利润余额)。事实表中的其他列是对其他表(称为维表)的外键引用。由于事实表中的每一行都表示一个事件,因此这些维度代表事件的发生地点,时间,方式和原因。
例如在图3-9中其中一个维度是已售出的产品。 dim_product表中的每一行代表一种待售产品包括库存单位SKU说明品牌名称类别脂肪含量包装尺寸等。fact_sales表中的每一行都使用外部表明在特定交易中销售了哪些产品。 (为了简单起见,如果客户一次购买几种不同的产品,则它们在事实表中被表示为单独的行)。
即使日期和时间通常使用维度表来表示,因为这允许对日期(诸如公共假期)的附加信息进行编码,从而允许查询区分假期和非假期的销售。
“星型模式”这个名字来源于这样一个事实,即当表关系可视化时,事实表在中间,由维表包围;与这些桌子的连接就像星星的光芒。
这个模板的变体被称为雪花模式其中尺寸被进一步分解为子尺寸。例如品牌和产品类别可能有单独的表格并且dim_product表格中的每一行都可以将品牌和类别作为外键引用而不是将它们作为字符串存储在dim_product表格中。雪花模式比星形模式更规范化但是星形模式通常是首选因为分析师使用它更简单[55]。
在典型的数据仓库中表格通常非常宽泛事实表格通常有100列以上有时甚至有数百[51]列。维度表也可以是非常宽的,因为它们包括可能与分析相关的所有元数据 - 例如dim_store表可以包括在每个商店提供哪些服务的细节它是否具有店内面包房方形镜头商店第一次开幕的日期最后一次改造的时间离最近的高速公路的距离等等。
## 面向列的存储
如果事实表中有万亿行和数PB的数据那么高效地存储和查询它们就成为一个具有挑战性的问题。维度表通常要小得多数百万行所以在本节中我们将主要关注事实的存储。
尽管事实表通常超过100列但典型的数据仓库查询一次只能访问4个或5个查询“SELECT *”查询很少用于分析)[51]。以例3-1中的查询为例它访问了大量的行在2013日历年中每次都有人购买水果或糖果但只需访问fact_sales表的三列date_keyproduct_sk和数量。查询忽略所有其他列。
**例3-1 分析人们是否更倾向于购买新鲜水果或糖果,这取决于一周中的哪一天**
```sql
SELECT
dim_date.weekday,
dim_product.category,
SUM(fact_sales.quantity) AS quantity_sold
FROM fact_sales
JOIN dim_date ON fact_sales.date_key = dim_date.date_key
JOIN dim_product ON fact_sales.product_sk = dim_product.product_sk
WHERE
dim_date.year = 2013 AND
dim_product.category IN ('Fresh fruit', 'Candy')
GROUP BY
dim_date.weekday, dim_product.category;
```
我们如何有效地执行这个查询?
在大多数OLTP数据库中存储都是以面向行的方式进行布局的表格的一行中的所有值都相邻存储。文档数据库是相似的整个文档通常存储为一个连续的字节序列。你可以在图3-1的CSV例子中看到这个。
为了处理像例3-1这样的查询您可能在`fact_sales.date_key` `fact_sales.product_sk`上有索引它们告诉存储引擎在哪里查找特定日期或特定产品的所有销售情况。但是面向行的存储引擎仍然需要将所有这些行每个包含超过100个属性从磁盘加载到内存中解析它们并过滤掉那些不符合要求的条件。这可能需要很长时间。
面向列的存储背后的想法很简单:不要将所有来自一行的值存储在一起,而是将来自每一列的所有值存储在一起。如果每个列存储在一个单独的文件中,查询只需要读取和解析查询中使用的那些列,这可以节省大量的工作。这个原理如[图3-10](img/fig3-10.png)所示。
![](img/fig3-10.png)
**图3-10 使用列存储关系型数据,而不是行**
列存储在关系数据模型中是最容易理解的但它同样适用于非关系数据。例如Parquet [57]是一种列式存储格式支持基于Google的Dremel [54]的文档数据模型。
面向列的存储布局依赖于包含相同顺序行的每个列文件。 因此如果您需要重新组装整行您可以从每个单独的列文件中获取第23项并将它们放在一起形成表的第23行。
### 列压缩
除了仅从磁盘加载查询所需的列以外,我们还可以通过压缩数据来进一步降低对磁盘吞吐量的需求。幸运的是,面向列的存储通常很适合压缩。
看看图3-10中每一列的值序列它们通常看起来是相当重复的这是压缩的好兆头。根据列中的数据可以使用不同的压缩技术。在数据仓库中特别有效的一种技术是位图编码如图3-11所示。
![](img/fig3-11.png)
**图3-11 压缩位图索引存储布局**
通常情况下一列中不同值的数量与行数相比较小例如零售商可能有数十亿的销售交易但只有100,000个不同的产品。现在我们可以得到一个有n个不同值的列并把它转换成n个独立的位图每个不同值的一个位图每行一位。如果该行具有该值则该位为1否则为0。
如果n非常小例如国家/地区列可能有大约200个不同的值则这些位图可以每行存储一位。但是如果n更大大部分位图中将会有很多的零我们说它们是稀疏的。在这种情况下位图可以另外进行游程编码如图3-11底部所示。这可以使列的编码非常紧凑。
这些位图索引非常适合数据仓库中常见的各种查询。例如:
```sql
WHERE product_sk IN306869
```
加载product_sk = 30product_sk = 68和product_sk = 69的三个位图并计算三个位图的按位或这可以非常有效地完成。
```sql
WHERE product_sk = 31 AND store_sk = 3
```
加载product_sk = 31和store_sk = 3的位图并逐位计算AND。 这是因为列按照相同的顺序包含行因此一列的位图中的第k位对应于与另一列的位图中的第k位相同的行。
对于不同种类的数据,也有各种不同的压缩方案,但我们不会详细讨论它们,参见[58]的概述。
> #### 面向列的存储和列族
>
> Cassandra和HBase有一个列族的概念他们从Bigtable继承[9]。然而把它们称为面向列是非常具有误导性的在每个列族中它们将一行中的所有列与行键一起存储并且不使用列压缩。因此Bigtable模型仍然主要是面向行的。
>
#### 内存带宽和向量处理
对于需要扫描数百万行的数据仓库查询来说一个巨大的瓶颈是从磁盘获取数据到内存的带宽。但是这不是唯一的瓶颈。分析数据库的开发人员也担心有效利用主存储器带宽到CPU缓存中的带宽避免CPU指令处理流水线中的分支错误预测和泡沫以及在现代中使用单指令多数据SIMD指令CPU [59,60]。
除了减少需要从磁盘加载的数据量以外面向列的存储布局也可以有效利用CPU周期。例如查询引擎可以将大量压缩的列数据放在CPU的L1缓存中然后在紧密的循环中循环即没有函数调用。一个CPU可以执行这样一个循环比代码要快得多这个代码需要处理每个记录的大量函数调用和条件。列压缩允许列中的更多行适合相同数量的L1缓存。前面描述的按位“与”和“或”运算符可以被设计为直接在这样的压缩列数据块上操作。这种技术被称为矢量化处理[58,49]。
### 列存储中的排序顺序
在列存储中存储行的顺序并不一定很重要。按插入顺序存储它们是最简单的因为插入一个新行就意味着附加到每个列文件。但是我们可以选择强制执行一个命令就像我们之前对SSTables所做的那样并将其用作索引机制。
注意每列独自排序是没有意义的因为那样我们就不会知道列中的哪些项属于同一行。我们只能重建一行因为我们知道一列中的第k项与另一列中的第k项属于同一行。
相反即使按列存储数据也需要一次对整行进行排序。数据库的管理员可以使用他们对常见查询的知识来选择表格应该被排序的列。例如如果查询通常以日期范围为目标例如上个月则可以将date_key作为第一个排序键。然后查询优化器只能扫描上个月的行这比扫描所有行要快得多。
第二列可以确定第一列中具有相同值的任何行的排序顺序。例如如果date_key是图3-10中的第一个排序关键字那么product_sk可能是第二个排序关键字因此同一天的同一产品的所有销售都将在存储中组合在一起。这将有助于需要在特定日期范围内按产品对销售进行分组或过滤的查询。
排序顺序的另一个好处是它可以帮助压缩列。如果主要排序列没有多个不同的值那么在排序之后它将具有很长的序列其中相同的值连续重复多次。一个简单的运行长度编码就像我们用于图3-11中的位图一样可以将该列压缩到几千字节 - 即使表中有数十亿行。
第一个排序键的压缩效果最强。第二和第三个排序键会更混乱,因此不会有这么长时间的重复值。排序优先级下面的列以基本上随机的顺序出现,所以它们可能不会被压缩。但前几列排序仍然是一个整体。
#### 几个不同的排序顺序
这个想法的巧妙扩展在C-Store中引入并在商业数据仓库Vertica [61,62]中被采用。不同的查询受益于不同的排序顺序,为什么不以相同的方式存储相同的数据呢?无论如何,数据需要复制到多台机器,这样,如果一台机器发生故障,您不会丢失数据。您可能还需要存储以不同方式排序的冗余数据,以便在处理查询时,可以使用最适合查询模式的版本。
在一个面向列的存储中有多个排序顺序有点类似于在一个面向行的存储中有多个二级索引。但最大的区别在于面向行的存储将每一行保存在一个地方(在堆文件或聚簇索引中),二级索引只包含指向匹配行的指针。在列存储中,通常在其他地方没有任何指向数据的指针,只有包含值的列。
### 写入列存储
这些优化在数据仓库中是有意义的,因为大多数负载由分析人员运行的大型只读查询组成。面向列的存储,压缩和排序都有助于更快地读取这些查询。然而,他们有写更加困难的缺点。
使用B树的更新就地方法对于压缩的列是不可能的。如果你想在排序表的中间插入一行你很可能不得不重写所有的列文件。由于行由列中的位置标识因此插入必须始终更新所有列。
幸运的是本章前面已经看到了一个很好的解决方案LSM树。所有的写操作首先进入一个内存中的存储在这里它们被添加到一个已排序的结构中并准备写入磁盘。内存中的存储是面向行还是列的这并不重要。当已经积累了足够的写入数据时它们将与磁盘上的列文件合并并批量写入新文件。这基本上是Vertica所做的[62]。
查询需要检查磁盘上的列数据和最近在内存中的写入,并将两者结合起来。但是,查询优化器隐藏了用户的这个区别。从分析师的角度来看,通过插入,更新或删除操作进行修改的数据会立即反映在后续查询中。
### 聚合:数据立方体和物化视图
并不是每个数据仓库都必定是一个列存储:传统的面向行的数据库和其他一些架构也被使用。然而,对于专门的分析查询,列式存储可以显着加快,所以它正在迅速普及[51,63]。
数据仓库的另一个值得一提的是物化汇总。如前所述数据仓库查询通常涉及一个聚合函数如SQL中的COUNTSUMAVGMIN或MAX。如果相同的聚合被许多不同的查询使用那么每次都可以通过原始数据来处理。为什么不缓存一些查询使用最频繁的计数或总和
创建这种缓存的一种方式是物化视图。在关系数据模型中它通常被定义为一个标准虚拟视图一个类似于表的对象其内容是一些查询的结果。不同的是物化视图是查询结果的实际副本写入磁盘而虚拟视图只是写入查询的捷径。从虚拟视图读取时SQL引擎会将其展开到视图的底层查询中然后处理展开的查询。
当底层数据发生变化时物化视图需要更新因为它是数据的非规范化副本。数据库可以自动完成但是这样的更新使得写入成本更高这就是在OLTP数据库中不经常使用物化视图的原因。在读取繁重的数据仓库中它们可能更有意义不管它们是否实际上改善了读取性能取决于个别情况
物化视图的常见特例称为数据立方体或OLAP立方体[64]。它是按不同维度分组的聚合网格。图3-12显示了一个例子。
![](img/fig3-12.png)
**图3-12 数据立方的两个维度,通过求和聚合**
想象一下,现在每个事实都只有两个维度表的外键 - 在图3-12中这些是日期和产品。您现在可以绘制一个二维表格一个轴线上的日期和另一个轴上的产品。每个单元包含具有该日期 - 产品组合的所有事实的属性例如net_price的聚集例如SUM。然后您可以沿着每行或每列应用相同的汇总并获得一个维度减少的汇总按产品的销售额无论日期还是按日期销售无论产品如何
一般来说事实往往有两个以上的维度。在图3-9中有五个维度日期产品商店促销和客户。要想象一个五维超立方体是什么样子是很困难的但是原理是一样的每个单元格都包含特定日期产品 - 商店 - 促销 - 客户组合)的销售。这些值可以在每个维度上重复概括。
物化数据立方体的优点是某些查询变得非常快,因为它们已经被有效地预先计算了。例如,如果您想知道每个商店的总销售额,则只需查看合适维度的总计,无需扫描数百万行。
缺点是数据立方体不具有查询原始数据的灵活性。例如没有办法计算哪个销售比例来自成本超过100美元的项目因为价格不是其中的一个维度。因此大多数数据仓库试图保留尽可能多的原始数据并将聚合数据如数据立方体仅用作某些查询的性能提升。
## 本章小结
在本章中,我们试图深入了解数据库如何处理存储和检索。将数据存储在数据库中会发生什么,以及稍后再次查询数据时数据库会做什么?
在高层次上我们看到存储引擎分为两大类优化事务处理OLTP和优化分析OLAP的类别。这些用例的访问模式之间有很大的区别
* OLTP系统通常面向用户这意味着他们可能会看到大量的请求。为了处理负载应用程序通常只触及每个查询中的少量记录。应用程序使用某种键来请求记录存储引擎使用索引来查找所请求的键的数据。磁盘寻道时间往往是这里的瓶颈。
* 数据仓库和类似的分析系统不太知名因为它们主要由业务分析人员使用而不是由最终用户使用。它们处理比OLTP系统少得多的查询量但是每个查询通常要求很高需要在短时间内扫描数百万条记录。磁盘带宽不是查找时间往往是瓶颈列式存储是这种工作负载越来越流行的解决方案。
在OLTP方面我们看到了来自两大主流学派的存储引擎
* 日志结构学派,只允许附加到文件和删除过时的文件,但不会更新已经写入的文件。 BitcaskSSTablesLSM-treeLevelDBCassandraHBaseLucene等都属于这个组。
* 就地更新学派,将磁盘视为一组可以覆盖的固定大小的页面。 B树是这种哲学的最大的例子被用在所有主要的关系数据库中还有许多非关系数据库。
日志结构的存储引擎是相对较新的发展。他们的主要想法是他们系统地将随机访问写入顺序写入磁盘由于硬盘驱动器和固态硬盘的性能特点可以实现更高的写入吞吐量。在完成OLTP方面我们通过一些更复杂的索引结构和为保留所有数据而优化的数据库做了一个简短的介绍。
然后我们从存储引擎的内部绕开看看典型数据仓库的高级架构。这一背景说明了为什么分析工作负载与OLTP差别很大当您的查询需要在大量行中顺序扫描时索引的相关性就会降低很多。相反非常紧凑地编码数据变得非常重要以最大限度地减少查询需要从磁盘读取的数据量。我们讨论了列式存储如何帮助实现这一目标。
作为一名应用程序开发人员,如果您掌握了有关存储引擎内部的知识,那么您就能更好地了解哪种工具最适合您的特定应用程序。如果您需要调整数据库的调整参数,这种理解可以让您设想一个更高或更低的值可能会产生什么效果。
尽管本章不能让你成为一个特定存储引擎的调参专家,但它至少有大概率使你有了足够的概念与词汇储备去读懂数据库的文档,从而选择合适的数据库。
## 参考文献
1. Alfred V. Aho, John E. Hopcroft, and Jeffrey D. Ullman:
*Data Structures and Algorithms*. Addison-Wesley, 1983. ISBN: 978-0-201-00023-8
1. Thomas H. Cormen, Charles E. Leiserson, Ronald L. Rivest, and
Clifford Stein: *Introduction to Algorithms*, 3rd edition. MIT Press, 2009.
ISBN: 978-0-262-53305-8
1. Justin Sheehy and David Smith:
“[Bitcask: A Log-Structured Hash Table for Fast Key/Value Data](http://basho.com/wp-content/uploads/2015/05/bitcask-intro.pdf),” Basho Technologies, April 2010.
1. Yinan Li, Bingsheng He, Robin Jun Yang, et al.:
“[Tree Indexing on Solid State Drives](http://www.vldb.org/pvldb/vldb2010/papers/R106.pdf),”
*Proceedings of the VLDB Endowment*, volume 3, number 1, pages 11951206,
September 2010.
1. Goetz Graefe:
“[Modern B-Tree Techniques](http://citeseerx.ist.psu.edu/viewdoc/download?doi=10.1.1.219.7269&rep=rep1&type=pdf),”
*Foundations and Trends in Databases*, volume 3, number 4, pages 203402, August 2011.
[doi:10.1561/1900000028](http://dx.doi.org/10.1561/1900000028)
1. Jeffrey Dean and Sanjay Ghemawat:
“[LevelDB Implementation Notes](https://github.com/google/leveldb/blob/master/doc/impl.html),”
*leveldb.googlecode.com*.
1. Dhruba Borthakur:
“[The History of RocksDB](http://rocksdb.blogspot.com/),”
*rocksdb.blogspot.com*, November 24, 2013.
1. Matteo Bertozzi:
“[Apache HBase I/O HFile](http://blog.cloudera.com/blog/2012/06/hbase-io-hfile-input-output/),” *blog.cloudera.com*, June, 29 2012.
1. Fay Chang, Jeffrey Dean, Sanjay Ghemawat, et al.:
“[Bigtable: A Distributed Storage System for Structured Data](http://research.google.com/archive/bigtable.html),” at *7th USENIX Symposium on Operating System Design and
Implementation* (OSDI), November 2006.
1. Patrick
O'Neil, Edward Cheng, Dieter Gawlick, and Elizabeth O'Neil:
“[The Log-Structured Merge-Tree (LSM-Tree)](http://www.cs.umb.edu/~poneil/lsmtree.pdf),”
*Acta Informatica*, volume 33, number 4, pages 351385, June 1996.
[doi:10.1007/s002360050048](http://dx.doi.org/10.1007/s002360050048)
1. Mendel Rosenblum and John K. Ousterhout:
“[The Design and Implementation of a Log-Structured File System](http://research.cs.wisc.edu/areas/os/Qual/papers/lfs.pdf),”
*ACM Transactions on Computer Systems*, volume 10, number 1, pages 2652, February 1992.
[doi:10.1145/146941.146943](http://dx.doi.org/10.1145/146941.146943)
1. Adrien Grand:
“[What Is in a Lucene Index?](http://www.slideshare.net/lucenerevolution/what-is-inaluceneagrandfinal),” at *Lucene/Solr Revolution*, November 14, 2013.
1. Deepak Kandepet:
“[Hacking Lucene—The Index Format]( http://hackerlabs.github.io/blog/2011/10/01/hacking-lucene-the-index-format/index.html),” *hackerlabs.org*, October 1, 2011.
1. Michael McCandless:
“[Visualizing Lucene's Segment Merges](http://blog.mikemccandless.com/2011/02/visualizing-lucenes-segment-merges.html),” *blog.mikemccandless.com*, February 11, 2011.
1. Burton H. Bloom:
“[Space/Time Trade-offs in Hash Coding with Allowable Errors](http://www.cs.upc.edu/~diaz/p422-bloom.pdf),” *Communications of the ACM*, volume 13, number 7, pages 422426, July 1970.
[doi:10.1145/362686.362692](http://dx.doi.org/10.1145/362686.362692)
1. “[Operating Cassandra: Compaction](https://cassandra.apache.org/doc/latest/operating/compaction.html),” Apache Cassandra Documentation v4.0, 2016.
1. Rudolf Bayer and Edward M. McCreight:
“[Organization and Maintenance of Large Ordered Indices](http://www.dtic.mil/cgi-bin/GetTRDoc?AD=AD0712079),” Boeing Scientific Research Laboratories, Mathematical and Information Sciences
Laboratory, report no. 20, July 1970.
1. Douglas Comer:
“[The Ubiquitous B-Tree](http://citeseerx.ist.psu.edu/viewdoc/download?doi=10.1.1.96.6637&rep=rep1&type=pdf),” *ACM Computing Surveys*, volume 11, number 2, pages 121137, June 1979.
[doi:10.1145/356770.356776](http://dx.doi.org/10.1145/356770.356776)
1. Emmanuel Goossaert:
“[Coding for SSDs](http://codecapsule.com/2014/02/12/coding-for-ssds-part-1-introduction-and-table-of-contents/),” *codecapsule.com*, February 12, 2014.
1. C. Mohan and Frank Levine:
“[ARIES/IM: An Efficient and High Concurrency Index Management Method Using Write-Ahead Logging](http://www.ics.uci.edu/~cs223/papers/p371-mohan.pdf),” at *ACM
International Conference on Management of Data* (SIGMOD), June 1992.
[doi:10.1145/130283.130338](http://dx.doi.org/10.1145/130283.130338)
1. Howard Chu:
“[LDAP at Lightning Speed]( https://buildstuff14.sched.com/event/08a1a368e272eb599a52e08b4c3c779d),”
at *Build Stuff '14*, November 2014.
1. Bradley C. Kuszmaul:
“[A Comparison of Fractal Trees to Log-Structured Merge (LSM) Trees](http://insideanalysis.com/wp-content/uploads/2014/08/Tokutek_lsm-vs-fractal.pdf),” *tokutek.com*,
April 22, 2014.
1. Manos Athanassoulis, Michael S. Kester,
Lukas M. Maas, et al.: “[Designing Access Methods: The RUM Conjecture](http://openproceedings.org/2016/conf/edbt/paper-12.pdf),” at *19th International Conference on Extending Database
Technology* (EDBT), March 2016.
[doi:10.5441/002/edbt.2016.42](http://dx.doi.org/10.5441/002/edbt.2016.42)
1. Peter Zaitsev:
“[Innodb Double Write](https://www.percona.com/blog/2006/08/04/innodb-double-write/),”
*percona.com*, August 4, 2006.
1. Tomas Vondra:
“[On the Impact of Full-Page Writes](http://blog.2ndquadrant.com/on-the-impact-of-full-page-writes/),” *blog.2ndquadrant.com*, November 23, 2016.
1. Mark Callaghan:
“[The Advantages of an LSM vs a B-Tree](http://smalldatum.blogspot.co.uk/2016/01/summary-of-advantages-of-lsm-vs-b-tree.html),” *smalldatum.blogspot.co.uk*, January 19, 2016.
1. Mark Callaghan:
“[Choosing Between Efficiency and Performance with RocksDB](http://www.codemesh.io/codemesh/mark-callaghan),” at *Code Mesh*, November 4, 2016.
1. Michi Mutsuzaki:
“[MySQL vs. LevelDB](https://github.com/m1ch1/mapkeeper/wiki/MySQL-vs.-LevelDB),”
*github.com*, August 2011.
1. Benjamin Coverston,
Jonathan Ellis, et al.: “[CASSANDRA-1608: Redesigned Compaction](https://issues.apache.org/jira/browse/CASSANDRA-1608), *issues.apache.org*, July 2011.
1. Igor Canadi, Siying Dong, and Mark Callaghan:
“[RocksDB Tuning Guide](https://github.com/facebook/rocksdb/wiki/RocksDB-Tuning-Guide),”
*github.com*, 2016.
1. <a href="http://dev.mysql.com/doc/refman/5.7/en/index.html">*MySQL
5.7 Reference Manual*</a>. Oracle, 2014.
1. <a href="http://msdn.microsoft.com/en-us/library/ms130214.aspx">*Books
Online for SQL Server 2012*</a>. Microsoft, 2012.
1. Joe Webb:
“[Using Covering Indexes to Improve Query Performance](https://www.simple-talk.com/sql/learn-sql-server/using-covering-indexes-to-improve-query-performance/),” *simple-talk.com*, 29 September 2008.
1. Frank Ramsak, Volker Markl, Robert Fenk, et al.:
“[Integrating the UB-Tree into a Database System Kernel](http://www.vldb.org/conf/2000/P263.pdf),”
at *26th International Conference on Very Large Data Bases* (VLDB), September 2000.
1. The PostGIS Development Group:
“[PostGIS 2.1.2dev Manual](http://postgis.net/docs/manual-2.1/),”
*postgis.net*, 2014.
1. Robert Escriva, Bernard Wong, and Emin Gün Sirer:
“[HyperDex: A Distributed, Searchable Key-Value Store](http://www.cs.princeton.edu/courses/archive/fall13/cos518/papers/hyperdex.pdf),” at *ACM SIGCOMM Conference*, August 2012.
[doi:10.1145/2377677.2377681](http://dx.doi.org/10.1145/2377677.2377681)
1. Michael McCandless:
“[Lucene's FuzzyQuery Is 100 Times Faster in 4.0](http://blog.mikemccandless.com/2011/03/lucenes-fuzzyquery-is-100-times-faster.html),” *blog.mikemccandless.com*, March 24, 2011.
1. Steffen Heinz, Justin Zobel, and Hugh E. Williams:
“[Burst Tries: A Fast, Efficient Data Structure for String Keys](http://citeseer.ist.psu.edu/viewdoc/summary?doi=10.1.1.18.3499),”
*ACM Transactions on Information Systems*, volume 20, number 2, pages 192223, April 2002.
[doi:10.1145/506309.506312](http://dx.doi.org/10.1145/506309.506312)
1. Klaus U. Schulz and Stoyan Mihov:
“[Fast String Correction with Levenshtein Automata](http://citeseerx.ist.psu.edu/viewdoc/summary?doi=10.1.1.16.652),”
*International Journal on Document Analysis and Recognition*,
volume 5, number 1, pages 6785, November 2002.
[doi:10.1007/s10032-002-0082-8](http://dx.doi.org/10.1007/s10032-002-0082-8)
1. Christopher D. Manning, Prabhakar Raghavan, and Hinrich Schütze:
<a href="http://nlp.stanford.edu/IR-book/">*Introduction to Information Retrieval*</a>.
Cambridge University Press, 2008. ISBN: 978-0-521-86571-5, available online at *nlp.stanford.edu/IR-book*
1. Michael Stonebraker, Samuel Madden, Daniel J. Abadi, et al.:
“[The End of an Architectural Era (Its Time for a Complete Rewrite)](http://citeseerx.ist.psu.edu/viewdoc/download?doi=10.1.1.137.3697&rep=rep1&type=pdf),” at
*33rd International Conference on Very Large Data Bases* (VLDB), September 2007.
1. “[VoltDB Technical Overview White Paper](https://www.voltdb.com/wptechnicaloverview),” VoltDB, 2014.
1. Stephen M. Rumble, Ankita Kejriwal, and John K. Ousterhout:
“[Log-Structured Memory for DRAM-Based Storage](https://www.usenix.org/system/files/conference/fast14/fast14-paper_rumble.pdf),” at *12th USENIX Conference on File and Storage
Technologies* (FAST), February 2014.
1. Stavros Harizopoulos, Daniel J. Abadi,
Samuel Madden, and Michael Stonebraker:
“[OLTP Through the Looking Glass, and What We Found There](http://hstore.cs.brown.edu/papers/hstore-lookingglass.pdf),” at *ACM International Conference on Management of Data*
(SIGMOD), June 2008.
[doi:10.1145/1376616.1376713](http://dx.doi.org/10.1145/1376616.1376713)
1. Justin DeBrabant, Andrew Pavlo, Stephen Tu, et al.:
“[Anti-Caching: A New Approach to Database Management System Architecture](http://www.vldb.org/pvldb/vol6/p1942-debrabant.pdf),” *Proceedings of the VLDB Endowment*, volume 6,
number 14, pages 19421953, September 2013.
1. Joy Arulraj, Andrew Pavlo, and Subramanya R. Dulloor:
“[Let's Talk About Storage & Recovery Methods for Non-Volatile Memory Database Systems](http://www.pdl.cmu.edu/PDL-FTP/NVM/storage.pdf),” at *ACM International Conference on
Management of Data* (SIGMOD), June 2015.
[doi:10.1145/2723372.2749441](http://dx.doi.org/10.1145/2723372.2749441)
1. Edgar F. Codd, S. B. Codd, and C. T. Salley:
“[Providing OLAP to User-Analysts: An IT Mandate](http://www.minet.uni-jena.de/dbis/lehre/ss2005/sem_dwh/lit/Cod93.pdf),” E. F. Codd Associates,
1993.
1. Surajit Chaudhuri and Umeshwar Dayal:
“[An Overview of Data Warehousing and OLAP Technology](https://www.microsoft.com/en-us/research/wp-content/uploads/2016/02/sigrecord.pdf),” *ACM SIGMOD Record*, volume 26, number 1, pages 6574,
March 1997. [doi:10.1145/248603.248616](http://dx.doi.org/10.1145/248603.248616)
1. Per-Åke Larson, Cipri Clinciu, Campbell Fraser, et al.:
“[Enhancements to SQL Server Column Stores](http://research.microsoft.com/pubs/193599/Apollo3%20-%20Sigmod%202013%20-%20final.pdf),” at *ACM International Conference on Management of Data*
(SIGMOD), June 2013.
1. Franz Färber, Norman May, Wolfgang Lehner, et al.:
“[The SAP HANA Database An Architecture Overview](http://sites.computer.org/debull/A12mar/hana.pdf),”
*IEEE Data Engineering Bulletin*, volume 35, number 1, pages 2833, March 2012.
1. Michael Stonebraker:
“[The Traditional RDBMS Wisdom Is (Almost Certainly) All Wrong](http://slideshot.epfl.ch/talks/166),” presentation at *EPFL*, May 2013.
1. Daniel J. Abadi:
“[Classifying the SQL-on-Hadoop Solutions](https://web.archive.org/web/20150622074951/http://hadapt.com/blog/2013/10/02/classifying-the-sql-on-hadoop-solutions/),” *hadapt.com*, October 2, 2013.
1. Marcel Kornacker, Alexander Behm, Victor Bittorf, et al.:
“[Impala: A Modern, Open-Source SQL Engine for Hadoop](http://pandis.net/resources/cidr15impala.pdf),” at *7th Biennial Conference on Innovative Data Systems
Research* (CIDR), January 2015.
1. Sergey Melnik, Andrey Gubarev, Jing Jing Long, et al.:
“[Dremel: Interactive Analysis of Web-Scale Datasets](http://research.google.com/pubs/pub36632.html),” at *36th International Conference on Very Large Data Bases* (VLDB), pages
330339, September 2010.
1. Ralph Kimball and Margy Ross:
*The Data Warehouse Toolkit: The Definitive Guide to Dimensional Modeling*,
3rd edition. John Wiley & Sons, July 2013. ISBN: 978-1-118-53080-1
1. Derrick Harris:
“[Why Apple, eBay, and Walmart Have Some of the Biggest Data Warehouses Youve Ever Seen](http://gigaom.com/2013/03/27/why-apple-ebay-and-walmart-have-some-of-the-biggest-data-warehouses-youve-ever-seen/),”
*gigaom.com*, March 27, 2013.
1. Julien Le Dem:
“[Dremel Made Simple with Parquet](https://blog.twitter.com/2013/dremel-made-simple-with-parquet),”
*blog.twitter.com*, September 11, 2013.
1. Daniel J. Abadi, Peter Boncz, Stavros
Harizopoulos, et al.:
“[The Design and Implementation of Modern Column-Oriented Database Systems](http://cs-www.cs.yale.edu/homes/dna/papers/abadi-column-stores.pdf),” *Foundations and Trends in
Databases*, volume 5, number 3, pages 197280, December 2013.
[doi:10.1561/1900000024](http://dx.doi.org/10.1561/1900000024)
1. Peter Boncz, Marcin Zukowski, and Niels Nes:
“[MonetDB/X100: Hyper-Pipelining Query Execution](http://www.cidrdb.org/cidr2005/papers/P19.pdf),”
at *2nd Biennial Conference on Innovative Data Systems Research* (CIDR), January 2005.
1. Jingren Zhou and Kenneth A. Ross:
“[Implementing Database Operations Using SIMD Instructions](http://www1.cs.columbia.edu/~kar/pubsk/simd.pdf),”
at *ACM International Conference on Management of Data* (SIGMOD), pages 145156, June 2002.
[doi:10.1145/564691.564709](http://dx.doi.org/10.1145/564691.564709)
1. Michael Stonebraker, Daniel J. Abadi, Adam Batkin, et al.:
“[C-Store: A Column-oriented DBMS](http://www.vldb2005.org/program/paper/thu/p553-stonebraker.pdf),”
at *31st International Conference on Very Large Data Bases* (VLDB), pages 553564, September 2005.
1. Andrew Lamb, Matt Fuller, Ramakrishna Varadarajan, et al.:
“[The Vertica Analytic Database: C-Store 7 Years Later](http://vldb.org/pvldb/vol5/p1790_andrewlamb_vldb2012.pdf),”
*Proceedings of the VLDB Endowment*, volume 5, number 12, pages 17901801, August 2012.
1. Julien Le Dem and Nong Li:
“[Efficient Data Storage for Analytics with Apache Parquet 2.0](http://www.slideshare.net/julienledem/th-210pledem),” at *Hadoop Summit*, San Jose,
June 2014.
1. Jim Gray, Surajit Chaudhuri, Adam Bosworth, et al.:
“[Data Cube: A Relational Aggregation Operator Generalizing Group-By, Cross-Tab, and Sub-Totals](http://arxiv.org/pdf/cs/0701155.pdf),” *Data Mining and Knowledge
Discovery*, volume 1, number 1, pages 2953, March 2007.
[doi:10.1023/A:1009726021843](http://dx.doi.org/10.1023/A:1009726021843)

700
ddia/ch4.md Normal file
View File

@ -0,0 +1,700 @@
# 4. 编码与演化
![](img/ch4.png)
> 唯变所适
>
> ——以弗所的赫拉克利特为柏拉图所引公元前360年
>
-------------------
[TOC]
应用程序不可避免地随时间而变化。新产品的推出,对需求的深入理解,或者商业环境的变化,总会伴随着*功能(feature)*的增增改改。[第一章](ch1.md)介绍了*可演化性(evolvability)*的概念:应该尽力构建能灵活适应变化的系统(参阅“可演化性:拥抱变化”)。
在大多数情况下,修改应用程序的功能也意味着需要更改其存储的数据:可能需要使用新的字段或记录类型,或者以新方式展示现有数据。
我们在[第二章](ch2.md)讨论的数据模型有不同的方法来应对这种变化。关系数据库通常假定数据库中的所有数据都遵循一个模式:尽管可以更改该模式(通过模式迁移,即`ALTER`语句),但是在任何时间点都有且仅有一个正确的模式。相比之下,*读时模式 schema-on-read*(或 “无模式” schemaless数据库不会强制一个模式因此数据库可以包含在不同时间写入的新老数据格式的混合参阅 “文档模型中的模式灵活性” )。
当数据格式(format)或模式(schema)发生变化时,通常需要对应用程序代码进行相应的更改(例如,为记录添加新字段,然后修改程序开始读写该字段)。但在大型应用程序中,代码变更通常不会立即完成:
* 对于服务端server-side应用程序可能需要执行*滚动升级 (rolling upgrade)*(也称为*阶段发布 staged rollout*),一次将新版本部署到少数几个节点,检查新版本是否运行正常,然后逐渐部完所有的节点。这样无需中断服务即可部署新版本,为频繁发布提供了可行性,从而带来更好的可演化性。
* 对于客户端client-side应用程序升不升级就要看用户的心情了。用户可能相当长一段时间里都不会去升级软件。
这意味着,新旧版本的代码,以及新旧数据格式可能会在系统中同时共处。系统想要继续顺利运行,就需要保持*双向兼容性*
* **向后兼容** (backward compatibility)
新代码可以读旧数据。
* **向前兼容** (forward compatibility)
旧代码可以读新数据。
向后兼容性通常并不难实现:新代码的作者当然知道由旧代码使用的数据格式,因此可以显示地处理它(最简单的办法是,保留旧代码即可读取旧数据)。
向前兼容性可能会更棘手,因为旧版的程序需要忽略新版数据格式中新增的部分。
本章中将介绍几种编码数据的格式,包括 JSONXMLProtocol BuffersThrift和Avro。尤其将关注这些格式如何应对模式变化以及它们如何对新旧代码数据需要共存的系统提供支持。然后将讨论如何使用这些格式进行数据存储和通信在Web服务中具象状态传输REST和远程过程调用RPC以及消息传递系统如Actor和消息队列
## 编码数据的格式
程序通常(至少)使用两种形式的数据:
1. 在内存中,数据保存在对象,结构体,列表,数组,哈希表,树等中。 这些数据结构针对CPU的高效访问和操作进行了优化通常使用指针
2. 如果要将数据写入文件,或通过网络发送,则必须将其*编码encode*为某种自包含的字节序列例如JSON文档。 由于每个进程都有自己独立的地址空间,一个进程中的指针对任何其他进程都没有意义,所以这个字节序列表示会与通常在内存中使用的数据结构完全不同。
所以,需要在两种表示之间进行某种类型的翻译。 从内存中表示到字节序列的转换称为**编码(Encoding)**(也称为**序列化 serialization**或**编组 marshalling**),反过来称为**解码(Decoding)****解析Parsing****反序列化 deserialization****反编组 unmarshalling**)。
> #### 术语冲突
> 不幸的是,在第七章:事务(Transaction)的上下文里,序列化(Serialization)这个术语也出现了而且具有完全不同的含义。尽管序列化可能是更常见的术语为了避免术语重载本书中坚持使用编码Encoding表达此含义。
>
> 译者注Marshal与Serialization的区别Marshal不仅传输对象的状态而且会一起传输对象的方法相关代码
这是一个常见的问题,因而有许多库和编码格式可供选择。 首先让我们概览一下。
### 语言特定的格式
许多编程语言都内建了将内存对象编码为字节序列的支持。例如Java有`java.io.Serializable [1]`Ruby有`Marshal [2]`Python有`pickle [3]`等等。许多第三方库也存在,例如`Kryo for Java [4]`。
这些编码库非常方便,可以用很少的额外代码实现内存对象的保存与恢复。但是它们也有一些深层次的问题:
* 这类编码通常与特定的编程语言深度绑定,其他语言很难读取这种数据。如果以这类编码存储或传输数据,那你就和这门语言绑死在一起了。并且很难将系统与其他组织的系统(可能用的是不同的语言)进行集成。
* 为了恢复相同对象类型的数据,解码过程需要**实例化任意类**的能力,这通常是安全问题的一个来源[5]:如果攻击者可以让应用程序解码任意的字节序列,他们就能实例化任意的类,这会允许他们做可怕的事情,如远程执行任意代码[6 7]。
* 在这些库中,数据版本控制通常是事后才考虑的。因为它们旨在快速简便地对数据进行编码,所以往往忽略了前向后向兼容性带来的麻烦问题。
* 效率编码或解码所花费的CPU时间以及编码结构的大小往往也是事后才考虑的。 例如Java的内置序列化由于其糟糕的性能和臃肿的编码而臭名昭着[8]。
因此,除非临时使用,采用语言内置编码通常是一个坏主意。
### JSONXML和二进制变体
谈到可以被许多编程语言编写和读取的标准化编码JSON和XML是显眼的竞争者。它们广为人知广受支持也“广受憎恶”。 XML经常被批评为过于冗长和不必要的复杂[9]。 JSON倍受欢迎主要由于它在Web浏览器中的内置支持通过成为JavaScript的一个子集以及相对于XML的简单性。 CSV是另一种流行的与语言无关的格式尽管功能较弱。
JSONXML和CSV是文本格式因此具有人类可读性尽管语法是一个热门辩题。除了表面的语法问题之外它们也有一些微妙的问题
* 数字的编码多有歧义之处。XML和CSV不能区分数字和字符串除非引用外部模式。 JSON虽然区分字符串和数字但不区分整数和浮点数而且不能指定精度。
* 当处理大量数据时,这个问题更严重了。例如,大于$2^{53}$的整数不能在IEEE 754双精度浮点数中精确表示因此在使用浮点数例如JavaScript的语言进行分析时这些数字会变得不准确。 Twitter上有一个大于$2^{53}$的数字的例子它使用一个64位的数字来标识每条推文。 Twitter API返回的JSON包含了两次推特ID一次是JSON数字一次是十进制字符串以此避免JavaScript程序无法正确解析数字的问题[10]。
* JSON和XML对Unicode字符串即人类可读的文本有很好的支持但是它们不支持二进制数据不带字符编码(character encoding)的字节序列。二进制串是很实用的功能所以人们通过使用Base64将二进制数据编码为文本来绕开这个限制。模式然后用于表示该值应该被解释为Base64编码。这个工作但它有点hacky并增加了33的数据大小。 XML [11]和JSON [12]都有可选的模式支持。这些模式语言相当强大,所以学习和实现起来相当复杂。 XML模式的使用相当普遍但许多基于JSON的工具嫌麻烦才不会使用模式。由于数据的正确解释例如数字和二进制字符串取决于模式中的信息因此不使用XML / JSON模式的应用程序可能需要对相应的编码/解码逻辑进行硬编码。
* CSV没有任何模式因此应用程序需要定义每行和每列的含义。如果应用程序更改添加新的行或列则必须手动处理该变更。 CSV也是一个相当模糊的格式如果一个值包含逗号或换行符会发生什么。尽管其转义规则已经被正式指定[13],但并不是所有的解析器都正确的实现了标准。
尽管存在这些缺陷但JSONXML和CSV已经足够用于很多目的。特别是作为数据交换格式即将数据从一个组织发送到另一个组织它们很可能仍然很受欢迎。这种情况下只要人们对格式是什么意见一致格式多么美观或者高效就没有关系。让不同的组织达成一致的难度超过了其他大多数问题。
#### 二进制编码
对于仅在组织内部使用的数据使用最小公分母编码格式的压力较小。例如可以选择更紧凑或更快的解析格式。虽然对小数据集来说收益可以忽略不计但一旦达到TB级别数据格式的选择就会产生巨大的影响。
JSON比XML简洁但与二进制格式一比还是太占地方。这一事实导致大量二进制编码版本JSON & XML的出现JSONMessagePackBSONBJSONUBJSONBISON和Smile等例如WBXML和Fast Infoset。这些格式已经被各种各样的领域所采用但是没有一个像JSON和XML的文本版本那样被广泛采用。
这些格式中的一些扩展了一组数据类型例如区分整数和浮点数或者增加对二进制字符串的支持另一方面它们没有盖面JSON / XML的数据模型。特别是由于它们没有规定模式所以它们需要在编码数据中包含所有的对象字段名称。也就是说在**例4-1**中的JSON文档的二进制编码中需要在某处包含字符串`userName``favoriteNumber`和`interest`。
**例4-1 本章中用于展示二进制编码的示例记录**
```json
{
"userName": "Martin",
"favoriteNumber": 1337,
"interests": ["daydreaming", "hacking"]
}
```
我们来看一个MessagePack的例子它是一个JSON的二进制编码。图4-1显示了如果使用MessagePack [14]对例4-1中的JSON文档进行编码则得到的字节序列。前几个字节如下
1. 第一个字节`0x83`表示接下来是**3**个字段(低四位= `0x03`)的*对象 object*(高四位= `0x80`)。 如果想知道如果一个对象有15个以上的字段会发生什么情况字段的数量塞不进4个bit里那么它会用另一个不同的类型标识符字段的数量被编码两个或四个字节
2. 第二个字节`0xa8`表示接下来是**8**字节长的字符串(最高四位= 0x08
3. 接下来八个字节是ASCII字符串形式的字段名称`userName`。由于之前已经指明长度,不需要任何标记来标识字符串的结束位置(或者任何转义)。
4. 接下来的七个字节对前缀为`0xa6`的六个字母的字符串值`Martin`进行编码,依此类推。
二进制编码长度为66个字节仅略小于文本JSON编码所取的81个字节删除了空白。所有的JSON的二进制编码在这方面是相似的。空间节省了一丁点以及解析加速是否能弥补可读性的损失谁也说不准。
在下面的章节中能达到比这好得多的结果只用32个字节对相同的记录进行编码。
![](img/fig4-1.png)
**图4-1 使用MessagePack编码的记录例4-1**
### Thrift与Protocol Buffers
Apache Thrift [15]和Protocol Buffersprotobuf[16]是基于相同原理的二进制编码库。 Protocol Buffers最初是在Google开发的Thrift最初是在Facebook开发的并且在2007 - 2008年都是开源的[17]。
Thrift和Protocol Buffers都需要一个模式来编码任何数据。要在Thrift的例4-1中对数据进行编码可以使用Thrift接口定义语言IDL来描述模式如下所示
```c
struct Person {
1: required string userName,
2: optional i64 favoriteNumber,
3: optional list<string> interests
}
```
Protocol Buffers的等效模式定义看起来非常相似
```protobuf
message Person {
required string user_name = 1;
optional int64 favorite_number = 2;
repeated string interests = 3;
}
```
Thrift和Protocol Buffers每一个都带有一个代码生成工具它采用了类似于这里所示的模式定义并且生成了以各种编程语言实现模式的类[18]。您的应用程序代码可以调用此生成的代码来对模式的记录进行编码或解码。
用这个模式编码的数据是什么样的令人困惑的是Thrift有两种不同的二进制编码格式[^iii]分别称为BinaryProtocol和CompactProtocol。先来看看BinaryProtocol。这种格式的编码示例4-1需要59个字节如图4-2 [19]所示。
![](img/fig4-2.png)
**图4-2 使用Thrift二进制协议编码的记录**
[^iii]: 实际上Thrift有三种二进制协议CompactProtocol和DenseProtocol尽管DenseProtocol只支持C ++实现,所以不算作跨语言[18]。 除此之外它还有两种不同的基于JSON的编码格式[19]。 真逗!
与图4-1类似每个字段都有一个类型注释用于指示它是一个字符串整数列表等还可以根据需要指定长度字符串的长度列表中的项目数 。出现在数据中的字符串“Martin”“daydreaming”“hacking”也被编码为ASCII或者说UTF-8与之前类似。
与图4-1相比最大的区别是没有字段名userNamefavoriteNumberinterest。相反编码数据包含字段标签它们是数字12和3。这些是模式定义中出现的数字。字段标记就像字段的别名 - 它们是说我们正在谈论的字段的一种紧凑的方式,而不必拼出字段名称。
Thrift CompactProtocol编码在语义上等同于BinaryProtocol但是如图4-3所示它只将相同的信息打包成只有34个字节。它通过将字段类型和标签号打包到单个字节中并使用可变长度整数来实现。数字1337不是使用全部八个字节而是用两个字节编码每个字节的最高位用来指示是否还有更多的字节来。这意味着-64到63之间的数字被编码为一个字节-8192和8191之间的数字以两个字节编码等等。较大的数字使用更多的字节。
![](img/fig4-3.png)
**图4-3 使用Thrift压缩协议编码的记录**
最后Protocol Buffers只有一种二进制编码格式对相同的数据进行编码如图4-4所示。 它的打包方式稍有不同但与Thrift的CompactProtocol非常相似。 Protobuf将同样的记录塞进了33个字节中。
![](img/fig4-4.png)
**图4-4 使用Protobuf编码的记录**
需要注意的一个细节:在前面所示的模式中,每个字段被标记为必需或可选,但是这对字段如何编码没有任何影响(二进制数据中没有任何字段指示是否需要字段)。所不同的是,如果未设置该字段,则所需的运行时检查将失败,这对于捕获错误非常有用。
#### 字段标签和模式演变
我们之前说过,模式不可避免地需要随着时间而改变。我们称之为模式演变。 Thrift和Protocol Buffers如何处理模式更改同时保持向后兼容性
从示例中可以看出编码的记录就是其编码字段的拼接。每个字段由其标签号码样本模式中的数字1,2,3标识并用数据类型例如字符串或整数注释。如果没有设置字段值则简单地从编码记录中省略。从中可以看到字段标记对编码数据的含义至关重要。您可以更改架构中字段的名称因为编码的数据永远不会引用字段名称但不能更改字段的标记因为这会使所有现有的编码数据无效。
您可以添加新的字段到架构,只要您给每个字段一个新的标签号码。如果旧的代码(不知道你添加的新的标签号码)试图读取新代码写入的数据,包括一个新的字段,其标签号码不能识别,它可以简单地忽略该字段。数据类型注释允许解析器确定需要跳过的字节数。这保持了前向兼容性:旧代码可以读取由新代码编写的记录。
向后兼容性呢?只要每个字段都有一个唯一的标签号码,新的代码总是可以读取旧的数据,因为标签号码仍然具有相同的含义。唯一的细节是,如果你添加一个新的领域,你不能要求。如果您要添加一个字段并将其设置为必需,那么如果新代码读取旧代码写入的数据,则该检查将失败,因为旧代码不会写入您添加的新字段。因此,为了保持向后兼容性,在模式的初始部署之后添加的每个字段必须是可选的或具有默认值。
删除一个字段就像添加一个字段,倒退和向前兼容性问题相反。这意味着您只能删除一个可选的字段(必填字段永远不能删除),而且您不能再次使用相同的标签号码(因为您可能仍然有数据写在包含旧标签号码的地方,而该字段必须被新代码忽略)。
#### 数据类型和模式演变
如何改变字段的数据类型?这可能是可能的 - 检查文件的细节 - 但是有一个风险价值将失去精度或被扼杀。例如假设你将一个32位的整数变成一个64位的整数。新代码可以轻松读取旧代码写入的数据因为解析器可以用零填充任何缺失的位。但是如果旧代码读取由新代码写入的数据则旧代码仍使用32位变量来保存该值。如果解码的64位值不适合32位则它将被截断。
Protobuf的一个奇怪的细节是它没有列表或数组数据类型而是有一个字段的重复标记这是第三个选项旁边必要和可选。如图4-4所示重复字段的编码正如它所说的那样同一个字段标记只是简单地出现在记录中。这具有很好的效果可以将可选单值字段更改为重复多值字段。读取旧数据的新代码会看到一个包含零个或一个元素的列表取决于该字段是否存在。读取新数据的旧代码只能看到列表的最后一个元素。
Thrift有一个专用的列表数据类型它使用列表元素的数据类型进行参数化。这不允许Protocol Buffers所做的从单值到多值的相同演变但是它具有支持嵌套列表的优点。
### Avro
Apache Avro [20]是另一种二进制编码格式与Protocol Buffers和Thrift有趣的不同。 它是作为Hadoop的一个子项目在2009年开始的因为Thrift不适合Hadoop的用例[21]。
Avro也使用模式来指定正在编码的数据的结构。 它有两种模式语言一种Avro IDL用于人工编辑一种基于JSON更易于机器读取。
我们用Avro IDL编写的示例模式可能如下所示
```c
record Person {
string userName;
union { null, long } favoriteNumber = null;
array<string> interests;
}
```
等价的JSON表示
```json
{
"type": "record",
"name": "Person",
"fields": [
{"name": "userName", "type": "string"},
{"name": "favoriteNumber", "type": ["null", "long"], "default": null},
{"name": "interests", "type": {"type": "array", "items": "string"}
]
}
```
首先,请注意架构中没有标签号码。 如果我们使用这个模式编码我们的例子记录例4-1Avro二进制编码只有32个字节长这是我们所见过的所有编码中最紧凑的。 编码字节序列的分解如图4-5所示。
如果您检查字节序列,您可以看到没有什么可以识别字段或其数据类型。 编码只是由连在一起的值组成。 一个字符串只是一个长度前缀后跟UTF-8字节但是在被包含的数据中没有任何内容告诉你它是一个字符串。 它可以是一个整数,也可以是其他的整数。 整数使用可变长度编码与Thrift的CompactProtocol相同进行编码。
![](img/fig4-5.png)
**图4-5 使用Avro编码的记录**
为了解析二进制数据,您按照它们出现在架构中的顺序遍历这些字段,并使用架构来告诉您每个字段的数据类型。这意味着如果读取数据的代码使用与写入数据的代码完全相同的模式,则只能正确解码二进制数据。阅读器和作者之间的模式不匹配意味着错误地解码数据。
那么Avro如何支持模式演变呢
#### 作者模式与读者模式
有了Avro当应用程序想要编码一些数据将其写入文件或数据库通过网络发送等它使用它知道的任何版本的模式编码数据例如架构可能被编译到应用程序中。这被称为作者的模式。
当一个应用程序想要解码一些数据(从一个文件或数据库读取数据,从网络接收数据等)时,它希望数据在某个模式中,这就是读者的模式。这是应用程序代码所依赖的模式,在应用程序的构建过程中,代码可能是从该模式生成的。
Avro的关键思想是作者的模式和读者的模式不必是相同的 - 他们只需要兼容。当数据解码读取Avro库通过并排查看作者的模式和读者的模式并将数据从作者的模式转换到读者的模式来解决差异。 Avro规范[20]确切地定义了这种解析的工作原理如图4-6所示。
例如,如果作者的模式和读者的模式的字段顺序不同,这是没有问题的,因为模式解析通过字段名匹配字段。如果读取数据的代码遇到出现在作者模式中但不在读者模式中的字段,则忽略它。如果读取数据的代码需要某个字段,但是作者的模式不包含该名称的字段,则使用在读者模式中声明的默认值填充。
![](img/fig4-6.png)
**图4-6 一个Avro Reader解决读写模式的差异**
#### 模式演变规则
使用Avro向前兼容性意味着您可以将新版本的架构作为编写器并将旧版本的架构作为读者。相反向后兼容意味着你可以有一个作为读者的新版本的模式和作为作者的旧版本。
为了保持兼容性,您只能添加或删除具有默认值的字段。 我们的Avro模式中的字段favourNumber的默认值为null。例如假设您添加一个默认值的字段所以这个新的字段存在于新的模式中而不是旧的。当使用新模式的阅读器读取使用旧模式写入的记录时将为缺少的字段填充默认值。
如果你要添加一个没有默认值的字段新的阅读器将无法读取旧作者写的数据所以你会破坏向后兼容性。如果您要删除没有默认值的字段旧的阅读器将无法读取新作者写入的数据因此您会打破兼容性。在一些编程语言中null是任何变量可以接受的默认值但在Avro中并不是这样如果要允许一个字段为null则必须使用联合类型。例如`union {nulllongstring}`字段;表示该字段可以是数字或字符串,也可以是`null`。如果它是union的分支之一那么只能使用null作为默认值.iv这比默认情况下可以为null是更加冗长的但是通过明确什么可以和不可以是什么有助于防止错误null [22]。
因此Avro没有像Protocol Buffers和Thrift那样的`optional`和`required`标记(它有联合类型和默认值)。
只要Avro可以转换类型就可以改变字段的数据类型。更改字段的名称是可能的但有点棘手读者的模式可以包含字段名称的别名所以它可以匹配旧作家的模式字段名称与别名。这意味着更改字段名称是向后兼容的但不能向前兼容。同样向联合类型添加分支也是向后兼容的但不能向前兼容。
##### 但作者模式到底是什么?
到目前为止,我们已经讨论了一个重要的问题:读者如何知道作者的模式是哪一部分数据被编码的?我们不能只将整个模式包括在每个记录中,因为模式可能比编码的数据大得多,从而使二进制编码节省的所有空间都是徒劳的。
答案取决于Avro使用的上下文。举几个例子
* 有很多记录的大文件
Avro的一个常见用途 - 尤其是在Hadoop环境中 - 用于存储包含数百万条记录的大文件,所有记录都使用相同的模式进行编码。 我们将在第10章讨论这种情况。在这种情况下该文件的作者可以在文件的开头只包含一次作者的模式。 Avro指定一个文件格式对象容器文件来做到这一点。
* 支持独立写入的记录的数据库
在一个数据库中,不同的记录可能会在不同的时间点使用不同的作者的模式编写 - 你不能假定所有的记录都有相同的模式。最简单的解决方案是在每个编码记录的开始处包含一个版本号,并在数据库中保留一个模式版本列表。读者可以获取记录,提取版本号,然后从数据库中获取该版本号的作者模式。使用该作者的模式,它可以解码记录的其余部分。 例如Espresso [23]就是这样工作的。)
* 通过网络连接发送记录
当两个进程通过双向网络连接进行通信时,他们可以在连接设置上协商模式版本,然后在连接的生命周期中使用该模式。 Avro RPC协议请参阅第131页上的“通过服务的数据流REST和RPC”如此工作。
具有模式版本的数据库在任何情况下都是非常有用的,因为它充当文档并为您提供了检查模式兼容性的机会[24]。作为版本号,你可以使用一个简单的递增整数,或者你可以使用模式的散列。
#### 动态生成的模式
与Protocol Buffers和Thrift相比Avro方法的一个优点是架构不包含任何标签号码。但为什么这很重要在模式中保留一些数字有什么问题
不同之处在于Avro对动态生成的模式更友善。例如假如你有一个关系数据库你想要把它的内容转储到一个文件中并且你想使用二进制格式来避免前面提到的文本格式JSONCSVSQL的问题。如果你使用Avro你可以很容易地从关系模式生成一个Avro模式在我们之前看到的JSON表示中并使用该模式对数据库内容进行编码并将其全部转储到Avro对象容器文件[25]中。您为每个数据库表生成一个记录模式每个列成为该记录中的一个字段。数据库中的列名称映射到Avro中的字段名称。
现在如果数据库模式发生变化例如一个表中添加了一列删除了一列则可以从更新的数据库模式生成新的Avro模式并在新的Avro模式中导出数据。数据导出过程不需要注意模式的改变 - 每次运行时都可以简单地进行模式转换。任何读取新数据文件的人都会看到记录的字段已经改变,但是由于字段是通过名字来标识的,所以更新的作者的模式仍然可以与旧的读者模式匹配。
相比之下如果您为此使用Thrift或Protocol Buffers则字段标记可能必须手动分配每次数据库模式更改时管理员都必须手动更新从数据库列名到字段标签。 这可能会自动化但模式生成器必须非常小心不要分配以前使用的字段标记。这种动态生成的模式根本不是Thrift或Protocol Buffers的设计目标而是为Avro。
#### 代码生成和动态类型的语言
Thrift和Protobuf依赖于代码生成在定义了模式之后可以使用您选择的编程语言生成实现此模式的代码。这在JavaC ++或C等静态类型语言中很有用因为它允许将高效的内存中结构用于解码的数据并且在编写访问数据结构的程序时允许在IDE中进行类型检查和自动完成。
在动态类型编程语言如JavaScriptRuby或Python生成代码没有太多意义因为没有编译时类型检查器来满足。代码生成在这些语言中经常被忽视因为它们避免了明确的编译步骤。而且对于动态生成的模式例如从数据库表生成的Avro模式代码生成对获取数据是一个不必要的障碍。
Avro为静态类型编程语言提供了可选的代码生成功能但是它也可以在不生成任何代码的情况下使用。如果你有一个对象容器文件它嵌入了作者的模式你可以简单地使用Avro库打开它并以与查看JSON文件相同的方式查看数据。该文件是自描述的因为它包含所有必要的元数据。
这个属性特别适用于动态类型的数据处理语言如Apache Pig [26]。在Pig中您可以打开一些Avro文件开始分析它们并编写派生数据集以Avro格式输出文件而无需考虑模式。
### 模式的优点
正如我们所看到的Protocol BuffersThrift和Avro都使用模式来描述二进制编码格式。他们的模式语言比XML模式或者JSON模式简单得多它支持更详细的验证规则例如“该字段的字符串值必须与该正则表达式匹配”或“该字段的整数值必须在0和100之间“。由于Protocol BuffersThrift和Avro实现起来更简单使用起来也更简单所以它们已经发展到支持相当广泛的编程语言。
这些编码所基于的想法绝不是新的。例如它们与ASN.1有很多相似之处它是1984年首次被标准化的模式定义语言[27]。它被用来定义各种网络协议其二进制编码DER仍然被用于编码SSL证书X.509),例如[28]。 ASN.1支持使用标签号码的模式演进类似于Protocol Buf-fers和Thrift [29]。然而这也是非常复杂和严重的文件记录所以ASN.1可能不是新应用程序的好选择。
许多数据系统也为其数据实现某种专有的二进制编码。例如大多数关系数据库都有一个网络协议您可以通过该协议向数据库发送查询并获取响应。这些协议通常特定于特定的数据库并且数据库供应商提供将来自数据库的网络协议的响应解码为内存数据结构的驱动程序例如使用ODBC或JDBC API
所以我们可以看到尽管JSONXML和CSV等文本数据格式非常普遍但基于模式的二进制编码也是一个可行的选择。他们有一些很好的属性
* 它们可以比各种“二进制JSON”变体更紧凑因为它们可以省略编码数据中的字段名称。
* 模式是一种有价值的文档形式,因为模式是解码所必需的,所以可以确定它是最新的(而手动维护的文档可能很容易偏离现实)。
* 保留模式数据库允许您在部署任何内容之前检查模式更改的向前和向后兼容性。
* 对于静态类型编程语言的用户来说,从模式生成代码的能力是有用的,因为它可以在编译时进行类型检查。
总而言之模式进化允许与JSON数据库提供的无模式/模式读取相同的灵活性请参阅第39页的“文档模型中的模式灵活性”同时还可以更好地保证数据和更好的工具。
## 数据流的类型
在本章的开始部分,我们曾经说过,无论何时您想要将某些数据发送到不共享内存的另一个进程,例如,只要您想通过网络发送数据或将其写入文件,就需要将它编码为一个字节序列。然后我们讨论了做这个的各种不同的编码。
我们讨论了向前和向后的兼容性,这对于可演化性来说非常重要(通过允许您独立升级系统的不同部分,而不必一次改变所有内容,可以轻松地进行更改)。兼容性是编码数据的一个进程和解码它的另一个进程之间的一种关系。
这是一个相当抽象的概念 - 数据可以通过多种方式从一个流程流向另一个流程。谁编码数据,谁解码?在本章的其余部分中,我们将探讨数据如何在流程之间流动的一些最常见的方式:
* 通过数据库请参阅第129页的“通过数据库的数据流”
* 通过服务调用请参阅第131页的“通过服务传输数据流REST和RPC”
* 通过异步消息传递请参阅第136页的“消息传递数据流”
### 数据库中的数据流
在数据库中,写入数据库的过程对数据进行编码,从数据库读取的过程对数据进行解码。可能只有一个进程访问数据库,在这种情况下,读者只是相同进程的后续版本 - 在这种情况下,您可以考虑将数据库中的内容存储为向未来的自我发送消息。
向后兼容性显然是必要的。否则你未来的自己将无法解码你以前写的东西。
一般来说,几个不同的进程同时访问数据库是很常见的。这些进程可能是几个不同的应用程序或服务,或者它们可能只是几个相同服务的实例(为了可扩展性或容错性而并行运行)。无论哪种方式,在应用程序发生变化的环境中,访问数据库的某些进程可能会运行较新的代码,有些进程可能会运行较旧的代码,例如,因为新版本当前正在部署在滚动升级,所以有些实例已经更新,而其他实例尚未更新。
这意味着数据库中的一个值可能会被更新版本的代码写入,然后被仍旧运行的旧版本的代码读取。因此,数据库也经常需要向前兼容。
但是,还有一个额外的障碍。假设您将一个字段添加到记录模式,并且较新的代码将该新字段的值写入数据库。随后,旧版本的代码(尚不知道新字段)将读取记录,更新记录并将其写回。在这种情况下,理想的行为通常是旧代码保持新的领域完整,即使它不能被解释。
前面讨论的编码格式支持未知域的保存但是有时候需要在应用程序层面保持谨慎如图4-7所示。例如如果将数据库值解码为应用程序中的模型对象稍后重新编码这些模型对象那么未知字段可能会在该翻译过程中丢失。
解决这个问题不是一个难题,你只需要意识到它。
![](img/fig4-7.png)
**图4-7 当较旧版本的应用程序更新以前由较新版本的应用程序编写的数据时,如果不小心,数据可能会丢失。**
#### 在不同的时间写入不同的值
数据库通常允许任何时候更新任何值。这意味着在一个单一的数据库中,可能有一些价值是五毫秒前写的,而一些价值是五年前写的。
在部署应用程序的新版本(至少是服务器端应用程序)时,您可能会在几分钟内完全用新版本替换旧版本。数据库内容也是如此:五年前的数据仍然存在于原始编码中,除非您已经明确地重写了它。这种观察有时被总结为数据超出代码。
将数据重写(迁移)到一个新的模式当然是可能的,但是在一个大数据集上执行是一个昂贵的事情,所以大多数数据库如果可能的话就避免它。大多数关系数据库都允许简单的模式更改,例如添加一个默认值为空的新列,而不重写现有数据[^v]读取旧行时,数据库将填充编码数据中缺少的任何列的空值在磁盘上。 LinkedIn的文档数据库Espresso使用Avro存储允许它使用Avro的模式演变规则[23]。
因此,架构演变允许整个数据库看起来好像是用单个模式编码的,即使底层存储可能包含用模式的各种历史版本编码的记录。
[^v]: 除了MySQL即使并非真的必要它也经常会重写整个表正如第39页的“文档模型中的架构灵活性”中所提到的。
#### 归档存储
也许您不时为数据库创建一个快照例如备份或加载到数据仓库请参阅第91页的“数据仓库”。在这种情况下即使源数据库中的原始编码包含来自不同时代的模式版本的混合数据转储通常也将使用最新模式进行编码。既然你正在复制数据那么你可能会一直对数据的副本进行编码。
由于数据转储是一次写入的而且以后是不可变的所以Avro对象容器文件等格式非常适合。这也是一个很好的机会可以将数据编码为面向分析的列式格式例如Parquet请参阅第97页的“列压缩”
在第10章中我们将详细讨论在档案存储中使用数据。
### 服务中的数据流REST 与 RPC
当您需要通过网络进行通信的进程时安排该通信的方式有几种。最常见的安排是有两个角色客户端和服务器。服务器通过网络公开API并且客户端可以连接到服务器以向该API发出请求。服务器公开的API被称为服务。
Web以这种方式工作客户Web浏览器向Web服务器发出请求使GET请求下载HTMLCSSJavaScript图像等并向POST请求提交数据到服务器。 API包含一组标准的协议和数据格式HTTPURLSSL / TLSHTML等。由于网络浏览器网络服务器和网站作者大多同意这些标准您可以使用任何网络浏览器访问任何网站至少在理论上
Web浏览器不是唯一的客户端类型。例如在移动设备或桌面计算机上运行的本地应用程序也可以向服务器发出网络请求并且在Web浏览器内运行的客户端JavaScript应用程序可以使用XMLHttpRequest成为HTTP客户端该技术被称为Ajax [30]。在这种情况下服务器的响应通常不是用于显示给人的HTML而是用于便于客户端应用程序代码如JSON进一步处理的编码数据。尽管HTTP可能被用作传输协议但顶层实现的API是特定于应用程序的客户端和服务器需要就该API的细节达成一致。
此外服务器本身可以是另一个服务的客户端例如典型的Web应用服务器充当数据库的客户端。这种方法通常用于将大型应用程序按照功能区域分解为较小的服务这样当一个服务需要来自另一个服务的某些功能或数据时就会向另一个服务发出请求。这种构建应用程序的方式传统上被称为面向服务的体系结构service-oriented architectureSOA最近被改进和更名为微服务体系结构[31,32]。
在某些方面服务类似于数据库它们通常允许客户端提交和查询数据。但是虽然数据库允许使用我们在第2章 中讨论的查询语言进行任意查询但是服务公开了一个特定于应用程序的API它只允许由服务的业务逻辑应用程序代码预定的输入和输出[33 ]。这种限制提供了一定程度的封装:服务可以对客户可以做什么和不可以做什么施加细粒度的限制。
面向服务/微服务架构的一个关键设计目标是通过使服务独立部署和演化来使应用程序更易于更改和维护。例如每个服务应该由一个团队拥有并且该团队应该能够经常发布新版本的服务而不必与其他团队协调。换句话说我们应该期望服务器和客户端的旧版本和新版本同时运行因此服务器和客户端使用的数据编码必须在不同版本的服务API之间兼容 - 正是我们所做的本章一直在谈论。
#### Web服务
当HTTP被用作与服务交谈的底层协议时它被称为Web服务。这可能是一个小错误因为Web服务不仅在Web上使用而且在几个不同的环境中使用。例如
1.运行在用户设备上的客户端应用程序例如移动设备上的本地应用程序或使用Ajax的JavaScript web应用程序通过HTTP向服务发出请求。这些请求通常通过公共互联网进行。
2.一种服务向同一组织拥有的另一项服务提出请求,这些服务通常位于同一数据中心内,作为面向服务/微型架构的一部分。 (支持这种用例的软件有时被称为中间件。)
3.一种服务通过互联网向不同组织所拥有的服务提出请求。这用于不同组织后端系统之间的数据交换。此类别包括由在线服务如信用卡处理系统提供的公共API或用于共享访问用户数据的OAuth。
有两种流行的Web服务方法REST和SOAP。他们在哲学方面几乎是截然相反的往往是各自支持者之间的激烈辩论即使在每个阵营内也有很多争论。 例如HATEOAS超媒体作为应用程序状态的引擎经常引发讨论[35]。)
REST不是一个协议而是一个基于HTTP原则的设计哲学[34,35]。它强调简单的数据格式使用URL来标识资源并使用HTTP功能进行缓存控制身份验证和内容类型协商。与SOAP相比REST已经越来越受欢迎至少在跨组织服务集成的背景下[36],并经常与微服务相关[31]。根据REST原则设计的API称为RESTful。
相比之下SOAP是用于制作网络API请求的基于XML的协议 尽管首字母缩写词相似SOAP并不是SOA的要求。 SOAP是一种特殊的技术而SOA是构建系统的一般方法。。虽然它最常用于HTTP但其目的是独立于HTTP并避免使用大多数HTTP功能。相反它带有庞大而复杂的多种相关标准Web服务框架称为WS- *),它们增加了各种功能[37]。
SOAP Web服务的API使用称为Web服务描述语言WSDL的基于XML的语言来描述。 WSDL支持代码生成客户端可以使用本地类和方法调用编码为XML消息并由框架再次解码访问远程服务。这在静态类型编程语言中非常有用但在动态类型编程语言中很少请参阅“代码生成和动态类型化语言”第125页
由于WSDL的设计不是人类可读的而且由于SOAP消息通常是手动构建的过于复杂所以SOAP的用户在很大程度上依赖于工具支持代码生成和IDE [38]。对于SOAP供应商不支持的编程语言的用户来说与SOAP服务的集成是困难的。
尽管SOAP及其各种扩展表面上是标准化的但是不同厂商的实现之间的互操作性往往会造成问题[39]。由于所有这些原因尽管许多大型企业仍然使用SOAP但在大多数小公司中已经不再受到青睐。
REST风格的API倾向于更简单的方法通常涉及较少的代码生成和自动化工具。定义格式如OpenAPI也称为Swagger [40]可用于描述RESTful API并生成文档。
#### 远程过程调用RPC的问题
Web服务仅仅是通过网络进行API请求的一系列技术的最新版本其中许多技术受到了大量的炒作但是存在严重的问题。 Enterprise JavaBeansEJB和Java的远程方法调用RMI仅限于Java。分布式组件对象模型DCOM仅限于Microsoft平台。公共对象请求代理体系结构CORBA过于复杂不提供前向或后向兼容性[41]。
所有这些都是基于远程过程调用RPC的思想该过程调用自20世纪70年代以来一直存在[42]。 RPC模型试图向远程网络服务发出请求看起来与在同一进程中调用编程语言中的函数或方法相同这种抽象称为位置透明。尽管RPC起初看起来很方便但这种方法根本上是有缺陷的[43,44]。网络请求与本地函数调用非常不同:
* 本地函数调用是可预测的,并且成功或失败,这仅取决于受您控制的参数。网络请求是不可预知的:由于网络问题,请求或响应可能会丢失,或者远程计算机可能很慢或不可用,这些问题完全不在您的控制范围之内。网络问题是常见的,所以你必须预测他们,例如通过重试失败的请求。
* 本地函数调用要么返回结果,要么抛出异常,或者永远不返回(因为进入无限循环或进程崩溃)。网络请求有另一个可能的结果:由于超时,它可能会返回没有结果。在这种情况下,你根本不知道发生了什么:如果你没有得到来自远程服务的响应,你无法知道请求是否通过。 我们将在第8章更详细地讨论这个问题。
* 如果您重试失败的网络请求,可能会发生请求实际上正在通过,只有响应丢失。在这种情况下,重试将导致该操作被执行多次,除非您在协议中引入除重(*幂等 idempotence*)机制。本地函数调用没有这个问题。 (我们在第十一章更详细地讨论幂等性)
* 每次调用本地功能时,通常需要大致相同的时间来执行。网络请求比函数调用要慢得多,而且其延迟也是非常可变的:在不到一毫秒的时间内它可能会完成,但是当网络拥塞或者远程服务超载时,可能需要几秒钟的时间完全一样的东西。
* 调用本地函数时,可以高效地将引用(指针)传递给本地内存中的对象。当你发出一个网络请求时,所有这些参数都需要被编码成可以通过网络发送的一系列字节。没关系,如果参数是像数字或字符串这样的基本类型,但是对于较大的对象很快就会变成问题。
客户端和服务可以用不同的编程语言实现所以RPC框架必须将数据类型从一种语言翻译成另一种语言。这可能会捅出大篓子因为不是所有的语言都具有相同的类型 - 例如回想一下JavaScript的数字大于$2^{53}$的问题请参阅第114页上的“JSONXML和二进制变体”。用单一语言编写的单个进程中不存在此问题。
所有这些因素意味着尝试使远程服务看起来像编程语言中的本地对象一样毫无意义,因为这是一个根本不同的事情。 REST的部分吸引力在于它并不试图隐藏它是一个网络协议的事实尽管这似乎并没有阻止人们在REST之上构建RPC库
#### RPC的当前方向
尽管有这样那样的问题RPC不会消失。在本章提到的所有编码的基础上构建了各种RPC框架例如Thrift和Avro带有RPC支持gRPC是使用Protocol Buffers的RPC实现Finagle也使用ThriftRest.li使用JSON over HTTP。
这种新一代的RPC框架更加明确的是远程请求与本地函数调用不同。例如Finagle和Rest.li使用futurespromises来封装可能失败的异步操作。`Futures`还可以简化需要并行发出多项服务的情况,并将其结果合并[45]。 gRPC支持流其中一个调用不仅包括一个请求和一个响应还包括一系列的请求和响应[46]。
其中一些框架还提供服务发现即允许客户端找出在哪个IP地址和端口号上可以找到特定的服务。我们将在第214页的“请求路由”中回到这个主题。
使用二进制编码格式的自定义RPC协议可以实现比通用的JSON over REST更好的性能。但是RESTful API还有其他一些显着的优点对于实验和调试只需使用Web浏览器或命令行工具curl无需任何代码生成或软件安装即可向其请求它是受支持的所有的主流编程语言和平台还有大量可用的工具服务器缓存负载平衡器代理防火墙监控调试工具测试工具等的生态系统。由于这些原因REST似乎是公共API的主要风格。 RPC框架的主要重点在于同一组织拥有的服务之间的请求通常在同一数据中心内。
#### 数据编码与RPC的演化
对于可演化性重要的是可以独立更改和部署RPC客户端和服务器。与通过数据库流动的数据相比如上一节所述我们可以在通过服务进行数据流的情况下做一个简化的假设假定所有的服务器都会先更新其次是所有的客户端。因此您只需要在请求上具有向后兼容性并且对响应具有前向兼容性。
RPC方案的前后向兼容性属性从它使用的编码方式中继承
* ThriftgRPC协议缓冲区和Avro RPC可以根据相应编码格式的兼容性规则进行演变。
* 在SOAP中请求和响应是使用XML模式指定的。这些可以演变但有一些微妙的陷阱[47]。
* RESTful API通常使用JSON没有正式指定的模式用于响应以及用于请求的JSON或URI编码/表单编码的请求参数。添加可选的请求参数并向响应对象添加新的字段通常被认为是保持兼容性的改变。
由于RPC经常被用于跨越组织边界的通信所以服务的兼容性变得更加困难因此服务的提供者经常无法控制其客户也不能强迫他们升级。因此需要长期保持兼容性也许是无限期的。如果需要进行兼容性更改则服务提供商通常会并排维护多个版本的服务API。
关于API版本化应该如何工作客户端如何指示它想要使用哪个版本的API没有一致意见[48]。对于RESTful API常用的方法是在URL或HTTP Accept头中使用版本号。对于使用API密钥来标识特定客户端的服务另一种选择是将客户端请求的API版本存储在服务器上并允许通过单独的管理界面更新该版本选项[49]。
### 消息传递中的数据流
我们一直在研究从一个过程到另一个过程的编码数据流的不同方式。到目前为止我们已经讨论了REST和RPC其中一个进程通过网络向另一个进程发送请求并期望尽可能快的响应以及数据库一个进程写入编码数据另一个进程在将来再次读取
在最后一节中我们将简要介绍一下RPC和数据库之间的异步消息传递系统。它们与RPC类似因为客户端的请求通常称为消息以低延迟传送到另一个进程。它们与数据库类似不是通过直接的网络连接发送消息而是通过称为消息代理也称为消息队列或面向消息的中间件的中介来临时存储消息。
与直接RPC相比使用消息代理有几个优点
* 如果收件人不可用或过载,可以充当缓冲区,从而提高系统的可靠性。
* 它可以自动将消息重新发送到已经崩溃的进程,从而防止消息丢失。
* 避免发件人需要知道收件人的IP地址和端口号这在虚拟机经常出入的云部署中特别有用
* 它允许将一条消息发送给多个收件人。
* 将发件人与收件人逻辑分离(发件人只是发布邮件,不关心使用者)。
然而与RPC相比差异在于消息传递通信通常是单向的发送者通常不期望收到其消息的回复。一个进程可能发送一个响应但这通常是在一个单独的通道上完成的。这种通信模式是异步的发送者不会等待消息被传递而只是发送它然后忘记它。
#### 消息掮客
过去信息掮客主要是TIBCOIBM WebSphere和webMethods等公司的商业软件的秀场。最近像RabbitMQActiveMQHornetQNATS和Apache Kafka这样的开源实现已经流行起来。我们将在第11章中对它们进行更详细的比较。
详细的交付语义因实现和配置而异,但通常情况下,消息代理的使用方式如下:一个进程将消息发送到指定的队列或主题,代理确保将消息传递给一个或多个消费者或订阅者到那个队列或主题。在同一主题上可以有许多生产者和许多消费者。
一个主题只提供单向数据流。但是消费者本身可能会将消息发布到另一个主题上因此可以将它们链接在一起就像我们将在第11章中看到的那样或者发送给原始消息的发送者使用的回复队列允许请求/响应数据流类似于RPC
消息代理通常不会执行任何特定的数据模型 - 消息只是包含一些元数据的字节序列,因此您可以使用任何编码格式。如果编码是向后兼容的,则您可以灵活地更改发行商和消费者的独立编码,并以任意顺序进行部署。
如果消费者重新发布消息到另一个主题则可能需要小心保留未知字段以防止前面在数据库环境中描述的问题图4-7
#### 分布式的Actor框架
actor模型是单个进程中并发的编程模型。逻辑被封装在角色中而不是直接处理线程以及竞争条件锁定和死锁的相关问题。每个角色通常代表一个客户或实体它可能有一些本地状态不与其他任何角色共享它通过发送和接收异步消息与其他角色通信。消息传送不保证在某些错误情况下消息将丢失。由于每个角色一次只能处理一条消息因此不需要担心线程每个角色可以由框架独立调度。
在分布式的行为者框架中,这个编程模型被用来跨越多个节点来扩展应用程序。不管发送方和接收方是在同一个节点上还是在不同的节点上,都使用相同的消息传递机制。如果它们在不同的节点上,则该消息被透明地编码成字节序列,通过网络发送,并在另一侧解码。
位置透明在actor模型中比在RPC中效果更好因为actor模型已经假定消息可能会丢失即使在单个进程中也是如此。尽管网络上的延迟可能比同一个进程中的延迟更高但是在使用参与者模型时本地和远程通信之间的基本不匹配是较少的。
分布式的Actor框架实质上是将消息代理和角色编程模型集成到一个框架中。但是如果要执行基于角色的应用程序的滚动升级则仍然需要担心向前和向后兼容性问题因为消息可能会从运行新版本的节点发送到运行旧版本的节点反之亦然。
三个流行的分布式actor框架处理消息编码如下
* 默认情况下Akka使用Java的内置序列化不提供前向或后向兼容性。 但是,你可以用类似缓冲区的东西替代它,从而获得滚动升级的能力[50]。
* `Orleans`默认使用不支持滚动升级部署的自定义数据编码格式; 要部署新版本的应用程序,您需要设置一个新的群集,将流量从旧群集迁移到新群集,然后关闭旧群集[51,52]。 像Akka一样可以使用自定义序列化插件。
* 在Erlang OTP中对记录模式进行更改是非常困难的尽管系统具有许多为高可用性设计的功能。 滚动升级是可能的,但需要仔细计划[53]。 一个新的实验性的`maps`数据类型2014年在Erlang R17中引入的类似于JSON的结构可能使得这个数据类型在未来更容易[54]。
## 本章小结
在本章中,我们研究了将数据结构转换为网络中的字节或磁盘上的字节的几种方法。我们看到了这些编码的细节不仅影响其效率,更重要的是应用程序的体系结构和部署它们的选项。
特别是,许多服务需要支持滚动升级,其中新版本的服务逐步部署到少数节点,而不是同时部署到所有节点。滚动升级允许在不停机的情况下发布新版本的服务(从而鼓励在罕见的大型版本上频繁发布小型版本),并使部署风险降低(允许在影响大量用户之前检测并回滚有故障的版本)。这些属性对于可演化性,以及对应用程序进行更改的容易性都是非常有利的。
在滚动升级期间,或出于各种其他原因,我们必须假设不同的节点正在运行我们的应用程序代码的不同版本。因此,在系统周围流动的所有数据都是以提供向后兼容性(新代码可以读取旧数据)和向前兼容性(旧代码可以读取新数据)的方式进行编码是重要的。
我们讨论了几种数据编码格式及其兼容性属性:
* 编程语言特定的编码仅限于单一编程语言,并且往往无法提供前向和后向兼容性。
* JSONXML和CSV等文本格式非常普遍其兼容性取决于您如何使用它们。他们有可选的模式语言这有时是有用的有时是一个障碍。这些格式对于数据类型有些模糊所以你必须小心数字和二进制字符串。
* 像ThriftProtocol Buffers和Avro这样的二进制模式驱动格式允许使用清晰定义的前向和后向兼容性语义进行紧凑高效的编码。这些模式可以用于静态类型语言的文档和代码生成。但是他们有一个缺点就是在数据可读之前需要对数据进行解码。
我们还讨论了数据流的几种模式,说明了数据编码是重要的不同场景:
* 数据库,写入数据库的进程对数据进行编码,并从数据库读取进程对其进行解码
* RPC和REST API客户端对请求进行编码服务器对请求进行解码并对响应进行编码客户端最终对响应进行解码
* 异步消息传递(使用消息代理或参与者),其中节点之间通过发送消息进行通信,消息由发送者编码并由接收者解码
我们可以小心地得出这样的结论:前向兼容性和滚动升级在某种程度上是可以实现的。愿您的应用程序的演变迅速、敏捷部署。
## 参考文献
1. “[Java Object Serialization Specification](http://docs.oracle.com/javase/7/docs/platform/serialization/spec/serialTOC.html),” *docs.oracle.com*, 2010.
1. “[Ruby 2.2.0 API Documentation](http://ruby-doc.org/core-2.2.0/),” *ruby-doc.org*, Dec 2014.
1. “[The Python 3.4.3 Standard Library Reference Manual](https://docs.python.org/3/library/pickle.html),” *docs.python.org*, February 2015.
1. “[EsotericSoftware/kryo](https://github.com/EsotericSoftware/kryo),”
*github.com*, October 2014.
1. “[CWE-502: Deserialization of Untrusted Data](http://cwe.mitre.org/data/definitions/502.html),” Common Weakness Enumeration, *cwe.mitre.org*,
July 30, 2014.
1. Steve Breen:
“[What Do WebLogic, WebSphere, JBoss, Jenkins, OpenNMS, and Your Application Have in Common? This Vulnerability](http://foxglovesecurity.com/2015/11/06/what-do-weblogic-websphere-jboss-jenkins-opennms-and-your-application-have-in-common-this-vulnerability/),” *foxglovesecurity.com*, November 6, 2015.
1. Patrick McKenzie:
“[What the Rails Security Issue Means for Your Startup](http://www.kalzumeus.com/2013/01/31/what-the-rails-security-issue-means-for-your-startup/),” *kalzumeus.com*, January 31, 2013.
1. Eishay Smith:
“[jvm-serializers wiki](https://github.com/eishay/jvm-serializers/wiki),”
*github.com*, November 2014.
1. “[XML Is a Poor Copy of S-Expressions](http://c2.com/cgi/wiki?XmlIsaPoorCopyOfEssExpressions),” *c2.com* wiki.
1. Matt Harris:
“[Snowflake: An Update and Some Very Important Information](https://groups.google.com/forum/#!topic/twitter-development-talk/ahbvo3VTIYI),” email to *Twitter Development
Talk* mailing list, October 19, 2010.
1. Shudi (Sandy) Gao, C. M. Sperberg-McQueen, and
Henry S. Thompson: “[XML Schema 1.1](http://www.w3.org/XML/Schema),” W3C Recommendation,
May 2001.
1. Francis Galiegue, Kris Zyp, and Gary Court:
“[JSON Schema](http://json-schema.org/),” IETF Internet-Draft, February 2013.
1. Yakov Shafranovich:
“[RFC 4180: Common Format and MIME Type for Comma-Separated Values (CSV) Files](https://tools.ietf.org/html/rfc4180),” October 2005.
1. “[MessagePack Specification](http://msgpack.org/),” *msgpack.org*.
1. Mark Slee, Aditya Agarwal, and Marc Kwiatkowski:
“[Thrift: Scalable Cross-Language Services Implementation](http://thrift.apache.org/static/files/thrift-20070401.pdf),” Facebook technical report, April 2007.
1. “[Protocol Buffers Developer Guide](https://developers.google.com/protocol-buffers/docs/overview),” Google, Inc., *developers.google.com*.
1. Igor Anishchenko:
“[Thrift vs Protocol Buffers vs Avro - Biased Comparison](http://www.slideshare.net/IgorAnishchenko/pb-vs-thrift-vs-avro),” *slideshare.net*, September 17, 2012.
1. “[A Matrix of the Features Each Individual Language Library Supports](http://wiki.apache.org/thrift/LibraryFeatures),”
*wiki.apache.org*.
1. Martin Kleppmann:
“[Schema Evolution in Avro, Protocol Buffers and Thrift](http://martin.kleppmann.com/2012/12/05/schema-evolution-in-avro-protocol-buffers-thrift.html),” *martin.kleppmann.com*, December 5, 2012.
1. “[Apache Avro 1.7.7 Documentation](http://avro.apache.org/docs/1.7.7/),” *avro.apache.org*, July 2014.
1. Doug Cutting, Chad Walters, Jim Kellerman, et al.:
“[&#91;PROPOSAL&#93; New Subproject: Avro](http://mail-archives.apache.org/mod_mbox/hadoop-general/200904.mbox/%3C49D53694.1050906@apache.org%3E),” email thread on *hadoop-general* mailing list,
*mail-archives.apache.org*, April 2009.
1. Tony Hoare:
“[Null References: The Billion Dollar Mistake](http://www.infoq.com/presentations/Null-References-The-Billion-Dollar-Mistake-Tony-Hoare),” at *QCon London*,
March 2009.
1. Aditya Auradkar and Tom Quiggle:
“[Introducing Espresso—LinkedIn's Hot New Distributed Document Store](https://engineering.linkedin.com/espresso/introducing-espresso-linkedins-hot-new-distributed-document-store),” *engineering.linkedin.com*, January 21, 2015.
1. Jay Kreps:
“[Putting Apache Kafka to Use: A Practical Guide to Building a Stream Data Platform (Part 2)](http://blog.confluent.io/2015/02/25/stream-data-platform-2/),” *blog.confluent.io*,
February 25, 2015.
1. Gwen Shapira:
“[The Problem of Managing Schemas](http://radar.oreilly.com/2014/11/the-problem-of-managing-schemas.html),” *radar.oreilly.com*, November 4, 2014.
1. “[Apache Pig 0.14.0 Documentation](http://pig.apache.org/docs/r0.14.0/),” *pig.apache.org*, November 2014.
1. John Larmouth:
<a href="http://www.oss.com/asn1/resources/books-whitepapers-pubs/larmouth-asn1-book.pdf">*ASN.1
Complete*</a>. Morgan Kaufmann, 1999. ISBN: 978-0-122-33435-1
1. Russell Housley, Warwick Ford, Tim Polk, and David Solo:
“[RFC 2459: Internet X.509 Public Key Infrastructure: Certificate and CRL Profile](https://www.ietf.org/rfc/rfc2459.txt),” IETF Network Working Group, Standards Track,
January 1999.
1. Lev Walkin:
“[Question: Extensibility and Dropping Fields](http://lionet.info/asn1c/blog/2010/09/21/question-extensibility-removing-fields/),” *lionet.info*, September 21, 2010.
1. Jesse James Garrett:
“[Ajax: A New Approach to Web Applications](http://www.adaptivepath.com/ideas/ajax-new-approach-web-applications/),” *adaptivepath.com*, February 18, 2005.
1. Sam Newman: *Building Microservices*.
O'Reilly Media, 2015. ISBN: 978-1-491-95035-7
1. Chris Richardson:
“[Microservices: Decomposing Applications for Deployability and Scalability](http://www.infoq.com/articles/microservices-intro),” *infoq.com*, May 25, 2014.
1. Pat Helland:
“[Data on the Outside Versus Data on the Inside](http://cidrdb.org/cidr2005/papers/P12.pdf),” at *2nd Biennial Conference on Innovative Data Systems Research* (CIDR),
January 2005.
1. Roy Thomas Fielding:
“[Architectural Styles and the Design of Network-Based Software Architectures](https://www.ics.uci.edu/~fielding/pubs/dissertation/fielding_dissertation.pdf),” PhD Thesis, University of
California, Irvine, 2000.
1. Roy Thomas Fielding:
“[REST APIs Must Be Hypertext-Driven](http://roy.gbiv.com/untangled/2008/rest-apis-must-be-hypertext-driven),” *roy.gbiv.com*, October 20 2008.
1. “[REST in Peace, SOAP](http://royal.pingdom.com/2010/10/15/rest-in-peace-soap/),” *royal.pingdom.com*, October 15, 2010.
1. “[Web Services Standards as of Q1 2007](https://www.innoq.com/resources/ws-standards-poster/),” *innoq.com*, February 2007.
1. Pete Lacey:
“[The S Stands for Simple](http://harmful.cat-v.org/software/xml/soap/simple),” *harmful.cat-v.org*, November 15, 2006.
1. Stefan Tilkov:
“[Interview: Pete Lacey Criticizes Web Services](http://www.infoq.com/articles/pete-lacey-ws-criticism),” *infoq.com*, December 12, 2006.
1. “[OpenAPI Specification (fka Swagger RESTful API Documentation Specification) Version 2.0](http://swagger.io/specification/),”
*swagger.io*, September 8, 2014.
1. Michi Henning:
“[The Rise and Fall of CORBA](http://queue.acm.org/detail.cfm?id=1142044),”
*ACM Queue*, volume 4, number 5, pages 2834, June 2006.
[doi:10.1145/1142031.1142044](http://dx.doi.org/10.1145/1142031.1142044)
1. Andrew D. Birrell and Bruce Jay Nelson:
“[Implementing Remote Procedure Calls](http://www.cs.princeton.edu/courses/archive/fall03/cs518/papers/rpc.pdf),” *ACM Transactions on Computer Systems* (TOCS),
volume 2, number 1, pages 3959, February 1984.
[doi:10.1145/2080.357392](http://dx.doi.org/10.1145/2080.357392)
1. Jim Waldo, Geoff Wyant, Ann Wollrath, and Sam Kendall:
“[A Note on Distributed Computing](http://m.mirror.facebook.net/kde/devel/smli_tr-94-29.pdf),”
Sun Microsystems Laboratories, Inc., Technical Report TR-94-29, November 1994.
1. Steve Vinoski:
“[Convenience over Correctness](http://steve.vinoski.net/pdf/IEEE-Convenience_Over_Correctness.pdf),” *IEEE Internet Computing*, volume 12, number 4, pages 8992, July 2008.
[doi:10.1109/MIC.2008.75](http://dx.doi.org/10.1109/MIC.2008.75)
1. Marius Eriksen:
“[Your Server as a Function](http://monkey.org/~marius/funsrv.pdf),” at
*7th Workshop on Programming Languages and Operating Systems* (PLOS), November 2013.
[doi:10.1145/2525528.2525538](http://dx.doi.org/10.1145/2525528.2525538)
1. “[grpc-common Documentation](https://github.com/grpc/grpc-common),” Google, Inc., *github.com*, February 2015.
1. Aditya Narayan and Irina Singh:
“[Designing and Versioning Compatible Web Services](http://www.ibm.com/developerworks/websphere/library/techarticles/0705_narayan/0705_narayan.html),” *ibm.com*, March 28, 2007.
1. Troy Hunt:
“[Your API Versioning Is Wrong, Which Is Why I Decided to Do It 3 Different Wrong Ways](http://www.troyhunt.com/2014/02/your-api-versioning-is-wrong-which-is.html),” *troyhunt.com*,
February 10, 2014.
1. “[API Upgrades](https://stripe.com/docs/upgrades),” Stripe, Inc., April 2015.
1. Jonas Bonér:
“[Upgrade in an Akka Cluster](http://grokbase.com/t/gg/akka-user/138wd8j9e3/upgrade-in-an-akka-cluster),” email to *akka-user* mailing list, *grokbase.com*, August 28, 2013.
1. Philip A. Bernstein, Sergey Bykov, Alan Geller, et al.:
“[Orleans: Distributed Virtual Actors for Programmability and Scalability](http://research.microsoft.com/pubs/210931/Orleans-MSR-TR-2014-41.pdf),” Microsoft Research
Technical Report MSR-TR-2014-41, March 2014.
1. “[Microsoft Project Orleans Documentation](http://dotnet.github.io/orleans/),” Microsoft Research, *dotnet.github.io*, 2015.
1. David Mercer, Sean Hinde, Yinso Chen, and Richard A O'Keefe:
“[beginner: Updating Data Structures](http://erlang.org/pipermail/erlang-questions/2007-October/030318.html),” email thread on *erlang-questions* mailing list, *erlang.com*,
October 29, 2007.
1. Fred Hebert:
“[Postscript: Maps](http://learnyousomeerlang.com/maps),” *learnyousomeerlang.com*,
April 9, 2014.

979
ddia/ch5.md Normal file
View File

@ -0,0 +1,979 @@
# 5. 复制
![](img/ch5.png)
> 天作孽,尤可治,自作孽,不可活。
>
> ——道格拉斯·亚当斯1992
------
[TOC]
复制意味着在通过网络连接的多台机器上保留相同数据的副本。正如在第二部分的介绍中所讨论的那样,您可能想要复制数据的原因有几个:
* 为了保持数据在地理位置上接近用户(从而减少延迟)
* 即使部分零件出现故障,系统也能继续工作(从而提高可用性)
* 为了扩大可以为读取查询服务的机器数量(从而提高读取吞吐量)
在本章中我们将假设您的数据集非常小以至于每台机器都可以保存整个数据集的副本。在第6章中我们将放宽这个假设讨论对单个机器来说太大的数据集的分割分片。在后面的章节中我们将讨论复制数据系统中可能发生的各种故障以及如何处理这些故障。
如果您正在复制的数据不会随时间而改变,那么复制很容易:您只需将数据复制到每个节点一次,即可完成。复制中的所有困难都在于处理复制数据的变化,这就是本章的内容。我们将讨论三种流行的复制节点间变化的算法:单主,多主和无主。几乎所有分布式数据库都使用这三种方法之一。
他们都有各种各样的优点和缺点,我们将详细审查。在复制时需要考虑许多折衷:例如,是否使用同步或异步复制,以及如何处理失败的副本。这些通常是数据库中的配置选项,虽然细节因数据库而异,但一般原则在许多不同的实现中是相似的。我们将在本章讨论这种选择的后果。
数据库的复制是一个老话题 - 自1970年代研究以来这些原则并没有太大的改变[1]因为网络的基本约束保持不变。然而除了研究之外许多开发人员仍然假定一个数据库只有一个节点。主流使用分布式数据库是最近的事情。由于许多应用程序开发人员都是这方面的新手对最终一致性等问题存在诸多误解。在第161页的“复制滞后问题”中我们将更加精确地了解最终的一致性并讨论诸如读写和单调读取保证等内容。
## 主从
存储数据库副本的每个节点称为*副本(replica)*。有了多个副本,一个问题不可避免地会出现:我们如何确保所有数据在所有副本上都结束?
每次写入数据库都需要处理每个副本;否则,副本将不再包含相同的数据。最常见的解决方案称为基于领导者的复制(也称为主动/被动或主从复制如图5-1所示。它的工作原理如下
1. 副本之一被指定为领导者(也称为 **主master** 或**首要的primary**)。当客户想要写入数据库时,他们必须将他们的请求发送给领导,首先将新数据写入其本地存储。
2. 其他副本被称为追随者只读副本从属副本热备份副本不同的人对热hot温warn冷cold 备份服务器有不同的定义。 例如在PostgreSQL中热备用来引用从客户端接受读取的副本而温备紧跟领袖但不处理来自客户端的任何查询。 就本书而言,差异并不重要。)每当领导者将新数据写入本地存储时,它也会将数据更改发送给其所有追随者作为复制的一部分记录或更改流。每个跟随者从领导者处获取日志,并相应地更新其本地数据库副本,方法是按照领导者处理的相同顺序应用所有写入。
3. 当客户想要从数据库中读取数据时,它可以查询领导或任何追随者。 然而,只有领导才能接受写操作(从客户端的角度来看,从库都是只读的)。
![](img/fig5-1.png)
**图5-1 基于领袖(主从)的复制**
### 同步复制与异步复制
复制系统的一个重要细节是复制是同步发生还是异步发生。 (在关系型数据库中,这通常是一个可配置的选项;其他系统通常被硬编码为一个或另一个)。
想想图5-1中发生的情况网站的用户更新他们的个人资料图像。在某个时间点客户发送更新请求给领导;不久之后,领导就收到了。在某个时候,领导者将数据转换转发给追随者。最后,领导通知客户更新成功。
图5-2显示了系统各个组件之间的通信用户的客户端领导者和两个关注者。时间从左到右流动。请求或响应消息显示为粗箭头。
![](img/fig5-2.png)
**图5-2 基于领导者的复制有一个同步和一个异步的从库。**
在图5-2的示例中跟随者1的复制是同步的领导者等待直到跟随者1确认在向用户报告成功之前以及在使写入对其他客户端可见之前接收到写入。跟随者2的复制是异步的领导者发送消息但不等待跟随者的响应。
该图表明在跟随者2处理消息之前存在显着的延迟。通常情况下复制速度非常快大多数数据库系统在不到一秒的时间内对关注者进行更改。但是不能保证需要多长时间。有些情况下追随者可能落后于领导者几分钟或更长时间;例如,如果跟随者正在从故障中恢复,如果系统正在接近最大容量,或者如果节点之间存在网络问题。
同步复制的优点是,跟随者保证有与领导者一致的最新数据副本。如果领导者突然失败,我们可以肯定的是,这些数据仍然可以在追随者身上找到。缺点是如果同步跟随器没有响应(因为它已经崩溃,或者出现网络故障,或者出于任何其他原因),写入不能被处理。领导者必须阻止所有写入,并等待同步副本再次可用。
因此,所有追随者都是同步的是不切实际的:任何一个节点的中断都会导致整个系统停滞不前。实际上,如果在数据库上启用同步复制,通常意味着其中一个跟随者是同步的,而其他的则是异步的。如果同步跟随器变得不可用或缓慢,则使一个异步跟随器同步。这保证您至少在两个节点上拥有最新的数据副本:领导者和同步追随者。 这种配置有时也被称为半同步[7]。
通常,基于领导者的复制配置为完全异步。 在这种情况下,如果领导失败并且不可恢复,则任何尚未复制给追随者的写入都将丢失。 这意味着写入不能保证持久,即使已经被客户确认。 然而,一个完全异步的配置具有领导者可以继续处理写入的优点,即使其所有追随者都落后了。
弱化的耐久性可能听起来像是一个坏的折衷,但异步复制却被广泛使用,特别是如果有很多追随者或者是地理分布的话。 我们将在第161页的“复制滞后问题”中回到这个问题。
#### *关于复制的研究*
如果主库故障,那么异步复制系统会丢失数据可能是一个严重的问题,因此研究人员继续研究不丢失数据但仍能提供良好性能和可用性的复制方法。 例如,**链式复制**[8,9]是同步复制的一种变体已经在一些系统如Microsoft Azure存储[10,11])中成功实现。
复制的一致性与共识得到几个节点以达成一个价值之间有着密切的联系我们将在第9章更详细地探讨这一领域的理论。在本章中我们将集中讨论更简单的形式 在实践中最常用于数据库的复制。
### 设置新从
有时候,你需要建立新的追随者 - 也许增加副本的数量,或者替换失败的节点。你如何确保新的追随者有一个领导者的数据的准确副本?
简单地将数据文件从一个节点复制到另一个节点通常是不够的:客户端不断向数据库写入数据,数据总是处于不断变化的状态,因此标准文件副本会在不同的时间点看到数据库的不同部分。结果可能没有任何意义。
您可以通过锁定数据库(使其不可用于写入)来使磁盘上的文件保持一致,但是这会违反我们的高可用性目标。幸运的是,建立一个跟随者通常可以在没有停机的情况下完成。从概念上讲,过程如下所示:
1. 在某个时间点对领导者的数据库进行一致的快照如果可能的话而不必锁定整个数据库。大多数数据库都具有这种功能因为它也是备份所必需的。在某些情况下需要第三方工具如MySQL的innobackupex [12]。
2. 将快照复制到新的跟随者节点。
3. 跟随者连接到领导并请求拍摄快照后发生的所有数据更改。这要求快照与领导者的复制日志中的确切位置相关联。该位置有不同的名称例如PostgreSQL将其称为*日志序列号(log sequence number, lsn)*MySQL将其称为*二进制日志坐标(binlog coordinates)*。
4. 从追随者处理了自快照以来的数据变化积压,我们说它已经赶上了。现在,它可以继续处理领导者发生的数据变化。
建立跟随者的实际步骤因数据库而异。在某些系统中,这个过程是完全自动化的,而在另外一些系统中,它可能是一个有点神秘的多步骤工作流程,需要由管理员手动执行。
### 处理节点失控
系统中的任何节点都可能因故障而意外停机,但可能由于计划内的维护(例如,重新引导机器以安装内核安全修补程序)。能够在不停机的情况下重新启动单个节点是操作和维护的一大优势。因此,我们的目标是保持整个系统的运行,尽管个别节点失效,并尽可能保持节点外部的影响。
如何通过基于领导者的复制实现高可用性?
#### 从库故障:追赶恢复
在其本地磁盘上,每个追随者记录从领导者收到的数据变更。如果跟随者崩溃并重新启动,或者如果领导者和跟随者之间的网络暂时中断,则跟随者可以很容易地恢复:从日志中知道在发生故障之前处理的最后一个事务。因此,跟随者可以连接到领导者并请求在跟随者断开连接时发生的所有数据改变。当它应用了这些变化后,它已经赶上了领导者,并可以像以前一样继续接收数据流的变化。
#### 领导失败:故障转移
处理领导者的失败是棘手的:其中一个追随者需要被提升为新的领导者,客户端需要重新配置以将他们的写入发送给新的领导者,其他追随者需要开始消费来自新的领导。这个过程被称为故障转移。
故障转移可以手动进行(通知管理员领导已经失败,并采取必要的步骤来创建新的领导者)或自动进行。自动故障转移过程通常由以下步骤组成:
1. 确定领导失败。有很多事情可能会出错崩溃停电网络问题等等。没有万无一失的方法来检测出现了什么问题所以大多数系统只是使用一个超时节点频繁地在相互之间来回弹跳消息并且如果一个节点在一段时间内例如30秒没有响应它被认为是死的。 (如果领导被故意拆除进行计划维护,这不适用。)
2. 选择一个新的领导者。这可以通过选举过程其中领导者由大多数剩余复制品选择来完成或者可以由之前选定的控制器节点来指定新的领导者。领导者的最佳人选通常是来自旧领导者的最新数据变更的副本以最小化任何数据丢失。让所有的节点同意一个新的领导是一个共识问题在第9章详细讨论。
3. 重新配置系统以使用新的领导者。客户端现在需要将他们的写请求发送给新领导(我们将在“请求路由”在本页中讨论这个问题)。如果老领导人回来了,可能仍然认为这是领导者,没有意识到其他副本迫使他下台。系统需要确保老领导成为追随者,并认可新领导。
故障转移会出现很多大麻烦:
* 如果使用异步复制,则新主库可能没有收到老主库宕机前最后的写入操作。在选出新主库后,如果老主库重新加入集群,新主库在此期间可能会收到冲突的写入,那这些写入该如何处理?最常见的解决方案是简单丢弃老主库未复制的写入,这很可能打破客户对于数据持久性的期望。
* 如果数据库需要和其他外部存储相协调那么丢弃写入内容是极其危险的操作。例如在GitHub [13]的一场事故中一个过时的MySQL从库被提升为主库。数据库使用自增ID作为主键因为新主库的计数器落后于老主库的计数器所以新主库重新分配了一些已经被老主库分配掉的ID作为主键。这些主键也在Redis中使用主键重用使得MySQL和Redis中数据产生不一致最后导致一些私有数据泄漏到错误的用户手中。
* 发生某些故障时见第8章可能会出现两个节点都以为自己是领导者的情况。这种情况称为**脑裂(split brain)**非常危险如果两个领导者都可以接受写操作却没有冲突解决机制参见第168页的“多主复制”那么数据就可能丢失或损坏。一些系统采取了安全防范措施当检测到两个领导节点同时存在时会关闭其中一个节点。这种机制称为**击剑(fencing)**,更夸张的术语是:***爆其他节点的头Shoot The Other Node In The Head , STONITH***。但设计粗糙的机制可能最后会导致两个节点都被关闭[14]。
* 领导被宣布死亡之前的正确超时是什么?在领导失败的情况下,超时时间越长意味着恢复的时间越长。但是,如果超时太短,可能会出现不必要的故障转移。例如,临时负载峰值可能导致节点的响应时间超过超时,或者网络故障可能导致延迟的数据包。如果系统已经处于高负载或网络问题的困扰之中,那么不必要的故障切换可能会使情况变得更糟,而不是更好。
这些问题没有简单的解决方案。因此,有些操作团队更愿意手动执行故障切换,即使软件支持自动故障切换。
这些问题 - 节点故障;不可靠的网络;并且在副本一致性,耐用性,可用性和延迟方面进行权衡 - 实际上是分布式系统中的基本问题。在第8章和第9章中我们将更深入地讨论它们。
### 复制日志的实现
基于领导者的复制如何在底层工作?在实践中使用了几种不同的复制方法,所以让我们简单地看一下。
#### 基于语句的复制
在最简单的情况下领导者记录它执行的每个写入请求语句并将该语句日志发送给其追随者。对于关系数据库来说这意味着每个INSERTUPDATE或DELETE语句都被转发给关注者和每个关注者。跟随者解析并执行该SQL语句就像从客户端收到一样。
虽然这听起来很合理,但这种复制方式可能有多种方式可以打破:
* 任何调用非确定性函数的语句(如`NOW()`获取当前日期和时间或`RAND()`获取一个随机数)可能会在每个副本上生成不同的值。
* 如果语句使用自动增量列或者它们依赖于数据库中的现有数据例如UPDATE ... WHERE <某些条件>),则必须按照每个副本上的完全相同的顺序执行它们,否则它们可能会有不同的效果。当有多个同时执行的事务时,这可能是限制性的。
* 有副作用的语句(例如,触发器,存储过程,用户定义的函数)可能会在每个副本上产生不同的副作用,除非副作用是绝对确定的。
有可能解决这些问题 - 例如,当语句被记录时,领导者可以用固定的返回值替换任何不确定的函数调用,以便追随者获得相同的值。但是,由于存在如此多的边缘情况,所以现在通常优选其他复制方法。
基于语句的复制在5.1版本之前在MySQL中使用。今天仍然有一些使用因为它非常紧凑但是默认情况下如果在语句中有任何不确定性MySQL现在会切换到基于行的复制稍后讨论。 VoltDB使用基于语句的复制并通过要求事务是确定性来保证安全[15]。
#### 传输预写式日志WAL
在第3章中我们讨论了存储引擎如何在磁盘上表示数据并且我们发现通常每个写操作都附加到日志中
* 对于日志结构存储引擎请参阅第70页的“SSTables和LSM-tree”此日志是存储的主要位置。日志段在后台压缩并垃圾回收。
* 对于覆盖单个磁盘块的B树请参阅第79页的“B树”每次修改都会先写入预写日志以便索引可以恢复到一致状态一个崩溃。
在任何一种情况下,日志都是包含对数据库所有写入的字节序列。我们可以使用完全相同的日志在另一个节点上构建副本:除了将日志写入磁盘之外,领导者还可以通过网络将其发送给其追随者。
当追随者处理这个日志时,它会建立一个和领导者一模一样的数据结构的副本。
PostgreSQL和Oracle等使用这种复制方法[16]。主要缺点是日志描述的数据很低WAL包含哪些磁盘块中的哪些字节发生了更改。这使复制紧密地耦合到存储引擎。如果数据库将其存储格式从一个版本更改为另一个版本则通常不可能在领导者和追随者上运行不同版本的数据库软件。
这看起来可能只是一个小实施细节但可能会产生巨大的运营影响。如果复制协议允许跟随者使用比领导者更新的软件版本则可以先执行升级跟随者然后执行故障转移使升级后的节点之一成为新的领导者从而执行数据库软件的零停机升级。如果复制协议不允许此版本不匹配WAL运输经常出现这种情况则此类升级需要停机。
#### 逻辑(基于行)日志复制
另一种方法是对复制和存储引擎使用不同的日志格式,这样可以使复制日志从存储引擎内部分离出来。这种复制日志被称为逻辑日志,以将其与存储引擎(物理)数据表示区分开来。
关系数据库的逻辑日志通常是以行的粒度描述对数据库表的写入的记录序列:
* 对于插入的行,日志包含所有列的新值。
* 对于已删除的行,日志包含足够的信息来唯一标识已删除的行。通常这将是主键,但是如果表上没有主键,则需要记录所有列的旧值。
* 对于更新的行,日志包含足够的信息来唯一标识更新的行,以及所有列的新值(或至少所有已更改的列的新值)。
修改多行的事务会生成多个这样的日志记录,后面跟着一条记录,指出事务已经提交。 MySQL的二进制日志当配置为使用基于行的复制时使用这种方法[17]。
由于逻辑日志与存储引擎内部分离,因此可以更容易地保持向后兼容,从而使领导者和跟随者能够运行不同版本的数据库软件甚至不同的存储引擎。
对于外部应用程序来说,逻辑日志格式也更容易解析。如果要将数据库的内容发送到外部系统(如数据),这一点很有用,例如复制到数据仓库进行离线分析,或建立自定义索引和缓存[18]。 这种技术被称为更改数据捕获我们将在第11章中回到它。
#### 基于触发器的复制
到目前为止描述的复制方法是由数据库系统实现的,不涉及任何应用程序代码。在很多情况下,这就是你想要的 - 但是在某些情况下需要更多的灵活性。例如如果您只想复制数据的一个子集或者想从一种数据库复制到另一种数据库或者如果您需要冲突解决逻辑请参阅第171页的“处理写入冲突”则可能需要将复制移动到应用程序层。
一些工具如Oracle GoldenGate [19],可以通过读取数据库日志来使应用程序可用数据。另一种方法是使用许多关系数据库中可用的功能:触发器和存储过程。
触发器允许您注册在数据库系统中发生数据更改写入事务时自动执行的自定义应用程序代码。触发器有机会将此更改记录到一个单独的表中通过这个表可以通过外部过程读取它。然后外部进程可以应用任何必要的应用程序逻辑并将数据更改复制到另一个系统。例如Databus for Oracle [20]和Bucardo for Postgres [21]就是这样工作的。
基于触发器的复制通常比其他复制方法具有更高的开销,并且比数据库的内置复制更容易出现错误和限制。然而,由于其灵活性,它仍然是有用的。
## 复制延迟问题
能够容忍节点故障只是需要复制的一个原因。正如在第二部分的介绍中提到的,其他原因是可扩展性(处理比单个机器可处理更多的请求)和延迟(将副本地理位置更靠近用户)。
基于领导者的复制需要所有写入都通过单个节点但只读查询可以转到任何副本。对于由大部分读取组成的工作负载以及只有很小比例的写入Web上的常见模式有一个有吸引力的选择创建许多追随者并将读取请求分布到以下各个位置。这将从领导者中移除负载并允许读取请求由附近的副本服务。
在这种扩展体系结构中,只需添加更多的追随者,就可以提高只读请求的服务容量。但是,这种方法实际上只适用于异步复制 - 如果您尝试同步复制到所有追随者,则单个节点故障或网络中断将使整个系统无法写入。而且越多的节点越有可能会被关闭,所以完全同步的配置将是非常不可靠的。
不幸的是,如果应用程序从异步跟随者读取,如果跟随者落后,它可能会看到过时的信息。这会导致数据库中出现明显的不一致:如果同时对领导者和跟随者执行相同的查询,则可能得到不同的结果,因为并非所有的写入都反映在跟随者中。这种不一致只是一个暂时的状态 - 如果你不再写数据库并等待一段时间,追随者最终会赶上并与领导者保持一致。出于这个原因,这种效应被称为最终一致性[22,23] 道格拉斯·特里Douglas Terry等人创造了最终的一致性。 [24]由Werner Vogels [22]推广成为许多NoSQL项目的战斗口号。 但是不仅NoSQL数据库最终是一致的异步复制关系数据库中的追随者具有相同的特征。
“最终”一词故意含糊不清:总的来说,复制品落后的程度是没有限制的。在正常的操作中,在领导者身上发生的写作和在追随者身上反映的延迟 - 复制滞后 - 可能仅仅是一秒的一部分,在实践中并不明显。但是,如果系统在接近容量的情况下运行,或者如果网络中存在问题,则滞后可以容易地增加到几秒甚至几分钟。
当滞后时间太长时,引入的不一致性不仅仅是一个理论问题,而且是一个真正的应用问题。在本节中,我们将重点介绍三个复制滞后时可能出现的问题,并概述解决这些问题的一些方法。
### 读已之写
许多应用程序让用户提交一些数据,然后查看他们提交的内容。这可能是客户数据库中的记录,也可能是对讨论主题的评论,或其他类似的内容。提交新数据时,必须将其发送给领导者,但是当用户查看数据时,可以从追随者读取数据。如果数据经常被查看,但只是偶尔写入,这是特别适合的。
对于异步复制存在一个问题如图5-3所示如果用户在写入后不久查看数据则新数据可能尚未到达副本。对用户来说他们看起来好像是提交的数据丢失了所以他们可以理解的不高兴
![](img/fig5-3.png)
**图5-3 用户进行写入,然后从旧副本中读取数据。 为了防止这种异常,我们需要写后读的一致性**
在这种情况下,我们需要读后写一致性,也称为读己之写一致性[24]。这是一个保证,如果用户重新加载页面,他们总是会看到他们自己提交的任何更新。它不会对其他用户做出承诺:其他用户的更新可能会在稍后才能看到。但是,它保证用户自己的输入已被正确保存。
我们如何在基于领导者的复制的系统中实现读后一致性?有各种可能的技术。提一些:
* 阅读用户可能已经修改过的内容时,请阅读领导者;否则,从追随者读取它。这就要求你有一些方法可以知道是否修改了某些东西,而不需要实际查询它。例如,社交网络上的用户个人资料信息通常只能由个人资料的所有者编辑,而不能由其他人编辑。因此,一个简单的规则是:总是从领导读取用户自己的个人资料,从跟随者读取其他用户的个人资料。
* 如果应用程序中的大部分内容都可能被用户编辑,那么这种方法将不会有效,因为大部分内容都必须从领导读取(否定读取缩放的好处)。在这种情况下,可以使用其他标准来决定是否从领导读取。例如,您可以跟踪上次更新的时间,并且在上次更新后的一分钟内,从领导者进行所有读取。您还可以监控追随者的复制滞后,并防止任何超过领导者一分多钟的追随者查询。
* 客户端可以记住最近一次写入的时间戳,然后系统可以确保为该用户提供任何读取的副本反映更新,至少在该时间戳之前。如果复制副本不够充足,则可以由另一副本处理读取,或者查询可以等到复制副本赶上。时间戳可以是逻辑时间戳(指示写入顺序的东西,例如日志序列号)或实际系统时钟(在这种情况下,时钟同步变得至关重要;请参阅“不可靠的时钟”第269页
* 如果您的副本分布在多个数据中心(与用户的地理接近度或可用性),则会增加复杂性。任何需要由领导者提供服务的请求都必须路由到包含领导者的数据中心。
如果同一用户从多个设备访问您的服务例如桌面Web浏览器和移动应用程序则会出现另一个复杂情况。在这种情况下您可能希望提供跨设备读写后一致性如果用户在某个设备上输入了一些信息然后在另一个设备上查看则应该看到他们刚输入的信息。
在这种情况下,还有一些需要考虑的问题:
* 需要记住用户上次更新时间戳的方法变得更加困难,因为在一台设备上运行的代码不知道在另一台设备上发生了什么更新。这个元数据将需要集中。
* 如果副本分布在不同的数据中心,则不能保证来自不同设备的连接将路由到同一数据中心。 (例如,如果用户的台式计算机使用家庭宽带连接,并且他们的移动设备使用蜂窝数据网络,则设备的网络路线可能完全不同)。如果您的方法需要领导者阅读,您可能首先需要将来自所有用户设备的请求路由到同一个数据中心。
### 单调读
我们从异步从库读取异常的第二个例子是,用户可能会感受到时光倒流。
如果用户从不同副本进行多次读取则可能发生这种情况。例如图5-4显示了用户2345两次进行相同的查询首先是一个滞后很少的追随者然后是一个滞后较大的追随者。 如果用户刷新一个网页并且每个请求被路由到一个随机的服务器这种情况是相当可能的。第一个查询返回最近由用户1234添加的评论但是第二个查询不返回任何东西因为滞后的追随者还没有拿起写。实际上第二个查询是在比第一个查询更早的时间点观察系统。如果第一个查询没有返回任何内容这将不会那么糟糕因为用户2345可能不知道用户1234最近添加了评论。然而如果用户2345第一次看见用户1234的评论然后看到它再次消失那么对于用户2345来说这是非常混乱的。
![](img/fig5-4.png)
**图5-4 用户首先从新副本读取,然后从旧副本读取。时光倒流。为了防止这种异常,我们需要单调的读取。**
单调读取[23]是这种异常不会发生的保证。这是一个比强有力的一致性更小的保证,但比最终的一致性更强有力的保证。当您读取数据时,您可能会看到一个旧值;单调读取仅意味着如果一个用户顺序地进行多次读取,则他们不会看到时间后退,即,在先前读取较新的数据之后,他们将不读取较旧的数据。
实现单调读取的一种方式是确保每个用户总是从同一个副本进行读取不同的用户可以从不同的副本读取。例如可以基于用户ID的散列来选择副本而不是随机选择副本。但是如果该副本失败用户的查询将需要重新路由到另一个副本。
### 一致前缀读
我们的第三个复制例子滞后于反常因果关系。 想象一下Poons先生和Cake夫人之间的以下简短对话
*Poons先生*
蛋糕夫人,你能看到未来有多远?
*蛋糕夫人*
通常约十秒钟,庞斯先生。
这两句话之间有因果关系:蛋糕夫人听到了庞斯先生的问题并回答了这个问题。
现在,想象第三个人正在通过追随者来听这个对话。 Cake夫人所说的事情经历了一个很少滞后的追随者但Poons先生所说的事情有更长的复制滞后时间见图5-5。 这个观察者会听到以下内容:
蛋糕夫人
通常约十秒钟,庞斯先生。
Poons先生
蛋糕夫人,你能看到未来有多远?
对于观察者来说,看起来好像克莱尔太太正在回答这个问题。
Poons甚至问过它。 这种精神力量是令人印象深刻的,但非常混乱[25]。
![](img/fig5-5.png)
**图5-5 如果某些分区的复制速度慢于其他分区,那么观察者在看到问题之前可能会看到答案。**
防止这种异常需要另一种类型的保证:一致的前缀读取[23]。 这个保证说,如果一系列的写入按照某个顺序发生,那么读取这些写入的任何人都会看到它们以相同的顺序出现。
这是分区分片数据库中的一个特殊问题我们将在第6章中讨论。如果数据库总是以相同的顺序应用写入则读取总是会看到一致的前缀所以这种异常不会发生。但是在许多分布式数据库中不同的分区独立运行因此不存在全局写入顺序当用户从数据库中读取数据时可能会看到数据库的某些部分处于较旧的状态而某些处于较新的状态。
一种解决方案是确保任何因果关系的写入都写入相同的分区但在某些无法高效完成的应用程序中。还有一些算法明确地跟踪因果依赖关系我们将在“关系和并发”一节第186页中的“发生”中返回一个主题。
### 复制延迟的解决方案
在使用最终一致的系统时,如果复制延迟增加到几分钟甚至几小时,则应该考虑应用程序的行为。如果答案是“没问题”,那很好。但是,如果结果对于用户来说是一个不好的经验,那么设计系统来提供更强的保证是很重要的,例如写后读。假设事实上它是异步的复制是同步的,这是一个问题。
如前所述,应用程序可以提供比底层数据库更强有力的保证,例如通过对领导者进行某种读取。但是,在应用程序代码中处理这些问题是复杂的,容易出错。
如果应用程序开发人员不必担心细微的复制问题,并且可以相信他们的数据库“做正确的事情”,那将会更好。这就是事务存在的原因:它们是数据库提供更强保障的一种方式这样应用程序可以更简单。
单节点事务已经存在很长时间了。然而,在向分布式(复制和分区)数据库转移时,许多系统放弃了这些数据库,声称交易在性能和可用性方面过于昂贵,并断言在可扩展系统中最终的一致性是不可避免的。这个陈述中有一些事实,但它过于简单,我们将在本书其余部分的过程中形成一个更细致的观点。我们将回到第七章和第九章的交易话题,我们将在第三部分讨论一些替代机制。
## 多主复制
本章到目前为止,我们只考虑使用单个领导的复制架构。 虽然这是一种常见的方法,但也有一些有趣的选择。
基于领导者的复制有一个主要的缺点:只有一个领导者,所有的写作都必须通过它.如果数据库被分区见第6章每个分区都有一个领导。 不同的分区可能在不同的节点上有其领导者,但是每个分区必须有一个领导者节点。)如果由于任何原因(例如由于你和领导之间的网络中断)而无法连接到领导者, 你不能写入数据库。
基于领导者的复制模型的自然延伸是允许多个节点接受写入。 复制仍然以同样的方式发生:处理写入的每个节点都必须将该数据更改转发给所有其他节点。 我们称之为多领导配置(也称为主 - 主或主动/主动复制)。 在这种情况下,每个领导者同时扮演其他领导者的追随者。
### 多主复制的应用场景
在单个数据中心内部使用多领导者设置很少有意义,因为这些好处很少超过复杂性。 但是,在某些情况下,这种配置是合理的。
#### 运维多数据中心
想象一下,你有一个数据库在几个不同的数据中心(也许这样你可以容忍整个数据中心的故障,或者为了更接近你的用户)复制品。 使用常规的基于领导者的复制设置,领导者必须位于其中一个数据中心,并且所有写入都必须经过该数据中心。
在多领导配置中,您可以在每个数据中心都有领导。 图5-6显示了这个架构的外观。 在每个数据中心内,使用常规的领导者跟随者复制; 在数据中心之间,每个数据中心的负责人都会将其更改复制到其他数据中心的领导。
#####
![](img/fig5-6.png)
**图5-6 跨多个数据中心的多领导复制**
我们来比较一下多数据中心部署中的单引擎和多引导器配置:
* *性能*
在单领导配置中,每个写作都必须通过互联网与领导者一起进入数据中心。这可能会增加写入时间,并可能违反了首先有多个数据中心的目的。在多领导配置中,每个写操作都可以在本地数据中心进行处理,并与其他数据中心异步复制。因此,数据中心之间的网络延迟对用户来说是隐藏的,这意味着感知的性能可能会更好。
* *数据中心的中断容忍*
在单引导者配置中,如果引导者的数据中心发生故障,故障转移可以促使另一个数据中心的追随者成为领导者。在多领导者配置中,每个数据中心可以独立于其他数据中心继续运行,并且当发生故障的数据中心恢复联机时,复制将迎头赶上。
* *容忍网络问题*
数据中心之间的通信通常通过公共互联网,这可能不如数据中心内的本地网络可靠。单引号配置对这个数据中心链接中的问题非常敏感,因为通过这个链接进行写操作是同步的。具有异步复制功能的多领导者配置通常可以更好地承受网络问题:暂时的网络中断不会妨碍正在处理的写入。
有些数据库默认情况下支持多领导配置但通常也使用外部工具实现例如用于MySQL的Tungsten Replicator [26]用于PostgreSQL的BDR [27]以及用于Oracle的GoldenGate [19]。
尽管多领导者复制具有优势但也有一个很大的缺点在两个不同的数据中心可能会同时修改相同的数据并且必须解决这些写冲突如图5-6中的“冲突解决”所示。我们将在第171页的“处理写入冲突”中讨论这个问题。
由于多引导程序复制在许多数据库中都有所改进,所以常常存在微妙的配置缺陷,并且与其他数据库功能之间出现意外的交互。例如,自动增量键,触发器和完整性约束可能是有问题的。出于这个原因,多领导者复制往往被认为是危险的领域,应尽可能避免[28]。
#### 需要离线操作的客户端
多领导者复制的另一种情况是如果您的应用程序在与Internet断开连接时需要继续工作
例如,考虑手机,笔记本电脑和其他设备上的日历应用程序。无论您的设备目前是否具有互联网连接,您都需要能够随时查看您的会议(发出读取请求)并输入新的会议(发出写入请求)。如果您在离线状态下进行任何更改,则当设备下次上线时,需要与服务器和其他设备同步。
在这种情况下,每个设备都有一个充当领导者的本地数据库(它接受写请求),并且在您所有设备上的日历副本之间存在异步多领导者复制过程(同步)。复制延迟可能是几小时甚至几天,具体取决于您何时可以访问互联网。
从架构的角度来看,这种设置基本上与数据中心之间的多领导者复制相同,极端:每个设备都是一个“数据中心”,它们之间的网络连接是非常不可靠的。正如破碎的日历同步实现的丰富历史所表明的,多领导者复制是一件棘手的事情。
有一些工具旨在使这种多领导者配置更容易。例如CouchDB就是为这种操作模式而设计的[29]。
#### 协同编辑
实时协作编辑应用程序允许多个人同时编辑文档。例如Etherpad [30]和Google Docs [31]允许多人同时编辑文本文档或电子表格该算法在第174页的“自动冲突解决”中简要讨论。我们通常不会将协作式编辑视为数据库复制问题但与前面提到的离线编辑用例有许多相似之处。当一个用户编辑文档时所做的更改将立即应用到其本地副本Web浏览器或客户端应用程序中的文档状态并异步复制到服务器和编辑同一文档的任何其他用户。
如果要保证不会发生编辑冲突,则应用程序必须先取得文档的锁定,然后用户才能对其进行编辑。如果另一个用户想要编辑同一个文档,他们首先必须等到第一个用户提交修改并释放锁定。这种协作模式相当于在领导者上进行交易的单领导者复制。
但是,为了加速协作,您可能希望将更改的单位设置得非常小(例如,一个按键),并避免锁定。这种方法允许多个用户同时进行编辑,但同时也带来了多领导者复制的所有挑战,包括需要解决冲突[32]。
### 处理写冲突
多领导者复制的最大问题是可能发生写冲突,这意味着需要解决冲突。
例如考虑一个由两个用户同时编辑的维基页面如图5-7所示。用户1将页面的标题从A更改为B并且用户2同时将标题从A更改为C.每个用户的更改已成功应用到其本地领导。但是,当异步复制时,会发现冲突[33]。单引导数据库中不会出现此问题。
![](img/fig5-7.png)
**图5-7 由两位领导同时更新同一记录引起的写入冲突**
#### 同步与异步冲突检测
在单主数据库中,第二个写入器将阻塞并等待第一个写入完成,或中止第二个写入事务,强制用户重试写入。另一方面,在多领导者设置中,两个写入都是成功的,并且在稍后的时间点仅仅异步地检测到冲突。那时要求用户解决冲突可能为时已晚。
原则上,可以使冲突检测同步 - 即等待写入被复制到所有副本,然后再告诉用户写入成功。但是,通过这样做,您将失去多领导者复制的主要优点:允许每个副本独立接受写入。如果您想要同步冲突检测,那么您可以使用单引导程序复制。
#### 避免冲突
处理冲突的最简单的策略就是避免它们:如果应用程序可以确保特定记录的所有写入都通过同一个领导者,那么冲突就不会发生。由于多领导者复制处理的许多实现冲突相当不好,避免冲突是一个经常推荐的方法[34]。
例如,在用户可以编辑自己的数据的应用程序中,可以确保来自特定用户的请求始终路由到同一数据中心,并使用该数据中心的领导者进行读写。不同的用户可能有不同的“家庭”数据中心(可能根据用户的地理位置选择),但从任何用户的角度来看,配置基本上都是单一的领导者。
但是,有时您可能需要更改指定的记录的领导 - 可能是因为一个数据中心出现故障,您需要将流量重新路由到另一个数据中心,或者可能是因为用户已经迁移到另一个位置,现在更接近不同的数据中心。在这种情况下,冲突避免会中断,你必须处理不同领导人同时写入的可能性。
#### 趋于一致的状态
单主程序数据库按顺序应用写操作:如果同一个字段有多个更新,则最后一个写操作将确定该字段的最终值。
在多领导者配置中没有定义的写入顺序所以不清楚最终值应该是什么。在图5-7中标题1首先更新为B然后更新为C;在领导者2中首先更新为C然后更新为B.两个订单都不是“更正确”的。
如果每个副本只是按照它看到写入的顺序写入那么数据库最终将处于不一致的状态最终值将是在领导者1处的C和在领导者2处的B.这是不可接受的 - 每个复制方案都必须确保数据在所有副本中最终都是相同的。因此,数据库必须以一种趋同的方式解决冲突,这意味着所有副本必须在所有更改都被复制时达到相同的最终值。
实现融合冲突解决有多种途径:
* 给每个写入一个唯一的ID例如一个时间戳一个长的随机数一个UUID或者一个键和值的哈希挑选最高ID的写入作为胜利者并丢弃其他写入。如果使用时间戳这种技术被称为最后一次写入胜利LWW。虽然这种方法很流行但是很容易造成数据丢失[35]。我们将在本章末尾更详细地讨论LWW第184页的“检测并发写入”
* 为每个副本分配一个唯一的ID并让始发于较高编号副本的写入始终优先于源自较低编号副本的写入。这种方法也意味着数据丢失。
* 以某种方式将这些值合并在一起 - 例如按字母顺序排序然后连接它们在图5-7中合并的标题可能类似于“B / C”
* 在保留所有信息的显式数据结构中记录冲突,并编写解决冲突的应用程序代码(可能通过提示用户)。
#### 自定义冲突解决逻辑
作为解决冲突最合适的方法可能取决于应用程序,大多数领导者复制工具允许您使用应用程序代码编写冲突解决逻辑。该代码可以在写入或读取时执行:
* *写时执行*
只要数据库系统检测到复制更改日志中存在冲突就会调用冲突处理程序。例如Bucardo允许您为此编写一段Perl代码。这个处理程序通常不能提示用户 - 它在后台进程中运行,并且必须快速执行。
* *读时执行*
当检测到冲突时所有冲突写入被存储。下一次读取数据时会将这些多个版本的数据返回给应用程序。应用程序可能会提示用户或自动解决冲突并将结果写回数据库。例如CouchDB以这种方式工作。
请注意,冲突解决通常适用于单个行或文档层面,而不是整个事务[36]。因此如果您有一笔交易原本会进行几次不同的写入请参阅第7章则为了冲突解决的目的每个写入仍被分开考虑。
#### *题外话:自动冲突解决*
冲突解决规则可能很快变得复杂,并且自定义代码可能容易出错。亚马逊是一个经常被引用的例子,由于冲突解决处理程序令人惊讶的效果:一段时间以来,购物车上的冲突解决逻辑将保留添加到购物车的物品,但不包括从购物车中移除的物品。因此,顾客有时会看到物品重新出现在他们的购物车中,即使他们之前已经被移走[37]。
已经有一些有趣的研究来自动解决由于数据修改引起的冲突。有几行研究值得一提:
* 无冲突的复制数据类型CRDT[32,38]是可以由多个用户同时编辑的集合映射有序列表计数器等的一系列数据结构它们以合理的方式自动解决冲突。一些CRDT已经在Riak 2.0中实现[39,40]。
* 可合并的持久数据结构[41]显式跟踪历史记录类似于Git版本控制系统并使用三向合并功能而CRDT使用双向合并
* 可进行的转换[42]是Etherpad [30]和Google Docs [31]等合作编辑应用背后的冲突解决算法。它是专为同时编辑项目的有序列表而设计的,例如构成文本文档的字符列表。
这些算法在数据库中的实现还很年轻,但很可能将来它们将被集成到更多的复制数据系统中。自动冲突解决方案可以使应用程序处理多领导者数据同步更为简单。
#### 什么是冲突?
有些冲突是显而易见的。在图5-7的例子中两个写操作并发地修改了同一个记录中的同一个字段并将其设置为两个不同的值。毫无疑问这是一个冲突。
其他类型的冲突可能更加微妙地被发现。例如,考虑一个会议室预订系统:它跟踪哪个房间是哪个人在哪个时间预订的。这个应用程序需要确保每个房间只有一组人同时预定(即不得有相同房间的重叠预订)。在这种情况下,如果同时为同一个房间创建两个不同的预订,则可能会发生冲突。即使应用程序在允许用户进行预订之前检查可用性,如果两次预订是由两个不同的领导者进行的,则可能会有冲突。
现在还没有一个现成的答案但在接下来的章节中我们将追溯到对这个问题有很好的理解。我们将在第7章中看到更多的冲突示例在第12章中我们将讨论用于检测和解决复制系统中冲突的可扩展方法。
### 多主复制拓扑
复制拓扑描述写入从一个节点传播到另一个节点的通信路径。如果你有两个领导者如图5-7所示只有一个合理的拓扑结构领导者1必须把他所有的写到领导者2反之亦然。有两个以上的领导各种不同的拓扑是可能的。图5-8举例说明了一些例子。
![](img/fig5-8.png)
**图5-8 三个可以设置多领导者复制的示例拓扑。**
最普遍的拓扑是全部到全部图5-8 [c]其中每个领导者将其写入每个其他领导。但是也会使用更多受限制的拓扑例如默认情况下MySQL仅支持圆形拓扑[34]其中每个节点接收来自一个节点的写入并将这些写入加上自己的任何写入转发给另一个节点。另一种流行的拓扑结构具有星形的形状v一个指定的根节点将写入转发给所有其他节点。星型拓扑可以推广到树。
在圆形和星形拓扑中,写入可能需要在到达所有副本之前通过多个节点。因此,节点需要转发从其他节点收到的数据更改。为了防止无限复制循环,每个节点被赋予一个唯一的标识符,并且在复制日志中,每个写入都被标记了所有已经通过的节点的标识符[43]。当一个节点收到用自己的标识符标记的数据更改时,该数据更改将被忽略,因为节点知道它已经被处理。
循环和星型拓扑的问题是,如果只有一个节点发生故障,则可能会中断其他节点之间的复制消息流,导致它们无法通信,直到节点修复。拓扑结构可以重新配置为在发生故障的节点上工作,但在大多数部署中,这种重新配置必须手动完成。更密集连接的拓扑结构(例如全部到全部)的容错性更好,因为它允许消息沿着不同的路径传播,避免单点故障。
另一方面全能拓扑也可能有问题。特别是一些网络链接可能比其他网络链接更快例如由于网络拥塞结果是一些复制消息可能“超过”其他复制消息如图5-9所示。
#####
![](img/fig5-9.png)
**图5-9 使用多主程序复制时,可能会在某些副本中写入错误的顺序。**
在图5-9中客户端A向领导者1的表中插入一行客户端B在领导者3上更新该行。然而领导者2可以以不同的顺序接收写入它可以首先接收更新其中从它的角度来看是对数据库中不存在的行的更新并且仅在稍后接收到相应的插入其应该在更新之前
这是一个因果关系的问题类似于我们在第165页上的“一致前缀读取”中看到的更新取决于先前的插入所以我们需要确保所有节点先处理插入然后再处理更新。仅仅在每一次写入时添加一个时间戳是不够的因为时钟不可能被充分地同步以便在引导2处正确地排序这些事件见第8章
要正确命令这些事件,可以使用一种称为**版本向量version vectors**的技术本章稍后将讨论这种技术请参阅第174页的“检测并发写入”。然而冲突检测技术在许多多领导者复制系统中执行得不好。例如在撰写本文时PostgreSQL BDR不提供写操作的因果排序[27]而Tungsten Replicator for MySQL甚至不尝试检测冲突[34]。
如果您正在使用具有多领导者复制功能的系统,那么应该了解这些问题,仔细阅读文档,并彻底测试您的数据库,以确保它确实提供了您认为具有的保证。
#####
## 无主复制
我们在本章到目前为止所讨论的复制方法 - 单引导者和多引导者复制 - 是基于客户端向一个节点(领导者)发送写请求的想法,数据库系统负责复制写入其他副本。领导决定了写入的顺序,而跟随者按相同的顺序应用领导的写入。
一些数据存储系统采用不同的方法,放弃领导者的概念,并允许任何副本直接接受来自客户端的写入。一些最早的复制数据系统是无领导的[1,44]但是在关系数据库主导时代这个想法大多被遗忘。在亚马逊将其用于其内部的Dynamo系统之后它再一次成为数据库的一种时尚架构[37] .Dynamo不适用于Amazon以外的用户。 令人困惑的是AWS提供了一个名为DynamoDB的托管数据库产品它使用了完全不同的体系结构它基于单引导程序复制。 RiakCassandra和Voldemort是由Dynamo启发的无领导复制模型的开源数据存储所以这类数据库也被称为*Dynamo风格*。
在一些无领导者的实现中,客户端直接将其写入到几个副本中,而在另一些情况下,协调器节点代表客户端进行写入。但是,与领导者数据库不同,协调员不执行特定的写入顺序。我们将会看到,这种设计上的差异对数据库的使用方式有着深远的影响。
### 当节点故障时写入数据库
假设你有一个带有三个副本的数据库而其中一个副本目前不可用或许正在重新启动以安装系统更新。在基于主机的配置中如果要继续处理写入则可能需要执行故障切换请参阅第133页的「处理节点中断」
另一方面在无领导配置中故障切换不存在。图5-10显示了发生了什么事情客户端用户1234并行发送写入到所有三个副本并且两个可用副本接受写入但是不可用副本错过了它。假设三个副本中的两个承认写入是足够的在用户1234已经收到两个确定的响应之后我们认为写入成功。客户简单地忽略了其中一个副本错过了写入的事实。
![](img/fig5-10.png)
**图5-10 仲裁写入,法定读取,并在节点中断后读取修复。**
现在想象一下,不可用的节点重新联机,客户端开始读取它。节点关闭时发生的任何写入都从该节点丢失。因此,如果您从该节点读取数据,则可能会将陈旧(过时)值视为响应。
为了解决这个问题当一个客户端从数据库中读取数据时它不仅仅发送它的请求到一个副本读请求也被并行地发送到多个节点。客户可能会从不同的节点获得不同的响应。即来自一个节点的最新值和来自另一个节点的陈旧值。版本号用于确定哪个值更新请参阅第174页的“检测并发写入”
#### 阅读修复和反熵
复制方案应确保最终将所有数据复制到每个副本。在一个不可用的节点重新联机之后,它如何赶上它错过的写入?
在Dynamo风格的数据存储中经常使用两种机制
* *修复读*
当客户端并行读取多个节点时它可以检测到任何陈旧的响应。例如在图5-10中用户2345获得了来自Replica 3的版本6值和来自副本1和2的版本7值。客户端发现副本3具有陈旧值并将新值写回复制品。这种方法适用于频繁阅读的值。
* *反熵过程*
此外,一些数据存储具有后台进程,该进程不断查找副本之间的数据差异,并将任何缺少的数据从一个副本复制到另一个副本。与基于领导者的复制中的复制日志不同,此反熵过程不会以任何特定的顺序复制写入,并且在复制数据之前可能会有显着的延迟。
并不是所有的系统都实现了这两个;例如Voldemort目前没有反熵过程。请注意如果没有反熵过程某些副本中很少读取的值可能会丢失从而降低了持久性因为只有在应用程序读取值时才执行读取修复。
#### 法定人数的读写
在图5-10的示例中我们认为即使仅在三个副本中的两个上进行处理写入仍然是成功的。如果三个副本中只有一个接受了写入会怎样我们能推多远呢
如果我们知道,每个成功的写操作意味着在三个副本中至少有两个出现,这意味着至多有一个副本可能是陈旧的。因此,如果我们从至少两个副本读取,我们可以确定至少有一个是最新的。如果第三个副本停机或响应速度缓慢,则读取仍可以继续返回最新值。
更一般地说如果有n个副本每个写入必须由w节点确认才能被认为是成功的并且我们必须至少为每个读取查询r个节点。 (在我们的例子中,$n = 3w = 2r = 2$)。只要$w + r> n$我们期望在读取时获得最新的值因为至少有一个r节点从阅读必须是最新的。读取和写入服从这些r和w值被称为法定读取和写入。[44] 有时候这种法定人数被称为严格的法定人数与马虎法定人数形成对比见第183页“马虎法定人数和暗示交接法”你可以认为r和w作为读或写所需的最低票数是有效的。
在Dynamo风格的数据库中参数nw和r通常是可配置的。一个常见的选择是使n为奇数通常为3或5并设置 $w = r =n + 1/ 2$(向上舍入)。但是,您可以根据需要更改数字。例如,设置$w = n$和$r = 1$的写入很少且读取次数较多的工作负载可能会受益。这使得读取速度更快,但具有只有一个失败节点导致所有数据库写入失败的缺点。
*可能有多于n个节点的集群但是任何给定的值只能存储在n个节点上。 这允许对数据集进行分区,从而支持比您可以放在一个节点上的数据集更大的数据集。 我们将在第6章回到分区。*
仲裁条件$w + r> n$允许系统容忍不可用的节点,如下所示:
* 如果$w <n$如果节点不可用我们仍然可以处理写入
* 如果$r <n$如果节点不可用我们仍然可以处理读取
* 对于$n = 3w = 2r = 2$,我们可以容忍一个不可用的节点。
* 对于$n = 5w = 3r = 3$,我们可以容忍两个不可用的节点。 这个案例如图5-11所示。
* 通常读取和写入操作始终并行发送到所有n个副本。 参数w和r决定我们等待多少个节点即在我们认为读或写成功之前有多少个节点需要报告成功。
![](img/fig5-11.png)
**图5-11 如果w + r > n读取r个副本至少有一个r副本必然包含了最近的成功写入**
如果少于所需的w或r节点可用则写入或读取将返回错误。 由于许多原因,节点可能不可用:因为由于执行操作的错误(由于磁盘已满而无法写入)导致节点关闭(崩溃,关闭电源),由于客户端和服务器之间的网络中断 节点,或任何其他原因。 我们只关心节点是否返回了成功的响应,而不需要区分不同类型的错误。
### 仲裁一致性的局限性
如果你有n个副本并且你选择w和r使得$w + r> n$你通常可以期望每个读取返回为一个键写的最近的值。情况就是这样因为你写的节点集合和你读过的节点集合必须重叠。也就是说您读取的节点中必须至少有一个具有最新值的节点如图5-11所示
通常r和w被选为多数超过 n/2 )节点,因为这确保了$w + r> n$同时仍然容忍多达n / 2个节点故障。但是法定人数不一定必须是大多数只是读和写操作使用的节点集合至少需要在一个节点上重叠。其他法定人数的分配是可能的这在分布式算法的设计中有一定的灵活性[45]。
您也可以将w和r设置为较小的数字以使$w + r≤n$即法定条件不满足。在这种情况下读取和写入操作仍将被发送到n个节点但操作成功需要少量的成功响应。
对于较小的w和r您更可能读取陈旧的值因为您的读取更有可能不包含具有最新值的节点。另一方面这种配置允许更低的延迟和更高的可用性如果存在网络中断并且许多副本变得无法访问则可以继续处理读取和写入的机会更大。只有当可达副本的数量低于w或r时数据库才分别变得不可用于写入或读取。
但是,即使在$w + r> n$的情况下,也可能存在返回陈旧值的边缘情况。这取决于实施,但可能的情况包括:
* 如果使用松散的法定人数请参阅第181页上的“马虎的仲裁与暗示交接”写入可能会以不同于r读取的节点结束因此r节点和w之间不再有保证重叠节点[46]。
* 如果两个写入同时发生不清楚哪一个先发生。在这种情况下唯一安全的解决方案是合并并发写入请参阅第171页的“处理写入冲突”。如果根据时间戳最后写入成功挑选出胜者则由于时钟偏差[35]写入可能会丢失。我们将返回第184页上的“检测并发写入”中的此主题。
* 如果写操作与读操作同时发生,写操作可能仅反映在某些副本上。在这种情况下,不确定读取是返回旧值还是新值。
* 如果在某些副本上写入成功而在其他节点上写入失败例如因为某些节点上的磁盘已满并且总体z上成功的次数少于w个副本不会在成功的副本上回滚。这意味着如果一个写入报告失败了后续的读取可能会或可能不会返回写入的值[47]。
* 如果携带新值的节点失败并且其数据从带有旧值的副本中恢复则存储新值的副本数可能会低于w从而打破法定条件。
* 即使一切工作正常也会出现边缘情况在这种情况下您可能会感到不安因为我们将在第334页上的“线性化和法定人数”中看到。
因此,尽管法定人数似乎保证读取返回最新的写入值,但在实践中并不那么简单。 Dynamo风格的数据库通常针对可以容忍最终一致性的用例进行优化。参数w和r允许您调整陈旧值读取的概率但不要把它们作为绝对保证。
尤其是您通常没有得到第161页上的“与延迟有关的问题”读取您的写入单调读取或一致的前缀读取中讨论的保证因此前面提到的异常可能会发生在应用程序中。更强有力的担保通常需要交易或共识。我们将在第七章和第九章回到这些话题。
#### 监控陈旧度
从操作的角度来看,监视你的数据库是否返回最新的结果是很重要的。即使您的应用程序可以容忍陈旧的读取,您也需要了解复制的健康状况。如果显着落后,应该提醒您,以便您可以调查原因(例如,网络中的问题或超载节点)。
对于基于领导者的复制,数据库通常会公开复制滞后的度量标准,您可以将其提供给监视系统。这是可能的,因为写入按照相同的顺序应用于领导者和追随者,并且每个节点在复制日志中具有一个位置(在本地应用的写入次数)。通过从领导者的当前位置中减去随从者的当前位置,您可以测量复制滞后量。
然而,在无领导者复制的系统中,没有固定的写入顺序,这使得监控变得更加困难。而且,如果数据库只使用读取修复(没有反熵),那么对于一个值可能会有多大的限制是没有限制的 - 如果一个值很少被读取,那么由一个陈旧副本返回的值可能是古老的。
已经有一些关于衡量无主复制数据库中的复制陈旧度的研究并根据参数nw和r来预测陈旧读取的预期百分比[48]。不幸的是,这还不是很常见的做法,但是将过时测量值包含在数据库的标准度量标准中是一件好事。最终的一致性是故意模糊的保证,但是对于可操作性来说,能够量化“最终”是很重要的。
### 松散仲裁与意见交换
具有适当配置的仲裁的数据库可以容忍个别节点的故障而不需要故障切换。他们也可以容忍个别节点变慢因为请求不必等待所有n个节点响应 - 当w或r节点响应时它们可以返回。这些特性使得数据库具有无需复制的吸引力适用于需要高可用性和低延迟的用例并且可以容忍偶尔的陈旧读取。
然而,法定人数(如迄今为止所描述的)并不像它们可能的那样具有容错性。网络中断可以很容易地将客户端从大量的数据库节点上切断。虽然这些节点是活着的,而其他客户端可能能够连接到它们,但是从数据库节点切断的客户端,它们也可能已经死亡。在这种情况下,剩余的可用节点可能会少于可用节点,因此客户端可能无法达到法定人数。
在一个大型的群集中节点数量明显多于n个在网络中断期间客户端可能连接到某些数据库节点而不是为了为特定值组装法定数量的节点。在这种情况下数据库设计人员需要权衡一下
* 将错误返回给我们无法达到w或r节点的法定数量的所有请求是否更好
* 或者我们是否应该接受写入然后将它们写入一些可达的节点但不在n值通常存在的n个节点之间
后者被认为是一个马虎的法定人数[37]写和读仍然需要w和r成功的响应但是那些可能包括不在指定的n个“主”节点中的值。比方说如果你把自己锁在房子外面你可能会敲开邻居的门问你是否可以暂时停留在沙发上。
一旦网络中断得到解决,代表另一个节点临时接受的一个节点的任何写入都被发送到适当的“本地”节点。这就是所谓的提示。 (一旦你再次找到你的房子的钥匙,你的邻居礼貌地要求你离开沙发回家。)
松散仲裁提高写入可用性特别有用只要有任何w节点可用数据库就可以接受写入。然而这意味着即使当$w + r> n$时也不能确定读取某个键的最新值因为最新的值可能已经临时写入了n之外的某些节点[47]。
因此在传统意义上一个马虎的法定人数实际上不是一个法定人数。这只是一个保证即数据存储在w节点的地方。不能保证r节点的读取直到提示已经完成。
在所有常见的Dynamo实现中松散的仲裁是可选的。在Riak中它们默认是启用的而在Cassandra和Voldemort中它们默认是禁用的[46,49,50]。
#### 多数据中心操作
我们先前讨论了跨数据中心复制作为多主复制的用例请参阅第162页的“多重复制复制”。无主复制还适用于多数据中心操作因为它旨在容忍冲突的并发写入网络中断和延迟尖峰。
Cassandra和Voldemort在正常的无主模型中实现了他们的多数据中心支持副本的数量n包括所有数据中心的节点在配置中您可以指定每个数据中心中您想拥有的副本的数量。无论数据中心如何每个来自客户端的写入都会发送到所有副本但客户端通常只等待来自其本地数据中心内的法定节点的确认从而不会受到跨数据中心链路延迟和中断的影响。对其他数据中心的高延迟写入通常被配置为异步发生尽管配置有一定的灵活性[50,51]。
Riak将客户端和数据库节点之间的所有通信保持在一个数据中心本地因此n描述了一个数据中心内的副本数量。数据库集群之间的跨数据中心复制在后台异步发生其风格类似于多领导者复制[52]。
### 侦测并发写入
Dynamo风格的数据库允许多个客户端同时写入相同的Key这意味着即使使用严格的法定人数也会发生冲突。这种情况与多领导者复制相似请参阅第171页的“处理写冲突”但在Dynamo样式的数据库中在读取修复或提示性切换期间也可能会产生冲突。
问题在于由于可变的网络延迟和部分故障事件可能在不同的节点以不同的顺序到达。例如图5-12显示了两个客户机A和B同时写入三节点数据存储区中的键X
* 节点1接收来自A的写入但由于暂时中断从不接收来自B的写入。
* 节点2首先接收来自A的写入然后接收来自B的写入。
* 节点3首先接收来自B的写入然后从A写入。
![](img/fig5-12.png)
**图5-12 并发写入Dynamo风格的数据存储没有明确定义的顺序。**
如果每个节点只要接收到来自客户端的写入请求就简单地覆盖了某个键的值那么节点就会永久地不一致如图5-12中的最终获取请求所示节点2认为X的最终值是B而其他节点认为值是A.
为了最终达成一致,副本应该趋于相同的价值。他们如何做到这一点?有人可能希望复制的数据库能够自动处理,但不幸的是,大多数的实现都很糟糕:如果你想避免丢失数据,你(应用程序开发人员)需要知道很多有关数据库冲突处理的内部信息。
我们在第171页的“处理写冲突”中简要介绍了一些解决冲突的技术。在总结本章之前让我们来更详细地探讨这个问题。
#### 最后写入胜(丢弃并发写入)
实现最终融合的一种方法是声明每个副本只需要存储最“最近”的值,并允许“更旧”的值被覆盖和抛弃。然后,只要我们有一种明确的方式来确定哪个写是“最近的”,并且每个写入最终都被复制到每个副本,那么复制最终会收敛到相同的值。
正如“最近”的引用所表明的这个想法其实颇具误导性。在图5-12的例子中当客户端向数据库节点发送写入请求时客户端都不知道另一个客户端因此不清楚哪一个先发生了。事实上说“发生”是没有意义的我们说写入是并发的所以它们的顺序是不确定的。
即使写入没有自然排序我们也可以强制任意排序。例如我们可以为每个写入附加一个时间戳挑选最“最近”的最大时间戳并丢弃具有较早时间戳的任何写入。这种冲突解决算法被称为最后写入胜利LWW是Cassandra [53]唯一支持的冲突解决方法也是Riak [35]中的一个可选特征。
LWW实现了最终收敛的目标但是以持久性为代价如果同一个Key有多个并发写入即使它们都被报告为客户端成功因为它们被写入w个副本其中一个写道会生存下来其他的将被无声丢弃。此外LWW甚至可能会删除不是并发的写入我们将在第291页的“有序事件的时间戳”中讨论。
有一些情况如缓存其中丢失的写入可能是可以接受的。如果丢失数据是不可接受的LWW是解决冲突的一个很烂的选择。
与LWW一起使用数据库的唯一安全方法是确保一个Key只写入一次然后视为不可变从而避免对同一个密钥进行并发更新。例如推荐使用Cassandra的方法是使用UUID作为键从而为每个写操作提供一个唯一的键[53]。
#### “此前发生”的关系和并发
我们如何判断两个操作是否是并发的?发展一个直觉,让我们看看一些例子:
* 在图5-9中两个写入不是并发的A的插入发生在B的增量之前因为B递增的值是A插入的值。换句话说B的操作建立在A的操作上所以B的操作必须有后来发生。我们也可以说B是因果依赖于A
* 另一方面图5-12中的两个写入是并发的当每个客户端启动操作时它不知道另一个客户端也正在执行操作同样的Key。因此操作之间不存在因果关系。
如果操作B了解操作A或者依赖于A或者以某种方式构建于操作A之上则操作A在另一个操作B之前发生。在另一个操作之前是否发生一个操作是定义什么并发的关键。事实上我们可以简单地说如果两个操作都不在另一个之前发生那么两个操作是并发的两个操作都不知道另一个[54]。
因此只要有两个操作A和B就有三种可能性A在B之前发生或者B在A之前发生或者A和B并发。我们需要的是一个算法来告诉我们两个操作是否是并发的。如果一个操作发生在另一个操作之前则后面的操作应该覆盖较早的操作但是如果这些操作是并发的则存在需要解决的冲突。
#### *并发性,时间和相对性*
如果两个操作“同时”发生,似乎应该称为并发 - 但事实上它们是否在时间上重叠并不重要。由于分布式系统中的时钟问题实际上很难判断两个事件是否同时发生这个问题我们将在第8章中详细讨论。
为了定义并发性,确切的时间并不重要:如果两个操作都不知道对方,我们只需调用两个并发操作,而不管它们发生的物理时间。人们有时把这个原理和狭义相对论的物理学联系起来[54],它引入了信息不能比光速更快的思想。因此,如果事件之间的时间短于光通过它们之间的距离,那么发生一定距离的两个事件不可能相互影响。
在计算机系统中,即使光速原则上允许一个操作影响另一个操作,但两个操作可能是并行的。例如,如果网络缓慢或中断,两个操作可能会发生一段时间,并且仍然是并发的,因为网络问题阻止一个操作能够知道另一个操作。
#### 捕捉此前发生关系
让我们来看一个算法,它确定两个操作是并发的,还是一个在另一个之前。为了简单起见,我们从一个只有一个副本的数据库开始。一旦我们已经制定了如何在单个副本上完成这项工作,我们可以将该方法概括为具有多个副本的无领导者数据库。
图5-13显示了两个客户端同时向同一购物车添加项目。 (如果这样的例子让你觉得太麻烦了,那么可以想象,两个空中交通管制员同时把飞机添加到他们正在跟踪的部门。)最初,购物车是空的。在它们之间,客户端向数据库发出五次写入:
1. 客户1将牛奶加入购物车。这是第一次写入该Key所以服务器成功存储并为其分配版本1.服务器还将值与版本号一起回送给客户端。
2. 客户2将鸡蛋加入购物车不知道客户1同时添加了牛奶客户2认为其蛋是购物车中的唯一物品。服务器为此写入分配版本2并将蛋和牛奶存储为两个单独的值。然后它将这两个值和版本号2一起返回给客户端。
3. 客户1不知道客户2的写入想要将面粉加入购物车因此认为当前的购物车内容应该是[牛奶,面粉]。它将此值与服务器先前向客户端1提供的版本号1一起发送到服务器。服务器可以从版本号中知道[牛奶,面粉]的写入取代了[牛奶]的先前值,但与[鸡蛋]同时出现。因此服务器将版本3分配给[牛奶,面粉]覆盖版本1值[牛奶]但保留版本2值[蛋]并将剩余的值返回给客户端。
4. 同时客户2想要加入火腿不知道客户1刚刚加了面粉。客户端2在最后一个响应中从服务器收到了两个值[牛奶]和[蛋],所以客户现在合并这些值,并添加火腿形成一个新的值,[鸡蛋,牛奶,火腿]。它将这个值发送到服务器以及以前的版本2.服务器检测到版本2会覆盖[eggs],但与[milkflour]同时发生,所以剩下的两个值是[milkflour]版本3和[鸡蛋,牛奶,火腿]与版本4。
5. 最后客户1想要加培根。它以前在版本3中从服务器接收[牛奶,面粉]和[鸡蛋],所以它合并这些,添加培根,并将最终值[牛奶,面粉,鸡蛋,培根]连同版本号3.这会覆盖[牛奶,面粉](请注意[鸡蛋]已经在最后一步被覆盖),但与[鸡蛋,牛奶,火腿]并发,所以服务器保留这两个并发值。
![](img/fig5-13.png)
**图5-13 捕获两个客户端之间的因果关系,同时编辑购物车。**
图5-13中的操作之间的数据流如图5-14所示。 箭头表示哪个操作发生在其他操作之前,意味着后面的操作知道或依赖于较早的操作。 在这个例子中,客户端永远不会完全掌握服务器上的数据,因为总是有另一个操作同时进行。 但是,旧版本的值最终会被覆盖,并且不会丢失任何写入。
![](img/fig5-14.png)
**图5-14 图5-13中的因果依赖关系图。**
请注意,服务器可以通过查看版本号来确定两个操作是否是并发的 - 它不需要解释该值本身(因此该值可以是任何数据结构)。该算法的工作原理如下:
* 服务器为每个密钥保留一个版本号,每次写入密钥时都增加版本号,并将新版本号与写入的值一起存储。
* 当客户端读取密钥时,服务器将返回所有未覆盖的值以及最新的版本号。在写之前,客户必须先读钥匙。
* 客户端写入密钥时,必须包含之前读取的版本号,并且必须将之前读取的所有值合并在一起。 (来自写入请求的响应可以像读取一样,返回所有当前值,这使得我们可以像购物车示例那样链接多个写入。)
* 当服务器接收到具有特定版本号的写入时,它可以覆盖该版本号或更低版本的所有值(因为它知道它们已经被合并到新的值中),但是它必须保持所有值更高版本号(因为这些值与传入的写入同时发生)。
当一个写入包含前一次读取的版本号时,它会告诉我们写入的是哪一种状态。如果在不包含版本号的情况下进行写操作,则与所有其他写操作并发,因此它不会覆盖任何内容 - 只会在随后的读取中作为其中一个值返回。
#### 合并同时写入的值
这种算法可以确保没有数据被无声地丢弃,但不幸的是,客户端需要做一些额外的工作:如果多个操作并发发生,则客户端必须通过合并并行写入的值来进行清理。 Riak称这些并发值兄弟姐妹。
合并兄弟值本质上是与多领导者复制中的冲突解决相同的问题我们先前讨论过请参阅第171页的“处理写冲突”。一个简单的方法是根据版本号或时间戳最后写入胜利选择一个值但这意味着丢失数据。所以你可能需要在应用程序代码中做更聪明的事情。
以购物车为例合并兄弟姐妹的一种合理方法就是参加工会。在图5-14中最后的两个兄弟姐妹是[牛奶,面粉,鸡蛋,熏肉]和[鸡蛋,牛奶,火腿]。注意牛奶和鸡蛋出现在两个,即使他们每个只写一次。合并的价值可能是像[牛奶,面粉,鸡蛋,培根,火腿],没有重复。
然而,如果你想让人们也可以从他们的手推车中删除东西,而不是仅仅添加东西,那么把兄弟姐妹联合起来可能不会产生正确的结果:如果你合并了两个兄弟手推车,并且只有一个那么被删除的项目会重新出现在兄弟姐妹的联合中[37]。为了防止这个问题,一个项目在删除时不能简单地从数据库中删除;相反,系统必须留下一个具有合适版本号的标记,以指示合并兄弟时该项目已被删除。这种删除标记被称为墓碑。 我们之前在第72页的“哈希索引”中的日志压缩环境中看到了墓碑。
因为在应用程序代码中合并兄弟是复杂且容易出错的所以设计数据结构可以自动执行这种合并如“自动冲突解决”第174页中讨论的。例如Riak的数据类型支持使用称为CRDT的数据结构家族[38,39,55]可以以合理的方式自动合并兄弟,包括保留删除。
#### 版本向量
图5-13中的示例只使用一个副本。如果有多个副本但没有领导者算法如何改变
图5-13使用单个版本号来捕获操作之间的依赖关系但是当多个副本接受写入连接时这是不够的。相反我们需要使用每个副本的版本号以及每个密钥。每个副本在处理写入时增加自己的版本号并且跟踪从其他副本中看到的版本号。这个信息指出了要覆盖哪些值以及保留哪些值作为兄弟。
所有副本的版本号集合称为版本向量[56]。这个想法的一些变体正在使用但最有趣的可能是在Riak 2.0 [58,59]中使用的虚线版本矢量[57]。我们不会深入细节,但是它的工作方式与我们在购物车示例中看到的非常相似。
与图5-13中的版本号一样当读取值时版本向量会从数据库副本发送到客户端并且随后写入值时需要将其发送回数据库。 Riak将版本向量编码为一个字符串它称为因果上下文。版本向量允许数据库区分重写和并发写入。
另外,就像在单个副本的例子中,应用程序可能需要合并兄弟。版本向量结构确保从一个副本读取并随后写回到另一个副本是安全的。这样做可能会导致兄弟姐妹被创建,但只要兄弟姐妹合并正确,就不会丢失数据。
> #### 版本矢量和矢量时钟
>
> 版本矢量有时也被称为矢量时钟,即使它们不完全相同。 细微差别 - 请参阅参考资料的细节[576061]。 简而言之,在比较副本的状态时,版本向量是正确的数据结构。
>
## 本章小结
在本章中,我们考察了复制的问题。复制可以用于几个目的:
***高可用性***
即使在一台机器(或多台机器,或整个数据中心)停机的情况下也能保持系统正常运行
***断开连接的操作***
允许应用程序在网络中断时继续工作
***延迟***
将数据放置在距离用户较近的地方,以便用户能够更快地与其交互
***可扩展性***
能够处理比单个机器更高的读取量可以通过对副本进行读取来处理
尽管是一个简单的目标 - 在几台机器上保留相同数据的副本,但复制却是一个非常棘手的问题。它需要仔细考虑并发和所有可能出错的事情,并处理这些故障的后果。至少,我们需要处理不可用的节点和网络中断(甚至不考虑更隐蔽的故障,例如由于软件错误导致的无提示数据损坏)。
我们讨论了复制的三种主要方法:
***单主复制***
客户端将所有写入操作发送到单个节点(领导者),该节点将数据更改事件流发送到其他副本(追随者)。读取可以在任何副本上执行,但从追随者读取可能是陈旧的。
***多主复制***
客户端发送每个写入到几个领导节点之一,其中任何一个都可以接受写入。领导者将数据更改事件流发送给彼此以及任何跟随者节点。
***无主复制***
客户端发送每个写入到几个节点,并从多个节点并行读取,以检测和纠正具有陈旧数据的节点。
每种方法都有优点和缺点。单引导复制是非常流行的,因为它很容易理解,不需要担心冲突解决。在出现故障节点,网络中断和延迟峰值的情况下,多领导者和无领导者复制可以更加稳健,但代价很难推理,只能提供非常弱的一致性保证。
复制可以是同步的,也可以是异步的,在发生故障时对系统行为有深远的影响。尽管在系统运行平稳时异步复制速度很快,但是在复制滞后增加和服务器故障时要弄清楚会发生什么,这一点很重要。如果一个领导者失败了,并且你推动一个异步更新的追随者成为新的领导者,那么最近承诺的数据可能会丢失。
我们研究了一些可能由复制滞后引起的奇怪效应,我们讨论了一些有助于决定应用程序在复制滞后时的行为的一致性模型:
***读写后一致性***
用户应该总是看到自己提交的数据。
***单调读取***
当用户在某个时间点看到数据后,他们不应该在较早的时间点看到数据。
***一致的前缀读取***
用户应该将数据视为具有因果意义的状态:例如,按照正确的顺序查看问题及其答复。
最后,我们讨论了多领导者和无领导者复制方法所固有的并发问题:因为他们允许多个写入并发发生冲突。我们研究了一个数据库可能使用的算法来确定一个操作是否发生在另一个操作之前,或者它们是否同时发生。我们还谈到了通过合并并发更新来解决冲突的方法。
在下一章中,我们将继续研究分布在多个机器上的数据,通过复制的对应方式:将大数据集分割成分区。
## 参考文献
1. Bruce G. Lindsay, Patricia Griffiths Selinger, C. Galtieri, et al.:
“[Notes on Distributed Databases](http://domino.research.ibm.com/library/cyberdig.nsf/papers/A776EC17FC2FCE73852579F100578964/$File/RJ2571.pdf),” IBM Research, Research Report RJ2571(33471), July 1979.
1. “[Oracle Active Data Guard Real-Time Data Protection and Availability](http://www.oracle.com/technetwork/database/availability/active-data-guard-wp-12c-1896127.pdf),” Oracle White Paper, June 2013.
1. “[AlwaysOn Availability Groups](http://msdn.microsoft.com/en-us/library/hh510230.aspx),” in *SQL Server Books Online*, Microsoft, 2012.
1. Lin Qiao, Kapil Surlaker, Shirshanka Das, et al.:
“[On Brewing Fresh Espresso: LinkedIns Distributed Data Serving Platform](http://www.slideshare.net/amywtang/espresso-20952131),” at *ACM International Conference on
Management of Data* (SIGMOD), June 2013.
1. Jun Rao:
“[Intra-Cluster Replication for Apache Kafka](http://www.slideshare.net/junrao/kafka-replication-apachecon2013),” at *ApacheCon North America*, February 2013.
1. “[Highly Available Queues](https://www.rabbitmq.com/ha.html),” in *RabbitMQ Server Documentation*, Pivotal Software, Inc., 2014.
1. Yoshinori Matsunobu:
“[Semi-Synchronous Replication at Facebook](http://yoshinorimatsunobu.blogspot.co.uk/2014/04/semi-synchronous-replication-at-facebook.html),” *yoshinorimatsunobu.blogspot.co.uk*, April 1, 2014.
1. Robbert van Renesse and Fred B. Schneider:
“[Chain Replication for Supporting High Throughput and Availability](http://static.usenix.org/legacy/events/osdi04/tech/full_papers/renesse/renesse.pdf),” at *6th USENIX Symposium on
Operating System Design and Implementation* (OSDI), December 2004.
1. Jeff Terrace and Michael J. Freedman:
“[Object Storage on CRAQ: High-Throughput Chain Replication for Read-Mostly Workloads](https://www.usenix.org/legacy/event/usenix09/tech/full_papers/terrace/terrace.pdf),” at *USENIX
Annual Technical Conference* (ATC), June 2009.
1. Brad Calder, Ju Wang, Aaron Ogus, et al.:
“[Windows Azure Storage: A Highly Available Cloud Storage Service with Strong Consistency](http://sigops.org/sosp/sosp11/current/2011-Cascais/printable/11-calder.pdf),” at *23rd ACM
Symposium on Operating Systems Principles* (SOSP), October 2011.
1. Andrew Wang:
“[Windows Azure Storage](http://umbrant.com/blog/2016/windows_azure_storage.html),”
*umbrant.com*, February 4, 2016.
1. “[Percona Xtrabackup - Documentation](https://www.percona.com/doc/percona-xtrabackup/2.1/index.html),” Percona LLC, 2014.
1. Jesse Newland:
“[GitHub Availability This Week](https://github.com/blog/1261-github-availability-this-week),” *github.com*, September 14, 2012.
1. Mark Imbriaco:
“[Downtime Last Saturday](https://github.com/blog/1364-downtime-last-saturday),”
*github.com*, December 26, 2012.
1. John Hugg:
“[All in with Determinism for Performance and Testing in Distributed Systems](https://www.youtube.com/watch?v=gJRj3vJL4wE),” at *Strange Loop*, September 2015.
1. Amit Kapila:
“[WAL Internals of PostgreSQL](http://www.pgcon.org/2012/schedule/attachments/258_212_Internals%20Of%20PostgreSQL%20Wal.pdf),” at *PostgreSQL Conference* (PGCon), May 2012.
1. <a href="http://dev.mysql.com/doc/internals/en/index.html">*MySQL
Internals Manual*</a>. Oracle, 2014.
1. Yogeshwer Sharma, Philippe Ajoux, Petchean Ang, et al.:
“[Wormhole: Reliable Pub-Sub to Support Geo-Replicated Internet Services](https://www.usenix.org/system/files/conference/nsdi15/nsdi15-paper-sharma.pdf),” at *12th USENIX
Symposium on Networked Systems Design and Implementation* (NSDI), May 2015.
1. “[Oracle GoldenGate 12c: Real-Time Access to Real-Time Information](http://www.oracle.com/us/products/middleware/data-integration/oracle-goldengate-realtime-access-2031152.pdf),” Oracle White Paper, October 2013.
1. Shirshanka Das, Chavdar Botev, Kapil Surlaker, et al.:
“[All Aboard the Databus!](http://www.socc2012.org/s18-das.pdf),” at
*ACM Symposium on Cloud Computing* (SoCC), October 2012.
1. Greg Sabino Mullane:
“[Version 5 of Bucardo Database Replication System](http://blog.endpoint.com/2014/06/bucardo-5-multimaster-postgres-released.html),” *blog.endpoint.com*, June 23, 2014.
1. Werner Vogels:
“[Eventually Consistent](http://queue.acm.org/detail.cfm?id=1466448),”
*ACM Queue*, volume 6, number 6, pages 1419, October 2008.
[doi:10.1145/1466443.1466448](http://dx.doi.org/10.1145/1466443.1466448)
1. Douglas B. Terry:
“[Replicated Data Consistency Explained Through Baseball](http://research.microsoft.com/pubs/157411/ConsistencyAndBaseballReport.pdf),” Microsoft Research, Technical Report
MSR-TR-2011-137, October 2011.
1. Douglas B. Terry, Alan J. Demers, Karin Petersen, et al.:
“[Session Guarantees for Weakly Consistent Replicated Data](http://citeseerx.ist.psu.edu/viewdoc/download?doi=10.1.1.71.2269&rep=rep1&type=pdf),” at *3rd International Conference
on Parallel and Distributed Information Systems* (PDIS), September 1994.
[doi:10.1109/PDIS.1994.331722](http://dx.doi.org/10.1109/PDIS.1994.331722)
1. Terry Pratchett: *Reaper Man: A Discworld
Novel*. Victor Gollancz, 1991. ISBN: 978-0-575-04979-6
1. “[Tungsten Replicator](http://tungsten-replicator.org/),” Continuent, Inc., 2014.
1. “[BDR 0.10.0 Documentation](http://bdr-project.org/docs/next/index.html),” The PostgreSQL Global Development Group, *bdr-project.org*, 2015.
1. Robert Hodges:
“[If You *Must* Deploy Multi-Master Replication, Read This First](http://scale-out-blog.blogspot.co.uk/2012/04/if-you-must-deploy-multi-master.html),” *scale-out-blog.blogspot.co.uk*,
March 30, 2012.
1. J. Chris Anderson, Jan Lehnardt, and Noah
Slater: *CouchDB: The Definitive Guide*. O'Reilly Media, 2010.
ISBN: 978-0-596-15589-6
1. AppJet, Inc.:
“[Etherpad and EasySync Technical Manual](https://github.com/ether/etherpad-lite/blob/e2ce9dc/doc/easysync/easysync-full-description.pdf),” *github.com*, March 26, 2011.
1. John Day-Richter:
“[Whats Different About the New Google Docs: Making Collaboration Fast](http://googledrive.blogspot.com/2010/09/whats-different-about-new-google-docs.html),” *googledrive.blogspot.com*,
23 September 2010.
1. Martin Kleppmann and Alastair R. Beresford:
“[A Conflict-Free Replicated JSON Datatype](http://arxiv.org/abs/1608.03960),”
arXiv:1608.03960, August 13, 2016.
1. Frazer Clement:
“[Eventual Consistency Detecting Conflicts](http://messagepassing.blogspot.co.uk/2011/10/eventual-consistency-detecting.html),” *messagepassing.blogspot.co.uk*, October 20, 2011.
1. Robert Hodges:
“[State of the Art for MySQL Multi-Master Replication](https://www.percona.com/live/mysql-conference-2013/sessions/state-art-mysql-multi-master-replication),” at *Percona Live: MySQL Conference &
Expo*, April 2013.
1. John Daily:
“[Clocks Are Bad, or, Welcome to the Wonderful World of Distributed Systems](http://basho.com/clocks-are-bad-or-welcome-to-distributed-systems/),” *basho.com*, November 12, 2013.
1. Riley Berton:
“[Is Bi-Directional Replication (BDR) in Postgres Transactional?](http://sdf.org/~riley/blog/2016/01/04/is-bi-directional-replication-bdr-in-postgres-transactional/),” *sdf.org*, January 4, 2016.
1. Giuseppe DeCandia, Deniz Hastorun, Madan Jampani, et al.:
“[Dynamo: Amazon's Highly Available Key-Value Store](http://www.allthingsdistributed.com/files/amazon-dynamo-sosp2007.pdf),” at *21st ACM Symposium on Operating
Systems Principles* (SOSP), October 2007.
1. Marc Shapiro, Nuno Preguiça, Carlos Baquero,
and Marek Zawirski: “[A Comprehensive Study of Convergent and Commutative Replicated Data Types](http://hal.inria.fr/inria-00555588/),” INRIA Research Report no. 7506,
January 2011.
1. Sam Elliott:
“[CRDTs: An UPDATE (or Maybe Just a PUT)](https://speakerdeck.com/lenary/crdts-an-update-or-just-a-put),” at *RICON West*, October 2013.
1. Russell Brown:
“[A Bluffers Guide to CRDTs in Riak](https://gist.github.com/russelldb/f92f44bdfb619e089a4d),” *gist.github.com*, October 28, 2013.
1. Benjamin Farinier, Thomas Gazagnaire, and
Anil Madhavapeddy: “[Mergeable Persistent Data Structures](http://gazagnaire.org/pub/FGM15.pdf),” at *26es Journées Francophones des Langages Applicatifs* (JFLA),
January 2015.
1. Chengzheng Sun and Clarence Ellis:
“[Operational Transformation in Real-Time Group Editors: Issues, Algorithms, and Achievements](http://citeseerx.ist.psu.edu/viewdoc/download?doi=10.1.1.53.933&rep=rep1&type=pdf),” at
*ACM Conference on Computer Supported Cooperative Work* (CSCW), November 1998.
1. Lars Hofhansl:
“[HBASE-7709: Infinite Loop Possible in Master/Master Replication](https://issues.apache.org/jira/browse/HBASE-7709),” *issues.apache.org*, January 29, 2013.
1. David K. Gifford:
“[Weighted Voting for Replicated Data](http://citeseerx.ist.psu.edu/viewdoc/summary?doi=10.1.1.84.7698),”
at *7th ACM Symposium on Operating Systems Principles* (SOSP), December 1979.
[doi:10.1145/800215.806583](http://dx.doi.org/10.1145/800215.806583)
1. Heidi Howard, Dahlia Malkhi, and Alexander Spiegelman:
“[Flexible Paxos: Quorum Intersection Revisited](https://arxiv.org/abs/1608.06696),”
*arXiv:1608.06696*, August 24, 2016.
1. Joseph Blomstedt:
“[Re: Absolute Consistency](http://lists.basho.com/pipermail/riak-users_lists.basho.com/2012-January/007157.html),” email to *riak-users* mailing list, *lists.basho.com*,
January 11, 2012.
1. Joseph Blomstedt:
“[Bringing Consistency to Riak](https://vimeo.com/51973001),” at *RICON West*,
October 2012.
1. Peter Bailis, Shivaram Venkataraman,
Michael J. Franklin, et al.:
“[Quantifying Eventual Consistency with PBS](http://www.bailis.org/papers/pbs-cacm2014.pdf),”
*Communications of the ACM*, volume 57, number 8, pages 93102, August 2014.
[doi:10.1145/2632792](http://dx.doi.org/10.1145/2632792)
1. Jonathan Ellis:
“[Modern Hinted Handoff](http://www.datastax.com/dev/blog/modern-hinted-handoff),”
*datastax.com*, December 11, 2012.
1. “[Project Voldemort Wiki](https://github.com/voldemort/voldemort/wiki),” *github.com*, 2013.
1. “[Apache Cassandra 2.0 Documentation](http://www.datastax.com/documentation/cassandra/2.0/index.html),” DataStax, Inc., 2014.
1. “[Riak Enterprise: Multi-Datacenter Replication](http://basho.com/assets/MultiDatacenter_Replication.pdf).” Technical whitepaper, Basho Technologies, Inc.,
September 2014.
1. Jonathan Ellis:
“[Why Cassandra Doesn't Need Vector Clocks](http://www.datastax.com/dev/blog/why-cassandra-doesnt-need-vector-clocks),” *datastax.com*, September 2, 2013.
1. Leslie Lamport:
“[Time, Clocks, and the Ordering of Events in a Distributed System](http://research.microsoft.com/en-US/um/people/Lamport/pubs/time-clocks.pdf),” *Communications of the ACM*,
volume 21, number 7, pages 558565, July 1978.
[doi:10.1145/359545.359563](http://dx.doi.org/10.1145/359545.359563)
1. Joel Jacobson:
“[Riak 2.0: Data Types](http://blog.joeljacobson.com/riak-2-0-data-types/),”
*blog.joeljacobson.com*, March 23, 2014.
1. D. Stott Parker Jr., Gerald J. Popek, Gerard Rudisin, et al.:
“[Detection of Mutual Inconsistency in Distributed Systems](http://zoo.cs.yale.edu/classes/cs426/2013/bib/parker83detection.pdf),” *IEEE Transactions on Software Engineering*,
volume 9, number 3, pages 240247, May 1983.
[doi:10.1109/TSE.1983.236733](http://dx.doi.org/10.1109/TSE.1983.236733)
1. Nuno Preguiça, Carlos Baquero, Paulo Sérgio
Almeida, et al.: “[Dotted Version Vectors: Logical Clocks for Optimistic Replication](http://arxiv.org/pdf/1011.5808v1.pdf),” arXiv:1011.5808, November 26,
2010.
1. Sean Cribbs:
“[A Brief History of Time in Riak](https://www.youtube.com/watch?v=HHkKPdOi-ZU),”
at *RICON*, October 2014.
1. Russell Brown:
“[Vector Clocks Revisited Part 2: Dotted Version Vectors](http://basho.com/posts/technical/vector-clocks-revisited-part-2-dotted-version-vectors/),” *basho.com*, November 10, 2015.
1. Carlos Baquero:
“[Version Vectors Are Not Vector Clocks](https://haslab.wordpress.com/2011/07/08/version-vectors-are-not-vector-clocks/),” *haslab.wordpress.com*, July 8, 2011.
1. Reinhard Schwarz and Friedemann Mattern:
“[Detecting Causal Relationships in Distributed Computations: In Search of the Holy Grail](http://dcg.ethz.ch/lectures/hs08/seminar/papers/mattern4.pdf),” *Distributed
Computing*, volume 7, number 3, pages 149174, March 1994.
[doi:10.1007/BF02277859](http://dx.doi.org/10.1007/BF02277859)

401
ddia/ch6.md Normal file
View File

@ -0,0 +1,401 @@
# 6. 分片
![](img/ch6.png)
> 显而易见,我们必须从电脑指令序列与限制约束中跳出来。 我们应当叙述定义、元数据、关系,而不是过程。
>
> —— Grace Murray Hopper未来的计算机及其管理1962
>
-------------
[TOC]
在第5章中我们讨论了复制 - 即在不同节点上有相同数据的多个副本。对于非常大的数据集或非常高的查询吞吐量这是不够的我们需要将数据拆分成分区也称为sharding[^i]
[^i]: 正如本章所讨论的分区是一种有意将大型数据库分解成小型数据库的方式。它与网络分区net splits无关这是节点之间网络中的一种故障类型。我们将在第8章讨论这些错误。
> ##### 术语澄清
>
> 我们在这里称之为分区`partition`的东西在MongoDBElasticsearch和Solr Cloud中被称为**分片shard**在HBase中称之为**区域(Region)**Bigtable中的 `tablet`Cassandra和Riak中的`vnode`以及Couchbase中的`vBucket`。但是分区partition是最为重要的术语所以我们坚持使用它。
>
通常情况下,分区是这样定义的,即每条数据(每条记录,每行或每个文档)只属于一个分区。有很多方法可以实现这一点,本章将深入讨论。实际上,每个分区都是自己的小型数据库,尽管数据库可能支持同时触及多个分区的操作。
要分区数据的主要原因是可扩展性。不同的分区可以放在不共享的集群中的不同节点上(请参阅[第二部分](part-ii.md)关于无共享架构的定义)。因此,大数据集可以分布在多个磁盘上,并且查询负载可以分布在多个处理器上。
对于在单个分区上运行的查询,每个节点可以独立执行对其自己的分区的查询,因此可以通过添加更多的节点来缩放查询吞吐量。大型,复杂的查询可能会跨越多个节点进行并行处理,尽管这会变得非常困难。
分区数据库在20世纪80年代由Teradata和NonStop SQL[【1】][1]等产品率先推出最近又被NoSQL数据库和基于Hadoop的数据仓库重新发明。有些系统是为事务性工作负载设计的其他系统则用于分析请参阅第90页上的“事务处理或分析这种差异会影响系统的调整方式但是分区的基本原理适用于这两种工作负载。
在本章中,我们将首先介绍分割大型数据集的不同方法,并观察数据索引如何与分区交互。然后,我们将讨论重新平衡,如果您想要添加或删除群集中的节点,则必须进行重新平衡。最后,我们将概述数据库如何将请求路由到正确的分区并执行查询。
## 分片与复制
![](img/fig6-1.png)
**图6-1 组合使用复制和分区:每个节点充当某些分区的领导者,其他分区充当追随者。**
## 键值数据的分片
假设你有大量的数据,你想分割它。你如何决定在哪些节点上存储哪些记录?
我们的分区目标是将数据和查询负载均匀分布在各个节点上。如果每个节点都公平分享那么理论上10个节点应该能够处理10倍的数据量和10倍的单个节点的读写吞吐量目前忽略复制
如果分区是不公平的那么一些分区比其他分区有更多的数据或查询我们称之为偏斜。歪斜的存在使分区效率下降得多。在极端的情况下所有的负载都可能在一个分区上所以10个节点中有9个是空闲的你的瓶颈就是单个的繁忙节点。一个负载不均衡的分区被称为热点。
避免热点的最简单方法是将记录随机分配给节点。这将在整个节点上平均分配数据,但是它有一个很大的缺点:当你试图读取一个特定的项目时,你无法知道它在哪个节点上,所以你必须并行地查询所有的节点。
我们可以做得更好。现在让我们假设您有一个简单的键值数据模型,其中您总是通过其主键访问记录。例如,在一篇老式的纸质百科全书中,你可以通过标题来查找一个条目;由于所有条目按字母顺序排序,因此您可以快速找到您要查找的条目。
### 根据键的范围分片
分区的一种方法是为每个分区分配一个连续的键范围从最小值到最大值如纸百科全书的卷图6-2。如果知道范围之间的界限则可以轻松确定哪个分区包含给定的键。如果您还知道哪个分区分配给哪个节点那么您可以直接向相应的节点发出请求或者在百科全书的情况下从书架上选取正确的书籍
![](img/fig6-2.png)
**图6-2 印刷版百科全书按照关键字范围进行分区**
键的范围不一定均匀分布因为您的数据可能不均匀分布。例如在图6-2中第1卷包含以A和B开头的单词但第12卷则包含以TUVXY和Z开头的单词。每个字母的两个字母只有一个音量导致一些卷比其他卷更大。为了均匀分配数据分区边界需要适应数据。
分区边界可以由管理员手动选择也可以由数据库自动选择我们将在第209页的“重新平衡分区”中更详细地讨论分区边界的选择。 Bigtable使用了这种分区策略其开源的HBase [23]RethinkDB和2.4版本之前的MongoDB [4][4]。
在每个分区中我们可以按照排序的顺序保存键请参见第70页上的“SSTables和LSM-树”。这具有范围扫描非常简单的优点您可以将键作为连接索引来处理以便在一个查询中获取多个相关记录请参阅第79页的“多列索引”。例如考虑存储来自传感器网络的数据的应用程序其中关键是测量的时间戳年 - 月 - 日 - 时 - 分 - 秒)。范围扫描在这种情况下非常有用,因为它们让您轻松获取某个月份的所有读数。
然而,关键范围分区的缺点是某些访问模式会导致热点。 如果密钥是时间戳,则分区对应于时间范围,例如,每天一个分区。 不幸的是,由于我们在测量发生时将数据从传感器写入数据库,因此所有写入操作都会转到同一个分区(即今天的分区),这样分区可能会因写入而过载,而其他分区则处于空闲状态[5]。
为了避免传感器数据库中的这个问题,您需要使用除时间戳以外的其他内容作为密钥的第一个元素。 例如,您可以在每个时间戳前添加传感器名称,以便分区首先按传感器名称,然后按时间。 假设同时有许多传感器处于活动状态,则写入负载将最终均匀分布在分区上。 现在,当您想要在一个时间范围内获取多个传感器的值时,您需要为每个传感器名称执行一个单独的范围查询。
### 根据键的哈希分片
由于这种倾斜和热点的风险,许多分布式数据存储使用散列函数来确定给定密钥的分区。
一个好的散列函数需要偏斜的数据并使其均匀分布。假设你有一个带有字符串的32位散列函数。无论何时给它一个新的字符串它将返回一个0到232-1之间的表面上的随机数。即使输入的字符串非常相似它们的散列也会均匀分布在这个数字范围内。
对于分区目的来说散列函数不需要密码强壮例如Cassandra和MongoDB使用MD5Voldemort使用Fowler-Noll-Vo函数。许多编程语言都有内置的简单哈希函数因为它们用于哈希表但是它们可能不适合分区例如在Java的Object.hashCode和Ruby的Object哈希中同一个键可能有不同的过程中不同的哈希值[6]。
一旦你有一个合适的密钥散列函数你可以为每个分区分配一个散列范围而不是一系列的密钥每个散列落在分区范围内的密钥将被存储在该分区中。如图6-3所示。
![](img/fig6-3.png)
**图6-3 按哈希键分区**
这种技术擅长在分区之间分配密钥。分区边界可以是均匀间隔的,也可以是伪随机选择的(在这种情况下,该技术有时被称为一致性散列)。
> 一致性哈希
> 一致性哈希由Karger等人定义。[7] 是一种平均分配负载的方法通过内容分发网络CDN等互联网系统的缓存。 它使用随机选择的分区边界来避免中央控制或分布式共识的需要。 请注意这里的一致性与复制一致性请参阅第5章或ACID一致性请参阅第7章无关而是描述了重新平衡的特定方法。
>
> 正如我们将在第209页的“重新平衡分区”中所看到的这种特殊的方法对于数据库实际上并不是很好所以在实际中很少使用某些数据库的文档仍然指的是一致性哈希但是它 往往是不准确的)。 因为这太混乱了,所以最好避免使用一致性哈希这个术语,而只是把它称为散列分区(hash partitioning)。
不幸的是通过使用Key散列进行分区我们失去了键范围分区的一个很好的属性执行高效范围查询的能力。曾经相邻的密钥现在分散在所有分区中所以它们的排序顺序就会丢失。在MongoDB中如果您启用了基于散列的分片模式则任何范围查询都必须发送到所有分区[4]。主键上的范围查询不受Riak [9]Couchbase [10]或Voldemort的支持。
Cassandra在两个分区策略之间达成了一个折衷[11,12,13]。 Cassandra中的表可以使用由多个列组成的复合主键来声明。只有该密钥的第一部分被散列来确定分区而其他列则被用作Cas- sandra的SSTables中排序数据的连接索引。因此查询无法在组合键的第一列中搜索一系列值但如果为第一列指定了固定值则可以对该键的其他列执行有效的范围扫描。
串联索引方法为一对多关系提供了一个优雅的数据模型。例如,在社交媒体网站上,一个用户可能会发布很多更新。如果更新的主键被选择为`user_idupdate_timestamp`,那么您可以有效地检索特定用户在某个时间间隔内按时间戳排序的所有更新。不同的用户可以存储在不同的分区上,但是在每个用户中,更新按时间戳顺序存储在单个分区上。
### 负载倾斜与消除热点
如前所述,哈希键确定其分区可以帮助减少热点。但是,它不能完全避免它们:在极端情况下,所有的读写操作都是针对同一个密钥的,所有的请求都会被路由到同一个分区。
这种工作量也许并不常见,但并非闻所未闻:例如,在社交媒体网站上,一个拥有数百万追随者的名人用户在做某事时可能会引发一场风暴[14]。这个事件可能导致大量写入同一个密钥密钥可能是名人的用户ID或者人们正在评论的动作的ID。哈希键不起作用因为两个相同ID的哈希值仍然是相同的。
如今大多数数据系统无法自动补偿这种高度偏斜的工作负载因此应用程序有责任减少偏斜。例如如果一个密钥被认为是非常热的一个简单的方法是在密钥的开始或结尾添加一个随机数。只要一个两位数的十进制随机数就可以将写入密钥分散到100个不同的密钥中从而允许这些密钥分配到不同的分区。
然而在不同的密钥之间进行分割任何读取都必须要做额外的工作因为他们必须从所有100个密钥中读取数据并将其合并。此技术还需要额外的簿记只为少量热键附加随机数是有意义的;对于写入吞吐量低的绝大多数密钥,这将是不必要的开销。因此,您还需要一些方法来跟踪哪些键被分割。
也许在将来,数据系统将能够自动检测和补偿偏斜的工作负载;但现在,您需要考虑自己的应用程序的权衡。
## 分片与次级索引
到目前为止,我们讨论的分区方案依赖于键值数据模型。如果只通过主键访问记录,我们可以从该键确定分区,并使用它来将读写请求路由到负责该键的分区。
如果涉及二级索引情况会变得更加复杂另见“其他索引结构”在第85页。辅助索引通常不能唯一地标识记录而是搜索特定值的发生的方式查找用户123的所有操作查找包含词语hogwash的所有文章查找所有颜色为红色的车辆等等上。
二级索引是关系数据库的吃饭家伙在文档数据库中也是通用的。许多键值存储如HBase和Volde-mort由于增加了实现的复杂性而避免了二级索引但是一些如Riak已经开始添加它们因为它们对于数据建模非常有用。最后二级索引是Solr和Elasticsearch等搜索服务器的存在理由。
二级索引的问题是它们不能整齐地映射到分区。有两种主要的方法可以用二级索引分区数据库:基于文档的分区和基于词的分区。
### 按文档的二级索引
例如假设您正在经营一个销售二手车的网站如图6-4所示。 每个列表都有一个唯一的ID--称之为文档ID--并且用文档ID对数据库进行分区例如分区0中的ID 0到499分区1中的ID 500到999等
你想让用户搜索汽车,允许他们通过颜色和通过过滤,所以你需要一个二级索引的颜色和(在文档数据库中这些将是字段(field),在关系数据库中,他们将是列(column) )。 如果您声明了索引,则数据库可以自动执行索引。例如,无论何时将红色汽车添加到数据库,数据库分区都会自动将其添加到索引条目`colorred`的文档ID列表中。
[^ii]: 如果您的数据库仅支持键值模型则可能会尝试通过在应用程序代码中创建从值到文档ID的映射来实现辅助索引。 如果您沿着这条路线走下去,您需要非常小心,以确保您的索引与基础数据保持一致。 竞争条件和间歇性写入失败(其中一些更改已保存,但其他更改未保存)很容易导致数据不同步 - 请参见第231页上的“多对象事务的需要”。。
![](img/fig6-4.png)
**图6-4 按文档分区二级索引**
在这种索引方法中每个分区是完全独立的每个分区维护自己的二级索引仅覆盖该分区中的文档。它不关心哪些数据存储在其他分区中。无论何时您需要写入数据库添加删除或更新文档只需处理包含您正在编写的文档ID的分区即可。出于这个原因文档分区索引也被称为本地索引而不是全局索引在下一节中描述
但是从文档分区索引中读取需要注意除非您对文档ID做了特别的处理否则没有理由将所有具有特定颜色或特定品牌的汽车放在同一个分区中。在图6-4中红色汽车出现在分区0和分区1中。因此如果要搜索红色汽车则需要将查询发送到所有分区并合并所有返回的结果。
这种查询分区数据库的方法有时被称为分散/聚集,并且可能会使二级索引的读取查询相当昂贵。即使您并行查询分区,分散/聚集也容易导致尾部延迟放大请参阅第16页的“实践中的百分比”。然而它被广泛使用MonDBDBRiak [15]Cassandra [16]Elasticsearch [17]SolrCloud [18]和VoltDB [19]都使用文档分区二级索引。大多数数据库供应商建议您构建分区方案,以便可以从单个分区提供二级索引查询,但这并不总是可行,尤其是当您在单个查询中使用多个二级索引时(例如按颜色并通过在同一时间)。
### 根据Term的二级索引
我们可以构建覆盖所有分区数据的全局索引,而不是每个分区都有自己的二级索引(本地索引)。但是,我们不能只把这个索引存储在一个节点上,因为它可能会成为一个瓶颈,打破了分区的目的。全局索引也必须进行分区,但可以与主键索引进行不同的分区。
![](img/fig6-5.png)
**图6-5 按术语对二级索引进行分区**
图6-5说明了这可能是什么情况来自所有分区的红色汽车在索引中显示为红色索引中的红色但索引是分区的以便从字母a到r开始的颜色出现在分区0中颜色以s开始z出现在第1部分。汽车制造商的指数也是相似的分区边界在f和h之间
我们将这种索引术语称为分割术语,因为我们期待的术语决定了索引的分割。在这里,例如,一个术语将是颜色:红色。名称术语来自全文索引(一种特定的二级索引),其中术语是文档中出现的所有单词。
和以前一样,我们可以通过术语本身来划分索引,或者使用术语的散列。通过术语本身进行划分对于范围扫描是有用的(例如,数字特性,例如汽车的要价),而对术语的哈希进行划分给出了负载的更均匀的分布。
全局(术语分区)索引优于文档分区索引的优点是它可以使读取更有效率:而不是分散/收集所有分区,客户端只需要向包含术语的分区发出请求它想要的。但是,全局索引的缺点在于写入速度较慢且较为复杂,因为写入单个文档现在可能会影响索引的多个分区(文档中的每个术语可能位于不同的分区上,位于不同的节点上) 。
在理想的世界里索引总是最新的写入数据库的每个文档都会立即反映在索引中。但是在分区索引中这将需要跨所有受写入影响的分区进行分布式事务这在所有数据库中都不受支持请参阅第7章和第9章
在实践中对全局二级索引的更新通常是异步的也就是说如果在写入之后不久读取索引刚才所做的更改可能尚未反映在索引中。例如Amazon DynamoDB指出在正常情况下其全局次级索引会在不到一秒的时间内更新但在基础架构出现故障的情况下可能会经历更长的传播延迟[20]。
全局术语分区索引的其他用途包括Riak的搜索功能[21]和Oracle数据仓库它允许您在本地索引和全局索引之间进行选择[22]。我们将回到第12章中实施分词二级索引的主题。
## 平衡分区
在数据库中,随着时间的推移,事情也在起变化。
* 查询吞吐量增加所以您想要添加更多的CPU来处理负载。
* 数据集大小增加所以您想添加更多的磁盘和RAM来存储它。
* 机器出现故障,其他机器需要接管故障机器的责任。
所有这些更改都要求数据和请求从一个节点移动到另一个节点。 从集群中的一个节点向另一个节点移动负载的过程称为重置。
无论使用哪种分区方案,重新平衡通常都会满足一些最低要求:
* 重新平衡之后,负载(数据存储,读取和写入请求)应该在集群中的节点之间公平地共享。
* 重新平衡正在发生时,数据库应该继续接受读取和写入。
* 节点之间不应移动超过所需的数据以便快速重新配置并尽量减少网络和磁盘I / O负载。
### 平衡策略
有几种不同的分区分配方式[23]。让我们依次简要讨论一下。
#### 别这样做hash mod N
我们在前面说过图6-3最好将可能的散列分成不同的范围并将每个范围分配给一个分区例如如果0≤散列则将键分配给分区0如果b0≤散列关键字<b1则等于b0等等
也许你想知道为什么我们不使用mod许多编程语言中的运算符。例如hashkeymod 10会返回一个介于0和9之间的数字如果我们将散列写为十进制数散列模10将是最后一个数字。如果我们有10个节点编号为0到9这似乎是将每个键分配给一个节点的简单方法。
mod N方法的问题是如果节点数量N发生变化大多数密钥将需要从一个节点移动到另一个节点。例如假设hashkey= 123456。如果最初有10个节点那么这个密钥从节点6开始因为123456 mod 10 = 6。当您增长到11个节点时密钥需要移动到节点3123456 mod 11 = 3当您增长到12个节点时需要移动到节点0123456 mod 12 = 0。这种频繁的举动使得再平衡过于昂贵。
我们需要一种不需要移动数据的方法。
#### 固定数量的分区
幸运的是有一个相当简单的解决方案创建比节点更多的分区并为每个节点分配多个分区。例如运行在10个节点的集群上的数据库可能会从一开始就被拆分为1,000个分区因此大约有100个分区被分配给每个节点。
现在如果一个节点被添加到集群中新节点可以从每个现有节点中窃取几个分区直到分区再次公平分配。这个过程如图6-6所示。如果从集群中删除一个节点则会发生相反的情况。
只有整个分区在节点之间移动。分区的数量不会改变,也不会将分配的密钥分配给分区。唯一改变的是将分区分配给节点。这种分配的改变并不是即时的 - 在网络上传输大量的数据需要一些时间 - 所以旧的分区分配被用于在传输过程中发生的任何读写操作。
#####
![](img/fig6-6.png)
**图6-6 将新节点添加到每个节点具有多个分区的数据库群集。**
原则上,您甚至可以解释集群中的硬件不匹配问题:通过为更强大的节点分配更多的分区,可以强制这些节点分担更多的负载。
在Riak [15]Elasticsearch [24]Couchbase [10]和Voldemort [25]中使用了这种重新平衡的方法。
在这种配置中,分区的数量通常在数据库第一次建立时是固定的,之后不会改变。虽然原则上可以拆分和合并分区(请参阅下一节),但固定数量的分区在操作上更简单,因此许多固定分区数据库选择不实施分区拆分。因此,一开始配置的分区数就是您可以拥有的最大节点数量,所以您需要选择足够高的分区以适应未来的增长。但是,每个分区也有管理开销,所以选择太高的数字是适得其反的。
如果数据集的总大小是高度可变的(例如,如果它开始很小,但随着时间的推移可能会变得更大),选择正确的分区数是困难的。由于每个分区包含总数据的固定部分,因此每个分区的大小与集群中的数据总量成比例增长。如果分区非常大,重新平衡和从节点故障恢复变得昂贵。但是,如果份额太小,则会产生太多的开销。当分区大小“恰到好处”,既不会太大,也不会太小,如果分区数量固定但数据集大小不一,则难以达到最佳性能。
#### 动态分区
对于使用键范围分区的数据库请参阅第202页的“按键范围分区”具有固定边界的固定数量的分区将非常不方便如果出现边界错误则可能会导致所有一个分区中的数据和所有其他分区中的数据为空。手动重新配置分区边界将非常繁琐。
出于这个原因关键的范围分区数据库如HBase和RethinkDB动态创建分区。当分区增长到超过配置的大小时在HBase上默认值是10GB它被分成两个分区因此大约一半的数据在split [26]的每一端结束。相反如果大量数据被删除并且分区缩小到某个阈值以下则可以将其与相邻分区合并。此过程与B树顶层发生的过程类似请参阅第79页上的“B-树”)。
每个分区分配给一个节点每个节点可以处理多个分区就像固定数量的分区一样。大型分区拆分后可以将其中的一半转移到另一个节点以平衡负载。在HBase的情况下分区文件的传输通过HDFS底层分布式文件系统来实现[3]。
动态分区的一个优点是分区数量适应总数据量。如果只有少量的数据,少量的分区就足够了,所以开销很小;如果有大量的数据,每个分区的大小被限制在一个可配置的最大值[23]。
但是需要注意的是一个空的数据库从一个分区开始因为没有关于在哪里绘制分区边界的先验信息。虽然数据集很小直到达到第一个分区的分割点时所有写入操作都必须由单个节点处理而其他节点则处于空闲状态。为了解决这个问题HBase和MongoDB允许在一个空的数据库上配置一组初始分区这被称为预分割。在键范围分区的情况下预分割要求您已经知道密钥分配将如何看起来像[4,26]。
动态分区不仅适用于关键的范围分区数据而且也适用于散列分区数据。从版本2.4开始MongoDB同时支持键范围和哈希分区并且在任何情况下动态分割分区。
#### 按比例分配节点
通过动态分区,分区的数量与数据集的大小成正比,因为拆分和合并过程将每个分区的大小保持在固定的最小值和最大值之间。另一方面,对于固定数量的分区,每个分区的大小与数据集的大小成正比。在这两种情况下,分区的数量都与节点的数量无关。
Cassandra和Ketama使用的第三种方法是使分区数与节点数成比例 - 换句话说,每个节点具有固定数量的分区[23,27,28]。在这种情况下,每个分区的大小与数据集大小成比例地增长,而节点数量保持不变,但是当增加节点数时,分区将再次变小。由于较大的数据量通常需要较大数量的节点进行存储,因此这种方法也使每个分区的大小相当稳定。
当一个新节点加入集群时它随机选择一个固定数量的现有分区进行拆分然后占用这些拆分分区中每个分区的一半同时将每个分区的另一半留在原地。随机化可能会产生不公平的分裂但是当在更大数量的分区上进行平均时在Cas- sandra中默认情况下每个节点有256个分区新节点最终从现有节点获得公平的负载份额。 Cassandra 3.0引入了另一种可重用的算法来避免不公平的分裂[29]。
随机选择分区边界要求使用基于散列的分区(所以可以从散列函数产生的数字范围中挑选边界)。实际上,这种方法最符合一致性散列的原始定义[7]请参阅第204页的“一致性散列”。较新的哈希函数可以在降低元数据开销的情况下达到类似的效果[8]。
### 运维:手动还是自动平衡
关于我们已经掩盖的重新平衡问题有一个重要问题:重新平衡是自动还是手动进行?
在全自动重新平衡系统自动决定何时将分区从一个节点移动到另一个节点而没有任何管理员交互和完全手动分区指派给节点由管理员明确配置之间有一个梯度仅在管理员明确重新配置时才会更改。例如CouchbaseRiak和Voldemort会自动生成建议的分区分配但需要管理员在生效之前提交它。
全自动重新平衡可以很方便,因为正常维护的操作工作较少。但是,这可能是不可预测的。再平衡是一个昂贵的操作,因为它需要重新路由请求并将大量数据从一个节点移动到另一个节点。如果没有做好,这个过程可能会使网络或节点负载过重,并在重新平衡过程中损害其他请求的性能。
这种自动化与自动故障检测相结合可能是危险的。例如,假设一个节点过载,并且对请求的响应暂时很慢。其他节点得出结论:过载的节点已经死亡,并自动重新平衡集群,使负载离开它。这会对超载节点,其他节点和网络造成额外的负载,从而使情况变得更糟,并可能导致级联失败。
出于这个原因,让一个人重新平衡循环是一件好事。这比完全自动的过程慢,但它可以帮助防止操作意外。
## 请求路由
现在我们已经将数据集分割到多个机器上运行的多个节点上。但是仍然存在一个悬而未决的问题当客户想要提出请求时如何知道要连接哪个节点随着分区重新平衡分区对节点的分配也发生变化。为了回答这个问题有人需要停留在这些变化之上如果我想读或写密钥“foo”需要连接哪个IP地址和端口号
这是一个称为服务发现的更普遍问题的实例,它不仅限于数据库。任何可通过网络访问的软件都有这个问题,特别是如果它的目标是实现高可用性(在多台机器上运行冗余配置)。许多公司已经编写了自己的内部服务发现工具,其中许多已经作为开源发布[30]。
在很高的层面上这个问题有几种不同的方法如图6-7所示
1. 允许客户联系任何节点(例如,通过循环负载均衡器)。如果该节点巧合地拥有请求所适用的分区,则它可以直接处理该请求;否则,它将请求转发到适当的节点,接收到答复,并将答复传递给客户端。
2. 首先将所有来自客户端的请求发送到路由选择层,这决定了应该处理每个请求的节点并相应地转发它。此路由层本身不处理任何请求;它仅充当分区感知负载平衡器。
3. 要求客户端知道分区和节点分配。在这种情况下,客户端可以直接连接到适当的节点,而不需要任何中介。
在所有情况下,关键问题是:作出路由决策的组件(可能是节点之一,还是路由层或客户端)如何了解分区向节点的分配变化?
![](img/fig6-7.png)
**图6-7 将请求路由到正确节点的三种不同方式。**
这是一个具有挑战性的问题,因为重要的是所有参与者都同意 - 否则请求将被发送到错误的节点,而不是正确处理。 在分布式系统中有达成共识的协议但很难正确实施见第9章
许多分布式数据系统都依赖于一个独立的协调服务比如Zoo-Keeper来跟踪这个集群元数据如图6-8所示。 每个节点在ZooKeeper中注册自己ZooKeeper维护分区到节点的权威映射。 其他参与者如路由层或分区感知客户端可以在ZooKeeper中订阅此信息。 只要分区改变了所有权或者添加或删除了一个节点ZooKeeper就会通知路由层以使路由信息保持最新状态。
![](img/fig6-8.png)
**图6-8 使用ZooKeeper跟踪分区分配给节点。**
例如LinkedIn的Espresso使用Helix [31]进行集群管理依靠ZooKeeper实现了一个路由层如图6-8所示。 HBaseSolrCloud和Kafka也使用ZooKeeper来跟踪分区分配。 MongoDB具有类似的体系结构但它依赖于自己的配置服务器实现和mongos守护进程作为路由层。
Cassandra和Riak采取不同的方法他们在节点之间使用**八卦协议**来传播群集状态的任何变化。可以将请求发送到任何节点并将该节点转发到所请求的分区的适当节点图6-7中的方法1。这个模型在数据库节点中增加了更多的复杂性但是避免了对像ZooKeeper这样的外部协调服务的依赖。
Couchbase不会自动重新平衡这简化了设计。通常情况下它配置了一个名为moxi的路由选择层它学习了来自集群节点的路由更改[32]。
当使用路由层或向随机节点发送请求时客户端仍然需要找到要连接的IP地址。这些分区并不像分配给节点那么快所以为此使用DNS通常就足够了。
### 并行查询执行
到目前为止,我们只关注读取或写入单个关键字的非常简单的查询(对于文档分区的二级索引,另外还有分散/聚集查询。这与大多数NoSQL分布式数据存储所支持的访问级别有关。
然而通常用于分析的大规模并行处理MPP关系数据库产品在其支持的查询类型方面要复杂得多。一个典型的数据仓库查询包含多个连接过滤分组和聚合操作。 MPP查询优化器将这个复杂的查询分解成许多执行阶段和分区其中许多可以在数据库集群的不同节点上并行执行。涉及扫描大部分数据集的查询尤其受益于这种并行执行。
数据仓库查询的快速并行执行是一个专门的话题考虑到分析的业务重要性它收到了很多商业利益。我们将在第10章讨论并行查询执行的一些技巧。有关并行数据库中使用的技术的更详细的概述请参阅参考文献[1,33]。
## 本章小结
在本章中,我们探讨了将大数据集划分成更小的子集的不同方法。如果您有太多的数据,在单台机器上存储和处理不再可行,则分区是必要的。分区的目标是在多台机器上均匀分布数据和查询负载,避免出现热点(负载不成比例的节点)。这需要选择适合于您的数据的分区方案,并在将节点添加到集群或从集群删除时重新分区。
我们讨论了两种主要的分区方法:
* 键范围分区,其中键排序,并且分区拥有从某个最小值到某个最大值的所有键。排序的优势在于可以进行有效的范围查询,但是如果应用程序经常按照排序顺序访问密切相关的密钥,则存在热点的风险。
在这种方法中,当分区变得太大时,通常将分区分成两个子分区,动态地重新平衡分区。
* 散列分区,散列函数应用于每个键,分区拥有一定范围的散列。这种方法破坏了键的排序,使得范围查询效率低下,但可以更均匀地分配负载。
通过散列进行分区时,通常先提前创建固定数量的分区,为每个节点分配多个分区,并在添加或删除节点时将整个分区从一个节点移动到另一个节点。动态分区也可以使用。
混合方法也是可能的,例如使用复合键:使用键的一部分来识别分区,而使用另一部分作为排序顺序。
我们还讨论了分区和二级索引之间的交互。第二个索引也需要分割,有两种方法:
* 文档分区索引(本地索引),其中辅助索引存储在与主键和值相同的分区中。这意味着只有一个分区需要在写入时更新,但是读取辅助索引需要在所有分区之间进行分散/收集。
* 使用索引值的术语分区索引(全局索引),其中二级索引是分开分开的。辅助索引中的条目可以包括来自主键的所有分区的记录。当文档写入时,需要更新二级索引的多个分区;但是,可以从单个分区提供读取。
最后,我们讨论了将查询路由到适当的分区的技术,从简单的分区感知负载平衡到复杂的并行查询执行引擎。
按照设计,每个分区大部分是独立运行的 - 这就是允许分区数据库扩展到多台机器的原因。但是,需要写入多个分区的操作难以推理:例如,如果写入一个分区成功,但另一个分区失败,会发生什么情况?我们将在下面的章节中讨论这个问题。
参考文献
--------------------
[1]: http://www.cs.cmu.edu/~pavlo/courses/fall2013/static/papers/dewittgray92.pdf "David J. DeWitt and Jim N. Gray: “Parallel Database Systems: The Future of High Performance Database Systems,” Communications of the ACM, volume 35, number 6, pages 8598, June 1992. doi:10.1145/129888.129894"
1. David J. DeWitt and Jim N. Gray: “[Parallel Database Systems: The Future of High Performance Database Systems](),”
*Communications of the ACM*, volume 35, number 6, pages 8598, June 1992. [doi:10.1145/129888.129894](http://dx.doi.org/10.1145/129888.129894)
2. Lars George: “[HBase vs. BigTable Comparison](http://www.larsgeorge.com/2009/11/hbase-vs-bigtable-comparison.html),” *larsgeorge.com*, November 2009.
3. “[The Apache HBase Reference Guide](https://hbase.apache.org/book/book.html),” Apache Software Foundation, *hbase.apache.org*, 2014.
4. MongoDB, Inc.: “[New Hash-Based Sharding Feature in MongoDB 2.4](http://blog.mongodb.org/post/47633823714/new-hash-based-sharding-feature-in-mongodb-24),” *blog.mongodb.org*, April 10, 2013.
5. Ikai Lan: “[App Engine Datastore Tip: Monotonically Increasing Values Are Bad](http://ikaisays.com/2011/01/25/app-engine-datastore-tip-monotonically-increasing-values-are-bad/),” *ikaisays.com*,
January 25, 2011.
6. Martin Kleppmann: “[Java's hashCode Is Not Safe for Distributed Systems](http://martin.kleppmann.com/2012/06/18/java-hashcode-unsafe-for-distributed-systems.html),” *martin.kleppmann.com*, June 18, 2012.
7. David Karger, Eric Lehman, Tom Leighton, et al.: “[Consistent Hashing and Random Trees: Distributed Caching Protocols for Relieving Hot Spots on the World Wide Web](http://www.akamai.com/dl/technical_publications/ConsistenHashingandRandomTreesDistributedCachingprotocolsforrelievingHotSpotsontheworldwideweb.pdf),” at *29th Annual ACM Symposium on Theory of Computing* (STOC), pages 654663, 1997. [doi:10.1145/258533.258660](http://dx.doi.org/10.1145/258533.258660)
8. John Lamping and Eric Veach: “[A Fast, Minimal Memory, Consistent Hash Algorithm](http://arxiv.org/pdf/1406.2294v1.pdf),” *arxiv.org*, June 2014.
9. Eric Redmond: “[A Little Riak Book](http://littleriakbook.com/),” Version 1.4.0, Basho Technologies, September 2013.
10. “[Couchbase 2.5 Administrator Guide](http://docs.couchbase.com/couchbase-manual-2.5/cb-admin/),” Couchbase, Inc., 2014.
11. Avinash Lakshman and Prashant Malik: “[Cassandra A Decentralized Structured Storage System](http://www.cs.cornell.edu/Projects/ladis2009/papers/Lakshman-ladis2009.PDF),” at *3rd ACM SIGOPS International Workshop on
Large Scale Distributed Systems and Middleware* (LADIS), October 2009.
12. Jonathan Ellis: “[Facebooks Cassandra Paper, Annotated and Compared to Apache Cassandra 2.0](http://www.datastax.com/documentation/articles/cassandra/cassandrathenandnow.html),”
*datastax.com*, September 12, 2013.
13. “[Introduction to Cassandra Query Language](http://www.datastax.com/documentation/cql/3.1/cql/cql_intro_c.html),” DataStax, Inc., 2014.
14. Samuel Axon: “[3% of Twitter's Servers Dedicated to Justin Bieber](http://mashable.com/2010/09/07/justin-bieber-twitter/),” *mashable.com*, September 7, 2010.
15. “[Riak 1.4.8 Docs](http://docs.basho.com/riak/1.4.8/),” Basho Technologies, Inc., 2014.
16. Richard Low: “[The Sweet Spot for Cassandra Secondary Indexing](http://www.wentnet.com/blog/?p=77),” *wentnet.com*, October 21, 2013.
17. Zachary Tong: “[Customizing Your Document Routing](http://www.elasticsearch.org/blog/customizing-your-document-routing/),” *elasticsearch.org*, June 3, 2013.
18. “[Apache Solr Reference Guide](https://cwiki.apache.org/confluence/display/solr/Apache+Solr+Reference+Guide),” Apache Software Foundation, 2014.
19. Andrew Pavlo: “[H-Store Frequently Asked Questions](http://hstore.cs.brown.edu/documentation/faq/),” *hstore.cs.brown.edu*, October 2013.
20. “[Amazon DynamoDB Developer Guide](http://docs.aws.amazon.com/amazondynamodb/latest/developerguide/),” Amazon Web Services, Inc., 2014.
21. Rusty Klophaus: “[Difference Between 2I and Search](http://lists.basho.com/pipermail/riak-users_lists.basho.com/2011-October/006220.html),” email to *riak-users* mailing list, *lists.basho.com*, October 25, 2011.
22. Donald K. Burleson: “[Object Partitioning in Oracle](http://www.dba-oracle.com/art_partit.htm),”*dba-oracle.com*, November 8, 2000.
23. Eric Evans: “[Rethinking Topology in Cassandra](http://www.slideshare.net/jericevans/virtual-nodes-rethinking-topology-in-cassandra),” at *ApacheCon Europe*, November 2012.
24. Rafał Kuć: “[Reroute API Explained](http://elasticsearchserverbook.com/reroute-api-explained/),” *elasticsearchserverbook.com*, September 30, 2013.
25. “[Project Voldemort Documentation](http://www.project-voldemort.com/voldemort/),” *project-voldemort.com*.
26. Enis Soztutar: “[Apache HBase Region Splitting and Merging](http://hortonworks.com/blog/apache-hbase-region-splitting-and-merging/),” *hortonworks.com*, February 1, 2013.
27. Brandon Williams: “[Virtual Nodes in Cassandra 1.2](http://www.datastax.com/dev/blog/virtual-nodes-in-cassandra-1-2),” *datastax.com*, December 4, 2012.
28. Richard Jones: “[libketama: Consistent Hashing Library for Memcached Clients](https://www.metabrew.com/article/libketama-consistent-hashing-algo-memcached-clients),” *metabrew.com*, April 10, 2007.
29. Branimir Lambov: “[New Token Allocation Algorithm in Cassandra 3.0](http://www.datastax.com/dev/blog/token-allocation-algorithm),” *datastax.com*, January 28, 2016.
30. Jason Wilder: “[Open-Source Service Discovery](http://jasonwilder.com/blog/2014/02/04/service-discovery-in-the-cloud/),” *jasonwilder.com*, February 2014.
31. Kishore Gopalakrishna, Shi Lu, Zhen Zhang, et al.: “[Untangling Cluster Management with Helix](http://www.socc2012.org/helix_onecol.pdf?attredirects=0),” at *ACM Symposium on Cloud Computing* (SoCC), October 2012.
[doi:10.1145/2391229.2391248](http://dx.doi.org/10.1145/2391229.2391248)
32. “[Moxi 1.8 Manual](http://docs.couchbase.com/moxi-manual-1.8/),” Couchbase, Inc., 2014.
33. Shivnath Babu and Herodotos Herodotou: “[Massively Parallel Databases and MapReduce Systems](http://research.microsoft.com/pubs/206464/db-mr-survey-final.pdf),” *Foundations and Trends in Databases*, volume 5, number 1, pages 1104, November 2013.[doi:10.1561/1900000036](http://dx.doi.org/10.1561/1900000036)
#####
#####

1068
ddia/ch7.md Normal file

File diff suppressed because it is too large Load Diff

360
ddia/ch8.md Normal file
View File

@ -0,0 +1,360 @@
# 8. 分布式系统的麻烦
![](img/ch8.png)
> 邂逅相遇
>
> 网络延迟
>
> 存之为吾
>
> 无食我数
>
> ——凯尔金斯伯里卡莉赖杰普森网络分区的危险2013年
---------
[TOC]
## 故障与部分失效
### 云计算与超级计算机
## 不可靠的网络
### 真实世界的网络故障
### 检测故障
### 超时与无穷的延迟
### 同步网络 vs 异步网络
## 不可靠的时钟
### 单调时钟与Time-Of-Day时钟
### 时钟同步与准确性
### 依赖同步时钟
### 暂停进程
## 知识、真相与谎言
### 真理掌握在大多数人手中
### 拜占庭故障
### 系统模型与现实
## 本章小结
## 参考文献
1. Mark Cavage:
“[Theres Just No Getting Around It: Youre Building a Distributed System](http://queue.acm.org/detail.cfm?id=2482856),” *ACM Queue*, volume 11, number 4, pages 80-89, April 2013.
[doi:10.1145/2466486.2482856](http://dx.doi.org/10.1145/2466486.2482856)
1. Jay Kreps:
“[Getting Real About Distributed System Reliability](http://blog.empathybox.com/post/19574936361/getting-real-about-distributed-system-reliability),” *blog.empathybox.com*, March 19, 2012.
1. Sydney Padua: *The Thrilling Adventures of
Lovelace and Babbage: The (Mostly) True Story of the First Computer*. Particular Books, April
2015. ISBN: 978-0-141-98151-2
1. Coda Hale:
“[You Cant Sacrifice Partition Tolerance](http://codahale.com/you-cant-sacrifice-partition-tolerance/),” *codahale.com*, October 7, 2010.
1. Jeff Hodges:
“[Notes on Distributed Systems for Young Bloods](http://www.somethingsimilar.com/2013/01/14/notes-on-distributed-systems-for-young-bloods/),” *somethingsimilar.com*, January 14, 2013.
1. Antonio Regalado:
“[Who Coined 'Cloud Computing&#x2019;?](http://www.technologyreview.com/news/425970/who-coined-cloud-computing/),” *technologyreview.com*, October 31, 2011.
1. Luiz André Barroso, Jimmy Clidaras, and Urs Hölzle:
“[The Datacenter as a Computer: An Introduction to the Design of Warehouse-Scale Machines, Second Edition](http://www.morganclaypool.com/doi/abs/10.2200/S00516ED2V01Y201306CAC024),”
*Synthesis Lectures on Computer Architecture*, volume 8, number 3,
Morgan & Claypool Publishers, July 2013.
[doi:10.2200/S00516ED2V01Y201306CAC024](http://dx.doi.org/10.2200/S00516ED2V01Y201306CAC024),
ISBN: 978-1-627-05010-4
1. David Fiala, Frank Mueller, Christian Engelmann, et al.:
“[Detection and Correction of Silent Data Corruption for Large-Scale High-Performance Computing](http://moss.csc.ncsu.edu/~mueller/ftp/pub/mueller/papers/sc12.pdf),” at
*International Conference for High Performance Computing, Networking, Storage and
Analysis* (SC12), November 2012.
1. Arjun Singh, Joon Ong, Amit Agarwal, et al.:
“[Jupiter Rising: A Decade of Clos Topologies and Centralized Control in Googles Datacenter Network](http://conferences.sigcomm.org/sigcomm/2015/pdf/papers/p183.pdf),” at
*Annual Conference of the ACM Special Interest Group on Data Communication* (SIGCOMM), August 2015.
[doi:10.1145/2785956.2787508](http://dx.doi.org/10.1145/2785956.2787508)
1. Glenn K. Lockwood:
“[Hadoop's Uncomfortable Fit in HPC](http://glennklockwood.blogspot.co.uk/2014/05/hadoops-uncomfortable-fit-in-hpc.html),” *glennklockwood.blogspot.co.uk*, May 16, 2014.
1. John von Neumann:
“[Probabilistic Logics and the Synthesis of Reliable Organisms from Unreliable Components](https://ece.uwaterloo.ca/~ssundara/courses/prob_logics.pdf),” in *Automata Studies (AM-34)*,
edited by Claude E. Shannon and John McCarthy, Princeton University Press, 1956.
ISBN: 978-0-691-07916-5
1. Richard W. Hamming:
*The Art of Doing Science and Engineering*. Taylor & Francis, 1997.
ISBN: 978-9-056-99500-3
1. Claude E. Shannon:
“[A Mathematical Theory of Communication](http://cs.brynmawr.edu/Courses/cs380/fall2012/shannon1948.pdf),” *The Bell System Technical Journal*, volume 27, number 3,
pages 379423 and 623656, July 1948.
1. Peter Bailis and Kyle Kingsbury:
“[The Network Is Reliable](https://queue.acm.org/detail.cfm?id=2655736),”
*ACM Queue*, volume 12, number 7, pages 48-55, July 2014.
[doi:10.1145/2639988.2639988](http://dx.doi.org/10.1145/2639988.2639988)
1. Joshua B. Leners, Trinabh Gupta, Marcos K. Aguilera, and Michael Walfish:
“[Taming Uncertainty in Distributed Systems with Help from the Network](http://www.cs.nyu.edu/~mwalfish/papers/albatross-eurosys15.pdf),” at *10th European Conference on
Computer Systems* (EuroSys), April 2015.
[doi:10.1145/2741948.2741976](http://dx.doi.org/10.1145/2741948.2741976)
1. Phillipa Gill, Navendu Jain, and Nachiappan Nagappan:
“[Understanding Network Failures in Data Centers: Measurement, Analysis, and Implications](http://conferences.sigcomm.org/sigcomm/2011/papers/sigcomm/p350.pdf),” at
*ACM SIGCOMM Conference*, August 2011.
[doi:10.1145/2018436.2018477](http://dx.doi.org/10.1145/2018436.2018477)
1. Mark Imbriaco:
“[Downtime Last Saturday](https://github.com/blog/1364-downtime-last-saturday),”
*github.com*, December 26, 2012.
1. Will Oremus:
“[The Global Internet Is Being Attacked by Sharks, Google Confirms](http://www.slate.com/blogs/future_tense/2014/08/15/shark_attacks_threaten_google_s_undersea_internet_cables_video.html),” *slate.com*, August 15,
2014.
1. Marc A. Donges:
“[Re: bnx2 cards Intermittantly Going Offline](http://www.spinics.net/lists/netdev/msg210485.html),” Message to Linux *netdev* mailing list, *spinics.net*, September 13, 2012.
1. Kyle Kingsbury:
“[Call Me Maybe: Elasticsearch](https://aphyr.com/posts/317-call-me-maybe-elasticsearch),” *aphyr.com*, June 15, 2014.
1. Salvatore Sanfilippo:
“[A Few Arguments About Redis Sentinel Properties and Fail Scenarios](http://antirez.com/news/80),” *antirez.com*, October 21, 2014.
1. Bert Hubert:
“[The Ultimate SO_LINGER Page, or: Why Is My TCP Not Reliable](http://blog.netherlabs.nl/articles/2009/01/18/the-ultimate-so_linger-page-or-why-is-my-tcp-not-reliable),” *blog.netherlabs.nl*, January 18, 2009.
1. Nicolas Liochon:
“[CAP: If All You Have Is a Timeout, Everything Looks Like a Partition](http://blog.thislongrun.com/2015/05/CAP-theorem-partition-timeout-zookeeper.html),” *blog.thislongrun.com*,
May 25, 2015.
1. Jerome H. Saltzer, David P. Reed, and
David D. Clark: “[End-To-End Arguments in System Design](http://www.ece.drexel.edu/courses/ECE-C631-501/SalRee1984.pdf),” *ACM Transactions on Computer Systems*, volume 2, number 4,
pages 277288, November 1984.
[doi:10.1145/357401.357402](http://dx.doi.org/10.1145/357401.357402)
1. Matthew P. Grosvenor, Malte Schwarzkopf, Ionel Gog, et al.:
“[Queues Dont Matter When You Can JUMP Them!](https://www.usenix.org/system/files/conference/nsdi15/nsdi15-paper-grosvenor_update.pdf),” at *12th USENIX Symposium on Networked
Systems Design and Implementation* (NSDI), May 2015.
1. Guohui Wang and T. S. Eugene Ng:
“[The Impact of Virtualization on Network Performance of Amazon EC2 Data Center](http://www.cs.rice.edu/~eugeneng/papers/INFOCOM10-ec2.pdf),” at *29th IEEE
International Conference on Computer Communications* (INFOCOM), March 2010.
[doi:10.1109/INFCOM.2010.5461931](http://dx.doi.org/10.1109/INFCOM.2010.5461931)
1. Van Jacobson:
“[Congestion Avoidance and Control](http://www.cs.usask.ca/ftp/pub/discus/seminars2002-2003/p314-jacobson.pdf),” at *ACM Symposium on Communications Architectures and
Protocols* (SIGCOMM), August 1988.
[doi:10.1145/52324.52356](http://dx.doi.org/10.1145/52324.52356)
1. Brandon Philips:
“[etcd: Distributed Locking and Service Discovery](https://www.youtube.com/watch?v=HJIjTTHWYnE),” at *Strange Loop*, September 2014.
1. Steve Newman:
“[A Systematic Look at EC2 I/O](http://blog.scalyr.com/2012/10/a-systematic-look-at-ec2-io/),” *blog.scalyr.com*, October 16, 2012.
1. Naohiro Hayashibara, Xavier Défago, Rami Yared, and
Takuya Katayama: “[The ϕ Accrual Failure Detector](http://hdl.handle.net/10119/4784),” Japan Advanced Institute of Science and Technology, School of Information
Science, Technical Report IS-RR-2004-010, May 2004.
1. Jeffrey Wang:
“[Phi Accrual Failure Detector](http://ternarysearch.blogspot.co.uk/2013/08/phi-accrual-failure-detector.html),” *ternarysearch.blogspot.co.uk*, August 11, 2013.
1. Srinivasan Keshav: *An Engineering Approach
to Computer Networking: ATM Networks, the Internet, and the Telephone Network*.
Addison-Wesley Professional, May 1997. ISBN: 978-0-201-63442-6
1. Cisco, “[Integrated Services Digital Network](http://docwiki.cisco.com/wiki/Integrated_Services_Digital_Network),” *docwiki.cisco.com*.
1. Othmar Kyas: *ATM Networks*.
International Thomson Publishing, 1995. ISBN: 978-1-850-32128-6
1. “[InfiniBand FAQ](http://www.mellanox.com/related-docs/whitepapers/InfiniBandFAQ_FQ_100.pdf),” Mellanox Technologies, December 22, 2014.
1. Jose Renato Santos, Yoshio Turner, and G. (John) Janakiraman:
“[End-to-End Congestion Control for InfiniBand](http://www.hpl.hp.com/techreports/2002/HPL-2002-359.pdf),” at *22nd Annual Joint Conference of the IEEE Computer and
Communications Societies* (INFOCOM), April 2003. Also published by HP Laboratories Palo
Alto, Tech Report HPL-2002-359.
[doi:10.1109/INFCOM.2003.1208949](http://dx.doi.org/10.1109/INFCOM.2003.1208949)
1. Ulrich Windl, David Dalton, Marc Martinec, and Dale R. Worley:
“[The NTP FAQ and HOWTO](http://www.ntp.org/ntpfaq/NTP-a-faq.htm),” *ntp.org*,
November 2006.
1. John Graham-Cumming:
“[How and why the leap second affected Cloudflare DNS](https://blog.cloudflare.com/how-and-why-the-leap-second-affected-cloudflare-dns/),” *blog.cloudflare.com*, January 1, 2017.
1. David Holmes:
“[Inside the Hotspot VM: Clocks, Timers and Scheduling Events Part I Windows](https://blogs.oracle.com/dholmes/entry/inside_the_hotspot_vm_clocks),” *blogs.oracle.com*,
October 2, 2006.
1. Steve Loughran:
“[Time on Multi-Core, Multi-Socket Servers](http://steveloughran.blogspot.co.uk/2015/09/time-on-multi-core-multi-socket-servers.html),” *steveloughran.blogspot.co.uk*, September 17, 2015.
1. James C. Corbett, Jeffrey Dean, Michael Epstein, et al.:
“[Spanner: Googles Globally-Distributed Database](http://research.google.com/archive/spanner.html),” at *10th USENIX Symposium on Operating System Design and
Implementation* (OSDI), October 2012.
1. M. Caporaloni and R. Ambrosini:
“[How Closely Can a Personal Computer Clock Track the UTC Timescale Via the Internet?](https://iopscience.iop.org/0143-0807/23/4/103/),” *European Journal of
Physics*, volume 23, number 4, pages L17L21, June 2012.
[doi:10.1088/0143-0807/23/4/103](http://dx.doi.org/10.1088/0143-0807/23/4/103)
1. Nelson Minar:
“[A Survey of the NTP Network](http://alumni.media.mit.edu/~nelson/research/ntp-survey99/),”
*alumni.media.mit.edu*, December 1999.
1. Viliam Holub:
“[Synchronizing Clocks in a Cassandra Cluster Pt. 1 The Problem](https://blog.logentries.com/2014/03/synchronizing-clocks-in-a-cassandra-cluster-pt-1-the-problem/),” *blog.logentries.com*, March 14, 2014.
1. Poul-Henning Kamp:
“[The One-Second War (What Time Will You Die?)](http://queue.acm.org/detail.cfm?id=1967009),” *ACM Queue*, volume 9, number 4, pages 4448, April 2011.
[doi:10.1145/1966989.1967009](http://dx.doi.org/10.1145/1966989.1967009)
1. Nelson Minar:
“[Leap Second Crashes Half the Internet](http://www.somebits.com/weblog/tech/bad/leap-second-2012.html),” *somebits.com*, July 3, 2012.
1. Christopher Pascoe:
“[Time, Technology and Leaping Seconds](http://googleblog.blogspot.co.uk/2011/09/time-technology-and-leaping-seconds.html),” *googleblog.blogspot.co.uk*, September 15, 2011.
1. Mingxue Zhao and Jeff Barr:
“[Look Before You Leap The Coming Leap Second and AWS](https://aws.amazon.com/blogs/aws/look-before-you-leap-the-coming-leap-second-and-aws/),” *aws.amazon.com*, May 18, 2015.
1. Darryl Veitch and Kanthaiah Vijayalayan:
“[Network Timing and the 2015 Leap Second](http://crin.eng.uts.edu.au/~darryl/Publications/LeapSecond_camera.pdf),” at *17th International Conference on Passive and Active
Measurement* (PAM), April 2016.
[doi:10.1007/978-3-319-30505-9_29](http://dx.doi.org/10.1007/978-3-319-30505-9_29)
1. “[Timekeeping in VMware Virtual Machines](http://www.vmware.com/resources/techresources/238),” Information Guide, VMware, Inc., December 2011.
1. “[MiFID II / MiFIR: Regulatory Technical and Implementing Standards Annex I (Draft)](https://www.esma.europa.eu/sites/default/files/library/2015/11/2015-esma-1464_annex_i_-_draft_rts_and_its_on_mifid_ii_and_mifir.pdf),”
European Securities and Markets Authority, Report ESMA/2015/1464, September 2015.
1. Luke Bigum:
“[Solving MiFID II Clock Synchronisation With Minimum Spend (Part 1)](https://www.lmax.com/blog/staff-blogs/2015/11/27/solving-mifid-ii-clock-synchronisation-minimum-spend-part-1/),” *lmax.com*, November 27, 2015.
1. Kyle Kingsbury:
“[Call Me Maybe: Cassandra](https://aphyr.com/posts/294-call-me-maybe-cassandra/),” *aphyr.com*, September 24, 2013.
1. John Daily:
“[Clocks Are Bad, or, Welcome to the Wonderful World of Distributed Systems](http://basho.com/clocks-are-bad-or-welcome-to-distributed-systems/),” *basho.com*,
November 12, 2013.
1. Kyle Kingsbury:
“[The Trouble with Timestamps](https://aphyr.com/posts/299-the-trouble-with-timestamps),” *aphyr.com*, October 12, 2013.
1. Leslie Lamport:
“[Time, Clocks, and the Ordering of Events in a Distributed System](http://research.microsoft.com/en-US/um/people/Lamport/pubs/time-clocks.pdf),” *Communications of the ACM*, volume
21, number 7, pages 558565, July 1978.
[doi:10.1145/359545.359563](http://dx.doi.org/10.1145/359545.359563)
1. Sandeep Kulkarni, Murat Demirbas, Deepak Madeppa, et al.:
“[Logical Physical Clocks and Consistent Snapshots in Globally Distributed Databases](http://www.cse.buffalo.edu/tech-reports/2014-04.pdf),” State University of New York at
Buffalo, Computer Science and Engineering Technical Report 2014-04, May 2014.
1. Justin Sheehy:
“[There Is No Now: Problems With Simultaneity in Distributed Systems](https://queue.acm.org/detail.cfm?id=2745385),” *ACM Queue*, volume 13, number 3, pages 3641, March 2015.
[doi:10.1145/2733108](http://dx.doi.org/10.1145/2733108)
1. Murat Demirbas:
“[Spanner: Google's Globally-Distributed Database](http://muratbuffalo.blogspot.co.uk/2013/07/spanner-googles-globally-distributed_4.html),” *muratbuffalo.blogspot.co.uk*, July 4, 2013.
1. Dahlia Malkhi and Jean-Philippe Martin:
“[Spanner's Concurrency Control](http://www.cs.cornell.edu/~ie53/publications/DC-col51-Sep13.pdf),” *ACM SIGACT News*, volume 44, number 3, pages 7377, September 2013.
[doi:10.1145/2527748.2527767](http://dx.doi.org/10.1145/2527748.2527767)
1. Manuel Bravo, Nuno Diegues, Jingna Zeng, et al.:
“[On the Use of Clocks to Enforce Consistency in the Cloud](http://sites.computer.org/debull/A15mar/p18.pdf),” *IEEE Data Engineering Bulletin*,
volume 38, number 1, pages 1831, March 2015.
1. Spencer Kimball:
“[Living Without Atomic Clocks](http://www.cockroachlabs.com/blog/living-without-atomic-clocks/),” *cockroachlabs.com*, February 17, 2016.
1. Cary G. Gray and David R. Cheriton:
“[Leases: An Efficient Fault-Tolerant Mechanism for Distributed File Cache Consistency](http://web.stanford.edu/class/cs240/readings/89-leases.pdf),” at
*12th ACM Symposium on Operating Systems Principles* (SOSP), December 1989.
[doi:10.1145/74850.74870](http://dx.doi.org/10.1145/74850.74870)
1. Todd Lipcon:
“[Avoiding Full GCs in Apache HBase with MemStore-Local Allocation Buffers: Part 1](http://blog.cloudera.com/blog/2011/02/avoiding-full-gcs-in-hbase-with-memstore-local-allocation-buffers-part-1/),”
*blog.cloudera.com*, February 24, 2011.
1. Martin Thompson:
“[Java Garbage Collection Distilled](http://mechanical-sympathy.blogspot.co.uk/2013/07/java-garbage-collection-distilled.html),” *mechanical-sympathy.blogspot.co.uk*, July 16, 2013.
1. Alexey Ragozin:
“[How to Tame Java GC Pauses? Surviving 16GiB Heap and Greater](http://java.dzone.com/articles/how-tame-java-gc-pauses),” *java.dzone.com*, June 28, 2011.
1. Christopher Clark, Keir Fraser, Steven Hand, et al.:
“[Live Migration of Virtual Machines](http://www.cl.cam.ac.uk/research/srg/netos/papers/2005-nsdi-migration.pdf),” at *2nd USENIX Symposium on Symposium on
Networked Systems Design & Implementation* (NSDI), May 2005.
1. Mike Shaver:
“[fsyncers and Curveballs](http://shaver.off.net/diary/2008/05/25/fsyncers-and-curveballs/),” *shaver.off.net*, May 25, 2008.
1. Zhenyun Zhuang and Cuong Tran:
“[Eliminating Large JVM GC Pauses Caused by Background IO Traffic](https://engineering.linkedin.com/blog/2016/02/eliminating-large-jvm-gc-pauses-caused-by-background-io-traffic),” *engineering.linkedin.com*, February 10,
2016.
1. David Terei and Amit Levy:
“[Blade: A Data Center Garbage Collector](http://arxiv.org/pdf/1504.02578.pdf),”
arXiv:1504.02578, April 13, 2015.
1. Martin Maas, Tim Harris, Krste Asanović, and John Kubiatowicz:
“[Trash Day: Coordinating Garbage Collection in Distributed Systems](https://timharris.uk/papers/2015-hotos.pdf),” at *15th USENIX Workshop on Hot Topics in Operating
Systems* (HotOS), May 2015.
1. “[Predictable Low Latency](http://cdn2.hubspot.net/hubfs/1624455/Website_2016/content/White%20papers/Cinnober%20on%20GC%20pause%20free%20Java%20applications.pdf),” Cinnober Financial Technology AB, *cinnober.com*, November 24, 2013.
1. Martin Fowler:
“[The LMAX Architecture](http://martinfowler.com/articles/lmax.html),”
*martinfowler.com*, July 12, 2011.
1. Flavio P. Junqueira and Benjamin Reed:
*ZooKeeper: Distributed Process Coordination*. O'Reilly Media, 2013.
ISBN: 978-1-449-36130-3
1. Enis Söztutar:
“[HBase and HDFS: Understanding Filesystem Usage in HBase](http://www.slideshare.net/enissoz/hbase-and-hdfs-understanding-filesystem-usage),” at *HBaseCon*,
June 2013.
1. Caitie McCaffrey:
“[Clients Are Jerks: AKA How Halo 4 DoSed the Services at Launch & How We Survived](http://caitiem.com/2015/06/23/clients-are-jerks-aka-how-halo-4-dosed-the-services-at-launch-how-we-survived/),” *caitiem.com*,
June 23, 2015.
1. Leslie Lamport, Robert Shostak, and Marshall Pease:
“[The Byzantine Generals Problem](http://research.microsoft.com/en-us/um/people/lamport/pubs/byz.pdf),” *ACM Transactions on Programming Languages and
Systems* (TOPLAS), volume 4, number 3, pages 382401, July 1982.
[doi:10.1145/357172.357176](http://dx.doi.org/10.1145/357172.357176)
1. Jim N. Gray:
“[Notes on Data Base Operating Systems](http://research.microsoft.com/en-us/um/people/gray/papers/DBOS.pdf),” in *Operating Systems: An Advanced Course*, Lecture
Notes in Computer Science, volume 60, edited by R. Bayer, R. M. Graham, and G. Seegmüller,
pages 393481, Springer-Verlag, 1978. ISBN: 978-3-540-08755-7
1. Brian Palmer:
“[How Complicated Was the Byzantine Empire?](http://www.slate.com/articles/news_and_politics/explainer/2011/10/the_byzantine_tax_code_how_complicated_was_byzantium_anyway_.html),” *slate.com*, October 20, 2011.
1. Leslie Lamport:
“[My Writings](http://research.microsoft.com/en-us/um/people/lamport/pubs/pubs.html),” *research.microsoft.com*, December 16, 2014. This page can be found by searching the
web for the 23-character string obtained by removing the hyphens from the string
<code>allla-mport-spubso-ntheweb</code>.
1. John Rushby:
“[Bus Architectures for Safety-Critical Embedded Systems](http://www.csl.sri.com/papers/emsoft01/emsoft01.pdf),” at *1st International Workshop on Embedded Software*
(EMSOFT), October 2001.
1. Jake Edge:
“[ELC: SpaceX Lessons Learned](http://lwn.net/Articles/540368/),” *lwn.net*,
March 6, 2013.
1. Andrew Miller and Joseph J. LaViola, Jr.:
“[Anonymous Byzantine Consensus from Moderately-Hard Puzzles: A Model for Bitcoin](http://nakamotoinstitute.org/static/docs/anonymous-byzantine-consensus.pdf),” University of Central
Florida, Technical Report CS-TR-14-01, April 2014.
1. James Mickens:
“[The Saddest Moment](https://www.usenix.org/system/files/login-logout_1305_mickens.pdf),” *USENIX ;login: logout*, May 2013.
1. Evan Gilman:
“[The Discovery of Apache ZooKeepers Poison Packet](http://www.pagerduty.com/blog/the-discovery-of-apache-zookeepers-poison-packet/),” *pagerduty.com*, May 7, 2015.
1. Jonathan Stone and Craig Partridge:
“[When the CRC and TCP Checksum Disagree](http://citeseerx.ist.psu.edu/viewdoc/download?doi=10.1.1.27.7611&rep=rep1&type=pdf),” at *ACM Conference on Applications,
Technologies, Architectures, and Protocols for Computer Communication* (SIGCOMM), August 2000.
[doi:10.1145/347059.347561](http://dx.doi.org/10.1145/347059.347561)
1. Evan Jones:
“[How Both TCP and Ethernet Checksums Fail](http://www.evanjones.ca/tcp-and-ethernet-checksums-fail.html),” *evanjones.ca*, October 5, 2015.
1. Cynthia Dwork, Nancy Lynch, and Larry Stockmeyer:
“[Consensus in the Presence of Partial Synchrony](http://www.net.t-labs.tu-berlin.de/~petr/ADC-07/papers/DLS88.pdf),” *Journal of the ACM*, volume 35, number 2, pages 288323,
April 1988. [doi:10.1145/42282.42283](http://dx.doi.org/10.1145/42282.42283)
1. Peter Bailis and Ali Ghodsi:
“[Eventual Consistency Today: Limitations, Extensions, and Beyond](http://queue.acm.org/detail.cfm?id=2462076),” *ACM Queue*, volume 11, number 3, pages 55-63, March 2013.
[doi:10.1145/2460276.2462076](http://dx.doi.org/10.1145/2460276.2462076)
1. Bowen Alpern and Fred B. Schneider:
“[Defining Liveness](https://www.cs.cornell.edu/fbs/publications/DefLiveness.pdf),”
*Information Processing Letters*, volume 21, number 4, pages 181185, October 1985.
[doi:10.1016/0020-0190(85)90056-0](http://dx.doi.org/10.1016/0020-0190(85)90056-0)
1. Flavio P. Junqueira:
“[Dude, Wheres My Metadata?](http://fpj.me/2015/05/28/dude-wheres-my-metadata/),”
*fpj.me*, May 28, 2015.
1. Scott Sanders:
“[January 28th Incident Report](https://github.com/blog/2106-january-28th-incident-report),” *github.com*, February 3, 2016.
1. Jay Kreps:
“[A Few Notes on Kafka and Jepsen](http://blog.empathybox.com/post/62279088548/a-few-notes-on-kafka-and-jepsen),” *blog.empathybox.com*, September 25, 2013.
1. Thanh Do, Mingzhe Hao, Tanakorn
Leesatapornwongsa, et al.:
“[Limplock: Understanding the Impact of Limpware on Scale-out Cloud Systems](http://ucare.cs.uchicago.edu/pdf/socc13-limplock.pdf),” at *4th ACM Symposium on Cloud Computing*
(SoCC), October 2013.
[doi:10.1145/2523616.2523627](http://dx.doi.org/10.1145/2523616.2523627)
1. Frank McSherry, Michael Isard, and Derek G. Murray:
“[Scalability! But at What COST?](http://www.frankmcsherry.org/assets/COST.pdf),”
at *15th USENIX Workshop on Hot Topics in Operating Systems* (HotOS),
May 2015.
![](img/fig8-1.png)
图8-1
![](img/fig8-2.png)
图8-2
![](img/fig8-3.png)
图8-3
![](img/fig8-4.png)
图8-4
![](img/fig8-5.png)
图8-5

506
ddia/ch9.md Normal file
View File

@ -0,0 +1,506 @@
# 9. 一致性与共识
![](img/ch9.png)
> 好死不如赖活着
> —— Jay Kreps, 关于Kafka与 Jepsen的若干笔记 (2013)
---------------
## 一致性保证
## 线性一致性
## 顺序保证
## 分布式事务与共识
## 本章小结
## 参考文献
1. Peter Bailis and Ali Ghodsi:
“[Eventual Consistency Today: Limitations, Extensions, and Beyond](http://queue.acm.org/detail.cfm?id=2462076),” *ACM Queue*, volume 11, number 3, pages 55-63, March 2013.
[doi:10.1145/2460276.2462076](http://dx.doi.org/10.1145/2460276.2462076)
1. Prince Mahajan, Lorenzo Alvisi, and Mike Dahlin:
“[Consistency, Availability, and Convergence](http://apps.cs.utexas.edu/tech_reports/reports/tr/TR-2036.pdf),” University of Texas at Austin, Department of Computer
Science, Tech Report UTCS TR-11-22, May 2011.
1. Alex Scotti:
“[Adventures in Building Your Own Database](http://www.slideshare.net/AlexScotti1/allyourbase-55212398),” at *All Your Base*, November 2015.
1. Peter Bailis, Aaron Davidson, Alan Fekete, et al.:
“[Highly Available Transactions: Virtues and Limitations](http://arxiv.org/pdf/1302.0309.pdf),” at *40th International Conference on Very Large Data Bases* (VLDB),
September 2014. Extended version published as pre-print arXiv:1302.0309 &#91;cs.DB&#93;.
1. Paolo Viotti and Marko Vukolić:
“[Consistency in Non-Transactional Distributed Storage Systems](http://arxiv.org/abs/1512.00168),” arXiv:1512.00168, 12 April 2016.
1. Maurice P. Herlihy and Jeannette M. Wing:
“[Linearizability: A Correctness Condition for Concurrent Objects](http://cs.brown.edu/~mph/HerlihyW90/p463-herlihy.pdf),” *ACM Transactions on Programming
Languages and Systems* (TOPLAS), volume 12, number 3, pages 463492, July 1990.
[doi:10.1145/78969.78972](http://dx.doi.org/10.1145/78969.78972)
1. Leslie Lamport:
“[On interprocess communication](http://research.microsoft.com/en-us/um/people/lamport/pubs/interprocess.pdf),” *Distributed Computing*, volume 1, number 2, pages 77101,
June 1986. [doi:10.1007/BF01786228](http://dx.doi.org/10.1007/BF01786228)
1. David K. Gifford:
“[Information Storage in a Decentralized Computer System](http://www.mirrorservice.org/sites/www.bitsavers.org/pdf/xerox/parc/techReports/CSL-81-8_Information_Storage_in_a_Decentralized_Computer_System.pdf),” Xerox Palo Alto Research Centers, CSL-81-8, June 1981.
1. Martin Kleppmann:
“[Please Stop Calling Databases CP or AP](http://martin.kleppmann.com/2015/05/11/please-stop-calling-databases-cp-or-ap.html),” *martin.kleppmann.com*, May 11, 2015.
1. Kyle Kingsbury:
“[Call Me Maybe: MongoDB Stale Reads](https://aphyr.com/posts/322-call-me-maybe-mongodb-stale-reads),” *aphyr.com*, April 20, 2015.
1. Kyle Kingsbury:
“[Computational Techniques in Knossos](https://aphyr.com/posts/314-computational-techniques-in-knossos),” *aphyr.com*, May 17, 2014.
1. Peter Bailis:
“[Linearizability Versus Serializability](http://www.bailis.org/blog/linearizability-versus-serializability/),” *bailis.org*, September 24, 2014.
1. Philip A. Bernstein, Vassos Hadzilacos, and Nathan Goodman:
<a href="http://research.microsoft.com/en-us/people/philbe/ccontrol.aspx">*Concurrency
Control and Recovery in Database Systems*</a>. Addison-Wesley, 1987. ISBN: 978-0-201-10715-9,
available online at *research.microsoft.com*.
1. Mike Burrows:
“[The Chubby Lock Service for Loosely-Coupled Distributed Systems](http://research.google.com/archive/chubby.html),” at *7th USENIX Symposium on Operating System
Design and Implementation* (OSDI), November 2006.
1. Flavio P. Junqueira and Benjamin Reed:
*ZooKeeper: Distributed Process Coordination*. O'Reilly Media, 2013.
ISBN: 978-1-449-36130-3
1. “[etcd 2.0.12 Documentation](https://coreos.com/etcd/docs/2.0.12/),” CoreOS, Inc., 2015.
1. “[Apache Curator](http://curator.apache.org/),” Apache Software Foundation, *curator.apache.org*, 2015.
1. Morali Vallath:
*Oracle 10g RAC Grid, Services & Clustering*. Elsevier Digital Press, 2006.
ISBN: 978-1-555-58321-7
1. Peter Bailis, Alan Fekete, Michael J Franklin, et al.:
“[Coordination-Avoiding Database Systems](http://arxiv.org/pdf/1402.2237.pdf),”
*Proceedings of the VLDB Endowment*, volume 8, number 3, pages 185196, November 2014.
1. Kyle Kingsbury:
“[Call Me Maybe: etcd and Consul](https://aphyr.com/posts/316-call-me-maybe-etcd-and-consul),” *aphyr.com*, June 9, 2014.
1. Flavio P. Junqueira, Benjamin C. Reed, and Marco Serafini:
“[Zab: High-Performance Broadcast for Primary-Backup Systems](https://pdfs.semanticscholar.org/b02c/6b00bd5dbdbd951fddb00b906c82fa80f0b3.pdf),” at *41st IEEE International Conference on Dependable
Systems and Networks* (DSN), June 2011.
[doi:10.1109/DSN.2011.5958223](http://dx.doi.org/10.1109/DSN.2011.5958223)
1. Diego Ongaro and John K. Ousterhout:
“[In Search of an Understandable Consensus Algorithm (Extended Version)](http://ramcloud.stanford.edu/raft.pdf),” at *USENIX Annual Technical Conference*
(ATC), June 2014.
1. Hagit Attiya, Amotz Bar-Noy, and Danny Dolev:
“[Sharing Memory Robustly in Message-Passing Systems](http://www.cse.huji.ac.il/course/2004/dist/p124-attiya.pdf),” *Journal of the ACM*, volume 42, number 1, pages 124142, January 1995.
[doi:10.1145/200836.200869](http://dx.doi.org/10.1145/200836.200869)
1. Nancy Lynch and Alex Shvartsman:
“[Robust Emulation of Shared Memory Using Dynamic Quorum-Acknowledged Broadcasts](http://groups.csail.mit.edu/tds/papers/Lynch/FTCS97.pdf),” at *27th Annual International Symposium on
Fault-Tolerant Computing* (FTCS), June 1997.
[doi:10.1109/FTCS.1997.614100](http://dx.doi.org/10.1109/FTCS.1997.614100)
1. Christian Cachin, Rachid Guerraoui, and Luís Rodrigues:
<a href="http://www.distributedprogramming.net/">*Introduction to Reliable and Secure Distributed
Programming*</a>, 2nd edition. Springer, 2011. ISBN: 978-3-642-15259-7,
[doi:10.1007/978-3-642-15260-3](http://dx.doi.org/10.1007/978-3-642-15260-3)
1. Sam Elliott, Mark Allen, and Martin Kleppmann:
[personal communication](https://twitter.com/lenary/status/654761711933648896),
thread on *twitter.com*, October 15, 2015.
1. Niklas Ekström, Mikhail Panchenko, and Jonathan Ellis:
“[Possible Issue with Read Repair?](http://mail-archives.apache.org/mod_mbox/cassandra-dev/201210.mbox/%3CFA480D1DC3964E2C8B0A14E0880094C9%40Robotech%3E),” email thread on *cassandra-dev* mailing list, October 2012.
1. Maurice P. Herlihy:
“[Wait-Free Synchronization](https://cs.brown.edu/~mph/Herlihy91/p124-herlihy.pdf),”
*ACM Transactions on Programming Languages and Systems* (TOPLAS), volume 13, number 1,
pages 124149, January 1991.
[doi:10.1145/114005.102808](http://dx.doi.org/10.1145/114005.102808)
1. Armando Fox and Eric A. Brewer:
“[Harvest, Yield, and Scalable Tolerant Systems](http://radlab.cs.berkeley.edu/people/fox/static/pubs/pdf/c18.pdf),” at *7th Workshop on Hot Topics in Operating
Systems* (HotOS), March 1999.
[doi:10.1109/HOTOS.1999.798396](http://dx.doi.org/10.1109/HOTOS.1999.798396)
1. Seth Gilbert and Nancy Lynch:
“[Brewers Conjecture and the Feasibility of Consistent, Available, Partition-Tolerant Web Services](http://www.comp.nus.edu.sg/~gilbert/pubs/BrewersConjecture-SigAct.pdf),”
*ACM SIGACT News*, volume 33, number 2, pages 5159, June 2002.
[doi:10.1145/564585.564601](http://dx.doi.org/10.1145/564585.564601)
1. Seth Gilbert and Nancy Lynch:
“[Perspectives on the CAP Theorem](http://groups.csail.mit.edu/tds/papers/Gilbert/Brewer2.pdf),” *IEEE Computer Magazine*, volume 45, number 2, pages 3036, February 2012.
[doi:10.1109/MC.2011.389](http://dx.doi.org/10.1109/MC.2011.389)
1. Eric A. Brewer:
“[CAP Twelve Years Later: How the 'Rules' Have Changed](http://cs609.cs.ua.edu/CAP12.pdf),” *IEEE Computer Magazine*, volume 45, number 2, pages 2329, February 2012.
[doi:10.1109/MC.2012.37](http://dx.doi.org/10.1109/MC.2012.37)
1. Susan B. Davidson, Hector Garcia-Molina, and Dale Skeen:
“[Consistency in Partitioned Networks](http://delab.csd.auth.gr/~dimitris/courses/mpc_fall05/papers/invalidation/acm_csur85_partitioned_network_consistency.pdf),” *ACM Computing Surveys*, volume 17, number 3, pages 341370, September 1985.
[doi:10.1145/5505.5508](http://dx.doi.org/10.1145/5505.5508)
1. Paul R. Johnson and Robert H. Thomas:
“[RFC 677: The Maintenance of Duplicate Databases](https://tools.ietf.org/html/rfc677),” Network Working Group, January 27, 1975.
1. Bruce G. Lindsay, Patricia Griffiths Selinger, C. Galtieri, et al.:
“[Notes on Distributed Databases](http://domino.research.ibm.com/library/cyberdig.nsf/papers/A776EC17FC2FCE73852579F100578964/$File/RJ2571.pdf),” IBM Research, Research Report RJ2571(33471), July 1979.
1. Michael J. Fischer and Alan Michael:
“[Sacrificing Serializability to Attain High Availability of Data in an Unreliable Network](http://www.cs.ucsb.edu/~agrawal/spring2011/ugrad/p70-fischer.pdf),” at
*1st ACM Symposium on Principles of Database Systems* (PODS), March 1982.
[doi:10.1145/588111.588124](http://dx.doi.org/10.1145/588111.588124)
1. Eric A. Brewer:
“[NoSQL: Past, Present, Future](http://www.infoq.com/presentations/NoSQL-History),”
at *QCon San Francisco*, November 2012.
1. Henry Robinson:
“[CAP Confusion: Problems with 'Partition Tolerance,'](http://blog.cloudera.com/blog/2010/04/cap-confusion-problems-with-partition-tolerance/)” *blog.cloudera.com*, April 26, 2010.
1. Adrian Cockcroft:
“[Migrating to Microservices](http://www.infoq.com/presentations/migration-cloud-native),” at *QCon London*, March 2014.
1. Martin Kleppmann:
“[A Critique of the CAP Theorem](http://arxiv.org/abs/1509.05393),” arXiv:1509.05393,
September 17, 2015.
1. Nancy A. Lynch:
“[A Hundred Impossibility Proofs for Distributed Computing](http://groups.csail.mit.edu/tds/papers/Lynch/podc89.pdf),” at *8th ACM Symposium on Principles of Distributed
Computing* (PODC), August 1989.
[doi:10.1145/72981.72982](http://dx.doi.org/10.1145/72981.72982)
1. Hagit Attiya, Faith Ellen, and Adam Morrison:
“[Limitations of Highly-Available Eventually-Consistent Data Stores](http://www.cs.technion.ac.il/people/mad/online-publications/podc2015-replds.pdf),” at *ACM Symposium on Principles of
Distributed Computing* (PODC), July 2015.
[doi:10.1145/2767386.2767419](http://dx.doi.org/10.1145/2767386.2767419)
1. Peter Sewell, Susmit Sarkar,
Scott Owens, et al.:
“[x86-TSO: A Rigorous and Usable Programmer's Model for x86 Multiprocessors](http://www.cl.cam.ac.uk/~pes20/weakmemory/cacm.pdf),” *Communications of the ACM*,
volume 53, number 7, pages 8997, July 2010.
[doi:10.1145/1785414.1785443](http://dx.doi.org/10.1145/1785414.1785443)
1. Martin Thompson:
“[Memory Barriers/Fences](http://mechanical-sympathy.blogspot.co.uk/2011/07/memory-barriersfences.html),” *mechanical-sympathy.blogspot.co.uk*, July 24, 2011.
1. Ulrich Drepper:
“[What Every Programmer Should Know About Memory](http://www.akkadia.org/drepper/cpumemory.pdf),” *akkadia.org*, November 21, 2007.
1. Daniel J. Abadi:
“[Consistency Tradeoffs in Modern Distributed Database System Design](http://cs-www.cs.yale.edu/homes/dna/papers/abadi-pacelc.pdf),” *IEEE Computer Magazine*,
volume 45, number 2, pages 3742, February 2012.
[doi:10.1109/MC.2012.33](http://dx.doi.org/10.1109/MC.2012.33)
1. Hagit Attiya and Jennifer L. Welch:
“[Sequential Consistency Versus Linearizability](http://courses.csail.mit.edu/6.852/01/papers/p91-attiya.pdf),” *ACM Transactions on Computer Systems* (TOCS),
volume 12, number 2, pages 91122, May 1994.
[doi:10.1145/176575.176576](http://dx.doi.org/10.1145/176575.176576)
1. Mustaque Ahamad, Gil Neiger, James E. Burns, et al.:
“[Causal Memory: Definitions, Implementation, and Programming](http://www-i2.informatik.rwth-aachen.de/i2/fileadmin/user_upload/documents/Seminar_MCMM11/Causal_memory_1996.pdf),” *Distributed
Computing*, volume 9, number 1, pages 3749, March 1995.
[doi:10.1007/BF01784241](http://dx.doi.org/10.1007/BF01784241)
1. Wyatt Lloyd, Michael J. Freedman,
Michael Kaminsky, and David G. Andersen:
“[Stronger Semantics for Low-Latency Geo-Replicated Storage](https://www.usenix.org/system/files/conference/nsdi13/nsdi13-final149.pdf),” at *10th USENIX Symposium on Networked
Systems Design and Implementation* (NSDI), April 2013.
1. Marek Zawirski, Annette Bieniusa, Valter Balegas, et al.:
“[SwiftCloud: Fault-Tolerant Geo-Replication Integrated All the Way to the Client Machine](http://arxiv.org/abs/1310.3107),” INRIA Research Report 8347, August 2013.
1. Peter Bailis, Ali Ghodsi, Joseph M Hellerstein, and Ion Stoica:
“[Bolt-on Causal Consistency](http://db.cs.berkeley.edu/papers/sigmod13-bolton.pdf),” at
*ACM International Conference on Management of Data* (SIGMOD), June 2013.
1. Philippe Ajoux, Nathan Bronson, Sanjeev
Kumar, et al.:
“[Challenges to Adopting Stronger Consistency at Scale](https://www.usenix.org/system/files/conference/hotos15/hotos15-paper-ajoux.pdf),” at *15th USENIX Workshop on Hot Topics in
Operating Systems* (HotOS), May 2015.
1. Peter Bailis:
“[Causality Is Expensive (and What to Do About It)](http://www.bailis.org/blog/causality-is-expensive-and-what-to-do-about-it/),” *bailis.org*, February 5, 2014.
1. Ricardo Gonçalves, Paulo Sérgio Almeida,
Carlos Baquero, and Victor Fonte:
“[Concise Server-Wide Causality Management for Eventually Consistent Data Stores](http://haslab.uminho.pt/tome/files/global_logical_clocks.pdf),” at *15th IFIP International
Conference on Distributed Applications and Interoperable Systems* (DAIS), June 2015.
[doi:10.1007/978-3-319-19129-4_6](http://dx.doi.org/10.1007/978-3-319-19129-4_6)
1. Rob Conery:
“[A Better ID Generator for PostgreSQL](http://rob.conery.io/2014/05/29/a-better-id-generator-for-postgresql/),” *rob.conery.io*, May 29, 2014.
1. Leslie Lamport:
“[Time, Clocks, and the Ordering of Events in a Distributed System](http://research.microsoft.com/en-US/um/people/Lamport/pubs/time-clocks.pdf),” *Communications of the ACM*,
volume 21, number 7, pages 558565, July 1978.
[doi:10.1145/359545.359563](http://dx.doi.org/10.1145/359545.359563)
1. Xavier Défago, André Schiper, and Péter Urbán:
“[Total Order Broadcast and Multicast Algorithms: Taxonomy and Survey](https://dspace.jaist.ac.jp/dspace/bitstream/10119/4883/1/defago_et_al.pdf),” *ACM Computing
Surveys*, volume 36, number 4, pages 372421, December 2004.
[doi:10.1145/1041680.1041682](http://dx.doi.org/10.1145/1041680.1041682)
1. Hagit Attiya and Jennifer Welch: *Distributed
Computing: Fundamentals, Simulations and Advanced Topics*, 2nd edition.
John Wiley & Sons, 2004. ISBN: 978-0-471-45324-6,
[doi:10.1002/0471478210](http://dx.doi.org/10.1002/0471478210)
1. Mahesh
Balakrishnan, Dahlia Malkhi, Vijayan Prabhakaran, et al.:
“[CORFU: A Shared Log Design for Flash Clusters](https://www.usenix.org/system/files/conference/nsdi12/nsdi12-final30.pdf),” at *9th USENIX Symposium on Networked
Systems Design and Implementation* (NSDI), April 2012.
1. Fred B. Schneider:
“[Implementing Fault-Tolerant Services Using the State Machine Approach: A Tutorial](http://www.cs.cornell.edu/fbs/publications/smsurvey.pdf),” *ACM Computing Surveys*, volume
22, number 4, pages 299319, December 1990.
1. Alexander Thomson, Thaddeus Diamond, Shu-Chun Weng, et al.:
“[Calvin: Fast Distributed Transactions for Partitioned Database Systems](http://cs.yale.edu/homes/thomson/publications/calvin-sigmod12.pdf),” at *ACM International Conference
on Management of Data* (SIGMOD), May 2012.
1. Mahesh Balakrishnan, Dahlia Malkhi, Ted Wobber, et al.:
“[Tango: Distributed Data Structures over a Shared Log](http://research.microsoft.com/pubs/199947/Tango.pdf),” at *24th ACM Symposium on Operating Systems
Principles* (SOSP), November 2013.
[doi:10.1145/2517349.2522732](http://dx.doi.org/10.1145/2517349.2522732)
1. Robbert van Renesse and Fred B. Schneider:
“[Chain Replication for Supporting High Throughput and Availability](http://static.usenix.org/legacy/events/osdi04/tech/full_papers/renesse/renesse.pdf),” at *6th USENIX
Symposium on Operating System Design and Implementation* (OSDI), December 2004.
1. Leslie Lamport:
“[How to Make a Multiprocessor Computer That Correctly Executes Multiprocess Programs](http://research-srv.microsoft.com/en-us/um/people/lamport/pubs/multi.pdf),” *IEEE
Transactions on Computers*, volume 28, number 9, pages 690691, September 1979.
[doi:10.1109/TC.1979.1675439](http://dx.doi.org/10.1109/TC.1979.1675439)
1. Enis Söztutar, Devaraj Das, and Carter Shanklin:
“[Apache HBase High Availability at the Next Level](http://hortonworks.com/blog/apache-hbase-high-availability-next-level/),” *hortonworks.com*, January 22, 2015.
1. Brian F Cooper, Raghu Ramakrishnan, Utkarsh Srivastava, et al.:
“[PNUTS: Yahoo!s Hosted Data Serving Platform](http://www.mpi-sws.org/~druschel/courses/ds/papers/cooper-pnuts.pdf),” at *34th International Conference on Very Large Data
Bases* (VLDB), August 2008.
[doi:10.14778/1454159.1454167](http://dx.doi.org/10.14778/1454159.1454167)
1. Tushar Deepak Chandra and Sam Toueg:
“[Unreliable Failure Detectors for Reliable Distributed Systems](http://courses.csail.mit.edu/6.852/08/papers/CT96-JACM.pdf),” *Journal of the ACM*,
volume 43, number 2, pages 225267, March 1996.
[doi:10.1145/226643.226647](http://dx.doi.org/10.1145/226643.226647)
1. Michael J. Fischer, Nancy Lynch, and Michael S. Paterson:
“[Impossibility of Distributed Consensus with One Faulty Process](https://groups.csail.mit.edu/tds/papers/Lynch/jacm85.pdf),” *Journal of the ACM*, volume 32, number 2, pages 374382, April 1985.
[doi:10.1145/3149.214121](http://dx.doi.org/10.1145/3149.214121)
1. Michael Ben-Or: “Another Advantage of Free
Choice: Completely Asynchronous Agreement Protocols,” at *2nd ACM Symposium on Principles of
Distributed Computing* (PODC), August 1983.
[doi:10.1145/800221.806707](http://dl.acm.org/citation.cfm?id=806707)
1. Jim N. Gray and Leslie Lamport:
“[Consensus on Transaction Commit](http://db.cs.berkeley.edu/cs286/papers/paxoscommit-tods2006.pdf),” *ACM Transactions on Database Systems* (TODS), volume 31,
number 1, pages 133160, March 2006.
[doi:10.1145/1132863.1132867](http://dx.doi.org/10.1145/1132863.1132867)
1. Rachid Guerraoui:
“[Revisiting the Relationship Between Non-Blocking Atomic Commitment and Consensus](https://pdfs.semanticscholar.org/5d06/489503b6f791aa56d2d7942359c2592e44b0.pdf),” at *9th International
Workshop on Distributed Algorithms* (WDAG), September 1995.
[doi:10.1007/BFb0022140](http://dx.doi.org/10.1007/BFb0022140)
1. Thanumalayan Sankaranarayana Pillai, Vijay Chidambaram,
Ramnatthan Alagappan, et al.: “[All File Systems Are Not Created Equal: On the Complexity of Crafting Crash-Consistent Applications](http://research.cs.wisc.edu/wind/Publications/alice-osdi14.pdf),”
at *11th USENIX Symposium on Operating Systems Design and Implementation* (OSDI),
October 2014.
1. Jim Gray:
“[The Transaction Concept: Virtues and Limitations](http://research.microsoft.com/en-us/um/people/gray/papers/theTransactionConcept.pdf),” at *7th International Conference on
Very Large Data Bases* (VLDB), September 1981.
1. Hector Garcia-Molina and Kenneth Salem:
“[Sagas](http://www.cs.cornell.edu/andru/cs711/2002fa/reading/sagas.pdf),” at
*ACM International Conference on Management of Data* (SIGMOD), May 1987.
[doi:10.1145/38713.38742](http://dx.doi.org/10.1145/38713.38742)
1. C. Mohan, Bruce G. Lindsay, and Ron Obermarck:
“[Transaction Management in the R* Distributed Database Management System](https://cs.brown.edu/courses/csci2270/archives/2012/papers/dtxn/p378-mohan.pdf),”
*ACM Transactions on Database Systems*, volume 11, number 4, pages 378396, December 1986.
[doi:10.1145/7239.7266](http://dx.doi.org/10.1145/7239.7266)
1. “[Distributed Transaction Processing: The XA Specification](http://pubs.opengroup.org/onlinepubs/009680699/toc.pdf),” X/Open Company Ltd., Technical Standard
XO/CAE/91/300, December 1991. ISBN: 978-1-872-63024-3
1. Mike Spille:
“[XA Exposed, Part II](http://www.jroller.com/pyrasun/entry/xa_exposed_part_ii_schwartz),”
*jroller.com*, April 3, 2004.
1. Ivan Silva Neto and Francisco Reverbel:
“[Lessons Learned from Implementing WS-Coordination and WS-AtomicTransaction](http://www.ime.usp.br/~reverbel/papers/icis2008.pdf),” at *7th IEEE/ACIS International Conference on
Computer and Information Science* (ICIS), May 2008.
[doi:10.1109/ICIS.2008.75](http://dx.doi.org/10.1109/ICIS.2008.75)
1. James E. Johnson, David E. Langworthy, Leslie Lamport,
and Friedrich H. Vogt:
“[Formal Specification of a Web Services Protocol](http://research.microsoft.com/en-us/um/people/lamport/pubs/wsfm-web.pdf),” at *1st International Workshop on Web Services and
Formal Methods* (WS-FM), February 2004.
[doi:10.1016/j.entcs.2004.02.022](http://dx.doi.org/10.1016/j.entcs.2004.02.022)
1. Dale Skeen:
“[Nonblocking Commit Protocols](http://www.cs.utexas.edu/~lorenzo/corsi/cs380d/papers/Ske81.pdf),” at *ACM International Conference on Management of Data* (SIGMOD), April 1981.
[doi:10.1145/582318.582339](http://dx.doi.org/10.1145/582318.582339)
1. Gregor Hohpe:
“[Your Coffee Shop Doesnt Use Two-Phase Commit](http://www.martinfowler.com/ieeeSoftware/coffeeShop.pdf),” *IEEE Software*, volume 22, number 2, pages 6466, March 2005.
[doi:10.1109/MS.2005.52](http://dx.doi.org/10.1109/MS.2005.52)
1. Pat Helland:
“[Life Beyond Distributed Transactions: An Apostates Opinion](http://www-db.cs.wisc.edu/cidr/cidr2007/papers/cidr07p15.pdf),” at *3rd Biennial Conference on Innovative Data Systems
Research* (CIDR), January 2007.
1. Jonathan Oliver:
“[My Beef with MSDTC and Two-Phase Commits](http://blog.jonathanoliver.com/my-beef-with-msdtc-and-two-phase-commits/),” *blog.jonathanoliver.com*, April 4, 2011.
1. Oren Eini (Ahende Rahien):
“[The Fallacy of Distributed Transactions](http://ayende.com/blog/167362/the-fallacy-of-distributed-transactions),” *ayende.com*, July 17, 2014.
1. Clemens Vasters:
“[Transactions in Windows Azure (with Service Bus) An Email Discussion](https://blogs.msdn.microsoft.com/clemensv/2012/07/30/transactions-in-windows-azure-with-service-bus-an-email-discussion/),” *vasters.com*, July 30, 2012.
1. “[Understanding Transactionality in Azure](https://docs.particular.net/nservicebus/azure/understanding-transactionality-in-azure),” NServiceBus Documentation, Particular Software, 2015.
1. Randy Wigginton, Ryan Lowe,
Marcos Albe, and Fernando Ipar:
“[Distributed Transactions in MySQL](https://www.percona.com/live/mysql-conference-2013/sites/default/files/slides/XA_final.pdf),” at *MySQL Conference and Expo*, April 2013.
1. Mike Spille:
“[XA Exposed, Part I](http://www.jroller.com/pyrasun/entry/xa_exposed),”
*jroller.com*, April 3, 2004.
1. Ajmer Dhariwal:
“[Orphaned MSDTC Transactions (-2 spids)](http://www.eraofdata.com/orphaned-msdtc-transactions-2-spids/),” *eraofdata.com*, December 12, 2008.
1. Paul Randal:
“[Real World Story of DBCC PAGE Saving the Day](http://www.sqlskills.com/blogs/paul/real-world-story-of-dbcc-page-saving-the-day/),” *sqlskills.com*, June 19, 2013.
1. “[in-doubt xact resolution Server Configuration Option](https://msdn.microsoft.com/en-us/library/ms179586.aspx),” SQL Server 2016 documentation, Microsoft, Inc.,
2016.
1. Cynthia Dwork, Nancy Lynch, and Larry Stockmeyer:
“[Consensus in the Presence of Partial Synchrony](http://www.net.t-labs.tu-berlin.de/~petr/ADC-07/papers/DLS88.pdf),” *Journal of the ACM*, volume 35, number 2, pages 288323,
April 1988. [doi:10.1145/42282.42283](http://dx.doi.org/10.1145/42282.42283)
1. Miguel Castro and Barbara H. Liskov:
“[Practical Byzantine Fault Tolerance and Proactive Recovery](http://zoo.cs.yale.edu/classes/cs426/2012/bib/castro02practical.pdf),” *ACM Transactions on Computer Systems*,
volume 20, number 4, pages 396461, November 2002.
[doi:10.1145/571637.571640](http://dx.doi.org/10.1145/571637.571640)
1. Brian M. Oki and Barbara H. Liskov:
“[Viewstamped Replication: A New Primary Copy Method to Support Highly-Available Distributed Systems](http://www.cs.princeton.edu/courses/archive/fall11/cos518/papers/viewstamped.pdf),” at
*7th ACM Symposium on Principles of Distributed Computing* (PODC), August 1988.
[doi:10.1145/62546.62549](http://dx.doi.org/10.1145/62546.62549)
1. Barbara H. Liskov and James Cowling:
“[Viewstamped Replication Revisited](http://pmg.csail.mit.edu/papers/vr-revisited.pdf),”
Massachusetts Institute of Technology, Tech Report MIT-CSAIL-TR-2012-021, July 2012.
1. Leslie Lamport:
“[The Part-Time Parliament](http://research.microsoft.com/en-us/um/people/lamport/pubs/lamport-paxos.pdf),” *ACM Transactions on Computer Systems*, volume 16, number 2,
pages 133169, May 1998.
[doi:10.1145/279227.279229](http://dx.doi.org/10.1145/279227.279229)
1. Leslie Lamport:
“[Paxos Made Simple](http://research.microsoft.com/en-us/um/people/lamport/pubs/paxos-simple.pdf),” *ACM SIGACT News*, volume 32, number 4, pages 5158, December 2001.
1. Tushar Deepak Chandra, Robert Griesemer, and Joshua
Redstone: “[Paxos Made Live An Engineering Perspective](http://www.read.seas.harvard.edu/~kohler/class/08w-dsi/chandra07paxos.pdf),” at *26th ACM Symposium on Principles of Distributed
Computing* (PODC), June 2007.
1. Robbert
van Renesse: “[Paxos Made Moderately Complex](http://www.cs.cornell.edu/home/rvr/Paxos/paxos.pdf),” *cs.cornell.edu*, March 2011.
1. Diego Ongaro:
“[Consensus: Bridging Theory and Practice](https://github.com/ongardie/dissertation),”
PhD Thesis, Stanford University, August 2014.
1. Heidi Howard, Malte Schwarzkopf, Anil Madhavapeddy,
and Jon Crowcroft: “[Raft Refloated: Do We Have Consensus?](http://www.cl.cam.ac.uk/~ms705/pub/papers/2015-osr-raft.pdf),” *ACM SIGOPS Operating Systems Review*, volume 49,
number 1, pages 1221, January 2015.
[doi:10.1145/2723872.2723876](http://dx.doi.org/10.1145/2723872.2723876)
1. André Medeiros:
“[ZooKeepers Atomic Broadcast Protocol: Theory and Practice](http://www.tcs.hut.fi/Studies/T-79.5001/reports/2012-deSouzaMedeiros.pdf),” Aalto University School of Science, March 20, 2012.
1. Robbert van Renesse, Nicolas Schiper, and
Fred B. Schneider: “[Vive La Différence: Paxos vs. Viewstamped Replication vs. Zab](http://arxiv.org/abs/1309.5671),” *IEEE Transactions on Dependable and Secure Computing*,
volume 12, number 4, pages 472484, September 2014.
[doi:10.1109/TDSC.2014.2355848](http://dx.doi.org/10.1109/TDSC.2014.2355848)
1. Will
Portnoy: “[Lessons Learned from Implementing Paxos](http://blog.willportnoy.com/2012/06/lessons-learned-from-paxos.html),” *blog.willportnoy.com*, June 14, 2012.
1. Heidi Howard, Dahlia Malkhi, and Alexander Spiegelman:
“[Flexible Paxos: Quorum Intersection Revisited](https://arxiv.org/abs/1608.06696),”
*arXiv:1608.06696*, August 24, 2016.
1. Heidi Howard and Jon Crowcroft:
“[Coracle: Evaluating Consensus at the Internet Edge](http://www.sigcomm.org/sites/default/files/ccr/papers/2015/August/2829988-2790010.pdf),” at *Annual Conference of the ACM Special Interest
Group on Data Communication* (SIGCOMM), August 2015.
[doi:10.1145/2829988.2790010](http://dx.doi.org/10.1145/2829988.2790010)
1. Kyle Kingsbury:
“[Call Me Maybe: Elasticsearch 1.5.0](https://aphyr.com/posts/323-call-me-maybe-elasticsearch-1-5-0),” *aphyr.com*, April 27, 2015.
1. Ivan Kelly:
“[BookKeeper Tutorial](https://github.com/ivankelly/bookkeeper-tutorial),”
*github.com*, October 2014.
1. Camille Fournier:
“[Consensus Systems for the Skeptical Architect](http://www.ustream.tv/recorded/61483409),” at *Craft Conference*, Budapest, Hungary, April 2015.
1. Kenneth P. Birman:
“[A History of the Virtual Synchrony Replication Model](https://www.truststc.org/pubs/713.html),” in *Replication: Theory and Practice*, Springer LNCS volume 5959, chapter 6,
pages 91120, 2010. ISBN: 978-3-642-11293-5,
[doi:10.1007/978-3-642-11294-2_6](http://dx.doi.org/10.1007/978-3-642-11294-2_6)
![](img/fig9-1.png)
##### 图9-1
![](img/fig9-2.png)
##### 图9-2
![](img/fig9-3.png)
##### 图9-3
![](img/fig9-4.png)
##### 图9-4
![](img/fig9-5.png)
##### 图9-5
![](img/fig9-6.png)
##### 图9-6
![](img/fig9-7.png)
##### 图9-7
![](img/fig9-8.png)
##### 图9-8
![](img/fig9-9.png)
##### 图9-9
![](img/fig9-10.png)
##### 图9-10

BIN
ddia/img/ch1.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 586 KiB

BIN
ddia/img/ch10.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 834 KiB

BIN
ddia/img/ch11.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 966 KiB

BIN
ddia/img/ch12.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 737 KiB

BIN
ddia/img/ch2.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 810 KiB

BIN
ddia/img/ch3.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 975 KiB

BIN
ddia/img/ch4.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 813 KiB

BIN
ddia/img/ch5.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 821 KiB

BIN
ddia/img/ch6.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 646 KiB

BIN
ddia/img/ch7.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 832 KiB

BIN
ddia/img/ch8.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 905 KiB

BIN
ddia/img/ch9.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 1016 KiB

BIN
ddia/img/fig1-1.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 267 KiB

BIN
ddia/img/fig1-2.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 153 KiB

BIN
ddia/img/fig1-3.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 178 KiB

BIN
ddia/img/fig1-4.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 113 KiB

BIN
ddia/img/fig1-5.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 176 KiB

BIN
ddia/img/fig10-1.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 147 KiB

BIN
ddia/img/fig10-2.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 100 KiB

BIN
ddia/img/fig10-3.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 109 KiB

BIN
ddia/img/fig11-1.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 95 KiB

BIN
ddia/img/fig11-2.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 86 KiB

BIN
ddia/img/fig11-3.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 96 KiB

BIN
ddia/img/fig11-4.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 63 KiB

BIN
ddia/img/fig11-5.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 63 KiB

BIN
ddia/img/fig11-6.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 27 KiB

BIN
ddia/img/fig11-7.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 98 KiB

BIN
ddia/img/fig12-1.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 67 KiB

BIN
ddia/img/fig2-1.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 571 KiB

BIN
ddia/img/fig2-2.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 158 KiB

BIN
ddia/img/fig2-3.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 264 KiB

BIN
ddia/img/fig2-4.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 316 KiB

BIN
ddia/img/fig2-5.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 263 KiB

BIN
ddia/img/fig2-6.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 245 KiB

BIN
ddia/img/fig3-1.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 168 KiB

BIN
ddia/img/fig3-10.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 309 KiB

BIN
ddia/img/fig3-11.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 309 KiB

BIN
ddia/img/fig3-12.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 219 KiB

BIN
ddia/img/fig3-2.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 107 KiB

BIN
ddia/img/fig3-3.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 176 KiB

BIN
ddia/img/fig3-4.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 226 KiB

BIN
ddia/img/fig3-5.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 172 KiB

BIN
ddia/img/fig3-6.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 159 KiB

BIN
ddia/img/fig3-7.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 134 KiB

BIN
ddia/img/fig3-8.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 194 KiB

BIN
ddia/img/fig3-9.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 364 KiB

BIN
ddia/img/fig4-1.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 263 KiB

BIN
ddia/img/fig4-2.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 212 KiB

BIN
ddia/img/fig4-3.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 198 KiB

BIN
ddia/img/fig4-4.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 180 KiB

BIN
ddia/img/fig4-5.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 178 KiB

BIN
ddia/img/fig4-6.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 130 KiB

BIN
ddia/img/fig4-7.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 222 KiB

BIN
ddia/img/fig5-1.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 144 KiB

BIN
ddia/img/fig5-10.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 167 KiB

BIN
ddia/img/fig5-11.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 142 KiB

BIN
ddia/img/fig5-12.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 137 KiB

BIN
ddia/img/fig5-13.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 221 KiB

BIN
ddia/img/fig5-14.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 72 KiB

BIN
ddia/img/fig5-2.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 105 KiB

BIN
ddia/img/fig5-3.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 133 KiB

BIN
ddia/img/fig5-4.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 156 KiB

BIN
ddia/img/fig5-5.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 186 KiB

BIN
ddia/img/fig5-6.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 140 KiB

BIN
ddia/img/fig5-7.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 120 KiB

BIN
ddia/img/fig5-8.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 93 KiB

BIN
ddia/img/fig5-9.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 162 KiB

BIN
ddia/img/fig6-1.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 175 KiB

BIN
ddia/img/fig6-2.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 151 KiB

BIN
ddia/img/fig6-3.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 112 KiB

BIN
ddia/img/fig6-4.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 223 KiB

BIN
ddia/img/fig6-5.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 206 KiB

BIN
ddia/img/fig6-6.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 202 KiB

BIN
ddia/img/fig6-7.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 163 KiB

BIN
ddia/img/fig6-8.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 258 KiB

BIN
ddia/img/fig7-1.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 81 KiB

BIN
ddia/img/fig7-10.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 229 KiB

BIN
ddia/img/fig7-11.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 240 KiB

BIN
ddia/img/fig7-2.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 125 KiB

BIN
ddia/img/fig7-3.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 89 KiB

BIN
ddia/img/fig7-4.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 80 KiB

BIN
ddia/img/fig7-5.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 152 KiB

BIN
ddia/img/fig7-6.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 148 KiB

BIN
ddia/img/fig7-7.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 260 KiB

BIN
ddia/img/fig7-8.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 248 KiB

BIN
ddia/img/fig7-9.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 192 KiB

Some files were not shown because too many files have changed in this diff Show More