全书术语

全书反复用到的术语,每个只在这里讲一次,章节页链过来。按第一次出现的章排,同一章里按出现顺序。每条给英文、本站的中文译法和本站自己写的解释(不是原书词汇表的翻译);末尾的链接回到第一次讲它的那一章。译本的译法可能和这里不同,按英文对。

第 1 章起

OLTP (online transaction processing)在线事务处理

按键取出少量记录,按用户的操作逐条增删改。查询是写在应用代码里的固定几种,每次只碰几行,要求延迟低。

第一次出现:第 1 章 §1.1

OLAP / analytics联机分析处理 / 分析

一次扫过大量记录,算计数、求和、平均这类汇总,不返回单条记录。查询多是分析师临时写的,数据集从 TB 到 PB 级。

第一次出现:第 1 章 §1.1

data warehouse数据仓库

一个单独的数据库,存公司各个业务系统数据的只读副本,专门给分析用。分析师在这里怎么查都不影响线上业务,存储方式也按分析查询优化。

第一次出现:第 1 章 §1.2

ETL / ELT (extract–transform–load)抽取、转换、加载

把数据从业务库抽出来,转换成适合分析的模式并清洗,再加载进数据仓库。先加载、在仓库里再转换的叫 ELT。后来推广为更一般的数据管道。

第一次出现:第 1 章 §1.2

data lake数据湖

集中存放可能对分析有用的数据副本,只存文件,不规定格式、数据模型和模式。比关系型存储灵活,也更便宜,数据科学家用得多。

第一次出现:第 1 章 §1.2

system of record (source of truth)记录系统(事实来源)

数据第一次写入的地方,存权威的那一份,每个事实只记一次。别的系统和它对不上时,以它为准。是不是记录系统取决于在应用里怎么用,不取决于用的是哪种数据库。

第一次出现:第 1 章 §1.3

derived data派生数据

从别处已有的数据加工出来的数据,比如缓存、索引、物化视图、训练出的模型。严格说是冗余的,丢了能从源头重建,但往往是读性能离不开的。

第一次出现:第 1 章 §1.3

node节点

分布式系统里,经网络通信的每一个参与进程。

第一次出现:第 1 章 §3

GDPR (General Data Protection Regulation)《通用数据保护条例》

欧盟的数据保护法规,2018 年起适用。书里多处提到它:被遗忘权给不可变日志和 LSM 树带来的删除难题,以及第 14 章引的同意、目的限定和数据最小化条文。

第一次出现:第 1 章 §4

data minimization数据最小化

只为明确的目的收集必要的数据,不挪作他用,不再需要就删。和「先多存,说不定以后有用」的大数据思路正相反。

第一次出现:第 1 章 §4

第 2 章起

fan-out扇出

一个请求引出多少个下游请求,这个倍数叫扇出。写的时候先推好(物化)的做法,写的代价按扇出放大。

第一次出现:第 2 章 §1.2

percentile百分位数

把响应时间从快到慢排好,排在某个位置上的值。p50 即中位数,p99 表示一百个请求里只有一个比它慢。几台机器的百分位不能取平均,要合并直方图再算。

第一次出现:第 2 章 §2.2

tail latency尾延迟

p99、p999 这类高百分位的响应时间。一个请求要并行调很多后端时,尾延迟会被放大。

第一次出现:第 2 章 §2.2

SLO / SLA服务水平目标 / 服务水平协议

SLO 用百分位、可用率之类的数给服务定目标;SLA 是写明没达到目标时怎么办的合同。

第一次出现:第 2 章 §2.3

fault tolerance容错

某些部件出故障时,系统仍然提供该提供的服务。容错总有范围:能扛住哪几类故障、扛住几个。

第一次出现:第 2 章 §3.1

shared-nothing architecture无共享架构

多台机器各有 CPU、内存、磁盘,靠普通网络在软件层面协调,也叫横向扩展。代价是要分片,还要面对分布式系统的全部复杂性。

第一次出现:第 2 章 §4.2

第 3 章起

declarative query language声明式查询语言

只说要什么样的结果(条件、排序、分组),不说怎么算;用哪个索引、按什么顺序连接、要不要并行,由数据库的查询优化器决定。所以数据库改进了执行方式,查询不用改。

第一次出现:第 3 章 §0

normalization / denormalization规范化 / 反规范化

给人看的信息只存一处,别处用一个不会变的 ID 引用,叫规范化;把信息抄进每条用到它的记录,叫反规范化。前者写便宜、读时要连接,后者读快、写时要更新所有副本。

第一次出现:第 3 章 §1.2

schema-on-read / schema-on-write读时模式 / 写时模式

数据库不检查数据结构,由读数据的代码假定并解释结构,叫读时模式;数据库在写入时保证数据符合显式的模式,叫写时模式。书里拿它类比动态和静态类型检查。

第一次出现:第 3 章 §1.5

event sourcing事件溯源

把每一次状态变化记成一条不可变、用过去时命名的事件,追加到日志里,日志是唯一的事实来源;读用从日志派生的物化视图。把写的表示和读的表示分开的原则叫 CQRS。

第一次出现:第 3 章 §3

materialized view物化视图

预先算好、存下来的查询结果,读得快,代价是源数据变了要去更新它。事件溯源里也叫投影或读模型。

第一次出现:第 3 章 §1.2

第 4 章起

log日志

只能往末尾追加的一串记录。书里说的日志不是程序打印给人看的那种,而是数据库内部的数据结构:预写日志、LSM 树的段、复制日志、消息队列,都是它。全书反复回到这个结构,因为追加写最快、最容易在崩溃后恢复,也最容易被别人按顺序读走。

第一次出现:第 4 章 §1

LSM-treeLSM 树(日志结构合并树)

一类存储引擎:写先进内存里的有序表,满了整个写成不可变的有序文件(段),后台不断把段合并,丢掉旧值和已删除的值。写入是成片的顺序写,适合写多的负载;读可能要查好几个段,靠布隆过滤器少读一些。

第一次出现:第 4 章 §1.1

compaction合并(压实)

在后台把几个文件合成一个新文件,同一个键只留最新的值,删掉的值和墓碑一起扔掉。LSM 树靠它回收空间、减少读时要查的文件数;代价是要占磁盘带宽,写入太快时可能跟不上。

第一次出现:第 4 章 §1.1

B-treeB 树

把磁盘分成固定大小的页,页里存一串有序的键和指向下层页的页号,组成一棵很矮的平衡树。改数据就覆盖写那一页;页满了就分裂。几乎所有关系数据库都用它做索引,读的性能稳定。

第一次出现:第 4 章 §1.2

write-ahead log (WAL)预写日志

改数据之前,先把「要改什么」追加写进一个日志并刷到盘上,然后才去改真正的数据结构。崩溃后按日志重做,就能回到一致的状态。B 树用它防页分裂改到一半;后面几章的复制、事务也会用到它。

第一次出现:第 4 章 §1.2

write amplification写放大

一次应用层的写,在磁盘上变成了好几次写:日志一次、数据页或段一次、每次合并再一次。用实际写盘的字节数除以「只追加、不建索引」要写的字节数来衡量。写放大越高,同样的磁盘带宽能扛的写越少,SSD 也磨损得越快。

第一次出现:第 4 章 §1.3

column-oriented storage列式存储

把一张表每一列的值存在一起,而不是把每一行的值存在一起。分析查询通常只用几列、却要扫很多行,列存只读需要的列,同一列的值又很好压缩。各列靠「第 k 个值属于第 k 行」对上。

第一次出现:第 4 章 §2.2

第 5 章起

rolling upgrade滚动升级

一次只给几个节点换新版本,确认没问题再换下一批,全程不停服。换完之前,新旧版本的代码同时在线,所以数据要两个方向都兼容。

第一次出现:第 5 章 §0

backward compatibility向后兼容

新代码能读旧代码写的数据。写新代码的人知道旧格式,一般不难做到。

第一次出现:第 5 章 §0

forward compatibility向前兼容

旧代码能读新代码写的数据。旧代码要跳过不认识的字段;读出来改完再写回时,还要把这些字段原样带上,否则会写丢。

第一次出现:第 5 章 §0

schema evolution模式演化

模式随时间改变(加字段、删字段、改名、改类型),同时保持向后和向前兼容。Protocol Buffers 靠标签号的规矩做到,Avro 靠写者模式、读者模式和默认值做到。

第一次出现:第 5 章 §1.3

remote procedure call (RPC)远程过程调用

想让一次网络请求看起来和调用本地函数一样。网络请求会超时、会重复、延迟忽高忽低,所以作者认为这种「位置透明」的抽象有根本缺陷。

第一次出现:第 5 章 §2.2

idempotence幂等

同一个操作做一次和做多次,结果一样。请求超时后不知道对方做没做,只有操作幂等,重试才安全。

第一次出现:第 5 章 §2.2

message broker消息代理

发送方和接收方之间暂存消息的中间件。它能做缓冲、能重新投递、能一条消息发给多个接收方,还让发送方不用知道接收方的地址。

第一次出现:第 5 章 §2.4

第 6 章起

failover故障切换

主库坏了,把一个从库提升为新主库,再让客户端和其他从库改认它。分三步:判定主库死亡(通常靠超时)、选新主库、重新配置。超时太长恢复慢,太短会误切换。

第一次出现:第 6 章 §1.3

split brain脑裂

两个节点都以为自己是主库,同时接受写入。没有冲突解决机制时,数据会丢失或损坏。防止的办法是限制或关掉旧主库(fencing)。

第一次出现:第 6 章 §1.3

replication lag复制延迟

一次写在主库生效,到它在从库上可见,中间隔的时间。平时不到一秒,负载高或网络出问题时可能到几秒甚至几分钟。

第一次出现:第 6 章 §1.5

eventual consistency最终一致性

停止写入、等足够久以后,各副本终究会一致。「终究」是多久没有上限,这是刻意说得含糊的。

第一次出现:第 6 章 §1.5

read-after-write (read-your-writes) consistency读己之写一致性

用户总能读到自己提交过的改动,对别人的改动不作承诺。常见实现:可能被自己改过的数据从主库读;或者记住自己最后一次写的位置,只读已经追上这个位置的副本。

第一次出现:第 6 章 §1.5

monotonic reads单调读

同一个用户连续读,不会先读到新数据、再读到更旧的。比强一致弱,比最终一致强。常见做法是让同一个用户固定读同一个副本。

第一次出现:第 6 章 §1.5

last write wins (LWW)最后写入者胜

冲突时留下时间戳最大的值,其余悄悄丢掉。并发的写本来就没有先后,所以实际上等于随机挑一个;用实时时钟时还会被时钟偏差影响。

第一次出现:第 6 章 §2.3

conflict-free replicated datatype (CRDT)无冲突复制数据类型

能把并发修改自动合并的数据结构,各副本处理过同一组写之后,不管到达顺序如何都收敛到同一状态。文本、列表、计数器、键值映射都有对应的实现。

第一次出现:第 6 章 §2.3

quorum法定人数

读和写各要多少个副本回应才算成功。n 个副本、写等 w 个、读等 r 个,w + r > n 时读和写的集合至少重叠一个副本。不一定非得是多数。

第一次出现:第 6 章 §3.1

version vector版本向量

每个副本一个版本号,合在一起用来判断两次写是先后关系还是并发。读的时候发给客户端,写的时候带回来。和向量时钟(vector clock)相近,但不完全一样。

第一次出现:第 6 章 §3.4

第 7 章起

shard / partition分片(分区)

数据切出来的一块,每条记录只属于一个分片,每个分片放在一台或几台机器上。分片通常和复制一起用:一条记录只属于一个分片,但这个分片可以有好几份副本。各系统叫法不同(partition、range、region、tablet、vnode……)。

第一次出现:第 7 章 §0

partition key分区键

决定一条记录进哪个分片的那个键或那一列,不一定是主键。知道分区键的查询只用去一个分片;不知道的就要问遍所有分片。

第一次出现:第 7 章 §1

rebalancing再平衡

加减机器或出现热点以后,把分片和负载在机器之间重新摊匀。代价是要在网络上搬大量数据,搬的同时还得照常处理读写。

第一次出现:第 7 章 §3

skew / hot spot倾斜 / 热点

有的分片数据或请求远多于其他分片,叫倾斜;负载特别高的那个分片叫热点。单个键特别热的叫热键,换哪种分片方案都只落在一个分片上。

第一次出现:第 7 章 §3

consistent hashing一致性哈希

一类把键映射到分片的算法:各分片分到的键大致一样多,分片数变化时只搬最少的键。这里的「一致」和副本一致性、ACID 的一致性都没有关系。

第一次出现:第 7 章 §3.2

第 8 章起

transaction事务

把一组读写当成一个逻辑整体:要么全部提交,要么全部中止、像没发生过一样,出了错应用可以放心重试。

第一次出现:第 8 章 §1

ACIDACID

原子性、一致性、隔离性、持久性的缩写,描述事务的安全保证。原子性指出错时整个中止,一致性指应用定义的不变式;各家实现差别大,作者说它如今多半是营销用语。

第一次出现:第 8 章 §1.1

snapshot isolation快照隔离

每个事务从开始那一刻的一致快照里读,看不到之后别人提交的写;通常用多版本实现,读不挡写、写不挡读。挡得住读偏斜,挡不住写偏斜。

第一次出现:第 8 章 §2.2

multiversion concurrency control (MVCC)多版本并发控制

一行同时保留几个版本,每个版本标着创建和删除它的事务号,读的事务按可见性规则挑自己该看的那个。快照隔离最常见的实现。

第一次出现:第 8 章 §2.2

write skew写偏斜

两个事务读同一批数据,按读到的前提各自写入(往往是不同的行),写完后前提已不成立。快照隔离挡不住,只有可串行化能自动防止。

第一次出现:第 8 章 §2.4

serializability可串行化

最强的隔离级别:并发执行的结果和某种一个接一个执行的结果相同,因而防得住所有竞争。实现有真串行执行、两阶段锁、SSI 三种。和线性一致性不是一回事。

第一次出现:第 8 章 §3

two-phase locking (2PL)两阶段锁

读拿共享锁、写拿排他锁、锁一直持有到事务结束的可串行化实现,用谓词锁或索引范围锁防幻读。读写互相阻塞,延迟不稳定。别和两阶段提交混淆。

第一次出现:第 8 章 §3.2

serializable snapshot isolation (SSI)可串行化快照隔离

在快照隔离上加冲突检测的乐观算法:事务照常执行、不因冲突等待,提交时如果发现自己读到的前提已被别人提交的写改掉,就中止。只读事务不受影响。

第一次出现:第 8 章 §3.3

two-phase commit (2PC)两阶段提交

让多个节点对一个事务要么都提交、要么都中止的协议:协调者先问所有参与者能否提交,全部答「是」才把提交的决定写进日志再通知大家。协调者崩溃时,答过「是」的参与者只能持锁等待。

第一次出现:第 8 章 §4.1

第 9 章起

partial failure部分失效

系统的一部分坏了,其余照常工作,而且常常说不清坏没坏、坏在哪。单机被设计成「要么好、要么全坏」,分布式系统做不到这一点,只能在软件里去容忍。

第一次出现:第 9 章 §1

monotonic clock单调时钟

保证只往前走的时钟,两次读数的差就是经过的时间,用来测超时和耗时。它的绝对值没有意义,不同机器之间的读数不能拿来比。

第一次出现:第 9 章 §3.1

lease租约

带过期时间的锁。持有者要定期续约;它崩溃或停顿后不再续,租约自然过期,别人可以接手。

第一次出现:第 9 章 §3.4

fencing token防护令牌

锁服务每授予一次锁或租约就递增的数字。客户端写的时候带上它,存储拒绝比已见最大值小的令牌,这样过期的持有者(僵尸)就写不进去。

第一次出现:第 9 章 §4.2

Byzantine fault拜占庭故障

节点不按协议行事,甚至故意撒谎,比如在同一次选举里投出互相矛盾的票。本书默认节点不可靠但诚实,不防这一类。

第一次出现:第 9 章 §4.3

system model系统模型

把算法对网络延迟、进程停顿、时钟误差和节点故障的假设写下来。时间方面有同步、部分同步、异步,故障方面有崩溃-停止、崩溃-恢复、拜占庭等。

第一次出现:第 9 章 §4.4

safety / liveness安全性 / 活性

两类正确性质。安全性是「坏事不发生」,一旦违反能指出是哪一刻、无法挽回;活性是「好事终会发生」,此刻没做到将来还有希望。

第一次出现:第 9 章 §4.4

第 10 章起

linearizability线性一致性

多副本对外表现得像只有一份数据。每个操作在请求发出到收到响应之间的某一刻原子地生效;一旦有人读到新值,此后开始的读都不能再读到旧值。它只管单个对象,和管事务的可串行化是两回事。

第一次出现:第 10 章 §1

CAP theoremCAP 定理

网络分区时,系统只能在线性一致和可用之间选一个。它只考虑一种一致性模型和一种故障,书里认为它如今基本只有历史意义。

第一次出现:第 10 章 §1.4

logical clock逻辑时钟

一种数事件的算法,不报几点钟,只能用来比先后。它的时间戳和因果一致:先发生的时间戳更小。

第一次出现:第 10 章 §2.1

Lamport timestampLamport 时间戳

写成(计数, 节点 ID)。每产生一个时间戳计数加一,看到更大的计数就把自己的抬上去。它给出一个和因果一致的全序,但分不出两个事件是否并发,也不保证线性一致。

第一次出现:第 10 章 §2.1

hybrid logical clock混合逻辑时钟

计数按物理时间走,又像 Lamport 时钟那样看到更大的时间戳就跟着往前拨。它的时间戳近似挂钟时间,顺序又和因果一致;书里举的例子是 CockroachDB。

第一次出现:第 10 章 §2.1

consensus共识

让多个节点就一个值达成一致,决定了就不再改。比较并设置(CAS)、锁、唯一约束、共享日志、原子提交都可以归约成共识,彼此等价。

第一次出现:第 10 章 §3

shared log / total order broadcast共享日志 / 全序广播

多个节点都能请求追加条目,所有节点按同一顺序读到这些条目。它和共识等价,多数共识系统提供的就是它。

第一次出现:第 10 章 §3.1

epoch number任期号

每次选主时递增的编号,Paxos 叫 ballot number,Raft 叫 term。共识算法只保证同一个任期里最多一个主,任期号大的主说了算。

第一次出现:第 10 章 §3.2

coordination service协调服务

ZooKeeper、etcd、Consul 这一类,用共识算法存少量变化慢的协调数据。它提供锁、租约、防护令牌、故障检测和变更通知。

第一次出现:第 10 章 §3.3

第 11 章起

batch processing批处理

读一批只读的、大小有限的输入,每次从头生成输出,不改输入,也不往外部系统写。主要看吞吐量,不看响应时间;输出错了可以删掉重跑。

第一次出现:第 11 章 §0

MapReduceMapReduce

一种批处理编程模型:用户只写 mapper(从每条记录里取出键和值)和 reducer(处理同一个键的全部值)两个函数,中间按键排序和分组由框架完成。2004 年由 Google 发表,现在基本被数据流引擎取代。

第一次出现:第 11 章 §0

dataflow engine数据流引擎

把一整条多阶段的工作流当作一个作业来执行的批处理引擎,比如 Spark、Flink。只在需要的地方排序,中间结果放在内存或本地盘,下游不必等上游全部跑完。

第一次出现:第 11 章 §3.2

shuffle洗牌

批处理里的分布式排序:按键的哈希把上游的输出分给下游各个任务,在各任务内排好序,保证同一个键落到同一个任务、而且挨在一起。连接和分组都靠它;结果是有序的,不是随机的。

第一次出现:第 11 章 §3.3

第 12 章起

change data capture (CDC)变更数据捕获

把写进数据库的每一个变更从复制日志里取出来,按提交顺序作为一条流交给搜索索引、缓存、数据仓库这类派生系统。这样数据库就成了主,其他系统都是它的从。

第一次出现:第 12 章 §2.2

第 13 章起

exactly-once semantics恰好一次语义

处理消息时出了故障要重试,最终效果仍和没出故障时一样:不丢,也不生效两次。常靠原子提交,或靠幂等加去重来实现。它只管系统自己那一段,用户端的重复提交还得端到端去重。

第一次出现:第 13 章 §3.1

end-to-end argument端到端论证

Saltzer、Reed、Clark 1984 年提出:有些功能(去重、完整性校验、加密)只有通信两端的应用才能完整、正确地实现。底层提供的版本有用,能降低出事的概率,但单靠它不够。

第一次出现:第 13 章 §3.1