第 1 章 数据库可靠性工程介绍

第 1 章 数据库可靠性工程介绍

本书旨在为读者提供指导与框架,助你成为优秀的数据库可靠性工程师。在定书名时,我们选择了面向可靠性工程师,而非管理员。

谷歌工程副总裁本•特雷诺就可靠性工程发表了如下看法:

基本上是以前由运维团队完成的工作,换成拥有软件专业知识的工程师来做,并且指望其有意愿和能力用自动化代替人工劳动。

如今的数据库专业人员必须是工程师,而不是管理员。我们构建、创造新事物。作为实践 DevOps 的工程师,我们一起工作,共担责任。作为工程师,我们利用可复用的流程、掌握的知识和积累的经验,来设计、构建和操作生产级数据存储及其数据结构。而作为数据库可靠性工程师,我们必须进一步深入掌握操作原则和数据库专业知识。

如果了解当今基础设施的非存储组件,就会发现通过编程(通常是自动的)方式,易于构建、运行以及销毁系统。这些组件的生命周期较短,以天计,有时甚至以小时或分钟计。当一个组件下线之后,就会启动其他许多组件,以保证服务质量。

我们的下一个目标是,在可靠性工程和 DevOps 文化的范式下,为设计、构建和维护数据存储确立指导原则和实践框架。无论你所在的企业处于哪个发展阶段,都可以把这些知识应用于任何数据库技术或环境中。

1.1 数据库可靠性工程师的指导原则

我们当初动笔的时候,问自己的第一个问题是:数据库行业这种新的迭代逻辑背后的原则是什么?如果重新定义设计、管理数据存储的方式,就需要定义受推崇的行为准则。

1.1.1 保护数据

传统上,保护数据一直是数据库专业人员的基本原则,现在仍是如此。以下是普遍接受的做法。

  • 软件工程师和数据库工程师的职责严格分离。
  • 有严格的备份和恢复流程,并定期测试。
  • 有规范的安全流程,并定期审计。
  • 有昂贵的数据库软件,并且持久、可靠。
  • 有昂贵的底层存储系统,并且所有组件都有冗余。
  • 大范围的变更管控和操作管理。

在具有协作文化氛围的团队中,职责严格分离不仅是一种负担,还会限制创新和速度。第 8 章将讨论创建安全网的方式,以此应对职责分离的问题。此外,这些环境更关注测试、自动化和减轻影响,而不是大范围的变更管控。

架构师和工程师比以往更倾向于选择开源数据存储,而这些数据存储不像 Oracle 那样能保证持久性。这种非严格的持久性,有时会给业务快速发展的团队带来所需的性能优势。第 11 章将讨论如何选择正确的数据存储方式,以及这些选择的影响。了解数据处理工具,并能有效地选择合适的工具,属于必备技能。

底层存储也发生了重大变化。在虚拟化时代,网络和临时存储在数据库设计中占有一席之地,第 5 章将进一步讨论这个问题。

构建在临时存储之上的生产数据库

2013 年,Pinterest 将 MySQL 数据库实例迁移到AWS(亚马逊云服务)的临时存储上。临时存储实际上意味着,如果计算实例发生故障或关闭,磁盘上存储的所有东西都将丢失。Pinterest 之所以选择临时存储,是因为它吞吐量可观且延迟较低。

要做到这一点,需要在自动化、完善的数据备份和恢复,以及应用程序方面大量投资,以容忍在重建节点时导致集群失效。临时存储不允许快照,这意味着不能通过快照前滚事务日志的方式进行恢复,而要通过网络复制完整的数据库。

这表明,运用正确的流程和工具,可以在临时存储的环境中保证数据的安全性。

数据保护的新方法大致如下。

  • 跨职能团队共担责任。
  • 由数据库可靠性工程师提供支持的标准化、自动化备份和恢复过程。
  • 由数据库可靠性工程师和安全团队提供支持的标准化安全策略和流程。
  • 自动化配置和部署应用的全部策略。
  • 数据需求决定数据存储,对持久性需求的评估将成为决策过程的一部分。
  • 依赖自动化过程、冗余和经过反复检验的良好实践,而不是昂贵、复杂的硬件。
  • 在部署和基础设施自动化过程中实现变更,重点关注测试、回退和减轻影响。

1.1.2 大量自助服务

到目前为止,有才干的数据库可靠性工程师比 SRE(site reliability engineer,网站可靠性工程师)更稀有,大多数公司雇不起两位以上这样的员工。因此,我们必须通过为团队创建自助服务平台,创造尽可能多的价值。制定标准并提供工具,以便团队能够顺利部署新服务,并按照所需的速度适当地更改,而无须依赖数据库工程师超负荷工作。自助服务的例子包括:

  • 提供合适的插件,确保从数据存储中收集适当的度量值;
  • 构建备份和恢复工具,使其可以部署到新的数据存储中;
  • 为数据存储定义参考架构和配置,这些数据存储被批准用于操作,并且可以由团队部署;
  • 和安全团队一起定义数据存储部署的标准;
  • 为数据库变更集构建安全的部署方式和测试脚本。

换言之,高效能数据库可靠性工程师的职责是授权和指导他人,而不是充当“守卫”。

1.1.3 消除琐事

谷歌 SRE 团队经常使用短语“消除琐事”(elimination of toil),《SRE:Google 运维解密》一书的第 5 章对此做了讨论。该书将“琐事”定义如下:

与运行生产服务相关的工作,往往是手动的、重复性的、自动化的、策略性的、缺乏持久价值的,并且随着服务的增长而线性扩展。

有效的自动化和标准化是必要的,可以确保数据库可靠性工程师不会困于琐事。本书将列举数据库可靠性工程师所面临的一些琐事及其缓解之法。尽管如此,“琐事”这个词的含义仍然是模糊的,有很多先入之见,且因人而异。本书讨论“琐事”时,着重谈论重复性、非创造性和非挑战性的人工工作。

手动变更数据库

在许多客户环境中,数据库工程师被要求审查和实施数据库变更,例如修改表或索引,添加、修改或删除数据,等等。所有人都安心于数据库管理员正在实施这些变更,并实时监控变更的影响。

在客户现场,变更的频率非常高,并且这些变更常常是有影响的。最终数据库管理员每周花 20 个小时对整个环境实施滚动变更。毫无疑问,花半周的时间来执行这些重复性的任务,难免让人心生不满,意欲放弃。

面对资源短缺,管理层最终允许数据库团队构建一个滚动变更 schema 的自动化工具。一旦数据库工程师审查并批准了变更集,软件工程师就可以运行该程序实施数据库变更了。之后所有人都能放心地使用工具引入变更并监控,从而让数据库可靠性工程师团队有更多时间来把这些流程集成到部署平台。

1.1.4 数据库并不特殊

我们的系统与满足业务需求的其他组件一样重要。我们必须努力实现标准化、自动化和弹性。对此至关重要的是,数据库集群的组件并非神圣的。有时我们会移除某些组件,毫无顾虑地进行替换。玻璃房里脆弱的数据存储已成历史。

“宠物”和“牛”的比喻通常用于描述定制的服务组件和通用服务组件之间的区别,这个比喻来自微软杰出的工程师比尔 • 贝克。“宠物”服务器是指当它们出现异常时,你需要精心照顾以使其恢复健康。它们也有名字。2000 年在 Travelocity 时,我们的服务器以动画片《辛普森一家》中的角色命名,运行 Oracle 的两台 SGI 服务器分别称作 Patty 和 Selma。我在深夜花了很多时间处理这两台服务器的问题,它们的维护成本很高。

“牛”服务器上有数字,但没有名字。不需要花时间定制服务器,更不用说登录各个主机了。当它们显现“生病”(异常)的迹象时,就把它们从“牛群”(集群)中剔除。当然,如果你发现患病的“牛”达到一定的数量时,就应该把那些待宰的“牛”留给“兽医”检查。但是,不必把这个比喻搞得更复杂。

数据存储是拥有“宠物特质”的最后一部分系统。毕竟它们拥有“数据”,所以不能简单地将它们视为寿命短、标准化程度高、可替代的“牛”。那么副本的特殊规则呢?从服务器的不同配置呢?

1.1.5 消除软件和运维之间的障碍

基础设施、配置、数据模型和脚本都是软件的组成部分。我们要像其他工程师那样,学习并采用软件生命周期的方式进行管理:编码、测试、集成、构建、测试和部署。我们提到测试了吗?

对于熟悉运维和脚本的人而言,这可能是最艰难的范例转换。在软件工程师引导组织、系统和服务以满足需求时,组织内可能存在阻抗不匹配(impedance mismatch)。软件工程组织有非常明确的方法来开发、测试、部署功能和应用程序。

在传统环境中,设计、构建、测试以及部署基础设施和相关服务的基本流程,在软件工程、系统工程和数据库管理员之间是分裂的。之前讨论的范式转换正在消除这种不匹配,这意味着数据库可靠性工程师和系统工程师需要使用相似的方法来完成工作。

 软件工程师必须学习运维

运维人员经常被告知“学习编程,否则辞退”。我认同这一点,但软件工程师也必须学习运维。那些没有学习运维和基础设施原理的软件工程师,编写的代码往往脆弱、低效,甚至不安全。只有所有团队水平相当,阻抗不匹配才会消失。

数据库可靠性工程师也可能发现自己直接融入了软件工程团队,在相同的代码库中工作,检查这些代码如何与数据存储交互,修改代码以优化性能、完善功能、增强可靠性。消除这种团队阻抗之后,相较于传统模型,可靠性、性能和速度会提升一个数量级,并且数据库可靠性工程师必须适应这些新流程、文化和工具。

1.2 运维核心概述

运维是数据库可靠性工程师的核心技能之一,是设计、构建、测试和维护具有一定规模且要求高可靠性系统的基石。这意味着如果你想成为数据库工程师,就需要知道这些。

宏观层面的运维不是一个角色。运维是企业围绕发布与维护高质量系统和软件,所积累的技能、知识和价值观的总和。它既是隐性价值观,也是显性价值观、习惯、团队知识和奖励体系。从技术支持人员到产品人员,再到首席执行官,共同参与运维。

这一点通常做得不好。许多公司的运维文化很糟糕,令人生厌。这可能会影响声誉,不管是在系统、数据库还是网络方面,许多人在想到运维工作时就会想到这一点。尽管如此,运维文化仍然是组织如何执行技术任务的关键。如果说哪家公司完全没有运维,肯定不可信。

也许你是软件工程师或者是基础设施和平台即服务的支持者,也许你质疑数据库工程师是否需要懂运维,并认为 Serverless 可以让软件工程师无须思考或关心运维工作,这种想法是完全错误的。事实恰恰相反,这是一个没有运维团队的美丽新世界——为你做运维工作的是谷歌 SRE、AWS 系统工程师、PagerDuty 和 DataDog 等。在当今世界,应用工程师需要在运维、架构和性能方面做得更好。

1.3 需求层次

你可能在大企业或创业公司工作过。当接触并研究系统时,有必要考虑一下,如果让你承担运维数据库系统的工作,第一天你会做些什么。有备份吗?备份能正常工作吗?你确定吗?是否有可以进行故障转移的副本?你知道如何进行故障转移吗?备份的电源、路由器、硬件或可用区与主服务器相同吗?当备份工作不正常时,你能发现吗?如何发现?

换言之,我们需要讨论数据库需求的层次结构。

按照马斯洛的需求层次理论,人类的欲望像一座金字塔,由下至上分别是:生存、安全、爱和归属感、尊重以及自我实现,而只有满足需求,人类才能蓬勃发展。金字塔的底部是最基本的需求,比如生存。每一层的需求都是进入更高一层的条件——在获得安全感之前要先满足生存需求,在获得爱和归属感之前要先满足安全需求,以此类推。一旦满足了下面 4 个层次的需求,人类就达到了自我实现,可以安全地探索、游戏、创造和充分发展潜能。这就是它对于人类的意义。下面用这个比喻来说明数据库需要什么。

1.3.1 生存和安全

数据库最基本的需求是备份、复制和故障转移。你有数据库吗?数据库运作正常吗?可以 ping 通吗?应用程序有响应吗?有备份吗?恢复有效吗?你怎么知道它工作不正常?

你的数据安全吗?是否有多个可用副本?你知道怎么进行故障转移吗?你的副本是分布在多个可用区、多个电源板和机架上吗?各个备份是否一致?你能恢复到某个时间点吗?你能发现数据有损坏吗?如何发现呢?第 7 章将深入探讨这些内容。

这也是开始准备扩展的时候。过早地扩展不可取,但在确定关键数据对象的 ID、存储系统和架构时,应该考虑分片、增长和扩展。

扩展模式

本书会经常提到扩展。扩展性是系统或服务应对负载不断增加的能力。这可能是真实的能力,因为已经部署了所有支持数据增长的部件;也可能是潜在的能力,因为处理组件和资源增加的基石已经铺好。一般而言,可以通过以下 4 种途径实现扩展。

  • 通过分配资源实现垂直扩展,也称垂直扩展
  • 通过复制系统或服务实现水平扩展,也称水平扩展
  • 将工作负载分成较小的功能集,让每个工作单元能够独立扩展,也称功能分区
  • 将特定工作负载分成相同的分区,而不是分成正在处理的特定数据集,也称分片

第 5 章将介绍上述模式的具体细节。

1.3.2 爱和归属感

爱和归属感意味着,在软件工程过程中,把数据当作一等公民,打破数据库和其他系统之间的竖井(silo)。这既是技术上的,也是文化上的,而这就是可以称其为“DevOps 需求”的原因。从高层次上讲,这意味着要像管理其他系统一样管理数据库,也意味着在文化上鼓励流动性和跨职能。在爱和归属感阶段,你会逐渐停止登录系统和以 root 身份执行命令。

在该阶段,你们会采用相同的代码审查流程和部署实践。数据库基础设施和配置应该采用与其他所有架构组件相同的流程。与数据打交道,应该和跟应用的其他部分打交道一样,这会鼓励所有人参与其中并支持数据库环境。

克制向开发人员灌输恐惧的冲动。这很容易做到,也很有诱惑力,因为一切尽在掌控的感觉非常好。但事实并非如此,而且你也无法掌控一切。如果你把精力放到构建“护栏”上,以防止任何人意外破坏,对所有人来说会更好。培养和授权所有人对自己的变更负责。不要再提杜绝故障,因为这是不可能的。换言之,创建有弹性的系统,并且鼓励所有人使用数据存储。

Etsy 的“护栏”

Etsy 引入了一个名为 Schemanator 的工具来实施数据库变更(或者说变更集),这对生产环境来说是非常安全的。多个“护栏”的存在能让软件工程师直接实施数据库变更。这些“护栏”如下所示。

  • 变更集的探索性审查,以验证 schema 设计是否遵循了相应规范。
  • 变更集的测试,以验证脚本能否执行成功。
  • 预先检查,让工程师知晓集群的当前状态。
  • 滚动升级,对“离线”的数据库执行有影响的变更。
  • 把工作流分解为子任务,以便在发生意外时可以取消。

1.3.3 尊重

尊重处于需求金字塔的次顶端。对人类来说,这意味着尊重和掌控;对数据库来说,这意味着可观测性、可调试性、自我检查和可探测性。关键是,不仅要了解存储系统本身,还要能关联相关事件。同样,该阶段包含两个方面:一是当前阶段生产服务的演进方式,二是人员。

服务本身应该能表明它是运行正常还是宕机或者出错了,而无须你查看监控图。随着服务的成熟,由于系统演变轨迹变得更加可预测,因此变更速度会变慢。由于存储系统在生产环境中运行,所以你对其弱点、行为以及故障状况的了解会日益加深,这类似于数据基础设施的青年时期。其间你最需要的是能够了解正在发生什么。产品越复杂,其动态部件就越多,也就需要投入更多精力开发工具来搞清楚状况。

还需要有“旋钮”来降级服务质量,避免服务彻底宕机,比如:

  • 将站点标记为只读;
  • 禁用某个特性;
  • 将写请求排队,延后处理;
  • 将恶意者或者特定端点拉进黑名单。

人员的需求相似,但并不完全相同。一种常见的情况是,他们对生产环境反应过度。他们对可能出现的问题没有清晰的认识,所以试图监控一切指标,以致草木皆兵。从没有监控图发展到成百上千的监控图(99% 是完全没有意义的)很简单,但这并非好事,实际上可能适得其反。如果这导致了更多的噪声,你的人员将无法找到问题的根源,而只能跟踪日志文件并猜测,这与没有监控图一样糟糕,甚至更糟糕。

这时,你会打断他们,唤醒他们,培训他们不要在意收到的警报或对其采取行动,这会耗尽他们的精力。在早期阶段,如果你希望所有人都随叫随到,就需要把事情文档化。当你处于起步阶段、随叫随到、迫使人们走出舒适区时,给他们一点帮助。编写简洁有效的文档和流程。

1.3.4 自我实现

就如每个人最好的自己是独一无二的,每个组织实现的存储层也是独一无二的。适合 Facebook 的存储系统,也许并不适合 Pinterest 或 GitHub,更不用说小型创业公司了。但是,就像健康、自律的人有自己的行为模式(他们不会在杂货店乱发脾气,保持健康饮食并且锻炼身体),健康、自我实现的存储系统也有类似的范式。

在这种情况下,自我实现意味着数据基础设施能帮助你实现目标,而且数据库相关工作流程不会妨碍进度。相反,它们能帮助开发人员完成工作,并帮助他们避免一些错误。常见的运维痛点和令人厌烦的故障应该由系统自我修复,系统能保持健康状态,而无须人工介入。这意味着有满足系统需求的扩容方案,无论是每过几个月就需要扩容 10 倍,还是系统要稳定运行 3 年之后才扩容。显然,如果数据库基础设施成熟、可靠,你就可以把更多时间花在思考其他事情上,比如创造新产品或者预料未来的问题,而不是处理当前的问题。

所处的需求层级随着时间的推移上下变动是正常的。这些层级作为框架,主要用于帮助思考问题的优先级,比如确保有可用的备份要比写脚本来动态重新分片和扩容重要得多。如果线上数据只有一个副本,又或者你不知道当主服务器宕机时如何进行故障转移,那么你应该停止手头工作,优先解决这个问题。

1.4 小结

数据库可靠性工程师是从现有的、众所周知的角色演变而来的。重要的是,本书给出的框架能让我们在纷繁多变的当今世界中,重新思考管理数据存储的职责。后文将详细探讨这些职责,优先讨论运维职责,因为这在数据库工程的日常工作中十分重要。勇敢前行吧,无畏的工程师们!

目录

  • 版权声明
  • O'Reilly Media, Inc. 介绍
  • 前言
  • 第 1 章 数据库可靠性工程介绍
  • 第 2 章 服务等级管理
  • 第 3 章 风险管理
  • 第 4 章 运维可见性
  • 第 5 章 基础设施工程
  • 第 6 章 基础设施管理
  • 第 7 章 备份和恢复
  • 第 8 章 发布管理
  • 第 9 章 安全
  • 第 10 章 数据存储、索引和复制
  • 第 11 章 数据存储领域指南
  • 第 12 章 数据架构示例
  • 第 13 章 数据库可靠性工程师行为指南
  • 关于作者
  • 封面介绍