mirror of
https://github.com/Vonng/ddia.git
synced 2024-12-06 15:20:12 +08:00
第一章精翻
This commit is contained in:
parent
ca55455b11
commit
8cf57347ba
@ -2,10 +2,12 @@
|
|||||||
|
|
||||||
* 作者: Martin Kleppmann
|
* 作者: Martin Kleppmann
|
||||||
* 原书名称:《Designing Data-Intensive Application》
|
* 原书名称:《Designing Data-Intensive Application》
|
||||||
* 译者:冯若航 (fengruohang@outlook.com , http://vonng.com/about)
|
* 译者:[冯若航]( http://vonng.com/about) (fengruohang@outlook.com )
|
||||||
* 建议本地使用[Typora](https://www.typora.io)以获取最佳阅读体验。
|
* 建议本地使用[Typora](https://www.typora.io)以获取最佳阅读体验。
|
||||||
|
|
||||||
|
|
||||||
|
-----------------
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
## 前言
|
## 前言
|
||||||
@ -46,23 +48,29 @@
|
|||||||
12. [数据系统的未来](ch12.md)
|
12. [数据系统的未来](ch12.md)
|
||||||
|
|
||||||
|
|
||||||
|
### [术语表](glossary.md)
|
||||||
|
|
||||||
|
### [后记](colophon.md)
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
## 翻译计划
|
## 翻译计划
|
||||||
|
|
||||||
机翻:只在乎结构:梳理文章结构、图片、引用、备注,内容不对照着原文基本没法看。
|
机翻:只在乎结构:梳理文章结构、图片、引用、备注。
|
||||||
|
|
||||||
初翻:人工修复格式错误和显著翻译错误,重新组织语言,保障基本的可读性。
|
初翻:保证自己经完全理解本章内容,人工修复显著的错误,重新组织语言。
|
||||||
|
|
||||||
精翻:确定一些术语的最终译法,保证可以流畅阅读,着力信达雅。
|
精翻:确定术语的最终译法,修复格式瑕疵,着力信达雅。
|
||||||
|
|
||||||
翻译完全看心情,但通常每周至少会完成一章的初翻。
|
通常机翻一章1个小时左右,初翻一章6小时,精翻一章两天。
|
||||||
|
|
||||||
|
精翻可以看,初翻凑合看,机翻没法看。估计春节后能初翻完一遍。精翻太累了,看心情吧。
|
||||||
|
|
||||||
| 章节 | 文件 | 计划 | 进度 |
|
| 章节 | 文件 | 计划 | 进度 |
|
||||||
| ------ | ------ | ---- | ---- |
|
| ------ | ------ | ---- | ---- |
|
||||||
| 序言 | [preface.md](preface.md) | | 机翻 |
|
| 序言 | [preface.md](preface.md) | | 机翻 |
|
||||||
| 第一部分:数据系统基础 ——概览 | [part-i.md](part-i.md) | | 精翻 20% |
|
| 第一部分:数据系统基础 ——概览 | [part-i.md](part-i.md) | | 初翻 |
|
||||||
| 第一章:可靠性、可扩展性、可维护性 | [ch1.md](ch1.md) | | 初翻 |
|
| 第一章:可靠性、可扩展性、可维护性 | [ch1.md](ch1.md) | | **精翻** |
|
||||||
| 第二章:数据模型与查询语言 | [ch2.md](ch2.md) | | 初翻 |
|
| 第二章:数据模型与查询语言 | [ch2.md](ch2.md) | | 初翻 |
|
||||||
| 第三章:存储与检索 | [ch3.md](ch3.md) | | 初翻 |
|
| 第三章:存储与检索 | [ch3.md](ch3.md) | | 初翻 |
|
||||||
| 第四章:编码与演化 | [ch4.md](ch4.md) | | 初翻 |
|
| 第四章:编码与演化 | [ch4.md](ch4.md) | | 初翻 |
|
||||||
@ -76,6 +84,7 @@
|
|||||||
| 第十章:批处理 | [ch10.md](ch10.md) | | 机翻 |
|
| 第十章:批处理 | [ch10.md](ch10.md) | | 机翻 |
|
||||||
| 第十一章:流处理 | [ch11.md](ch11.md) | | 机翻 |
|
| 第十一章:流处理 | [ch11.md](ch11.md) | | 机翻 |
|
||||||
| 第十二章:数据系统的未来 | [ch12.md](ch12.md) | | 机翻 |
|
| 第十二章:数据系统的未来 | [ch12.md](ch12.md) | | 机翻 |
|
||||||
|
| 术语表 | [glossary.md](glossary.md) | | - |
|
||||||
| 后记 | [colophon.md](colophon.md) | | 机翻 |
|
| 后记 | [colophon.md](colophon.md) | | 机翻 |
|
||||||
|
|
||||||
|
|
||||||
|
458
ddia/ch1.md
458
ddia/ch1.md
@ -1,4 +1,4 @@
|
|||||||
# 1.可靠性,可扩展性,可维护性
|
# 第一章:可靠性,可扩展性,可维护性
|
||||||
|
|
||||||
![](img/ch1.png)
|
![](img/ch1.png)
|
||||||
|
|
||||||
@ -14,26 +14,21 @@
|
|||||||
|
|
||||||
数据密集型应用通常由标准组件构建而成,标准组件提供了很多通用的功能:例如,许多应用程序需要:
|
数据密集型应用通常由标准组件构建而成,标准组件提供了很多通用的功能:例如,许多应用程序需要:
|
||||||
|
|
||||||
* 存储数据,以便自己或其他应用程序之后能再次找到。( **数据库(database)**)
|
***数据库(database)***:存储数据,以便自己或其他应用程序之后能再次找到
|
||||||
|
|
||||||
|
***缓存(cache)***:记住开销昂贵操作的结果,加快读取速度
|
||||||
|
|
||||||
* 记住开销昂贵操作的结果,加快读取速度。(**缓存(cache)**)
|
***搜索索引(search indexes)***:允许用户按关键字搜索数据,或以各种方式对数据进行过滤
|
||||||
|
|
||||||
|
***流处理(stream processing)***:向其他进程发送消息,进行异步处理
|
||||||
|
|
||||||
* 允许用户按关键字搜索数据,或以各种方式对数据进行过滤。(**搜索索引(search indexes)**)
|
***批处理(batch processing)***: 定期压缩累积的大批量数据
|
||||||
|
|
||||||
|
|
||||||
* 向其他进程发送消息,进行异步处理。(**流处理(stream processing)**)
|
|
||||||
|
|
||||||
|
|
||||||
* 定期压缩累积的大批量数据。(**批处理(batch processing)**)
|
|
||||||
|
|
||||||
|
|
||||||
如果这些功能听上去平淡无奇,那真让人心酸。因为这些**数据系统(data system)**是如此成功的抽象,我们一直用着它们,却没有想太多。绝大多数工程师不会想从零开始编写存储引擎,开发应用时,数据库已经是足够完美工具了。
|
如果这些功能听上去平淡无奇,那真让人心酸。因为这些**数据系统(data system)**是如此成功的抽象,我们一直用着它们,却没有想太多。绝大多数工程师不会想从零开始编写存储引擎,开发应用时,数据库已经是足够完美工具了。
|
||||||
|
|
||||||
但事实并没有这么简单。不同的应用有不同的需求,所以数据库系统也是百花齐放,有着各式各样的特性。有很多不同的手段可以实现缓存,也有好几种方法可以搞定搜索索引,诸如此类。所以开发应用时仍然有必要弄清楚什么样的工具和方法最适合手头的工作。而且,当单个工具解决不了你的问题时,你会发现组合使用这些工具还是挺有难度的。
|
但事实并没有这么简单。不同的应用有不同的需求,所以数据库系统也是百花齐放,有着各式各样的特性。有很多不同的手段可以实现缓存,也有好几种方法可以搞定搜索索引,诸如此类。所以开发应用时仍然有必要弄清楚什么样的工具和方法最适合手头的工作。而且,当单个工具解决不了你的问题时,你会发现组合使用这些工具还是挺有难度的。
|
||||||
|
|
||||||
本书将是一趟关于数据系统原理、实践与应用的旅途,并讲述了设计数据密集型应用的方法。我们将探索不同工具之间的共性与特性,以及各自的实现原理。
|
本书将是一趟关于数据系统原理、实践与应用的旅程,并讲述了设计数据密集型应用的方法。我们将探索不同工具之间的共性与特性,以及各自的实现原理。
|
||||||
|
|
||||||
本章将从我们所要实现的基础目标开始:可靠,可扩展、可维护的数据系统。我们将澄清这些词语的含义,概述考量这些目标的方法。并回顾一些后续章节所需的基础知识。在接下来的章节中我们将抽丝剥茧,研究设计数据密集型应用时可能遇到的设计决策。
|
本章将从我们所要实现的基础目标开始:可靠,可扩展、可维护的数据系统。我们将澄清这些词语的含义,概述考量这些目标的方法。并回顾一些后续章节所需的基础知识。在接下来的章节中我们将抽丝剥茧,研究设计数据密集型应用时可能遇到的设计决策。
|
||||||
|
|
||||||
@ -41,15 +36,15 @@
|
|||||||
|
|
||||||
## 关于数据系统的思考
|
## 关于数据系统的思考
|
||||||
|
|
||||||
通常认为,数据库,消息队列,缓存这些,是差异显著的工具分类。虽然数据库和消息队列表面上有一些相似性—— 都会存一段时间的数据。——但它们有迥然不同的访问模式,这意味着迥异的性能特征和迥异的实现。
|
通常认为,数据库,消息队列,缓存这些,是差异显著的工具分类。虽然数据库和消息队列表面上有一些相似性—— 都会存一段时间的数据——但它们有迥然不同的访问模式,这意味着迥异的性能特征和迥异的实现。
|
||||||
|
|
||||||
那么为什么要把它们混为一谈,放在一个 **数据系统(data system)**的总称之下呢?
|
那为什么要把它们混为一谈,放在一个 **数据系统(data system)**的总称之下呢?
|
||||||
|
|
||||||
近些年来出现了许多新的数据存储工具与数据处理工具。它们针对各种不同应用场景进行优化,不再适用于传统的类别[【1】][1]。类别之间的界限越来越模糊,例如:数据存储也被当成消息队列用(Redis),消息队列带有类似数据库的持久保证(Apache Kafka)。
|
近些年来,出现了许多新的数据存储工具与数据处理工具。它们针对不同应用场景进行优化,不再适用于传统的类别【1】。类别之间的界限越来越模糊,例如:数据存储也被当成消息队列用(Redis),消息队列带有类似数据库的持久保证(Apache Kafka)。
|
||||||
|
|
||||||
其次,越来越多的应用程序有各式各样苛刻广泛的要求,单个工具不足以满足所有的数据处理和存储需求。取而代之的是,工作被拆分成一系列能被单个工具能高效完成的任务。并通过应用代码将这些工具缝合起来。
|
其次,越来越多的应用程序有着各种严格而广泛的要求,单个工具不足以满足所有的数据处理和存储需求。取而代之的是,工作被拆分成一系列能被单个工具高效完成的任务。并通过应用代码将这些工具缝合起来。
|
||||||
|
|
||||||
例如,如果把缓存和全文搜索功能从主数据库分离出来,多了一个应用管理的缓存(Memcached或类似品)和一个全文搜索服务器(例如Elasticsearch或Solr),那么使缓存/索引与主数据库保证同步通常是应用代码的责任。[图1-1]() 给出了这种架构可能的样子(细节将在后面的章节中详细介绍)。
|
例如,如果将缓存(应用管理的缓存层,Memcached或同类产品)和全文搜索(全文搜索服务器,例如Elasticsearch或Solr)功能从主数据库剥离出来,那么使缓存/索引与主数据库保持同步通常是应用代码的责任。[图1-1](img/fig1-1.png) 给出了这种架构可能的样子(细节将在后面的章节中详细介绍)。
|
||||||
|
|
||||||
![](img/fig1-1.png)
|
![](img/fig1-1.png)
|
||||||
|
|
||||||
@ -65,7 +60,7 @@
|
|||||||
|
|
||||||
***可靠性(Reliability)***
|
***可靠性(Reliability)***
|
||||||
|
|
||||||
系统在困境(硬件故障、软件故障、人为错误)中仍可正常工作(正确完成功能,能并达到期望性能水准)。
|
系统在**困境(adversity)**(硬件故障、软件故障、人为错误)中仍可正常工作(正确完成功能,能并达到期望性能水准)。
|
||||||
|
|
||||||
***可扩展性(Scalability)***
|
***可扩展性(Scalability)***
|
||||||
|
|
||||||
@ -73,9 +68,9 @@
|
|||||||
|
|
||||||
***可维护性(Maintainability)***
|
***可维护性(Maintainability)***
|
||||||
|
|
||||||
许多不同的人(工程师、运维)在不同的生命周期,都能在高效地在系统上工作(使系统保持现有行为,适应新的应用场景)。(参阅”可维护性“)
|
许多不同的人(工程师、运维)在不同的生命周期,都能在高效地在系统上工作(使系统保持现有行为,适应新的应用场景)。(参阅”[可维护性](#可维护性)“)
|
||||||
|
|
||||||
人们经常追求这些词汇,却并没有清楚理解它们到底意味着什么。为了工程的严谨性,本章的剩余部分将探讨可靠性、可扩展性、可维护性的含义。为实现这些目标而使用的各种技术,架构和算法,将在后续的章节中研究。
|
人们经常追求这些词汇,却没有清楚理解它们到底意味着什么。为了工程的严谨性,本章的剩余部分将探讨可靠性、可扩展性、可维护性的含义。为实现这些目标而使用的各种技术,架构和算法将在后续的章节中研究。
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
@ -91,429 +86,372 @@
|
|||||||
|
|
||||||
如果所有这些在一起意味着“正确工作”,那么可以把可靠性粗略理解为”即使出现问题,也能继续正确工作”。
|
如果所有这些在一起意味着“正确工作”,那么可以把可靠性粗略理解为”即使出现问题,也能继续正确工作”。
|
||||||
|
|
||||||
可能出问题的东西叫做**故障(fault)**,能预料并应对故障的系统特性可称为**容错(fault-tolerant)**或**韧性(resilient)**。第一个术语可能会产生误导:它暗示可以让系统容忍所有可能的错误,实际中这是不可能的。如果整个地球(及其上的所有服务器)都被黑洞吞噬,容忍这种错误需要将网络托管到宇宙中。能不能通过这种预算就祝你好运了。所以在讲容错时,只有谈论*特定类型*的错误才有意义。
|
造成错误的原因叫做**故障(fault)**,能预料并应对故障的系统特性可称为**容错(fault-tolerant)**或**韧性(resilient)**。前者可能会产生误导:它暗示着可以让系统容忍所有可能的错误,实际中这是不可能的。如果整个地球(及其上的所有服务器)都被黑洞吞噬,容这种错需要把网络托管到太空里。这种预算能不能批准就祝你好运了。所以在讨论容错时,只有谈论**特定类型(certain types)**的错误才有意义。
|
||||||
|
|
||||||
注意**故障(fault)**不同于**失效(failure)**[【2】][2]。**故障**通常定义为系统的一部分偏离其标准,而**失效**则是系统作为一个整体停止向用户提供服务。故障的概率不可能降到零,因此最好设计容错机制,以防**故障**导致**失效**。本书们将介绍几种用不可靠的部件构建可靠系统的技术。
|
注意**故障(fault)**不同于**失效(failure)**【2】。**故障**通常定义为系统的一部分状态偏离其标准,而**失效**则是系统作为一个整体停止向用户提供服务。故障的概率不可能降到零,因此最好设计容错机制以防**故障**导致**失效**。本书们将介绍几种用不可靠的部件构建可靠系统的技术。
|
||||||
|
|
||||||
反直觉的是,在这类容错系统中,通过故意触发来**提高**故障率是有意义的。例如在没有警告的情况下随机地杀死单个进程。许多高危漏洞实际上由糟糕的错误处理导致的[【3】][3];通过故意引发故障,来确保容错机制不断运行并接受考验,从而提高故障自然发生时系统能正确处理的信心。Netflix *Chaos Monkey*[【4】][4]就是这种方法的一个例子。
|
反直觉的是,在这类容错系统中,通过故意触发来**提高**故障率是有意义的。例如在没有警告的情况下随机地杀死单个进程。许多高危漏洞实际上是由糟糕的错误处理导致的【3】;通过故意引发故障来确保容错机制不断运行并接受考验,从而提高故障自然发生时系统能正确处理的信心。Netflix *Chaos Monkey*【4】就是这种方法的一个例子。
|
||||||
|
|
||||||
尽管比起**阻止错误(Prevent error)**,我们通常更倾向于容忍错误。但也有**预防胜于治疗**的情况(比如不存在治疗方法时)。安全问题就属于这种情况。例如,如果攻击者破坏了系统,并获取了敏感数据,这种事是撤销不了的。但本书主要讨论的是可以恢复的故障类型,如下所述。
|
尽管比起**阻止错误(prevent error)**,我们通常更倾向于**容忍错误**。但也有**预防胜于治疗**的情况(比如不存在治疗方法时)。安全问题就属于这种情况。例如,如果攻击者破坏了系统,并获取了敏感数据,这种事是撤销不了的。但本书主要讨论的是可以恢复的故障种类,如下面几节所述。
|
||||||
|
|
||||||
### 硬件故障
|
### 硬件故障
|
||||||
|
|
||||||
当想到系统失效的原因时,硬件故障总会第一个进入脑海。硬盘崩溃,内存出错,机房断电,有人拔错网线。任何与大型数据中心打交道的人都会告诉你,当拥有很多机器时,这些事情**总是**会发生的。
|
当想到系统失效的原因时,**硬件故障(hardware faults)**总会第一个进入脑海。硬盘崩溃,内存出错,机房断电,有人拔错网线。任何与大型数据中心打过交道的人都会告诉你,当拥有很多机器时,这些事情**总是**会发生的。
|
||||||
|
|
||||||
硬盘的**平均无故障时间(MTTF, mean time to failure)**据报道称约为10到50年[【5】][5][【6】][6]。因此,在一个有一万个磁盘的存储集群上,期望上每天平均会有一个磁盘挂掉。
|
硬盘的**平均无故障时间(MTTF, mean time to failure)**据报道称约为10到50年【5】【6】。因此从期望上讲,在有一万个磁盘的存储集群上,平均每天会有一个磁盘出故障。
|
||||||
|
|
||||||
为了减少系统的故障率,第一反应通常是增加单个硬件的冗余度。磁盘可以组RAID,服务器可能有双路电源和热插拔CPU,数据中心可能有电池和柴油发电机作为后备电源。当某个组件挂掉时,换下来并由冗余组件取而代之。这种方法并不能完全防止因为硬件问题导致的系统失效,但它简单易懂,通常也足以让机器不间断运行多年。
|
为了减少系统的故障率,第一反应通常都是增加单个硬件的冗余度。磁盘可以组RAID,服务器可能有双路电源和热插拔CPU,数据中心可能有电池和柴油发电机作为后备电源。当某个组件挂掉时,换下来并由冗余组件取而代之。这种方法并不能完全防止由硬件问题导致的系统失效,但它简单易懂,通常也足以让机器不间断运行很多年。
|
||||||
|
|
||||||
直到最近,硬件冗余对于大多数应用来说已经足够了,它使单台机器完全失效变得相当罕见。只要你能快速地把备份恢复到新机器上,故障停机时间对于大多数应用程序都算不上灾难性的。少部分需要高可用的应用可能会采用多个冗余硬件副本。
|
直到最近,硬件冗余对于大多数应用来说已经足够了,它使单台机器完全失效变得相当罕见。只要你能快速地把备份恢复到新机器上,故障停机时间对大多数应用而言都算不上灾难性的。只有少量高可用性至关重要的应用才会要求有多套硬件冗余。
|
||||||
|
|
||||||
但随着数据量和应用计算需求的增加,越来越多的应用开始大量使用机器,这会相应地增加硬件故障率。此外,在一些云平台(**如亚马逊网络服务(AWS, Amazon Web Services)**)中,虚拟机实例在没有警告的情况下变得不可用[7],这是因为平台旨在优先考虑单机可靠性的灵活性和弹性。
|
但随着数据量和应用计算需求的增加,越来越多的应用开始大量使用机器,这会相应地增加硬件故障率。此外在一些云平台(**如亚马逊网络服务(AWS, Amazon Web Services)**)中,虚拟机实例不可用却没有任何警告也是很常见的【7】,因为云平台的设计就是优先考虑**灵活性(flexibility)**和**弹性(elasticity)**[^i],而不是单机可靠性。
|
||||||
|
|
||||||
因此,通过优先使用软件容错技术或除了硬件冗余之外,还有一种趋向于可以容忍整个机器损失的系统。这样的系统还具有运维优势:如果需要重启机器(例如应用操作系统安全补丁),则单服务器系统需要计划的停机时间,而可以容忍机器故障的系统可以一次修补一个节点没有整个系统的停机时间(滚动升级;参见第4章)。
|
在硬件冗余的基础上进一步引入软件容错机制,系统在容忍整个(单台)机器故障的道路上就更进了一步。这样的系统也有运维上的便利:如果需要重启机器(例如应用操作系统安全补丁),单服务器系统需要计划停机。而允许机器失效的系统则可以一次修复一个节点,不需要整个系统停机。
|
||||||
|
|
||||||
|
[^i]: 在[应对负载的方法](#应对负载的方法)一节定义
|
||||||
|
|
||||||
### 软件错误
|
### 软件错误
|
||||||
|
|
||||||
我们通常认为硬件故障是随机的,相互独立的:一台机器的磁盘失败并不意味着另一台机器的磁盘将会失败。可能存在较弱的相关性(例如,由于常见原因,例如服务器机架中的温度),否则大量硬件组件不可能同时发生故障。
|
通常认为硬件故障是随机的、相互独立的:一台机器的磁盘失效并不意味着另一台机器的磁盘也会失效。可能会存在比较弱的相关性(举个例子,由于同样的原因导致,例如服务器机架的温度),否则大量硬件组件不可能同时发生故障。
|
||||||
另一类错误是系统内部的系统错误[8]。这样的错误很难预测,而且由于它们在节点间相互关联,所以往往比不相关的硬件故障造成更多的系统故障[5]。例子包括:
|
|
||||||
|
|
||||||
* 给定特定的错误输入时,导致应用程序服务器的每个实例崩溃的软件错误。例如,考虑到2012年6月30日的闰秒,由于Linux内核中的一个错误,导致许多应用程序同时挂起。
|
另一类错误是内部的**系统性错误(systematic error)**【7】。这类错误难以预料,而且因为是跨节点相关的,所以比起不相关的硬件故障往往可能造成更多的**系统失效**【5】。例子包括:
|
||||||
* 失控进程会占用一些共享资源 - CPU时间,内存,磁盘空间或网络带宽。
|
|
||||||
* 系统依赖的服务变慢,变为无响应,或者开始返回损坏的响应。
|
|
||||||
* 级联故障,其中一个组件中的小故障触发另一个组件中的故障,进而触发进一步的故障[10]。
|
|
||||||
|
|
||||||
导致这类软件故障的错误通常会长时间处于休眠状态,直到被不寻常的情况触发为止。在这种情况下,显示出软件正在对其环境做出某种假设 - 虽然这种假设通常是正确的,但由于某种原因它最终会被否定[11]。
|
* 接受特定的错误输入,便导致所有应用服务器实例崩溃的BUG。例如2012年6月30日的闰秒,由于Linux内核中的一个错误,许多应用同时挂掉了。
|
||||||
|
* 失控进程会占用一些共享资源——CPU时间,内存,磁盘空间或网络带宽。
|
||||||
|
* 系统依赖的服务变慢,没有响应,或者开始返回错误的响应。
|
||||||
|
* 级联故障,一个组件中的小故障触发另一个组件中的故障,进而触发更多的故障【10】。
|
||||||
|
|
||||||
软件中的系统故障问题没有快速的解决方案。许多小事情可以帮助:仔细考虑系统中的假设和交互;彻底的测试;过程隔离;允许进程崩溃并重新启动;测量,监控和分析生产中的系统行为。如果一个系统需要提供一些保证(例如在一个消息队列中,输入消息的数量等于输出消息的数量),它可以在运行时不断检查自己,并在出现差异时发出警报被发现[12]。
|
导致这类软件故障的BUG通常会潜伏很长时间,直到被异常情况触发为止。这种情况意味着软件对其环境做出了某种假设——虽然这种假设通常来说是正确的,但由于某种原因最后不再成立了【11】。
|
||||||
|
|
||||||
|
软件中的系统性故障没有速效药。但很多小办法会有帮助:仔细考虑系统中的假设和交互;彻底的测试;进程隔离;允许进程崩溃并重启;测量、监控并分析生产环境中的系统行为。如果系统提供一些保证(例如在一个消息队列中,进入与发出的消息数量相等),则系统可以在运行时不断自检,并在出现**差异(discrepancy)**时报警【12】。
|
||||||
|
|
||||||
### 人为错误
|
### 人为错误
|
||||||
|
|
||||||
人类设计和建造软件系统,保持系统运行的操作人员也是人。即使他们有最好的意图,人类也是不可靠的。例如,一项关于大型互联网服务的研究发现,运营商的配置错误是导致中断的主要原因,而硬件故障(服务器或网络)仅在10-25%的中断中发挥作用[13]。
|
设计并构建了软件系统的工程师是人类,维持系统运行的运维也是人类。即使他们怀有最大的善意,人类也是不可靠的。举个例子,一项关于大型互联网服务的研究发现,运维配置错误是导致服务中断的首要原因,而硬件故障(服务器或网络)仅在10-25%的服务中断中起作用【13】。
|
||||||
|
|
||||||
尽管人类不可靠,我们如何使我们的系统可靠?最好的系统结合了几种方法:
|
尽管人类不可靠,但系统如何变得可靠?最好的系统会组合使用几种办法:
|
||||||
|
|
||||||
* 以最大限度地减少错误机会的方式设计系统。例如,精心设计的抽象,API和管理界面使得“做正确的事情”变得容易,并且阻止“错误的事情”。然而,如果接口过于严格,人们会绕过它们,否定它们的好处。这是一个棘手的平衡得到正确的。
|
* 以最小化犯错机会的方式设计系统。例如,精心设计的抽象、API和管理后台使做对事情更容易,搞砸事情更困难。但如果接口限制太多,人们就会否定它们的好处而想办法绕开。这是一个很难正确把握的棘手平衡。
|
||||||
* 将人们犯最多错误的地方与可能导致失败的地方分开。特别是提供功能齐全的非生产性沙箱环境,使用户可以在不影响真实用户的情况下使用真实数据安全地探索和实验。
|
* 将人们最容易犯错的地方与可能导致失效的地方**解耦(decouple)**。特别是提供一个功能齐全的非生产环境**沙箱(sandbox)**,使人们可以在不影响真实用户的情况下,使用真实数据安全地探索和实验。
|
||||||
* 从单元测试到全系统集成测试和手动测试,在各个层面进行彻底测试[3]。自动化测试广泛使用,易于理解,特别适用于覆盖在正常运行中很少出现的角落案例。
|
* 在各个层次进行彻底的测试【3】,从单元测试、全系统集成测试到手动测试。自动化测试易于理解,已经被广泛使用,特别适合用来覆盖正常情况中少见的**边缘场景(corner case)**。
|
||||||
* 允许从人为错误中快速轻松地恢复,以最大限度地减少故障情况下的影响。 例如,快速回滚配置更改,逐渐推出新代码(以便任何意外的错误只影响一小部分用户),并提供重新计算数据的工具(万一事实证明旧计算 是不正确的)。
|
* 允许从人为错误中简单快速地恢复,以最大限度地减少失效情况带来的影响。 例如,快速回滚配置变更,分批发布新代码(以便任何意外错误只影响一小部分用户),并提供数据重算工具(以备旧的计算出错)。
|
||||||
* 设置详细和明确的监控,如性能指标和错误率。 在其他工程学科中,这被称为遥测。 (一旦火箭离开了地面,遥测技术对于追踪发生的事情和理解失败是必不可少的。)监测可以向我们展示预警信号,并让我们检查是否有任何假设或限制是违反的。迟来。 发生问题时,度量标准对于诊断问题是非常有价值的。
|
* 配置详细和明确的监控,比如性能指标和错误率。 在其他工程学科中这指的是**遥测(telemetry)**。 (一旦火箭离开了地面,遥测技术对于跟踪发生的事情和理解失败是至关重要的。)监控可以向我们发出预警信号,并允许我们检查是否有任何地方违反了假设和约束。当出现问题时,指标数据对于问题诊断是非常宝贵的。
|
||||||
* 实施良好的管理实践和培训 - 一个复杂而重要的方面,超出了本书的范围。
|
* 良好的管理实践与充分的培训——一个复杂而重要的方面,但超出了本书的范围。
|
||||||
|
|
||||||
### 可靠性有多重要?
|
### 可靠性有多重要?
|
||||||
|
|
||||||
可靠性不仅仅针对核电站和空中交通管制软件,更多的普通应用也预计可靠运行。商业应用程序中的错误会导致生产力的损失(如果数据报告不完整,则会面临法律风险),而且电子商务网站的中断可能会导致收入损失和声誉受损。
|
可靠性不仅仅是针对核电站和空中交通管制软件而言,我们也期望许多平凡的应用能可靠地运行。商务应用中的错误会导致生产力损失(也许数据报告不完整还会有法律风险),而电商网站的中断则可能会导致收入和声誉的巨大损失。
|
||||||
|
|
||||||
即使在“非关键”应用中,我们也对用户负有责任。考虑一个父母,他们的所有照片和他们的孩子的视频存储在您的照片应用程序[15]。如果数据库突然被破坏,他们会感觉如何?他们会知道如何从备份恢复它?
|
即使在“非关键”应用中,我们也对用户负有责任。试想一位家长把所有的照片和孩子的视频储存在你的照片应用里【15】。如果数据库突然损坏,他们会感觉如何?他们可能会知道如何从备份恢复吗?
|
||||||
|
|
||||||
在某些情况下,我们可能选择牺牲可靠性来降低开发成本(例如,为未经证实的市场开发原型产品)或运营成本(例如,利润率极低的服务),但是我们应该非常清楚我们什么时候偷工减料。
|
在某些情况下,我们可能会选择牺牲可靠性来降低开发成本(例如为未经证实的市场开发产品原型)或运营成本(例如利润率极低的服务),但我们偷工减料时,应该清楚意识到自己在做什么。
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
## 可扩展性
|
## 可扩展性
|
||||||
|
|
||||||
即使系统今天运行稳定,但这并不意味着未来一定能够可靠运行。降级的一个常见原因是负载增加:或许系统已经从10,000个并发用户增加到100000个并发用户,或者从100万增加到1000万。也许正在处理的数据量比以前大得多。
|
系统今天能可靠运行,并不意味未来也能可靠运行。服务**降级(degradation)**的一个常见原因是负载增加:或许系统已经从一万个并发用户增长到十万个并发用户,或者从一百万增长到一千万。也许现在处理的数据量级比过去大得多。
|
||||||
|
|
||||||
可伸缩性(Scalability)是我们用来描述系统应对负载增加的能力的术语。但是请注意,这不是我们可以附加到系统上的一维标签:说“X可伸缩”或“Y不能缩放”是没有意义的。相反,讨论可扩展性意味着考虑如“如果系统以特定方式增长,我们有什么选择来应对增长?”和“我们如何增加计算资源来处理额外的负载?”等问题。
|
**可扩展性(Scalability)**是用来描述系统应对负载增长能力的术语。但是请注意,这不是贴在系统上的一维标签:说“X可扩展”或“Y不可扩展”是没有任何意义的。相反,讨论可扩展性意味着考虑诸如“如果系统以特定方式增长,有什么选项可以应对增长?”和“如何增加计算资源来处理额外的负载?”等问题。
|
||||||
|
|
||||||
### 描述负载
|
### 描述负载
|
||||||
|
|
||||||
首先,我们需要简洁地描述系统的当前负载。只有这样我们才能讨论增长问题(如果我们的负荷加倍,会发生什么?)。负载可以用一些我们称之为负载参数的数字来描述。参数的最佳选择取决于系统的体系结构:它可能是每秒向Web服务器发出的请求,数据库中的读写比率,聊天室中同时活动的用户数量,缓存或其他东西。也许平均情况对你来说很重要,或者你的瓶颈主要是少数极端情况。
|
讨论增长问题(如果负载加倍会发生什么?)前,首先要能简要描述系统的当前负载。负载可以用一些称为**负载参数(load parameters)**的数字来描述。参数的最佳选择取决于系统架构:它可能是每秒向Web服务器发出的请求,数据库中的读写比率,聊天室中同时活跃的用户数量,缓存命中率或其他东西。也许平均情况对你很重要,也许你的瓶颈是少数极端场景。
|
||||||
|
|
||||||
为了使这个想法更加具体,我们以2012年11月发布的数据[16]为例,以Twitter为例。 Twitter的两个主要业务是:
|
为了使这个概念更加具体,我们以推特在2012年11月发布的数据【16】为例。推特的两个主要业务是:
|
||||||
|
|
||||||
* 发布推文:用户可以向其追随者发布新消息(平均每秒4.6k个请求/秒,峰值超过12k个请求/秒)。
|
***发布推文***
|
||||||
|
|
||||||
|
用户可以向其粉丝发布新消息(平均 4.6k请求/秒,峰值超过 12k请求/秒)。
|
||||||
|
|
||||||
* 主页时间线:用户可以查看他们关注的人发布的推文(300k请求/秒)。
|
***主页时间线***
|
||||||
|
|
||||||
简单地处理每秒12,000次写入(发布推文的最高速率)将是相当容易的。然而,Twitter的扩张挑战并不是主要由于推特量,而是由扇出(fan-out:从电子工程中借用的一个术语,它描述了连接到另一个门输出的逻辑门输入的数量。 输出需要提供足够的电流来驱动所有连接的输入。 在事务处理系统中,我们使用它来描述为了服务一个传入请求而需要做的其他服务的请求数量。), 每个用户跟随很多人,每个用户跟着很多人。大致有两种方法来实现这两个操作:
|
用户可以查阅他们关注的人发布的推文(300k请求/秒)。
|
||||||
|
|
||||||
1. 发布推文只需将新推文插入推文的全局集合即可。当用户请求他们的主页时间线时,查找他们关注的所有人,为每个用户查找所有推文,并合并(按时间排序)。在如图1-2所示的关系数据库中,可以编写如下查询:
|
处理每秒12,000次写入(发推文的速率峰值)还是很简单的。然而推特的扩展性挑战并不是主要来自推特量,而是来自**扇出(fan-out)**——每个用户关注了很多人,也被很多人关注。
|
||||||
|
|
||||||
```sql
|
[^ii]: 扇出:从电子工程学中借用的术语,它描述了输入连接到另一个门输出的逻辑门数量。 输出需要提供足够的电流来驱动所有连接的输入。 在事务处理系统中,我们使用它来描述为了服务一个传入请求而需要执行其他服务的请求数量。
|
||||||
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. 发布推文时,只需将新推文插入全局推文集合即可。当一个用户请求自己的主页时间线时,首先查找他关注的所有人,查询这些被关注用户发布的推文并按时间顺序合并。在如[图1-2](img/fig1-2.png)所示的关系型数据库中,可以编写这样的查询:
|
||||||
|
|
||||||
**图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
|
||||||
|
```
|
||||||
|
![](img/fig1-2.png)
|
||||||
|
|
||||||
![](img/fig1-3.png)
|
**图1-2 推特主页时间线的关系型模式简单实现**
|
||||||
|
|
||||||
**图1-2 用于分发推特至关注者的数据流水线,带有负载参数(2012年11月)**
|
2. 为每个用户的主页时间线维护一个缓存,就像每个用户的推文收件箱([图1-3](img/fig1-3.png))。 当一个用户发布推文时,查找所有关注该用户的人,并将新的推文插入到每个主页时间线缓存中。 因此读取主页时间线的请求开销很小,因为结果已经提前计算好了。
|
||||||
|
|
||||||
Twitter的第一个版本使用了方法1,但系统努力跟上主页时间线查询的负载,所以公司转向了方法2.这更好地发挥作用,因为发布的推文的平均比率几乎比主页时间线查询频率低了两个数量级,所以在这种情况下,最好在写入时间做更多的工作,而在读取时间做更少的工作。
|
![](img/fig1-3.png)
|
||||||
|
|
||||||
然而,方法2的缺点是发布推文现在需要大量的额外工作。平均来说,一条推特被发送到约75个追随者,所以每秒4.6k的推文变成主页时间线缓存每秒345k的写入。但是这个平均值隐藏了每个用户的关注者数量与一些用户差异很大的事实
|
**图1-3 用于分发推特至关注者的数据流水线,2012年11月的负载参数【16】**
|
||||||
|
|
||||||
有超过三千万的追随者。这意味着一个推特可能会导致超过3000万的写入时间表!及时做到这一点 - Twitter试图在5秒内向粉丝发送推文 - 是一个重大的挑战。
|
推特的第一个版本使用了方法1,但系统很难跟上主页时间线查询的负载。所以公司转向了方法2,方法2的效果更好,因为发推频率比查询主页时间线的频率几乎低了两个数量级,所以在这种情况下,最好在写入时做更多的工作,而在读取时做更少的工作。
|
||||||
在Twitter的例子中,每个用户的关注者分布(可能是这些用户发微博的频率)是讨论可伸缩性的关键负载参数,因为它决定了扇出负载。您的应用程序可能具有非常不同的特征,但您可以应用相似的原则来推理其负载。
|
|
||||||
|
|
||||||
推特轶事的最后一个转折:现在,方法2 健壮的实施了,Twitter正在转向两种方法的混合。大多数用户的推文在发布的时候仍然是在主页时间线上,但是很少有粉丝(即名人)的用户被排除在外。用户可能关注的任何名人的推文都会单独提取,并在阅读时与用户的家庭时间线合并,如方法1所示。这种混合方法能够持续提供良好的性能。我们将在第12章重新讨论这个例子,因为我们已经覆盖了更多的技术层面。
|
然而方法2的缺点是,发推现在需要大量的额外工作。平均来说,一条推文会发往约75个关注者,所以每秒4.6k的发推写入,变成了对主页时间线缓存每秒345k的写入。但这个平均值隐藏了用户粉丝数差异巨大的现实,一些用户有超过三千万的粉丝。这意味着一条推文就可能会导致主页时间线缓存的3000万次写入!及时完成这种操作是一个巨大的挑战——推特尝试在5秒内向粉丝发送推文。
|
||||||
|
|
||||||
|
在推特的例子中,每个用户粉丝数的分布(可能按这些用户的发推频率来加权)是讨论可扩展性的关键负载参数,因为它决定了扇出负载。你的应用程序可能具有非常不同的特征,但可以使用相似的原则来考虑你的负载。
|
||||||
|
|
||||||
|
推特轶事的最终转折:现在方法2已经稳健地实现了,但Twitter又转向了两种方法的混合。大多数用户发推时仍然是扇出写入粉丝的主页时间线缓存中。但是少数拥有海量粉丝的用户(即名流)被排除在外。当用户读取主页时间线时,来自所关注名流的推文都会单独拉取,并与用户的主页时间线缓存合并,如方法1所示。这种混合方法能始终如一地提供良好性能。在[第12章](ch12.md)中将重新讨论这个例子,那时我们已经覆盖了更多的技术层面。
|
||||||
|
|
||||||
### 描述性能
|
### 描述性能
|
||||||
|
|
||||||
一旦描述了系统的负载,就可以调查负载增加时发生的情况。你可以用两种方法来看它:
|
一旦系统的负载可以被描述,就可以研究当负载增加会发生什么。可以从两种角度来看:
|
||||||
|
|
||||||
* 增加负载参数并保持系统资源(CPU,内存,网络带宽等)不变时,系统性能如何受影响?
|
* 增加负载参数并保持系统资源(CPU,内存,网络带宽等)不变时,会如何影响系统性能?
|
||||||
* 当您增加一个负载参数时,如果要保持性能不变,您需要增加多少资源?
|
* 当增加负载参数时,如需保持性能不变,需要增加多少资源?
|
||||||
|
|
||||||
这两个问题都需要性能数字,所以让我们简单地看一下系统的性能。
|
这两个问题都需要性能数据,所以让我们简单地看一下如何描述系统的性能。
|
||||||
|
|
||||||
在像Hadoop这样的批处理系统中,我们通常关心吞吐量 - 每秒处理的记录数量,或者在一定数量的数据集上运行作业的总时间.(理想情况下,批量作业的运行时间是数据集的大小除以吞吐量。 在实践中,由于歪斜(数据不是均匀分布在工作进程中),而且需要等待最慢的任务完成,所以运行时间往往更长)在在线系统中,通常是什么更重要的是服务的响应时间 - 也就是客户端发送请求和接收响应之间的时间。
|
对于Hadoop这样的批处理系统,通常关心的是**吞吐量(throughput)**——每秒可以处理的记录数量,或者在特定规模数据集上运行作业的总时间[^iii]。对于在线系统,通常更重要的是服务的**响应时间(response time)**——也就是客户端发送请求和接收响应之间的时间。
|
||||||
|
|
||||||
|
[^iii]: 理想情况下,批量作业的运行时间是数据集的大小除以吞吐量。 在实践中由于数据倾斜(数据不是均匀分布在每个工作进程中),需要等待最慢的任务完成,所以运行时间往往更长。
|
||||||
|
|
||||||
|
> #### 延迟和响应时间
|
||||||
|
>
|
||||||
|
> **延迟(latency)**和**响应时间(response time)**通常当成同义词用,但它们并不一样。响应时间是客户所看到的,除了实际处理请求的时间(**服务时间(service time)**)之外,还包括网络延迟和排队延迟。延迟是一个请求等待处理的**持续时长**——在这段时间内,它是**休眠的(latent)**,等待服务【17】。
|
||||||
|
>
|
||||||
|
|
||||||
#### 延迟和响应时间
|
即使不断重复发送同样的请求,每次得到的响应时间也都会略有不同。现实世界的系统会处理各式各样的请求,响应时间可能会有很大差异。因此需要将响应时间视为一个可以测量的**分布(distribution)**,而不是单个数值。
|
||||||
|
|
||||||
延迟(Latency)和响应时间(Response Time)通常用作同义词,但它们并不相同。响应时间是**客户看到的**:除了处理请求的实际时间(服务时间)之外,还包括网络延迟和排队延迟。**延迟是一个请求等待处理的时间** - 在这个时间内,它是潜在的,等待服务[17]。
|
在[图1-4](img/fig1-4.png)中,每个灰条表代表一次对服务的请求,其高度表示请求花费了多长时间。大多数请求是相当快的,但偶尔会出现需要更长的时间的异常值。也许是因为缓慢的请求实质上开销更大,例如它们可能会处理更多的数据。但即使在你认为所有的请求都会花费同样时间的情况下,结果也会有变化:随机的附加延迟可能由于各种各样的原因被引入:上下文切换到后台进程,网络数据包丢失与TCP重传,垃圾收集暂停,强制从磁盘读取的页面错误,服务器机架中的震动【18】,或者其他许多原因。
|
||||||
|
|
||||||
即使你只是一次又一次地提出相同的请求,每次尝试都会得到一个稍微不同的响应时间。实际上,在处理各种请求的系统中,响应时间可能会有很大差异。因此,我们需要将响应时间视为一个单一的数字,而不是一个可以衡量的价值分布。
|
|
||||||
|
|
||||||
在图1-4中,每个灰色条表示对服务的请求,其高度表示请求花了多长时间。大多数请求是相当快的,但是偶尔出现的异常值需要更长的时间。也许缓慢的请求本质上更昂贵,例如,因为它们处理更多的数据。但是即使在你认为所有的请求都要花费同样的时间的情况下,你也会得到一些变化:上下文切换到后台进程可能引入随机的附加延迟,网络数据包丢失和TCP重传,垃圾收集暂停,强制从磁盘读取的页面错误,服务器机架[18]中的机械振动或许多其他原因。
|
|
||||||
|
|
||||||
![](img/fig1-4.png)
|
![](img/fig1-4.png)
|
||||||
|
|
||||||
**图1-4 展示了一个服务100次请求响应时间的均值与百分位数**
|
**图1-4 展示了一个服务100次请求响应时间的均值与百分位数**
|
||||||
|
|
||||||
通常看到报告的服务的平均响应时间。 (严格地说,“平均”一词并不是指任何特定的公式,但实际上它通常被理解为算术平均值:给定n 个值,加起来所有的值,除以n)。然而,平均值如果你想知道你的“典型”响应时间,那么它不是一个很好的指标,因为它不能告诉你有多少用户实际上经历了这个延迟。
|
通常报表都会展示服务的平均响应时间。 (严格来讲“平均”一词并不指代任何特定公式,但实际上它通常被理解为**算术平均值(arithmetic mean)**:给定n个值,加起来除以n)。然而如果你想知道“**典型(typical)**”响应时间,那么平均值并不是一个非常好的指标,因为它不能告诉你有多少用户实际上经历了这个延迟。
|
||||||
|
|
||||||
通常使用百分比更好。如果将响应时间列表从最快到最慢排序,那么中值是中间值:例如,如果您的中值响应时间是200毫秒,这意味着一半请求的返回时间少于200毫秒,一半你的要求比这个要长。
|
通常使用**百分位点(percentiles)**会更好。如果将响应时间列表按最快到最慢排序,那么**中位数(median)**就在正中间:举个例子,如果你的响应时间中位数是200毫秒,这意味着一半请求的返回时间少于200毫秒,另一半比这个要长。
|
||||||
|
|
||||||
如果您想知道用户通常需要等待多长时间,那么这使中间值成为一个好的度量标准:用户请求的一半服务时间少于中间响应时间,另一半服务时间比中间值长。中位数也被称为第50百分位,有时缩写为p50。请注意,中位数是指单个请求;如果用户提出了几个请求(在一个会话过程中,或者由于多个资源被包含在一个页面中),至少其中一个请求比中间值慢的可能性远远大于50%。
|
如果想知道典型场景下用户需要等待多长时间,那么中位数是一个好的度量标准:一半用户请求的响应时间少于响应时间的中位数,另一半服务时间比中位数长。中位数也被称为第50百分位点,有时缩写为p50。注意中位数是关于单个请求的;如果用户同时发出几个请求(在一个会话过程中,或者由于一个页面中包含了多个资源),则至少一个请求比中位数慢的概率远大于50%。
|
||||||
|
|
||||||
为了弄清楚你的异常值有多糟糕,你可以看看更高的百分位数:第95,99和99.9百分位数是常见的(缩写p95,p99和p999)。它们是95%,99%或99.9%的请求比特定阈值更快的响应时间阈值。例如,如果第95百分位响应时间是1.5秒,则意味着100个请求中的95个占用少于1.5秒,并且100个请求中的5个占用1.5秒或更多。如图1-4所示。
|
为了弄清异常值有多糟糕,可以看看更高的百分位点:第95,99和99.9百分位点也是常见的(缩写为p95,p99和p999)。它们意味着95%,99%或99.9%的请求响应时间要比该阈值快。例如,如果第95百分位点响应时间是1.5秒,则意味着100个请求中的95个响应时间快于1.5秒,而100个请求中的5个响应时间超过1.5秒。如[图1-4](img/fig1-4.png)所示。
|
||||||
|
|
||||||
响应时间的高百分比(也称为尾部延迟 Tail Percentil)非常重要,因为它们直接影响用户的服务体验。例如,亚马逊描述了内部服务的响应时间要求,**以百分之九十九为单位,即使只影响一千个请求中的一个**。这是因为要求最慢的客户往往是那些账户数据最多的客户,因为他们进行了大量的采购 - 也就是说,他们是最有价值的客户[19]。通过确保网站快速发展,让客户满意是非常重要的:亚马逊还观察到,响应时间增加了100毫秒,销售量减少了1%[20],而另一些人则报告说,1秒钟的减速会减少客户 - 收敛度为16%[21,22]。
|
响应时间的高百分位点(也称为**尾部延迟(tail percentil)**)非常重要,因为它们直接影响用户的服务体验。例如亚马逊在描述内部服务的响应时间要求时以99.9百分位点为准,即使它只影响一千个请求中的一个。这是因为请求响应最慢的客户往往也是数据最多的客户,因为他们掏钱了——也可以说,最有价值的客户【19】。保证网站响应迅速对于客户的满意度非常重要:亚马逊观察到,响应时间增加100毫秒,销售量就减少1%【20】,而另一些报告说,慢1秒钟会减少16%的客户满意度指标【21,22】。
|
||||||
|
|
||||||
另一方面,优化第99.99个百分点(10000个请求中最慢的1个)被认为太昂贵,并且不能为亚马逊的目的带来足够的好处。以非常高的百分比来减少响应时间是困难的,因为它们很容易受到您控制之外的随机事件的影响,并且好处正在减少。
|
另一方面,优化第99.99百分位点(一万个请求中最慢的一个)被认为太昂贵了,不能为亚马逊的目标带来足够好处。减小高百分位点处的响应时间相当困难,因为它很容易受到随机事件的影响,这超出了控制范围,而且效益也很小。
|
||||||
|
|
||||||
例如,百分比通常用于服务级别目标(SLO)和服务级别协议(SLA),即定义服务的预期性能和可用性的合同。 SLA可能会声明,如果服务的响应时间中位数小于200毫秒,并且在1秒内响应时间较长(如果响应时间较长,则可能会下降),则认为该服务已启动。可能需要至少99.9%的时间。这些指标为服务客户设定了期望值,并允许客户在SLA未达到的情况下要求退款。
|
百分位点通常用于**服务级别目标(SLO, service level objectives)**和**服务级别协议(SLA, service level agreements)**,即定义服务预期性能和可用性的合同。 SLA可能会声明,如果服务响应时间的中位数小于200毫秒,且99.9百分位点低于1秒,则认为服务工作正常(如果响应时间更长,就认为服务不达标)。这些指标为客户设定了期望值,并允许客户在SLA未达标的情况下要求退款。
|
||||||
|
|
||||||
排队延迟通常占高百分比响应时间的很大一部分。由于服务器只能并行处理少量的事务(例如,受其CPU核数量的限制),所以只需要少量缓慢的请求来阻止后续请求的处理,这种效果有时被称为头部阻塞。即使这些后续请求在服务器上快速处理,由于等待事先请求完成的时间,客户端将看到总体响应时间缓慢。由于这种影响,测量客户端的响应时间非常重要。
|
**排队延迟(queueing delay)**通常占了高百分位点处响应时间的很大一部分。由于服务器只能并行处理少量的事务(例如,受其CPU核数的限制),所以只要有少量缓慢的请求就能阻碍后续请求的处理,这种效应有时被称为**头部阻塞(head-of-line blocking)**。即使后续请求在服务器上处理的非常迅速,由于需要等待先前请求完成,客户端最终看到的是缓慢的总体响应时间。因为存在这种效应,测量客户端的响应时间非常重要。
|
||||||
|
|
||||||
当为了测试系统的可扩展性而人为地产生负载时,产生负载的客户端需要不受响应时间的影响而不断发送请求。如果客户端在发送下一个请求之前等待先前的请求完成,那么这种行为会在测试中人为地保持队列的长度,而不是在实际中保持队列的长度,这会影响测量结果[23]。
|
为测试系统的可扩展性而人为产生负载时,产生负载的客户端要独立于响应时间不断发送请求。如果客户端在发送下一个请求之前等待先前的请求完成,这种行为会产生人为排队的效果,使得测试时的队列比现实情况更短,使测量结果产生偏差【23】。
|
||||||
|
|
||||||
> #### 实践中的百分位点
|
> #### 实践中的百分位点
|
||||||
>
|
>
|
||||||
> 在多重调用的后端服务里,高百分位数变得特别重要。即使并行调用,最终用户请求仍然需要等待最慢的并行呼叫完成。如图1-5所示,只需要一个缓慢的呼叫就可以使整个最终用户请求变慢。即使只有一小部分后端呼叫速度较慢,如果最终用户请求需要多个后端调用,则获得较慢调用的机会也会增加,因此较高比例的最终用户请求速度会变慢(效果称为尾部延迟放大[24])。
|
> 在多重调用的后端服务里,高百分位数变得特别重要。即使并行调用,最终用户请求仍然需要等待最慢的并行呼叫完成。如图1-5所示,只需要一个缓慢的呼叫就可以使整个最终用户请求变慢。即使只有一小部分后端呼叫速度较慢,如果最终用户请求需要多个后端调用,则获得较慢调用的机会也会增加,因此较高比例的最终用户请求速度会变慢(效果称为尾部延迟放大【24】)。
|
||||||
>
|
>
|
||||||
> 如果您想将响应时间百分点添加到您的服务的监视仪表板,则需要持续有效地计算它们。例如,您可能希望在最近10分钟内保持请求响应时间的滚动窗口。每一分钟,您都会计算出该窗口中的中值和各种百分数,并将这些度量值绘制在图上。
|
> 如果您想将响应时间百分点添加到您的服务的监视仪表板,则需要持续有效地计算它们。例如,您可能希望在最近10分钟内保持请求响应时间的滚动窗口。每一分钟,您都会计算出该窗口中的中值和各种百分数,并将这些度量值绘制在图上。
|
||||||
>
|
>
|
||||||
> 简单的实现是在时间窗口内保存所有请求的响应时间列表,并且每分钟对列表进行排序。如果对你来说效率太低,那么有一些算法能够以最小的CPU和内存成本(如正向衰减[25],t-digest [26]或HdrHistogram [27])来计算百分位数的近似值。请注意,平均百分比(例如,减少时间分辨率或合并来自多台机器的数据)在数学上没有意义 - 聚合响应时间数据的正确方法是添加直方图[28]。
|
> 简单的实现是在时间窗口内保存所有请求的响应时间列表,并且每分钟对列表进行排序。如果对你来说效率太低,那么有一些算法能够以最小的CPU和内存成本(如正向衰减【25】,t-digest【26】或HdrHistogram 【27】)来计算百分位数的近似值。请注意,平均百分比(例如,减少时间分辨率或合并来自多台机器的数据)在数学上没有意义 - 聚合响应时间数据的正确方法是添加直方图【28】。
|
||||||
|
|
||||||
![](img/fig1-5.png)
|
![](img/fig1-5.png)
|
||||||
|
|
||||||
**图1-5 当一个请求需要多个后端请求时,单个慢后端请求就会拖慢整个终端用请求**
|
**图1-5 当一个请求需要多个后端请求时,单个后端慢请求就会拖慢整个终端用户的请求**
|
||||||
|
|
||||||
|
### 应对负载的方法
|
||||||
|
|
||||||
|
现在我们已经讨论了用于描述负载的参数,和用于衡量性能的指标。可以开始认真讨论可扩展性了:当负载参数增加时,如何保持良好的性能?
|
||||||
|
|
||||||
### 应对负荷的方法
|
适应某一个级别负载的架构不太可能应付10倍的负载。如果你正在开发一个快速增长的服务,那么每次负载发生数量级的增长时,你可能都需要重新考虑架构——或者比这更频繁。
|
||||||
|
|
||||||
现在我们已经讨论了用于描述测量性能的负载和度量的参数,我们可以开始认真讨论可伸缩性:即使当我们的负载参数增加一些时,我们如何保持良好的性能呢?
|
人们经常讨论**纵向扩展(scaling up)**(**垂直扩展(vertical scaling)**,转向更强大的机器)和**横向扩展(scaling out)**(**水平扩展(horizontal scaling)**,将负载分布到多台小机器上)之间的对立。跨多台机器分配负载也称为“**无共享(shared-nothing)**”架构。可以在单台机器上运行的系统通常更简单,但高端机器可能非常贵,所以非常密集的负载通常无法避免地需要横向扩展。现实世界中的优秀架构需要将这两种方法务实地结合:例如使用几台足够强大的机器可能比大量的小型虚拟机更简单也更便宜。
|
||||||
|
|
||||||
适合于一个级别的负载的体系结构不太可能应付10倍的负载。如果您正在开发一个快速增长的服务,那么您可能需要重新考虑每个数量级负载增长的架构 - 或者甚至更多。
|
有些系统是**弹性(elastic)**的,这意味着可以在检测到负载增加时自动增加计算资源,而其他系统则是手动扩展(人工分析容量并决定向系统添加更多的机器)。如果负载**极难预测(highly unpredictable)**,则弹性系统可能很有用,但手动扩展系统更简单,并且意外操作可能会更少(参阅“[重新平衡分区](ch6.md#分区再平衡)”)。
|
||||||
|
|
||||||
人们经常谈到 scale-up(垂直扩展,转向更强大的机器)和scale-out(水平扩展,将负载分配到多个小型机器)之间的矛盾。在多台机器上分配负载也称为“无共享(shared-nothing)”体系结构。可以在一台机器上运行的系统通常更简单,但是高端机器可能变得非常昂贵,所以非常密集的工作量通常无法避免向外扩展。实际上,优秀的体系结构通常包含一些实用的方法:例如,使用几个功能相当强大的机器可能比大量的小型虚拟机更简单,更便宜。
|
跨多台机器部署**无状态服务(stateless services)**非常简单,但将带状态的数据系统从单节点变为分布式配置则可能引入许多额外复杂度。出于这个原因,直到最近常识都是将数据库放在单个节点上(纵向扩展),直到扩展成本或可用性需求迫使其改为分布式。
|
||||||
|
|
||||||
有些系统是弹性的,这意味着他们可以在检测到负载增加时自动添加计算资源,而其他系统则是手动扩展(人工分析容量并决定向系统添加更多计算机)。如果负载高度不可预测,则弹性系统可能非常有用,但手动缩放系统更简单,并且可能具有更少的操作意外(请参阅“重新平衡分区”第195页)。
|
随着分布式系统的工具和抽象越来越好,至少对于某些类型的应用而言,这种常识可能会改变。可以预见分布式数据系统将成为未来的默认设置,即使对不处理大量数据或流量的场景也如此。本书的其余部分将介绍多种分布式数据系统,不仅讨论它们在可扩展性方面的表现,还包括易用性和可维护性。
|
||||||
|
|
||||||
在多台机器上分发无状态服务非常简单,从单一节点到分布式设置的状态数据系统可能会带来很多额外的复杂性。出于这个原因,直到最近,人们普遍认为将数据库保持在单个节点上(扩展),直到缩放成本或高可用性要求迫使您将其改为分布式的。
|
大规模的系统架构通常是应用特定的。——没有通用的,一招鲜吃遍天的可扩展架构(不正式的叫法:**万金油(magic scaling sauce)** )。应用的问题可能是读取量,写入量,要存储的数据量,数据的复杂度,响应时间要求,访问模式,或者所有这些问题的大杂烩。
|
||||||
|
|
||||||
随着分布式系统的工具和抽象变得越来越好,这种常识可能会改变,至少对于某些类型的应用来说。可以想象,分布式数据系统将成为未来的默认设置,即使对于不处理大量数据或流量的用例也是如此。在本书的其余部分中,我们将介绍多种分布式数据系统,并讨论它们不仅在可伸缩性方面的表现,还包括易用性和可维护性。
|
举个例子,用于处理每秒十万个请求(每个大小为1 kB)的系统与用于处理每分钟3个请求(每个大小为2GB)的系统看上去会非常不一样,尽管两个系统有同样的数据吞吐量。
|
||||||
大规模运行的系统体系结构通常对应用程序具有高度的特定性 - 没有像通用的,一刀切的可扩展体系结构(非正式地称为魔力缩放magic scaling sauce )这样的事物。问题可能是读取量,写入量,要存储的数据量,数据的复杂程度,响应时间要求,访问模式,或者(通常)所有这些的混合物以及更多的问题。
|
|
||||||
|
|
||||||
例如,设计用于处理每秒100,000个请求(每个大小为1 kB)的系统与为每分钟3个请求(每个大小为2 GB)设计的系统看起来非常不同,即使两个系统的大小相同数据吞吐量。
|
一个良好适配应用的可扩展架构,是围绕着**假设(assumption)**建立的:哪些操作是常见的,哪些操作是罕见的——即负载参数。如果假设最终是错误的,那么为扩展所做的工程投入就白费了,最糟糕的是适得其反。在早期创业公司或非正式产品中,通常支持产品快速迭代的能力,要比可扩展至未来的假想负载要重要的多。
|
||||||
|
|
||||||
一个适合特定应用的体系结构是围绕着哪些操作是常见的,哪些是负载参数是罕见的。如果这些假设结果是错误的,那么缩放的工程努力至多是浪费的,最糟糕的是适得其反。在早期阶段的初创公司或非正式的产品中,能够快速迭代产品特征比扩展到假设的未来负载更重要。
|
尽管这些架构是应用程序特定的,但可扩展的架构通常也是从通用的积木块搭建而成的,并以常见的模式排列。在本书中,我们将讨论这些构件和模式。
|
||||||
|
|
||||||
尽管它们是特定于特定应用程序的,但可扩展架构通常是从通用构建模块构建而成,并以熟悉的模式排列。在本书中,我们将讨论这些构件和模式。
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
## 可维护性
|
## 可维护性
|
||||||
|
|
||||||
众所周知,软件的大部分成本并没不在最初的开发阶段,而是在于持续的维护修复漏洞:保持系统正常运行,调查故障,适应新的平台,修改新的用例,偿还技术债务,增加新的功能。
|
众所周知,软件的大部分开销并不在最初的开发阶段,而是在于持续的维护——修复漏洞,保持系统正常运行,调查失效,适配新的平台,为新的场景进行修改,偿还技术债,添加新的功能。
|
||||||
|
|
||||||
然而不幸的是,许多从事软件系统工作的人不喜欢维护所谓的遗留系统 - 也许涉及修复其他人的错误或处理已经过时的平台,或者被迫做从未有意为之的系统。每一个遗留系统都是以自己的方式让人不爽,所以很难给出一个一般的建议来处理它们。
|
不幸的是,许多从事软件系统行业的人不喜欢维护所谓的**遗留(legacy)**系统——也许涉及修复其他人的错误,和过时的平台打交道,或者系统被迫使用于一些份外工作。每一个遗留系统都以自己的方式让人不爽,所以很难给出一个通用的建议来和它们打交道。
|
||||||
|
|
||||||
但是,我们可以也应该设计软件,以便在维护期间尽可能减少痛苦,从而避免自己创建传统软件。为此,我们将特别关注软件系统的三个设计原则:
|
但是我们可以,也应该以这样一种方式来设计软件:在设计之初就尽量考虑尽可能减少维护期间的痛苦,从而避免自己的软件系统变成遗留系统。为此,我们将特别关注软件系统的三个设计原则:
|
||||||
|
|
||||||
* 可操作性
|
***可操作性(Operability)***
|
||||||
|
|
||||||
方便运营团队保持系统平稳运行。
|
便于运维团队保持系统平稳运行。
|
||||||
|
|
||||||
* 简单
|
***简单性(Simplicity)***
|
||||||
|
|
||||||
通过从系统中消除尽可能多的复杂性,使新工程师能够轻松理解系统。 (注意这与用户界面的简单性不一样。)
|
从系统中消除尽可能多的**复杂度(complexity)**,使新工程师也能轻松理解系统。(注意这和用户接口的简单性不一样。)
|
||||||
|
|
||||||
可进化
|
***可演化性(evolability)***
|
||||||
|
|
||||||
使工程师能够轻松地对将来的系统进行更改,并根据需求变化将其适用于意外的用例。也被称为可扩展性,可修改性或可塑性。
|
使工程师在未来能轻松地对系统进行更改,当需求变化时为新应用场景做适配。也称为**可扩展性(extensibility)**,**可修改性(modifiability)**或**可塑性(plasticity)**。
|
||||||
|
|
||||||
|
和之前提到的可靠性、可扩展性一样,实现这些目标也没有简单的解决方案。不过我们会试着想象具有可操作性,简单性和可演化性的系统会是什么样子。
|
||||||
|
|
||||||
正如以前的可靠性和可扩展性一样,实现这些目标也没有简单的解决方案。相反,我们会考虑可操作性,简单性和可演化性的系统。
|
### 可操作性:人生苦短,关爱运维
|
||||||
|
|
||||||
### 可操作性:关爱运维
|
有人认为,“良好的运维经常可以绕开垃圾(或不完整)软件的局限性,而再好的软件摊上垃圾运维也没法可靠运行“。尽管运维的某些方面可以,而且应该是自动化的,但在最初建立正确运作的自动化机制仍然取决于人。
|
||||||
|
|
||||||
有人认为,“良好的运维经常可以解决不好的(或不完整的)软件的局限性,再好的系统也架不住垃圾运维。尽管运维的某些方面可以而且应该是自动化的,但首先要确保自动化的正确性,然后由人来完成。
|
运维团队对于保持软件系统顺利运行至关重要。一个优秀运维团队的典型职责如下(或者更多)【29】:
|
||||||
|
|
||||||
运维团队对于保持软件系统顺利运行至关重要。一个优秀的运维团队通常负责以下内容,以及更多[29]:
|
* 监控系统的运行状况,并在服务状态不佳时快速恢复服务
|
||||||
|
* 跟踪问题的原因,例如系统故障或性能下降
|
||||||
|
* 及时更新软件和平台,比如安全补丁
|
||||||
|
* 了解系统间的相互作用,以便在异常变更造成损失前进行规避。
|
||||||
|
* 预测未来的问题,并在问题出现之前加以解决(例如,容量规划)
|
||||||
|
* 建立部署,配置、管理方面的良好实践,编写相应工具
|
||||||
|
* 执行复杂的维护任务,例如将应用程序从一个平台迁移到另一个平台
|
||||||
|
* 当配置变更时,维持系统的安全性
|
||||||
|
* 定义工作流程,使运维操作可预测,并保持生产环境稳定。
|
||||||
|
* 铁打的营盘流水的兵,维持组织对系统的了解。
|
||||||
|
|
||||||
* 监控系统的运行状况,并在服务状况不佳时快速恢复服务
|
良好的可操作性意味着更轻松的日常工作,进而运维团队能专注于高价值的事情。数据系统可以通过各种方式使日常任务更轻松:
|
||||||
* 追踪问题的原因,例如系统故障或性能下降
|
|
||||||
* 保持软件和平台保持最新状态,包括安全补丁
|
|
||||||
* 了解不同的系统如何相互影响,以便在造成损害之前避免有问题的更改
|
|
||||||
* 预测未来的问题并在问题出现之前加以解决(例如扩容计划)
|
|
||||||
* 建立部署,配置管理等方面的良好实践和工具
|
|
||||||
* 执行复杂的维护任务,例如将应用程序从一个平台移动到另一个平台
|
|
||||||
* 随着配置更改,维护系统的安全性
|
|
||||||
* 定义使操作可预测的流程,并帮助保持生产环境稳定
|
|
||||||
* 保持组织对系统的了解,即使是个人来来去去
|
|
||||||
|
|
||||||
良好的可操作性意味着使日常工作变得简单,使运营团队能够专注于高价值的活动。数据系统可以做各种事情,使日常任务变得简单,包括:
|
* 通过良好的监控,提供对系统内部状态和运行时行为的**可见性(visibility)**
|
||||||
|
* 为自动化提供良好支持,将系统与标准化工具相集成
|
||||||
* 提供对系统的运行时行为和内部的可视性,并具有良好的监控能力
|
* 避免依赖单台机器(在整个系统继续不间断运行的情况下允许机器停机维护)
|
||||||
* 为自动化和与标准工具的集成提供良好的支持
|
* 提供良好的文档和易于理解的操作模型(“如果做X,会发生Y”)
|
||||||
* 避免依赖个别机器(在整个系统继续不间断运行的情况下允许机器停机维护)
|
* 提供良好的默认行为,但需要时也允许管理员自由覆盖默认值
|
||||||
* 提供良好的文档和易于理解的操作模型(“如果我做X,Y会发生”)
|
* 有条件时进行自我修复,但需要时也允许管理员手动控制系统状态
|
||||||
* 提供良好的默认行为,还可以让管理员在需要时自由覆盖默认值
|
* 行为可预测,最大限度减少意外
|
||||||
* 在适当的情况下进行自我修复,并在需要时让管理员手动控制系统状态
|
|
||||||
* 展现可预见的行为,最大限度地减少惊喜
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
### 简单性:管理复杂性
|
### 简单性:管理复杂度
|
||||||
|
|
||||||
小型软件项目可以有简单而富有表现力的代码,但随着项目越来越大,它们往往变得非常复杂,难以理解。这种复杂性拖慢了每个需要在系统上工作的人员,进一步增加了维护成本。一个陷入复杂的软件项目有时被描述为一个大泥潭[30]。
|
小型软件项目可以使用简单讨喜,富表现力的代码。但随着项目越来越大,它们往往变得非常复杂,难以理解。这种复杂度拖慢了所有系统相关人员,进一步增加了维护成本。一个陷入复杂泥潭的软件项目有时被描述为**烂泥坑(a big ball of mud)**【30】。
|
||||||
|
|
||||||
复杂性有各种可能的症状:状态空间的爆炸,模块的紧密耦合,纠结的依赖关系,不一致的命名和术语,旨在解决性能问题的黑客攻击,解决其他问题的特殊框架等等。已经有很多关于这个话题的说法[31,32,33]。
|
**复杂度(complexity)**有各种可能的症状:状态空间激增,模块间紧密耦合,纠结的依赖关系,不一致的命名和术语,解决性能问题的Hack,需要绕开的特例,等等。已经有很多关于这个话题的讨论【31,32,33】。
|
||||||
|
|
||||||
当复杂性使维护困难时,预算和时间安排通常会超支。在复杂的软件中,当发生变化时,引入错误的风险也更大:系统开发人员难以理解和推理时,隐藏的假设,意想不到的后果和意外的交互更容易被忽略。相反,降低复杂性大大提高了软件的可维护性,因此简单性应该是我们构建系统的关键目标。
|
因为复杂度导致维护困难时,预算和时间安排通常会超支。在复杂的软件中进行变更,引入错误的风险也更大:当开发人员难以理解系统时,隐藏的假设、无意的后果和意外的交互就更容易被忽略。相反,降低复杂度能极大地提高软件的可维护性,因此简单性应该是构建系统的一个关键目标。
|
||||||
|
|
||||||
简化系统并不一定意味着减少其功能;它也意味着消除意外的复杂性。 Moseley和Marks [32]把复杂性定义为偶然的,如果软件解决的问题不是固有的(用户看到的),而只是由实现产生的。
|
简化系统并不一定意味着减少功能;它也可以意味着消除**额外的(accidental)**的复杂度。 Moseley和Marks【32】把**额外复杂度**定义为:由实现产生,而非继承自(软件本身所解决)问题的复杂度。
|
||||||
|
|
||||||
我们用来消除意外复杂性的最好工具之一是抽象。一个好的抽象可以隐藏大量的实现细节在一个干净,简单易懂的外观背后。一个好的抽象也可以用于各种不同的应用程序。这不仅是重复使用效率比多次重复实现类似的东西更高效,而且还会导致更高质量的软件,因为抽象组件中的质量改进将有利于所有使用它的应用程序。
|
用于消除**额外复杂度**的最好工具之一是**抽象(abstraction)**。一个好的抽象可以将大量实现细节隐藏在一个干净,简单易懂的外观下面。一个好的抽象也可以广泛用于各类不同应用。比起重复造很多轮子,重用抽象不仅更有效率,而且有助于开发高质量的软件。抽象组件的质量改进将使所有使用它的应用受益。
|
||||||
|
|
||||||
例如,高级编程语言是隐藏机器代码,CPU寄存器和系统调用的抽象。 SQL是隐藏复杂的磁盘和内存数据结构,
|
例如,高级编程语言是一种抽象,隐藏了机器码、CPU寄存器和系统调用。 SQL也是一种抽象,隐藏了复杂的磁盘/内存数据结构、来自其他客户端的并发请求、崩溃后的不一致性。当然在用高级语言编程时,我们仍然用到了机器码;只不过没有**直接(directly)**使用罢了,正是因为编程语言的抽象,我们才不必去考虑这些实现细节。
|
||||||
|
|
||||||
来自其他客户端的并发请求以及崩溃之后的不一致的抽象。当然,在用高级语言编程时,我们仍然使用机器码;我们只是不直接使用它,因为编程语言抽象使我们不必考虑它。
|
抽象可以帮助我们将系统的复杂度控制在可管理的水平。但是找到好的抽象是非常困难的。在分布式系统领域虽然有许多好的算法,但我们并不清楚它们应该打包成什么样抽象
|
||||||
|
|
||||||
但是,找到好的抽象是非常困难的。在分布式系统领域,虽然有许多好的算法,但是我们应该如何将它们打包成抽象,这样就不那么清楚了,这些抽象可以帮助我们将系统的复杂性保持在可管理的水平。
|
本书将紧盯那些允许我们将大型系统的部分提取为定义明确,可重用的组件的优秀抽象。
|
||||||
|
|
||||||
在整本书中,我们将继续睁大眼睛来看好抽象,从而使我们能够将大型系统的一部分抽象成定义明确,可重用的组件。
|
### 可演化性:拥抱变化
|
||||||
|
|
||||||
|
系统的需求永远不变,基本是不可能的。更可能的情况是,它们处于常态的变化中:你了解了新的事实,出现意想不到的应用场景,业务优先级发生变化,用户要求新功能,新平台取代旧平台,法律或监管要求发生变化,系统增长迫使架构变化等。
|
||||||
|
|
||||||
|
在组织流程方面,**敏捷(agile)**工作模式为适应变化提供了一个框架。敏捷社区还开发了对在频繁变化的环境中开发软件很有帮助的技术工具和模式,如**测试驱动开发(TDD, test-driven development)**和**重构(refactoring)**。
|
||||||
|
|
||||||
### 可演化性:易于改变
|
这些敏捷技术的大部分讨论都集中在相当小的规模(同一个应用中的几个代码文件)。本书将探索在更大数据系统层面上提高敏捷性的方法,可能由几个不同的应用或服务组成。例如,为了将装配主页时间线的方法从方法1变为方法2,你会如何“重构”推特的架构 ?
|
||||||
|
|
||||||
你的系统的需求不会永远保持不变。他们更有可能处于不断变化的状态:您学习新的事实,之前出现意想不到的用例,业务优先级发生变化,用户请求新功能,新平台取代旧平台,法律或监管要求发生变化,系统增长强迫架构发生变化等
|
修改数据系统并使其适应不断变化需求的容易程度,是与**简单性**和**抽象性**密切相关的:简单易懂的系统通常比复杂系统更容易修改。但由于这是一个非常重要的概念,我们将用一个不同的词来指代数据系统层面的敏捷性:**可演化性(evolvability)**【34】。
|
||||||
|
|
||||||
在组织流程方面,敏捷工作模式为适应变化提供了一个框架。敏捷社区还开发了技术工具和模式,这些工具和模式在频繁变化的环境中开发软件时很有帮助,如测试驱动开发(TDD)和重构。
|
|
||||||
|
|
||||||
这些敏捷技术的大部分讨论都集中在相当小的本地规模(同一个应用程序中的源代码文件)。在本书中,我们将探索在更大的数据系统层面上提高敏捷性的方法,可能由几个不同特性的应用程序或服务组成。例如,您将如何“重构”Twitter的架构来将Home Time从方法1重构为方法2?
|
|
||||||
|
|
||||||
您可以轻松修改数据系统并使其适应不断变化的需求,这与其简单性和抽象性密切相关:简单易懂的系统通常比复杂系统更容易修改。但是由于这是一个非常重要的想法,我们将用一个不同的词来指代数据系统层面的敏捷性:可进化性[34]。
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
## 本章小结
|
## 本章小结
|
||||||
|
|
||||||
在本章中,我们探讨了一些关于数据密集型应用程序的基本思路。这些原则将指导我们阅读本书的其余部分,在这里我们深入技术细节。
|
本章探讨了一些关于数据密集型应用的基本思考方式。这些原则将指导我们阅读本书的其余部分,那里将会深入技术细节。
|
||||||
|
|
||||||
一个应用程序必须满足各种要求才能有用。有一些功能需求(它应该做什么,比如允许以各种方式存储,检索,搜索和处理数据)以及一些非功能性需求(一般属性如安全性,可靠性,合规性,可伸缩性,兼容性和可维护性)。在本章中,我们详细讨论了可靠性,可扩展性和可维护性。
|
一个应用必须满足各种需求才称得上有用。有一些**功能需求(functional requirements)**(它应该做什么,比如允许以各种方式存储,检索,搜索和处理数据)以及一些**非功能性需求(nonfunctional )**(通用属性,例如安全性,可靠性,合规性,可扩展性,兼容性和可维护性)。在本章详细讨论了可靠性,可扩展性和可维护性。
|
||||||
|
|
||||||
**可靠性**意味着即使发生故障,也能使系统正常工作。故障可以是硬件(通常是随机的和不相关的),软件(缺陷通常是系统的,难以处理的),以及人类(不可避免地会不时出错)。容错技术可以隐藏最终用户的某些类型的故障。
|
**可靠性(Reliability)**意味着即使发生故障,系统也能正常工作。故障可能发生在硬件(通常是随机的和不相关的),软件(通常是系统性的Bug,很难处理),和人类(不可避免地时不时出错)。**容错技术**可以对终端用户隐藏某些类型的故障。
|
||||||
|
|
||||||
**可扩展性**意味着即使在负载增加的情况下也有保持性能的策略。为了讨论可扩展性,我们首先需要定量描述负载和性能的方法。我们简单地将Twitter的家庭时间表作为描述负载的一个例子,并将响应时间百分比作为衡量每个时间段的一种方式。在可扩展的系统中,您可以添加处理能力以在高负载下保持可靠。
|
**可扩展性(Scalability)**意味着即使在负载增加的情况下也有保持性能的策略。为了讨论可扩展性,我们首先需要定量描述负载和性能的方法。我们简要了解了推特主页时间线的例子,介绍描述负载的方法,并将响应时间百分位点作为衡量性能的一种方式。在可扩展的系统中可以添加**处理容量(processing capacity)**以在高负载下保持可靠。
|
||||||
|
|
||||||
**可维护性**有许多方面,但实质上是为需要使用该系统的工程和运营团队提供更好的生活。良好的抽象可以帮助降低复杂性,并使系统更易于修改和适应新的用例。良好的可操作性意味着对系统的健康具有良好的可见性,并具有有效的管理方式。
|
**可维护性(Maintainability)**有许多方面,但实质上是关于工程师和运维团队的生活质量的。良好的抽象可以帮助降低复杂度,并使系统易于修改和适应新的应用场景。良好的可操作性意味着对系统的健康状态具有良好的可见性,并拥有有效的管理手段。
|
||||||
|
|
||||||
不幸的是,为了使应用程序可靠,可扩展或可持续,并不容易。但是,某些模式和技术会不断出现在不同的应用程序中。在接下来的几章中,我们将看看数据系统的一些例子,并分析它们如何实现这些目标。
|
|
||||||
在本书后面的第三部分中,我们将看看由几个组件组成的系统的模式,比如图1-1中的组件。
|
|
||||||
|
|
||||||
|
不幸的是,使应用可靠,可扩展或可持续并不容易。但是某些模式和技术会不断重新出现在不同的应用中。在接下来的几章中,我们将看到一些数据系统的例子,并分析它们如何实现这些目标。
|
||||||
|
|
||||||
|
在本书后面的[第三部分](part-iii.md)中,我们将看到一种模式:几个组件协同工作以构成一个完整的系统(例如[图1-1](img/fig1-1.png)中的)
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
## 参考文献
|
## 参考文献
|
||||||
|
|
||||||
[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. Michael Stonebraker and Uğur Çetintemel: “['One Size Fits All': An Idea Whose Time Has Come and Gone](http://citeseerx.ist.psu.edu/viewdoc/download?doi=10.1.1.68.9136&rep=rep1&type=pdf),” at *21st International Conference on Data Engineering* (ICDE), April 2005.
|
||||||
|
|
||||||
|
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.
|
||||||
|
|
||||||
1. Walter L. Heimerdinger and Charles B. Weinstock:
|
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.
|
||||||
“[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.:
|
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.
|
||||||
“[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:
|
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),
|
||||||
“[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.
|
October 2010.
|
||||||
|
|
||||||
5. Brian Beach:
|
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.
|
||||||
“[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:
|
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.
|
||||||
“[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
|
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)
|
||||||
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:
|
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.
|
||||||
“[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:
|
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.
|
||||||
“[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:
|
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.
|
||||||
“[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:
|
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.
|
||||||
“[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:
|
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.
|
||||||
“[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:
|
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.
|
||||||
“[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:
|
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.
|
||||||
“[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:
|
15. Raffi Krikorian: “[Timelines at Scale](http://www.infoq.com/presentations/Twitter-Timeline-Scalability),” at *QCon San Francisco*, November 2012.
|
||||||
“[Timelines at Scale](http://www.infoq.com/presentations/Twitter-Timeline-Scalability),”
|
|
||||||
at *QCon San Francisco*, November 2012.
|
|
||||||
|
|
||||||
16. Martin Fowler:
|
16. Martin Fowler: *Patterns of Enterprise Application Architecture*. Addison Wesley, 2002. ISBN: 978-0-321-12742-6
|
||||||
*Patterns of Enterprise Application Architecture*. Addison Wesley, 2002.
|
|
||||||
ISBN: 978-0-321-12742-6
|
|
||||||
|
|
||||||
17. Kelly Sommers:
|
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.
|
||||||
“[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.:
|
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.
|
||||||
“[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:
|
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.
|
||||||
“[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:
|
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.
|
||||||
“[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:
|
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.
|
||||||
“[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:
|
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.
|
||||||
“[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:
|
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 74–80, February 2013. [doi:10.1145/2408776.2408794](http://dx.doi.org/10.1145/2408776.2408794)
|
||||||
“[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 74–80, February 2013.
|
|
||||||
[doi:10.1145/2408776.2408794](http://dx.doi.org/10.1145/2408776.2408794)
|
|
||||||
|
|
||||||
24. Graham Cormode, Vladislav
|
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.
|
||||||
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:
|
25. Ted Dunning and Otmar Ertl: “[Computing Extremely Accurate Quantiles Using t-Digests](https://github.com/tdunning/t-digest),” *github.com*, March 2014.
|
||||||
“[Computing Extremely Accurate Quantiles Using t-Digests](https://github.com/tdunning/t-digest),” *github.com*, March 2014.
|
|
||||||
|
|
||||||
26. Gil Tene:
|
26. Gil Tene: “[HdrHistogram](http://www.hdrhistogram.org/),” *hdrhistogram.org*.
|
||||||
“[HdrHistogram](http://www.hdrhistogram.org/),” *hdrhistogram.org*.
|
|
||||||
|
|
||||||
27. Baron Schwartz:
|
27. Baron Schwartz: “[Why Percentiles Don’t Work the Way You Think](https://www.vividcortex.com/blog/why-percentiles-dont-work-the-way-you-think),” *vividcortex.com*, December 7, 2015.
|
||||||
“[Why Percentiles Don’t 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:
|
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
|
||||||
“[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.
|
System Administration Conference* (LISA), November 2007.
|
||||||
|
|
||||||
29. Brian Foote and Joseph Yoder:
|
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.
|
||||||
“[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
|
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
|
||||||
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:
|
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.
|
||||||
“[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:
|
32. Rich Hickey: “[Simple Made Easy](http://www.infoq.com/presentations/Simple-Made-Easy),” at *Strange Loop*, September 2011.
|
||||||
“[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:
|
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)
|
||||||
“[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)
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
@ -12,9 +12,11 @@ Martin是一位常规会议演讲者,博主和开源贡献者。他认为,
|
|||||||
|
|
||||||
## 关于译者
|
## 关于译者
|
||||||
|
|
||||||
* [冯若航](https://vonng.com/about)
|
[冯若航](https://vonng.com/about)
|
||||||
|
|
||||||
PostgreSQL DBA @ TanTan,前Alibaba+-Finplus 架构师/全栈工程师 (15.08 ~ 17.12)
|
PostgreSQL DBA @ TanTan
|
||||||
|
|
||||||
|
前Alibaba+-Finplus 架构师/全栈工程师 (15.08 ~ 17.12)
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
240
ddia/glossary.md
Normal file
240
ddia/glossary.md
Normal file
@ -0,0 +1,240 @@
|
|||||||
|
# 术语表 【DRAFT】
|
||||||
|
|
||||||
|
> 请注意,本术语表中的定义简短而简单,旨在传达核心思想,而不是术语的完整细微之处。 有关更多详细信息,请参阅正文中的参考资料。
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
[TOC]
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
### 异步(asynchronous)
|
||||||
|
|
||||||
|
不等待某些事情完成(例如,通过网络将数据发送到另一个节点),并且不会假设要花多长时间。请参阅第153页上的“同步与异步复制”,第284页上的“同步与异步网络”,以及第306页上的“系统模型与现实”。
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
### 原子(atomic)
|
||||||
|
|
||||||
|
1.在并发操作的上下文中:描述一个在单个时间点看起来生效的操作,所以另一个并发进程永远不会遇到处于“半完成”状态的操作。另见隔离。
|
||||||
|
|
||||||
|
2.在事务的上下文中:即使出现故障,将一组必须全部提交或全部回滚的写入组合在一起。参见第223页的“原子性”和第354页的“原子提交和两阶段提交(2PC)”。
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
### 背压(backpressure)
|
||||||
|
|
||||||
|
强制一些数据的发送者减慢,因为收件人不能保留
|
||||||
|
与它一起。也称为流量控制。请参阅第441页上的“消息系统”。
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
### 批处理(batch process)
|
||||||
|
|
||||||
|
一种计算,它将一些固定的(通常是大的)数据集作为输入,并将其他一些数据作为输出,而不修改输入。见第十章。
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
### 边界(bounded)
|
||||||
|
|
||||||
|
有一些已知的上限或大小。例如,在网络延迟的情况下(请参阅“超时和未定义的延迟”在本页281)和数据集(请参阅第11章的介绍)。
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
### 拜占庭故障(Byzantine fault)
|
||||||
|
|
||||||
|
以任意方式表现不正确的节点,例如通过向其他节点发送矛盾或恶意消息。请参阅第304页上的“拜占庭故障”。
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
### 缓存(cache)
|
||||||
|
|
||||||
|
最近记住使用数据的组件,以加快未来对相同数据的读取速度。它通常是不完整的:因此,如果缓存中缺少某些数据,则必须从某些底层较慢的数据存储系统具有完整的数据副本。
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
### CAP定理(CAP theorem)
|
||||||
|
|
||||||
|
一个被广泛误解的理论结果,在实践中是没有用的。参见第336页的“CAP定理”。
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
### 因果关系(causality)
|
||||||
|
|
||||||
|
事件之间的依赖关系,当一件事发生在另一件事情之前。例如,后面的事件是对早期事件的回应,或者建立在更早的事件上,或者应该根据先前的事件来理解。请参阅第186页上的“发生之前的关系和并发性”和第339页上的“排序和因果关系”。
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
### 共识(consensus)
|
||||||
|
|
||||||
|
分布式计算的一个基本问题,就是让几个节点同意某些事情(例如,哪个节点应该是数据库集群的领导者)。问题比乍看起来要困难得多。请参阅第364页上的“容错共识”。
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
### 数据仓库(data warehouse)
|
||||||
|
|
||||||
|
一个数据库,其中来自几个不同的OLTP系统的数据已经被合并和准备用于分析目的。请参阅第91页上的“数据仓库”。
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
### 声明式(declarative)
|
||||||
|
|
||||||
|
描述某些东西应该具有的属性,但不知道如何实现它的确切步骤。在查询的上下文中,查询优化器采用声明性查询并决定如何最好地执行它。请参阅第42页上的“数据的查询语言”。
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
### 非规范化(denormalize)
|
||||||
|
|
||||||
|
为了加速读取,在标准数据集中引入一些冗余或重复数据,通常采用缓存或索引的形式。非规范化的值是一种预先计算的查询结果,视图。请参见“单对象和多对象操作”(第228页)和“从同一事件日志中派生多个视图”(第461页)。
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
### 派生数据(derived data)
|
||||||
|
|
||||||
|
通过可重复的流程从其他数据创建的数据集,如有必要,您可以再次运行该数据集。通常,需要派生数据来加速对数据的特定读访问。索引,缓存和物化视图是派生数据的示例。参见第三部分的介绍。
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
### 确定性(deterministic)
|
||||||
|
|
||||||
|
描述一个函数,如果给它相同的输入,则总是产生相同的输出。这意味着它不能依赖于随机数字,时间,网络通信或其他不可预测的事情。
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
### 分布式(distributed)
|
||||||
|
|
||||||
|
在由网络连接的多个节点上运行。以部分故障为特征:系统的某些部分可能被破坏,而其他部分仍在工作,软件通常不可能知道究竟是什么被破坏。请参阅第274页上的“故障和部分故障”。
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
### 持久(durable)
|
||||||
|
|
||||||
|
以某种方式存储数据,即使发生各种故障,也不会丢失数据。请参阅第226页上的“耐用性”。
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
### ETL(Extract-Transform-Load)
|
||||||
|
|
||||||
|
提取-转换-加载(Extract-Transform-Load)。从源数据库中提取数据,将其转换为更适合分析查询的形式,并将其加载到数据仓库或批处理系统中的过程。请参阅第91页上的“数据仓库”。
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
### 故障转移(failover)
|
||||||
|
|
||||||
|
在具有单一领导者的系统中,故障转移是将领导角色从一个节点转移到另一个节点的过程。请参阅第156页的“处理节点中断”。
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
### 容错(fault-tolerant)
|
||||||
|
|
||||||
|
如果出现问题(例如,机器崩溃或网络连接失败),可以自动恢复。请参阅第6页上的“可靠性”。
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
### 流量控制(flow control)
|
||||||
|
|
||||||
|
见背压(backpressure)。
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
### 追随者(follower)
|
||||||
|
|
||||||
|
不直接接受来自客户端的任何写入的副本,但仅处理从领导者收到的数据更改。也称为辅助,从,只读副本或热备份。请参阅第152页上的“领导和追随者”。
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
### 全文检索(full-text search)
|
||||||
|
|
||||||
|
通过任意关键字来搜索文本,通常具有附加特征,例如匹配类似的拼写词或同义词。全文索引是一种支持这种查询的次级索引。请参见第88页上的“全文搜索和模糊索引”。
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
### 图(graph)
|
||||||
|
|
||||||
|
由顶点组成的数据结构(可以引用的东西,也称为节点或实体)和边(从一个顶点到另一个顶点的连接,也称为关系或弧)。请参阅第49页上的“类似图形的数据模型”。
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
### 散列(hash)
|
||||||
|
|
||||||
|
汇集有共同点的记录。在一个记录与另一个记录有关(外键,文档参考,图中的边)的情况下最常用,查询需要获
|
||||||
|
|
||||||
|
取参考所指向的记录。请参阅第33页上的“多对一和多对多关系”和第393页上的“减少端连接和分组”。
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
### 幂等(idempotent)
|
||||||
|
|
||||||
|
### 索引(index)
|
||||||
|
|
||||||
|
### 隔离(isolation)
|
||||||
|
|
||||||
|
### 连接(join)
|
||||||
|
|
||||||
|
### 领导者(leader)
|
||||||
|
|
||||||
|
当数据或服务被复制到多个节点时,领导是被允许进行更改的指定副本。领导者可以通过某些协议选举产生,也可以由管理者手动选择。也被称为主或主。见“领导和F
|
||||||
|
|
||||||
|
### 线性化(linearizable)
|
||||||
|
|
||||||
|
### 局部性(locality)
|
||||||
|
|
||||||
|
### 锁(lock)
|
||||||
|
|
||||||
|
### 日志(log)
|
||||||
|
|
||||||
|
### 物化(materialize)
|
||||||
|
|
||||||
|
### 节点(node)
|
||||||
|
|
||||||
|
### 规范化(normalized)
|
||||||
|
|
||||||
|
### OLAP(Online Analytic Processing)
|
||||||
|
|
||||||
|
### OLTP(Online Transaction Processing)
|
||||||
|
|
||||||
|
### 分区(partitioning)
|
||||||
|
|
||||||
|
### 百分位点(percentile)
|
||||||
|
|
||||||
|
### 主键(primary key)
|
||||||
|
|
||||||
|
### 法定人数(quorum)
|
||||||
|
|
||||||
|
### 再平衡(rebalance)
|
||||||
|
|
||||||
|
### 复制(replication)
|
||||||
|
|
||||||
|
### 模式(schema)
|
||||||
|
|
||||||
|
### 次级索引(secondary index)
|
||||||
|
|
||||||
|
### 可序列化(serializable)
|
||||||
|
|
||||||
|
### 无共享(shared-nothing)
|
||||||
|
|
||||||
|
### 偏差(skew)
|
||||||
|
|
||||||
|
脑裂(split brain)
|
||||||
|
|
||||||
|
### 存储过程(stored procdure)
|
||||||
|
|
||||||
|
### 流处理(stream process)
|
||||||
|
|
||||||
|
### 同步(synchronous)
|
||||||
|
|
||||||
|
### 记录系统(system of record)
|
||||||
|
|
||||||
|
### 超时(timeout)
|
||||||
|
|
||||||
|
### 全序(total order)
|
||||||
|
|
||||||
|
### 事务(transaction)
|
||||||
|
|
||||||
|
### 两阶段提交(2PC, two-phase commit)
|
||||||
|
|
||||||
|
### 两阶段锁定(2PL, two-phase locking)
|
||||||
|
|
||||||
|
### 无限制(unbounded)
|
||||||
|
|
||||||
|
w
|
Loading…
Reference in New Issue
Block a user