欢迎大家赞助一杯啤酒🍺 我们准备了下酒菜:Formal mathematics/Isabelle/ML, Formal verification/Coq/ACL2/Agda, C++/Lisp/Haskell
MySQL Pool Scanner
探秘Facebook自动化管理神器:MySQL Pool Scanner
Facebook拥有世界上最大的MySQL数据库集群,其中包含了成千上万台服务器,这些服务器分布在跨越两个大洲的多个数据中心里。
通过几乎将所有的任务全部自动化,这个集群只有一只非常小的MySQL DBA团队来进行管理,集群甚至可以自己运行。而实现这种自动化的核心组件之一就是所谓的MPS系统,即“MySQL Pool Scanner”。
MPS是一个大部分使用Python编写的复杂状态机。它能够代替DBA执行很多例行任务,并且可以让我们以很少或是不施加人为干预就能执行批量维护工作。
单一数据库结点
在Facebook数以千计的数据库服务器中,每一个都能存储一定数量的MySQL实例。一个实例是一个单独的MySQL进程,以其自身的数据集监听着一个单独的端口。简单来说,我们假设在图表和示例中每个服务器正好有两个实例。
整个数据集分割为无数的shard,并且每个实例都拥有一组这样的shard,每个都在其自身的数据库Schema里。一个Facebook用户的信息在其创建的时候会分配给一个shard,这样每个shard就会包含有成千上万用户的相关数据。
用一个单一数据库服务器的图表可以更容易解释这一点:
每个实例在驻留于不同服务器上的其他实例上都有几个副本,而这些服务器通常是在不同数据中心里的。这样做主要是为了实现两个目的:
- 高可用性:如果一台服务器宕机了,我们在其他地方还有可用数据来提供服务。
- 性能:不同的地理位置拥有它们自己的副本,这样便可以使读取服务本地化。
这里是一个简单的replica set示意,它的每个服务器都只有一个实例,并且其他实例为空(我们称这些是spares):
一个服务器本质上是实例容器,所以现实中的情况可以会变得更为复杂。
例如,一个单一服务器拥有一个主实例也可能拥有一个不同主实例的从实例,像下面这样:
这里MPS依赖于两个重要的“building block”操作:
1. 创建一个副本/放置服务器
第一个building block操作是在一台不同的主机上创建一个实例的副本。我们使用Xtrabackup的修改版本来执行大多数复制操作。如果我们在复制成功完成后移除实例,替代过程也是同样的操作。
首先,系统为此操作分配一个空闲实例。我们选择其中一个从实例或主实例并复制其数据到新分配的空闲实例。下表显示了这一替代操作,它在复制完成后将实例移除:
2. 升级主实例
第二个building block操作是将一个不同的实例升级为一个replica set的主实例。
在升级过程中,我们首先选择一个目标,停止写入到replica set,将从实例改为从新的主实例进行复制,并恢复写入。在下图中演示了一个删除操作,即在升级成功完成之后旧实例会被丢弃。为简单起见,下面的replica set只包含三个实例:
这两个操作对于大多数使用MySQL的公司来说通常是很复杂的过程,而在Facebook,它不需要人为干预的情况下就已经可以由MPS快速而安全的全自动化运行。
主机管理和状态
通过上文我们已经解决了基本问题,现在可以利用这些building block来探索更为抽象的概念。
MPS会连接到一个存有当前所有数据库主机状态和元数据的库,这个库还包含了当前和过期MPS的复制操作。注册表是由数据库服务器自身进行管理,因此数据库集群和MPS可与不需要安装一个复杂的应用服务器。MPS本身实际上是无状态的,它在自己的主机池上运行并依赖于上述的库来进行状态管理。而状态是分别并行处理的。
当一个服务器在数据中心被“唤醒”(连接并配置好一个新的机架),它会每隔几分钟运行一个本地代理。此代理会执行以下步骤:
- 收集关于它自身的数据。(我在哪里?我有什么硬件?我正在运行什么版本的软件?)
- 根据问题对主机进行分类。(是否是在active的集群中被唤醒的?磁盘运转是否正常?闪存卡是否正常?)
- 确保服务器已注册,核心库系统中所包含的元数据保持最新。
- 在首次运行中,如果没有服务器的当前记录就将服务器上的实例置为初始的“reimage”状态。这便是新服务器在MPS中生命的开端。
- 所以每隔几分钟,每台正常的服务器都会到核心库“报道”并更新其状态,同时同步数据使用和系统健康度之类的事项。
目前MPS管理的最小单元就是一个实例。每个实例可以处于不同的状态。这些重要状态如下所列:
- 生产状态:实例正在服务于生产环境的流量。
- 空闲状态:实例准备被复制或被分配一些其他工作。
- 空闲分配状态:实例已被选中作为复制的对象,并且复制正在进行中。
- 空闲解除分配状态:.临时分流状态。实例已经改从生产环境移除并等待分流和清理。不会有实例在此状态停留很久。
- 排出状态:实例未被使用,而是预留给测试,数据中心维护等。需要有人工干预使得主机脱离此状态。
- 重塑(reimage)状态: 此状态下,拥有所有实例的服务器正处在重塑或修复过程中。此状态下的服务器会被移交并由一个称为Windex的协同系统加以管理。
由于MPS执行操作或是人工干预,一个实例可能会在不同状态间转换。以下状态表显示了几个主要状态以及可能让一个实例在不同状态间转换的操作。
上图只展示了MPS中一个实例很小一部分的可能采取的路径。这里所描述的状态改变是简单复制和维护操作的结果。还有很多其他原因可以让实例改变状态,并且将所有操作和检查都进行硬编码会让软件维护起来变得困难复杂。满足“问题”是MPS中另一个基本概念。
“问题”是附属于实例的一个属性。如果一台主机上所有的实例都有此问题,那么我们就会认为它是附属于服务器本身的。另外一种考虑问题的方式类似于标签。MPS会通过一个决策矩阵来协助有某个特定问题的实例做出决策。它基本上是一个个元组之间的映射(状态,问题)——(行动,状态)。
通过具体例子理解起来会更容易一些:
- (生产,低空闲)——(替换,空闲解除分配):用有限空间在生产中替代一个实例,同时将其迁移至一台不同的服务器。
- (空闲解除分配,旧内核)——(迁移,重塑):如果一个实例在此状态发生迁移,它就不会有生产数据,那么为什么不对它进行重塑呢?
- (生产,主实例位于撤退位置)——(升级,生产):我们应该把主实例升级至正确的位置,并将此实例置于生产状态。
MPS中不同的状态和“问题”使得我们可以创建一个灵活、可维护的基础设施,用来管理服务器的整个生命周期。
MPS所解决的常见问题
在一个大型数据中心中,每天都会有几十个甚至上百个的服务器故障发生。下面介绍一些不需要人工干预,MPS就能自行处理的日常故障:
- 检测到损坏的从实例并将其禁用,直到它们在后台被替换。
- 损坏的主实例降级,这样正常运行的副本便会取代它们并在后台进行替换。
- 服务器上由于增长而耗尽空间的实例会被迁移至未充分使用的服务器。
当数据中心中存在成千上万台服务器的时候,升级新内核、改变分区大小或是升级控制器固件的维护工作会变得非常复杂。而对于像是迁移某些框架或是为工程团队分配测试服务器这些本地化操作也面临同样的问题。以下是一个运维人员可以通过单一命令让MPS执行的常见维护操作:
- 将任意数量的数据库服务器下架并移出生产环境。大多数这样的操作可以在24小时内完成。
- 在特定并发下重塑上万台机器(例如执行内核升级)。MPS会替代每台机器然后发送给Windex。
- 为一个新项目或测试分配任意数量的空闲空间。例如想要200台服务器来运行测试?完全没问题。
- 在一个新数据中心的特定并发下,为整个Facebook数据集创建副本。
用MPS将基础任务自动化,这样可以对我们所管理的服务器进行更好的规划,而且还能解放MySQL数据库团队来让他们从事更具挑战的工作。
关于作者:Shlomo Priymak是Facebook MySQL运营团队的DBA。
- 英文原文:Under the hood: MySQL Pool Scanner (MPS)
- 翻译来源:TechTarget中国,我们在此基础上增加了中文翻译文章中缺失的两张图片,并做了一些修正。