Dropbox刚启动时,一位Hacker News的用户评论说,可以使用FTP和Git通过多个bash脚本来实现它。 现在不能以任何方式说这,这是一个庞大的云文件存储,每天有数十亿个新文件,这些文件不仅以某种方式存储在数据库中,而且还可以将任何数据库还原到最近六天内的任何点。
在剪切下,
Glory Bakhmutov (
m0sth8 )在Highload ++ 2017上的报告的
笔录内容是关于Dropbox中的数据库如何开发以及现在如何排列的。
关于演讲者: Glory to Bakhmutov-Dropbox团队的站点可靠性工程师,非常喜欢Go,有时还会出现在golangshow.com播客中。
目录内容

简明语言的Dropbox架构
Dropbox于2008年出现。 本质上,这是一个云文件存储。 Dropbox刚启动时,Hacker News的用户评论说,可以使用FTP和Git通过多个bash脚本来实现它。 但是,尽管如此,Dropbox仍在发展中,现在它已成为一项相当大的服务,每天有超过15亿用户,20万个企业和大量(数十亿!)新文件。
Dropbox是什么样的?
我们有几个客户端(Web界面,使用Dropbox的应用程序的API,桌面应用程序的API)。 所有这些客户端都使用API并与两个大型服务进行通信,这些服务在逻辑上可以分为:
- 元服务器
- 块服务器
Metaserver存储有关文件的元信息:大小,注释,在Dropbox中指向此文件的链接等。 Blockserver仅存储有关文件的信息:文件夹,路径等。
如何运作?例如,您有一个带有某种视频的video.avi文件。
幻灯片链接- 客户端将这个文件分成几个块(在这种情况下,每个块4 MB),计算校验和,然后向Metaserver发送请求:“我有一个* .avi文件,我想上传它,哈希量就这样。”
- Metaserver返回答案:“我没有这些块,让我们下载!” 或者,他可以回答说他具有全部或部分块,并且仅需要加载其余块。
幻灯片链接- 之后,客户端转到Blockserver,发送哈希量和存储在Blockserver上的数据块本身。
- Blockserver确认操作。
幻灯片链接当然,这是一个非常简化的方案,协议要复杂得多:同一网络中客户端之间存在同步,内核驱动程序具有解决冲突的能力,等等。 这是一个相当复杂的协议,但它在原理上像这样工作。

当客户端在Metaserver上保存某些内容时,所有信息都将发送到MySQL。 Blockserver还在MySQL中存储有关文件,文件结构,文件组成的信息。 Blockserver还将块本身存储在Block Storage中,后者又存储有关哪个块位于何处,在哪个服务器上以及如何对其进行处理的信息,也存储在MYSQL中。
为了存储数十亿字节的用户文件,我们同时将额外的信息存储在分布在6000台服务器中的数十PB的数据库中。
数据库开发历史
数据库在Dropbox中如何发展?

在2008年,一切始于一台Metaserver和一台全球数据库。 Dropbox需要将所有信息存储在某个地方,他将其保存在唯一的全局MySQL中。 持续时间不长,因为用户数量增加了,并且数据库中的单个数据库和平板电脑的膨胀速度比其他数据库快。

因此,在2011年,几个表被提交到单独的服务器:
- User ,其中包含有关用户的信息,例如登录名和oAuth令牌;
- 主机 ,带有来自Blockserver的文件信息;
- 杂项 ,它不参与处理生产中的请求,但用于实用程序功能,例如批处理作业。

但是在2012年之后,Dropbox开始非常快速地增长,自那时以来,
我们的年增长率为
大约1亿用户 。

有必要考虑到如此巨大的增长,因此,在2011年底,我们有了分片-由1600个分片组成的基础。 最初,只有8个服务器,每个服务器具有200个分片。 现在它是400个主服务器,每个服务器上有4个分片。
幻灯片链接在2012年,我们意识到为每个添加的业务逻辑创建表并在数据库中更新它们非常困难,沉闷且有问题。 因此,在2012年,我们发明了自己的图形存储,称为
Edgestore ,此后,应用程序生成的所有业务逻辑和元信息都存储在Edgestore中。
Edgestore本质上是从客户端抽象MySQL。 客户端具有某些实体,这些实体通过从gRPC API到Edgestore Core的链接互连,该实体将这些数据转换成MySQL并以某种方式存储在其中(基本上,它从缓存中提供所有这些信息)。
幻灯片链接2015年,我们离开了Amazon S3 ,开发了自己的名为Magic Pocket的云存储。 它包含有关块文件位于何处,在哪个服务器上以及有关这些块在服务器之间移动(存储在MySQL中)的信息。
幻灯片链接但是MySQL的使用非常棘手-本质上,它是一个大型的分布式哈希表。 这是一个非常不同的负载,主要是在读取随机记录上。 90%的利用率是I / O。
数据库架构
首先,我们立即确定了一些用于构建数据库体系结构的原则:
- 可靠性和耐用性 。 这是最重要的原则,也是客户对我们的期望-数据不会丢失。
- 解决方案的最优性是同等重要的原则。 例如,备份应快速完成,并且也应快速恢复。
- 解决方案的简单性 -在架构上以及在服务和进一步开发支持方面。
- 拥有成本 。 如果有什么方法可以优化解决方案,但价格昂贵,则不适合我们。 例如,比主服务器落后一天的从服务器非常方便进行备份,但是您需要再增加1,000到6,000台服务器-这样的从服务器的拥有成本非常高。
所有原则都必须是
可验证和可衡量的 ,也就是说,它们必须具有度量标准。 如果我们在谈论拥有成本,那么我们必须计算我们拥有多少台服务器,例如,去数据库的服务器,多少台服务器用于备份的服务器以及最终为Dropbox花费的成本。 当我们选择一个新的解决方案时,我们会计算所有指标并专注于它们。 选择任何解决方案时,我们都会完全遵循这些原则。
基本拓扑
该数据库的结构如下:
- 在主数据中心,我们有一个主记录,所有记录都记录在其中。
- 主服务器有两个从属服务器,在它们之间进行半同步复制。 服务器通常会死掉(大约每周10个),因此我们需要两个从属服务器。
- 从服务器位于单独的群集中。 群集是数据中心中彼此独立的,完全独立的房间。 如果一个房间烧坏了,第二个房间仍然可以正常工作。
- 同样在另一个数据中心中,我们拥有所谓的伪主设备(中间主设备),它实际上只是一个从设备,而另一个从设备也是如此。

选择这样的拓扑是因为,如果第一个数据中心突然死在我们里面,那么在第二个数据中心中,我们将拥有
几乎完整的拓扑 。 我们只需更改Discovery中的所有地址,客户端即可工作。
特殊拓扑
我们也有专门的拓扑。
Magic Pocket拓扑由一台主服务器和两台从属服务器组成。 这样做是因为Magic Pocket本身会在区域之间复制数据。 如果丢失了一个群集,则可以通过擦除代码从其他区域还原所有数据。
双活拓扑是Edgestore使用的自定义拓扑。 它在两个数据中心中的每个数据中心中都有一个主机和两个从机,它们彼此是从机。 这是一个非常
危险的方案 ,但是Edgestore在其级别上确切知道哪个主机可以在其范围内写入哪些数据。 因此,此拓扑不会中断。

实例
我们已经安装了4-5年前配置的相当简单的服务器:
- 2个Xeon 10内核;
- 5TB(8 SSD突袭0 *);
- 384 GB内存。
*突袭0-因为更换整个服务器比驱动器更容易,更快捷。
单实例
在此服务器上,我们有一个大型MySQL实例,在该实例上有多个分片。 这个MySQL实例会立即为自己分配几乎所有的内存。 服务器上还运行着其他进程:代理,统计信息收集,日志等。

该解决方案的优点在于:
+
易于管理 。 如果需要替换MySQL实例,只需替换服务器。
+
做faylovers 。
另一方面:
-任何操作都发生在整个MySQL实例上并且立即在所有分片上发生是有问题的。 例如,如果您需要备份,我们会立即备份所有分片。 如果您需要进行faylover,我们将同时对所有四个碎片进行faylover。 因此,可访问性遭受了4倍以上的苦难。
-复制一个分片的问题会影响其他分片。 MySQL复制不是并行的,并且所有分片都在单个线程上工作。 如果一个碎片发生了故障,那么其余碎片也会成为受害者。
因此,现在我们转向另一种拓扑。
多实例

在新版本中,服务器上一次启动了多个MySQL实例,每个实例都有一个分片。 有什么更好的?
+我们
只能对一个特定的分片执行操作 。 也就是说,如果需要faylover,则仅切换一个分片,如果需要备份,则仅备份一个分片。 这意味着操作将大大加快-对于四台服务器,是四倍。
+
碎片几乎不会互相影响 。
+
改进复制。 我们可以混合使用不同类别和类别的数据库。 Edgestore占用大量空间,例如全部4 TB,而Magic Pocket仅占用1 TB,但利用率为90%。 也就是说,我们可以组合使用不同方式使用I / O和机器资源的不同类别,并启动4个复制流。
当然,此解决方案有其缺点:
-最大的
缺点是,
要处理所有这些事情要困难得多 。 我们需要一些聪明的调度程序,他将了解他可以在哪里进行此实例,哪里将有最佳负载。
-
比故障转移更难 。
因此,我们现在才转向这一决定。
发现
客户必须以某种方式知道如何连接到所需的数据库,因此我们具有发现功能,该功能应该:
- 很快将拓扑更改通知客户端。 如果我们更改了主服务器和从服务器,则客户应该几乎立即了解它。
- 该拓扑不应依赖于MySQL复制拓扑,因为通过某些操作,我们会更改MySQL拓扑。 例如,当我们进行拆分时,在目标主机上的准备步骤中,我们将在其中转移部分碎片,一些从属服务器将重新配置为该目标主机。 客户不需要了解这一点。
- 操作的原子性和状态验证很重要。 同一数据库中的两个不同服务器不可能同时成为主服务器。
发现是如何发展的
最初,一切都很简单:配置中源代码中的数据库地址。 当我们需要更新地址时,一切都可以很快部署。

不幸的是,如果有很多服务器,这将不起作用。

以上是我们拥有的第一个发现。 有一些数据库脚本更改了ConfigDB中的铭牌-这是一个单独的MySQL铭牌,并且客户端已经侦听此数据库并定期从那里获取数据。

该表非常简单,有一个数据库类别,一个分片键,一个数据库类主/从,代理和一个数据库地址。 实际上,客户端请求了一个类别,一个DB类,一个分片键,并且返回了已经可以建立连接的MySQL地址。

一旦有很多服务器,就添加了Memcache,客户端开始与它进行通信。
但后来我们对其进行了重新设计。 MySQL脚本开始通过gRPC通过瘦客户机与我们称为RegisterService的服务进行通信。 发生某些更改时,RegisterService有了一个队列,他了解如何应用这些更改。 RegisterService将数据保存在AFS中。 AFS是我们基于ZooKeeper的内部系统。

第二种解决方案(此处未显示)直接使用ZooKeeper,这会产生问题,因为每个分片都是ZooKeeper中的一个节点。 例如,有10万个客户端连接到ZooKeeper,如果它们由于某种错误而突然死亡,那么对ZooKeeper的10万个请求将立即到来,这将直接丢弃它并且它不能上升。
因此,开发
了AFS系统,供整个Dropbox使用 。 实际上,它为所有客户抽象了ZooKeeper的工作。 AFS守护程序在每台服务器上本地运行,并提供以下形式的非常简单的文件API:创建文件,删除文件,请求文件,接收文件更改通知以及比较和交换操作。 也就是说,您可以尝试用某个版本替换文件,并且如果在更改过程中此版本已更改,则操作将被取消。
本质上,这是对ZooKeeper的抽象,其中存在本地退避和抖动算法。 ZooKeeper不再在负载下崩溃。 使用AFS,我们在S3和GIT中进行备份,然后本地AFS自身通知客户端数据已更改。

在AFS中,数据存储为文件,即文件系统API。 例如,上面是shard.slave_proxy文件-最大,大约需要28 Kb,并且当我们更改shard和slave_proxy类的类别时,所有订阅此文件的客户端都会收到通知。 他们重新读取了该文件,其中包含所有必要的信息。 他们使用分片键获得类别并重新配置与数据库的连接池。
运作方式
我们使用非常简单的操作:升级,克隆,备份/恢复。
操作是一个简单的状态机 。 进行操作时,我们执行一些检查,例如旋转检查,超时检查几次,检查是否可以执行此操作。 之后,我们进行了一些不影响外部系统的准备工作。 接下来,操作本身。
一个操作中的所有步骤都有一个
回滚步骤 (撤消)。 如果操作有问题,该操作将尝试将系统还原到其原始位置。 如果一切正常,那么将进行清理并完成操作。
对于任何操作,我们都有一个如此简单的状态机。
晋升(更换主人)
这是数据库中非常常见的操作。 有人质疑如何在可以正常工作的热主服务器上进行更改-这将很重要。 只是所有这些操作都是在从属服务器上执行的,然后从属服务器更改主服务器位置。 因此,
促销操作非常频繁 。

我们需要更新内核-我们进行交换,我们需要更新MySQL的版本-我们在从属服务器上进行更新,切换到主服务器,然后在此处进行更新。

我们已经取得了非常快的晋升。 例如,
对于四个分片,我们现在可以升级大约10-15秒。 上图显示,随着促销活动的增加,其遭受的损失为0.0003%。
但是正常的升级并不是那么有趣,因为它们是每天执行的常规操作。 故障转移很有趣。
故障转移(替换损坏的主机)
故障转移意味着数据库已死。
- 如果服务器真的死了,这就是一个理想的情况。
- 实际上,碰巧服务器部分处于活动状态。
- 有时服务器死机非常缓慢。 突袭控制器,磁盘系统出现故障,某些请求返回答案,但某些流被阻止并且不返回答案。
- 可能是主人简单地超负荷了并且不响应我们的健康检查。 但是,如果我们晋升,新主人也会超负荷工作,只会变得更糟。
每天更换已故主服务器的
次数约为
2-3次 ,这是一个完全自动化的过程,不需要人工干预。 关键部分大约需要30秒钟,它还有很多其他检查,以查看服务器是否确实处于活动状态,或者是否已经死亡。
下面是faylover工作原理的示例图。

在所选部分中,我们
重新启动主服务器 。 这是必需的,因为我们拥有MySQL 5.6,并且半同步复制并不是无损的。 因此,幻象读取是可能的,并且我们需要这个主控(即使它尚未死)也要尽快杀死,以使客户端与之断开连接。 因此,我们通过Ipmi进行硬重置-这是我们必须做的第一个最重要的操作。 在MySQL 5.7版本中,这并不是很关键。
集群同步。 为什么我们需要集群同步?

如果我们回想一下带有拓扑的上一张图片,则一台主服务器具有三台从属服务器:两个位于一个数据中心中,另一个位于另一个数据中心中。 通过升级,我们需要将主服务器置于同一主数据中心。 但是有时,当从属服务器加载时,使用半同步,由于未加载半同步从属设备,它会成为另一个数据中心中的从属设备。 因此,我们首先需要同步整个集群,然后已经在需要的数据中心中对从属服务器进行了升级。 这非常简单地完成:
- 我们停止所有从属服务器上的所有I / O线程。
- 此后,我们已经确定主机是“只读”的,因为Semisync已断开连接,并且没有人可以在那里写任何东西。
- 接下来,我们选择具有最大的已检索/已执行的GTID集的从站,即具有已下载或已应用的最大事务的从站。
- 我们将所有从属服务器重新配置到此选定的从属服务器,启动I / O线程,并使它们同步。
- 我们一直等到它们同步后,我们才能使整个集群同步。 , executed GTID set .
—
.
promotion , :

- slave -, , master, promotion.
- slave- master, , ACLs, , - proxy, , - .
- read_only = 0, , master , . master .
- - . - , , , , , proxy .
- .
, rollback , . rollback reboot. , , , — change master — master .
— . , , , , .
● slave
, slave-, . .
●
, , . .
●
, , . . 3 .
, , , :
- . 1 40 .
- .
, . 1 40 , , , .
, . . 4 .

- 24 . HDFS, .
- 6 unsharded databases, Global DB. , , , .
- 3 S3.
- 3 S3 .

. , 3 , HDFS 3 , 6 S3. .
, .

, , . , , recovery - . , , - . 100 , .
, , , , , , , . .

hot-, Percona xtrabackup. —stream=xbstream, , . script-splitter, , .
MySQL 2x. 3 , , , 1 500 . , , HDFS S3.
.

, , HDFS S3, , splitter xtrabackup, . crash-recovery.
hot , crash-recovery . , . binlog, master.
binlogs?binlog'. master , 4 , 100 , HDFS.
: Binlog Backuper, . , , binlog HDFS.

, 4 , 5 , , , . HDFS S3 .
.
:
- — 10 , 45 — .
- , scheduler multi instance slave master .
- — , . , , , , , , . pt-table-checksum , .
, :
- 1 10 , . crash-recovery, .
- .

slave -, . , . .
++
. Hardware , (HDD) 10 , + crash recovery xtrabackup, . , , . , , , , HDD , HDFS .
, — :
- ;
- .
, HDFS, , , .
自动化技术
, 6 000 . , , — :
- Auto-replace;
- DBManager;
- Naoru, Wheelhouse
Auto-replace
, , , , — , -. , .
Availability () — , . — recovery , .

MySQL , heartbeat. Heartbeat — timestamp.

, , , master read-write. heartbeat.
auto-replace , .
, 91 .?- , heartbeat . , . heartbeat', , heartbeat' 30 .
- 接下来,查看其数量是否满足阈值。 如果不是,则服务器出了点问题-因为它没有发送心跳。
- 之后,我们进行反向检查,以防万一-这两个服务突然失效,网络出现故障或全局数据库由于某种原因无法写入心跳。 作为反向检查,我们连接到损坏的数据库并检查其状态。
- 如果所有其他方法均失败,我们将查看主控职位是否在进步,是否有记录。 如果什么都没有发生,那么该服务器肯定无法正常工作。
- 最后一步实际上是自动替换。
自动替换非常保守,他从不想做很多自动操作。
- 首先,我们检查最近是否进行了任何拓扑操作? 也许刚刚添加了该服务器,但服务器上的某些内容尚未运行。
- 我们会随时检查同一集群中是否有任何替换项。
- 检查我们有什么故障限制。 如果我们一次遇到许多问题(10、20),那么我们将不会自动解决所有问题,因为我们可能会无意中破坏所有数据库的运行。
因此,我们一次
只能解决一个问题 。
因此,对于从属服务器,我们开始克隆并将其简单地从拓扑中删除,如果它是主服务器,则我们启动feylover,即所谓的紧急升级。
数据库管理器
DBManager是用于管理数据库的服务。 它具有:
- 精明的任务计划程序,确切地知道什么时候开始工作;
- 日志和所有信息:谁启动,何时启动,什么启动-这是真理的源头;
- 同步点。

DBManager在架构上非常简单。
- 有一些客户端,要么是通过Web界面执行某些操作的DBA,要么是编写了通过gRPC访问的DBA的脚本/服务。
- 有一些外部系统,例如Wheelhouse和Naoru,它们通过gRPC进入DBManager。
- 有一个调度程序,他了解可以开始什么操作,何时何地开始。
- 有一个非常愚蠢的工人,当对其进行操作时,会启动它,并通过PID进行检查。 工作程序可能会重新启动,进程不会中断。 所有工作人员都尽可能靠近要在其上进行操作的服务器,因此,例如,在更新ACLS时,我们不需要进行多次往返。
- 在每个SQL主机上,我们都有一个DBAgent-这是一个RPC服务器。 当您需要在服务器上执行某些操作时,我们将发送RPC请求。
我们有一个用于DBManager的Web界面,您可以在其中查看当前正在运行的任务,这些任务的日志,启动它的人以及何时启动,对特定数据库的服务器执行了哪些操作等。

有一个非常简单的CLI界面,您可以在其中运行任务,也可以在方便的视图中查看它们。

补救措施
我们也有一个响应问题的系统。 例如,当发生故障时,驱动器崩溃或某些服务无法正常工作,
Naoru可以正常工作
。 这是整个Dropbox都能使用的系统,每个人都可以使用它,并且它是专门为此类小任务而构建的。 我在2016年的
报告中谈到了Naoru。
Wheelhouse基于
状态机,专为长流程而设计。 例如,我们需要在6,000台计算机的整个群集上更新所有MySQL上的内核。 Wheelhouse清楚地做到了这一点-在从属服务器上进行更新,启动升级,从属服务器成为主服务器,在主服务器上进行更新。 此操作可能需要一个月甚至两个月。
监控方式

这很重要。
如果不监视系统,则很可能无法正常工作。
我们监视MySQL中的所有内容-我们可以从MySQL获得的所有信息都存储在某个地方,我们可以及时访问它。 我们将信息存储在InnoDb上,关于请求,事务,事务长度,事务长度的百分比,复制,网络上的统计信息-全部-全部-大量指标。
警报
我们配置了992个警报。 实际上,没有人在看指标,在我看来,没有人上班并开始看指标图,还有更多有趣的任务。

因此,当达到某些阈值时,会有警报起作用。
我们有992个警报,无论发生什么情况,我们都将对其进行查找 。
突发事件

我们拥有PagerDuty-通过该服务将警报发送给开始采取行动的负责人。

在这种情况下,紧急升级中发生了错误,并且在此之后立即记录了有关主机崩溃的警报。 之后,值班人员检查了阻止紧急升级的原因,并进行了必要的人工操作。
我们肯定会分析发生的每个事件,对于每个事件,我们在任务跟踪器中都有一个任务。 即使此事件是警报中的问题,我们也会创建一个任务,因为如果问题出在警报逻辑和阈值中,则需要对其进行更改。 警报不应该破坏人们的生活。 警报总是很痛苦的,尤其是在凌晨4点。
测试中
与监视一样,我确信每个人都在测试。 除了涵盖代码的单元测试之外,我们还具有集成测试,可用于测试:
如果我们有促销操作,则在集成测试中测试促销操作。 如果我们有克隆,那么我们将克隆我们拥有的所有拓扑。
拓扑示例
我们为所有场合提供了拓扑:2个具有多实例,分片,无分片,集群,集群的数据中心,以及一个数据中心-通常几乎是任何拓扑-甚至是我们不使用的拓扑,只是为了看看。

在此文件中,我们仅具有设置,哪些服务器以及需要提高的设置。 例如,我们需要提升master,并且我们说我们需要使用此类实例数据,此类端口上的此类数据库来进行此操作。 Bazel几乎将所有内容一起使用,后者基于这些文件创建拓扑,启动MySQL服务器,然后开始测试。

该测试看起来非常简单:我们指出正在使用哪种拓扑。 在此测试中,我们测试auto_replace。
- 我们创建auto_replace服务,然后启动它。
- 我们在拓扑中杀死主服务器,稍等片刻,看看目标从服务器已成为主服务器。 如果不是,则测试失败。
阶段
舞台环境与生产环境中的数据库相同,但是它们上没有用户流量,但是存在一些通过Percona Playback,sysbench和类似系统类似于生产的合成流量。
在Percona Playback中,我们记录流量,然后在具有不同强度的舞台环境中丢失流量,我们可以更快地丢失2-3倍。 也就是说,它是人为的,但非常接近实际负载。
这是必需的,因为在集成测试中我们无法测试生产。 我们无法测试警报或指标有效的事实。 在测试阶段,我们测试警报,指标,操作,定期杀死服务器,并查看它们是否正常收集。
另外,我们一起测试所有自动化,因为在集成测试中,很可能测试了系统的一部分,并且在升级中,所有自动化系统同时工作。 有时您认为系统会以这种方式运行,而不会以其他方式运行,但是它可能以完全不同的方式运行。
DRT(灾难恢复测试)
我们还在真实基础上进行生产测试。 这称为灾难恢复测试。 我们为什么需要这个?
●我们要测试我们的保修。
这是由许多大公司完成的。 例如,Google拥有一项运行非常稳定的服务-100%的时间-使用它的所有服务都确定该服务确实100%稳定并且永不崩溃。 因此,Google必须故意放弃该服务,以便用户考虑这种可能性。
就是这样-我们保证MySQL可以正常工作-有时它不工作! 并且我们保证在一段时间内它可能无法正常工作,客户应该考虑到这一点。 有时,我们会杀死生产主服务器,或者如果要进行转换,则会杀死所有从服务器,以查看半同步复制的行为。
●客户已准备好应对这些错误(更换主机和将其死亡)
为什么这么好? 我们有一个案例,在促销期间,1600个中的4个碎片的可用性下降到20%。 似乎有问题,对于1600年以来的4个分片,应该还有一些其他数字。 该系统的故障转移很少,大约每月一次,每个人都决定:“嗯,这是一次故障转移,它确实发生了。”
在某个时候,当我们切换到新系统时,一个人决定优化这两个心跳记录服务并将它们组合为一个。 这项服务做了其他事情,最终死了,心跳停止了记录。 碰巧的是,对于这个客户,我们每天有8个faylover。 一切顺利-20%的可用性。
事实证明,在此客户端中,存活时间为6小时。 因此,主人死后,我们将所有连接保持了6个小时。 池无法继续工作-它的连接已保留,受到限制,无法正常工作。 它被修复了。
我们再次进行feylover-不再是20%,但仍然很多。 仍然有问题。 原来,该池的执行存在错误。 当请求时,池变成许多分片,然后将所有这些连接。 如果某些碎片发烧,则Go代码中会出现某些竞争状况,整个池将被阻塞。 所有这些碎片将不再起作用。
灾难恢复测试非常有用,因为客户必须为这些错误做好准备,他们必须检查其代码。
●Plus灾难恢复测试非常好,因为它是在工作时间内进行的,并且一切就绪,减轻了压力,人们知道现在会发生什么。 这不会在晚上发生,这很棒。
结论
1.一切都需要自动化,永远不要动手。
每当有人用我们的双手爬入系统时,一切都会死掉并破坏我们的系统-每次! -即使是简单的操作。 例如,一个奴隶死亡,一个人不得不添加第二个奴隶,但是他决定用手将死亡的奴隶从拓扑中移除。 但是,他没有死者,而是复制到现场直播命令-主节点完全没有从属。 此类操作不应手动完成。
2.测试应该是连续且自动化的(并在生产中)。
您的系统在变化,基础架构也在变化。 如果您检查了一次,并且似乎可以使用,则并不意味着它明天就可以使用。 因此,您需要每天不断进行自动化测试,包括在生产中。
3.确保拥有客户(图书馆)。
用户可能不知道数据库如何工作。 他们可能不明白为什么需要超时,保持活动状态。 因此,最好拥有这些客户-您会更加镇定。
4.必须确定您构建系统的原则和担保,并始终遵守它们。
因此,您可以支持6000台数据库服务器。
在报告后的问题中,尤其是对它们的回答,还有很多有用的信息。问与答
-如果分片上的负载不平衡,会发生什么情况-有关某些文件的某些元信息被证明更受欢迎? 是否可以散布此碎片,或者碎片上的负载在任何地方都不会相差一个数量级?
她没有数量级上的差异。 它几乎是正态分布的。 我们有节流功能,也就是说,实际上我们无法使分片超载,我们在客户端级别上有节流功能。 通常,碰巧有一颗星星上传了一张照片,碎片几乎爆炸了。 然后我们禁止这个链接
-您说有992条警报。 您能否详细说明它-是开箱即用还是创建的? 如果创建了,是人工劳动还是机器学习之类的东西?
这都是手动创建的。 我们拥有自己的内部系统,称为Vortex,该系统存储指标并支持警报。 有一个yaml文件指出存在某种情况,例如,必须每天执行备份,如果满足此条件,则警报将不起作用。 如果不执行,则会发出警报。
这是我们的内部发展,因为很少有人可以存储所需数量的指标。
-做DRT的神经必须有多强? 随着每一分钟的恐慌,您掉落的CODERED不会上升。
通常,在数据库中工作确实很痛苦。 如果数据库崩溃,则该服务将无法正常工作,整个Dropbox将无法正常工作。 这真是痛苦。 DRT很有用,因为它是商务手表。 也就是说,我准备好了,我坐在办公桌前,我喝咖啡,我很新鲜,我准备做任何事情。
更糟糕的是,它发生在凌晨4点,而不是DRT。 例如,我们最近遇到的最后一次重大故障。 注入新系统时,我们忘记为MySQL设置OOM分数。 还有另一个读取binlog的服务。 在某些时候,我们的操作员是手动的-再次手动! -运行命令以删除Percona校验和表中的某些信息。 只是一个简单的删除,一个简单的操作,但是此操作生成了巨大的binlog。 该服务将该二进制日志读入内存,OOM Killer来了,并想杀死谁? 而且我们忘记了设置OOM分数,它杀死了MySQL!
我们有40位大师在凌晨4点死亡。 当40位大师逝世时,确实非常恐怖和危险。 DRT并不可怕也不危险。 我们躺了大约一个小时。
顺便说一句,DRT是排练此类时刻的好方法,这样我们就可以确切地知道如果某些事情突然发生,需要采取什么行动顺序。
-我想了解更多有关切换主从的信息。 首先,例如为什么不使用群集? 数据库集群,即不是具有切换功能的主从服务器,而是主控主应用程序,因此,如果一个数据库主应用程序崩溃,那么它就不会令人恐惧。
您是说类似组复制,galera集群等吗? 在我看来,该组应用程序尚未准备就绪。 不幸的是,我们还没有尝试过Galera。 当协议中包含faylover时,这非常好,但是不幸的是,它们还有很多其他问题,因此切换到该解决方案并不容易。
-在MySQL 8中似乎有一个类似InnoDb的集群。 没有尝试?
我们仍然有5.6值得。 我不知道何时切换到8。也许我们会尝试。
-在这种情况下,如果您有一个大的主服务器,则从一个主服务器切换到另一个主服务器时,结果表明队列在高负载的从服务器上累积。 如果熄灭了主机,则队列是否有必要到达,以便从机切换到主机模式-还是以其他方式完成操作?
主服务器上的负载由Semisync调节。 Semisync将主记录限制为从属服务器性能。 当然,可能是事务来了,半同步成功了,但是从属设备很长一段时间都丢失了该事务。 然后,您必须等待,直到从站将这个事务丢失为止。
-但是随后将掌握新数据,这将是必要的...
当开始升级过程时,我们将禁用I / O。 此后,主服务器无法写入任何内容,因为已复制了半同步。 不幸的是,幻影阅读可能会出现,但这已经是另一个问题。
-这些都是美丽的状态机-编写的脚本是什么,添加新步骤有多难? 对编写此系统的人需要做什么?
所有脚本都用Python编写,所有服务都用Go编写。 这是我们的政策。 更改逻辑很容易-只需在生成状态图的Python代码中即可。
-您可以阅读有关测试的更多信息。 测试如何编写,它们如何在虚拟机中部署节点-这些容器是吗?
是的 我们将在Bazel的帮助下进行测试。 有一些配置文件(json),Bazel选择了一个脚本,该脚本使用此配置文件为我们的测试创建拓扑。 此处描述了不同的拓扑。
所有这些都在docker容器中对我们有用:可以在CI或Devbox中使用。 我们有一个Devbox系统。 我们都在某个远程服务器上进行开发,例如,它可以在该服务器上工作。 在那里,它还可以在Bazel内部,泊坞容器内或Bazel沙箱中运行。 Bazel非常复杂,但很有趣。
-当在一台服务器上创建4个实例时,内存效率是否降低了?
每个实例都变小了。 因此,MySQL使用的内存越少,生存起来就越容易。 任何系统都更容易以少量的内存进行操作。 在这个地方,我们没有丢失任何东西。 我们有最简单的C组,可以限制内存中的这些实例。
-如果您有6,000台用于存储数据库的服务器,您能说出文件中存储了数十亿PB吗?
这些是数十EB,我们从亚马逊倾倒了一年的数据。
-原来,您有8台服务器,其中有200个分片,然后是400台服务器,每个分4个分片。 您有1600个分片-这是某种硬编码的值吗? 你不能再做一次吗? 如果您需要3200个碎片,会不会很痛?
是的,它最初是1600。这是在不到10年前完成的,我们仍然活着。 但是我们仍然有4个碎片-我们仍然可以增加空间4倍。
-服务器如何死亡,主要是出于什么原因? 自发的块状甲壳动物会发生吗?
最重要的是磁盘飞出。 我们有RAID 0-磁盘崩溃了,主机崩溃了。 这是主要问题,但是对于我们来说,更换此服务器更容易。 Google可以更轻松地替换数据中心,我们还有服务器。 我们几乎从来没有腐败校验和。 老实说,我不记得那是最后一次。 我们只是经常更新向导。 我们一位大师的生命期限限制为60天。 它不能使用更长的时间,之后我们用新服务器替换它,因为某种原因在MySQL中不断累积,并且60天后我们发现问题开始出现。 也许不在MySQL中,也许在Linux中。
, . 60 , . .
— , 6 . , JPEG , JPEG, , ? , , - ? — , ?
, . — Dropbox .
— ? ? , , - , , ? , 10 . , 7 , 6 , . ?
Dropbox - , . . , , , - .
, . , , , . - , 6 , , , , .
, facebook youtube- — Highload++ 2018 . , 1 .