Badoo 中存储和共享照片的架构

Badoo 中存储和共享照片的架构

阿尔乔姆·杰尼索夫( 博0rsh201, Badoo上)

Badoo 是世界上最大的交友网站。 目前我们在全球拥有约 330 亿注册用户。 但就我们今天的对话而言,更重要的是我们存储了大约 3 PB 的用户照片。 我们的用户每天上传约 3,5 万张新照片,阅读量约为 每秒 80 万个请求。 这对于我们的后端来说是相当多的,有时会遇到困难。

Badoo 中存储和共享照片的架构

我将讨论这个系统的设计,它一般存储和发送照片,我将从开发人员的角度来看它。 我们将简要回顾它的发展过程,其中我将概述主要里程碑,但我只会更详细地讨论我们当前正在使用的解决方案。

现在让我们开始吧。


正如我所说,这将是一次回顾展,为了从某个地方开始,让我们举一个最常见的例子。

Badoo 中存储和共享照片的架构

我们有一个共同的任务,我们需要接受、存储和发送用户照片。 在这种形式中,任务是通用的,我们可以使用任何东西:

  • 现代云存储,
  • 盒装解决方案,现在也有很多;
  • 我们可以在我们的数据中心设置几台机器,并在它们上面放置大硬盘并在那里存储照片。

从历史上看,无论现在还是过去(当时它还处于起步阶段),Badoo 都运行在我们自己的 DC 内的自己的服务器上。 因此,这个选择对我们来说是最佳选择。

Badoo 中存储和共享照片的架构

我们只是拿了几台机器,称之为“照片”,然后我们就得到了一个存储照片的集群。 但似乎缺少了一些东西。 为了让这一切发挥作用,我们需要以某种方式确定我们将在哪台机器上存储哪些照片。 在这里,也没有必要开放美国。

Badoo 中存储和共享照片的架构

我们在存储中添加一些包含用户信息的字段。 这将是分片键。 在我们的例子中,我们将其称为 place_id,这个地点 id 指向存储用户照片的位置。 我们制作地图。

在第一阶段,这甚至可以手动完成 - 我们说该用户在这样的地方的照片将登陆这样的服务器。 借助这张地图,我们始终知道用户何时上传照片、将其保存在哪里以及从哪里提供照片。

这是一个绝对微不足道的方案,但它具有相当显着的优点。 首先,正如我所说,它很简单;第二,通过这种方法,我们可以通过简单地交付新车并将其添加到地图中来轻松水平扩展。 您不需要做任何其他事情。

我们有一段时间就是这样。

Badoo 中存储和共享照片的架构

这是2009年左右的事。 他们交付汽车,交付...

在某些时候我们开始注意到这个方案有一定的缺点。 有什么缺点?

首先,能力有限。 我们无法将尽可能多的硬盘塞到一台物理服务器上。 随着时间的推移和数据集的增长,这已经成为一个确定的问题。

第二。 这是一种非典型的机器配置,因为此类机器很难在其他集群中重用;它们非常具体,即它们的性能应该较弱,但同时具有大硬盘。

这都是 2009 年的情况,但原则上这些要求今天仍然适用。 我们有一个回顾,所以 2009 年一切都非常糟糕。

最后一点是价格。

Badoo 中存储和共享照片的架构

当时价格非常昂贵,我们需要寻找一些替代方案。 那些。 我们需要以某种方式更好地利用数据中心的空间和所有这些所在的物理服务器。 我们的系统工程师开始了一项大型研究,他们审查了许多不同的选项。 他们还研究了 PolyCeph 和 Lustre 等集群文件系统。 存在性能问题并且操作相当困难。 他们拒绝了。 我们尝试通过 NFS 将整个数据集安装在每辆车上,以便以某种方式对其进行扩展。 阅读也很糟糕,我们尝试了不同供应商的不同解决方案。

最后,我们决定使用所谓的存储区域网络。

Badoo 中存储和共享照片的架构

这些是专门为存储大量数据而设计的大型 SHD。 它们是带有磁盘的架子,安装在最终的光学输出机器上。 那。 我们有某种类型的机器池,非常小,这些 SHD 对我们的发送逻辑来说是透明的,即让我们的 nginx 或任何其他人能够处理这些照片的请求。

这个决定有明显的优势。 这是SHD。 它的目的是存储照片。 这比简单地为机器配备硬盘驱动器更便宜。

第二加。

Badoo 中存储和共享照片的架构

这是容量变大了很多,即我们可以在更小的体积中容纳更多的存储空间。

但也有很快就出现的缺点。 随着系统上的用户数量和负载的增长,性能问题开始出现。 这里的问题非常明显 - 任何设计用于在小容量中存储大量照片的 SHD 通常都会受到密集读取的影响。 对于任何云存储或其他任何东西来说实际上都是如此。 现在我们还没有一个可以无限扩展的理想存储,你可以往里面塞任何东西,而且它可以很好地容忍读取。 尤其是休闲读物。

Badoo 中存储和共享照片的架构

就像我们的照片一样,因为照片的请求不一致,这会极大地影响它们的性能。

即使根据今天的数据,如果我们在连接存储的计算机上获得超过 500 RPS 的照片速度,问题就已经开始了。 这对我们来说已经够糟糕了,因为用户数量在不断增长,事情只会变得更糟。 这需要以某种方式进行优化。

为了优化,我们当时决定,显然,要查看负载曲线 - 一般来说,正在发生什么,需要优化什么。

Badoo 中存储和共享照片的架构

在这里,一切都掌握在我们手中。

我已经在第一张幻灯片中说过:我们每秒有 80 万个阅读请求,而每天只有 3,5 万次上传。 也就是说,这是三个数量级的差异。 显然,阅读需要优化,而且具体如何优化也很清楚。

还有一个小点。 该服务的具体细节是,一个人注册、上传照片,然后开始主动查看其他人,喜欢他们,并主动向其他人展示。 然后他找到伴侣或找不到伴侣,这取决于结果如何,并停止使用该服务一段时间。 此时此刻,当他使用它时,他的照片非常热门——它们很受欢迎,很多人都在观看它们。 一旦他停止这样做,他很快就会像以前一样不再与其他人接触,而且几乎从来没有人要求他拍照。

Badoo 中存储和共享照片的架构

那些。 我们有一个非常小的热数据集。 但同时也有很多人对他提出要求。 这里一个完全显而易见的解决方案是添加缓存。

具有 LRU 的缓存将解决我们所有的问题。 我们在做什么?

Badoo 中存储和共享照片的架构

我们在带有存储的大型集群前面添加了另一个相对较小的集群,称为照片缓存。 这本质上只是一个缓存代理。

它是如何从内部运作的? 这是我们的用户,这是存储。 一切都和以前一样。 我们在中间添加什么?

Badoo 中存储和共享照片的架构

只是一台带有物理本地磁盘的机器,速度很快。 例如,这是 SSD 的情况。 并且某种本地缓存存储在该磁盘上。

它是什么样子的? 用户发送照片请求。 NGINX 首先在本地缓存中查找它。 如果没有,则只需 proxy_pass 到我们的存储,从那里下载照片并将其提供给用户。

但这非常平庸,不清楚里面发生了什么。 它的工作原理是这样的。

Badoo 中存储和共享照片的架构

缓存在逻辑上分为三层。 当我说“三层”时,这并不意味着存在某种复杂的系统。 不,这些只是文件系统中的三个目录:

  1. 这是刚刚从代理下载的照片所在的缓冲区。
  2. 这是一个热缓存,用于存储当前主动请求的照片。
  3. 还有一个冷缓存,当收到的请求较少时,照片会逐渐从热缓存中推出。

为此,我们需要以某种方式管理该缓存,需要重新排列其中的照片等。 这也是一个非常原始的过程。

Badoo 中存储和共享照片的架构

Nginx 只是将每个请求写入 RAMDisk access.log,其中指示当前所服务的照片的路径(当然是相对路径)以及所服务的分区。 那些。 它可能会说“照片 1”,然后是缓冲区、热缓存、冷缓存或代理。

根据这一点,我们需要以某种方式决定如何处理照片。

我们在每台机器上运行一个小守护程序,它不断读取此日志并将有关某些照片的使用情况的统计信息存储在内存中。

Badoo 中存储和共享照片的架构

他只是在那里收集、保留计数器并定期执行以下操作。 他将主动请求的照片(有很多请求)移动到热缓存,无论它们在哪里。

Badoo 中存储和共享照片的架构

很少被请求且请求频率较低的照片会逐渐从热缓存中推出到冷缓存中。

Badoo 中存储和共享照片的架构

当我们用完缓存空间时,我们只是开始不加区别地从冷缓存中删除所有内容。 顺便说一句,这很有效。

为了在将照片代理到缓冲区时立即保存照片,我们使用 proxy_store 指令,并且缓冲区也是 RAMDisk,即对于用户来说,它的工作速度非常快。 这涉及缓存服务器本身的内部结构。

剩下的问题是如何在这些服务器之间分发请求。

假设有一个由二十台存储机器和三台缓存服务器组成的集群(事情就是这样发生的)。

Badoo 中存储和共享照片的架构

我们需要以某种方式确定哪些请求针对哪些照片以及将它们放在哪里。

最常见的选项是循环法。 还是偶然做的?

这显然有很多缺点,因为在这种情况下我们使用缓存的效率会非常低。 请求将落在一些随机机器上:在这里它被缓存,但在下一台机器上它不再存在。 如果这一切都奏效,那将是非常糟糕的。 即使集群中的机器数量很少。

我们需要以某种方式明确地确定哪个服务器来处理哪个请求。

有一种平庸的方式。 我们从 URL 中获取哈希值,或者从 URL 中的分片键中获取哈希值,然后将其除以服务器数量。 将工作? 将要。

Badoo 中存储和共享照片的架构

那些。 我们有一个2%的请求,例如,对于某些“example_url”,它总是会落在索引为“XNUMX”的服务器上,并且缓存将不断被尽可能最好地处理。

但这种方案中存在重新分片的问题。 重新分片——我的意思是改变服务器的数量。

假设我们的缓存集群无法再应对,我们决定添加另一台机器。

我们来补充一下。

Badoo 中存储和共享照片的架构

现在一切都不能被三整除,而是可以被四整除。 因此,我们以前拥有的几乎所有密钥、几乎所有 URL 现在都位于其他服务器上。 整个缓存只是短暂地失效了。 所有请求都落在我们的存储集群上,它变得不适、服务失败和用户不满意。 我不想那样做。

这个选项也不适合我们。

那。 我们应该做什么? 我们必须以某种方式有效地利用缓存,一遍又一遍地将相同的请求发送到同一台服务器上,但要抵制重新分片。 而且有这样的解决方案,并没有那么复杂。 这称为一致性哈希。

Badoo 中存储和共享照片的架构

它看起来像什么?

Badoo 中存储和共享照片的架构

我们从分片键中获取一些函数并将其所有值传播到圆上。 那些。 在点0处,它的最小值和最大值收敛。 接下来,我们将所有服务器放置在同一个圆上,大致如下:

Badoo 中存储和共享照片的架构

每个服务器由一个点定义,顺时针方向到达该点的扇区相应地由该主机提供服务。 当请求发送给我们时,我们立即看到,例如,请求 A - 它有一个哈希 - 并且由服务器 2 提供服务。请求 B - 由服务器 3 提供服务。等等。

Badoo 中存储和共享照片的架构

在这种情况下重新分片时会发生什么?

Badoo 中存储和共享照片的架构

我们不会像以前那样使整个缓存无效,也不会移动所有密钥,而是将每个扇区移动一小段距离,以便相对而言,我们要添加的第六个服务器适合可用空间,并且我们将其添加到那里。

Badoo 中存储和共享照片的架构

当然,在这种情况下,钥匙也会移出。 但他们的离开比以前要弱得多。 我们看到前两个密钥保留在他们的服务器上,而缓存服务器仅针对最后一个密钥进行了更改。 这工作起来非常有效,如果您增量添加新主机,那么这里就不会有大问题。 你一次添加一点,等到缓存再次满了,一切就正常了。

唯一的问题仍然是拒绝。 让我们假设某种汽车出了故障。

Badoo 中存储和共享照片的架构

我们此时并不真的想重新生成此映射,使部分缓存无效,等等,例如,如果机器重新启动,并且我们需要以某种方式服务请求。 我们只需在每个站点保留一个备份照片缓存,作为当前关闭的任何计算机的替代品。 如果我们的一台服务器突然不可用,流量就会流向那里。 当然,我们那里没有任何缓存,即虽然很冷,但至少用户请求正在被处理。 如果这是一个很短的间隔,那么我们就会完全平静地体验它。 只是存储负载增加了。 如果这个间隔很长,那么我们已经可以做出决定 - 是否从地图上删除该服务器,或者可能用另一个服务器替换它。

这是关于缓存系统的。 让我们看看结果。

看起来这里并没有什么复杂的事情。 但这种管理缓存的方法给了我们大约 98% 的欺骗率。 那些。 每秒这80万个请求中,只有1600个到达存储,这是完全正常的负载,他们平静地忍受它,我们总是有储备。

我们将这些服务器放置在三个 DC 中,并获得了三个存在点 - 布拉格、迈阿密和香港。

Badoo 中存储和共享照片的架构

那。 他们或多或少位于我们每个目标市场的本地。

作为一个不错的奖励,我们得到了这个缓存代理,CPU 实际上是空闲的,因为它并不需要提供内容。 在那里,我们使用 NGINX+ Lua 实现了很多功利逻辑。

Badoo 中存储和共享照片的架构

例如,我们可以尝试使用 webp 或渐进式 jpeg(这些是有效的现代格式),看看它如何影响流量,做出一些决定,在某些国家/地区启用它等等; 即时动态调整照片大小或裁剪照片。

这是一个很好的用例,例如,您有一个显示照片的移动应用程序,并且该移动应用程序不希望浪费客户端的 CPU 来请求大照片,然后将其调整到特定大小以将其推送到风景。 我们可以简单地在 UPort 条件 URL 中动态指定一些参数,照片缓存将自行调整照片的大小。 通常,它将选择我们在磁盘上实际拥有的大小,尽可能接近所请求的大小,并在特定坐标中降价销售。

顺便说一下,我们公开了过去五年高负载系统开发者大会的视频记录 高负荷++。 观看、学习、分享和订阅 YouTube频道.

我们还可以在那里添加很多产品逻辑。 例如,我们可以使用URL参数添加不同的水印,我们可以对照片进行模糊、模糊或像素化。 这是当我们想要展示一个人的照片,但又不想展示他的脸时,这个效果很好,都在这里实现了。

我们得到了什么? 我们获得了三个存在点、良好的技巧率,同时这些机器上没有空闲的 CPU。 当然,他现在变得比以前更重要了。 我们需要给自己提供更强大的汽车,但这是值得的。

这涉及照片的归还。 这里的一切都非常清楚和明显。 我想我没有发现美国,几乎所有的CDN都是这样工作的。

而且,最有可能的是,经验丰富的听众可能会有一个问题:为什么不将所有内容都更改为 CDN? 情况大致相同;所有现代 CDN 都可以做到这一点。 原因有很多。

首先是照片。

Badoo 中存储和共享照片的架构

这是我们基础设施的关键点之一,我们需要对其进行尽可能多的控制。 如果这是来自第三方供应商的某种解决方案,并且您对其没有任何权力,那么当您拥有大型数据集并且拥有非常大的流量时,您将很难接受它用户请求。

让我举一个例子。 现在,有了我们的基础设施,相对而言,我们可以在出现一些问题或地下敲击时,到机器那里去搞乱。 我们可以添加一些我们只需要的指标的集合,我们可以以某种方式进行实验,看看这如何影响图表,等等。 现在正在这个缓存集群上收集大量统计数据。 我们会定期查看它并花很长时间探索一些异常现象。 如果是在CDN侧,那就更难控制了。 或者,例如,如果发生某种事故,我们知道发生了什么,我们知道如何忍受它以及如何克服它。 这是第一个结论。

第二个结论也比较具有历史性,因为系统已经发展了很长时间,不同阶段有很多不同的业务需求,并不总是符合CDN的概念。

上一点的结论是

Badoo 中存储和共享照片的架构

这是因为在照片缓存上我们有很多特定的逻辑,不能总是根据请求添加。 任何 CDN 都不可能根据您的要求向您添加一些自定义内容。 例如,如果您不希望客户端能够更改某些内容,请加密 URL。 是否要更改服务器上的 URL 并对其进行加密,然后在此处发送一些动态参数。

这表明什么结论? 就我们而言,CDN 并不是一个很好的选择。

Badoo 中存储和共享照片的架构

就您而言,如果您有任何特定的业务需求,那么您可以很容易地实现我自己向您展示的内容。 这将与类似的负载曲线完美配合。

但如果您有某种通用解决方案,并且任务不是很具体,那么您绝对可以安全地采用 CDN。 或者,时间和资源对您来说是否比控制更重要。

Badoo 中存储和共享照片的架构

现代 CDN 几乎拥有我现在告诉你的一切。 除了增加或减少某些功能外。

这是关于赠送照片。

现在让我们回顾一下并讨论一下存储。

2013年即将过去。

Badoo 中存储和共享照片的架构

添加了缓存服务器,性能问题就消失了。 一切安好。 数据集正在增长。 截至 2013 年,我们有大约 80 台服务器连接到存储,每个 DC 中有大约 40 台缓存服务器。 每个 DC 上的数据量为 560 TB,即总计约 PB。

Badoo 中存储和共享照片的架构

并且随着数据集的增长,运营成本开始大幅上升。 这是什么意思?

Badoo 中存储和共享照片的架构

在这张绘制的图中 - 使用 SAN、连接到它的机器和缓存 - 有很多故障点。 如果我们之前已经处理过缓存服务器的故障,那么一切或多或少都是可预测和可以理解的,但在存储方面一切都更糟糕。

首先,存储区域网络 (SAN) 本身可能会发生故障。

其次,它通过光学连接到终端机器。 光卡和火花塞可能有问题。

Badoo 中存储和共享照片的架构

当然,它们的数量不如 SAN 本身那么多,但尽管如此,这些也是故障点。

接下来是机器本身,它连接到存储。 它也可能会失败。

Badoo 中存储和共享照片的架构

总的来说,我们有三个失败点。

此外,除了故障点之外,存储本身的维护也很繁重。

这是一个复杂的多组件系统,系统工程师可能很难使用它。

最后也是最重要的一点。 如果这三个点中的任何一个发生故障,我们就有非零的机会丢失用户数据,因为文件系统可能崩溃。

Badoo 中存储和共享照片的架构

假设我们的文件系统损坏了。 首先,它的恢复需要很长时间——如果数据量很大,可能需要一周的时间。 其次,最终我们很可能会得到一堆难以理解的文件,需要以某种方式组合到用户照片中。 我们还面临着丢失数据的风险。 风险相当高。 而且这种情况发生的次数越多,整个链条中出现的问题越多,这种风险就越高。

必须对此采取一些措施。 我们决定只需要备份数据。 这实际上是一个显而易见的解决方案,也是一个很好的解决方案。 我们做了什么?

Badoo 中存储和共享照片的架构

这是我们的服务器之前连接到存储时的样子。 这是一个主要部分,它只是一个块设备,实际上代表通过光学进行远程存储的安装座。

我们刚刚添加了第二部分。

Badoo 中存储和共享照片的架构

我们在它旁边放置了第二个存储(幸运的是,它的钱并没有那么贵),并将其称为备份分区。 它也通过光纤连接并位于同一台机器上。 但我们需要以某种方式同步它们之间的数据。

这里我们只是就近做一个异步队列。

Badoo 中存储和共享照片的架构

她不是很忙。 我们知道我们没有足够的记录。 队列只是 MySQL 中的一个表,其中写入诸如“您需要备份这张照片”之类的行。 对于任何更改或上传,我们都会使用异步或某种后台工作人员从主分区复制到备份。

因此我们总是有两个一致的部分。 即使该系统的一部分出现故障,我们也可以随时通过备份更改主分区,一切都会继续工作。

但也正因为如此,阅读负荷大大增加,因为…… 除了从主要部分阅读的客户之外,因为他们首先查看那里的照片(那里是最近的照片),然后在备份中查找它,如果他们没有找到它(但 NGINX 就是这么做的),我们的系统也是一个加备份,现在从主分区读取。 这并不是说这是一个瓶颈,但我本质上不想增加负载,就像这样。

我们添加了第三个磁盘,这是一个小型 SSD,并将其称为缓冲区。

Badoo 中存储和共享照片的架构

现在如何运作。

用户将照片上传到缓冲区,然后将一个事件扔到队列中,指示需要将其复制到两个部分。 它被复制,并且照片在缓冲区中保存一段时间(例如一天),然后才从那里清除。 这极大地提高了用户体验,因为用户上传照片后,通常请求会立即开始跟进,或者他自己更新页面并刷新。 但这完全取决于上传的应用程序。

或者,例如,他开始向其他人展示自己的人在这张照片之后立即发送请求。 它尚未在缓存中;第一个请求发生得非常快。 本质上与照片缓存相同。 慢存储根本不参与其中。 当一天后它被清除时,它要么已经缓存在我们的缓存层上,要么很可能没有人再需要它了。 那些。 由于如此简单的操作,这里的用户体验得到了很好的发展。

嗯,最重要的是:我们不再丢失数据。

Badoo 中存储和共享照片的架构

就说我们停了下来 可能 丢失数据,因为我们并没有真正丢失它。 但有危险。 我们看到这个解决方案当然是好的,但是它有点像消除问题的症状,而不是彻底解决问题。 一些问题仍然存在。

首先,这是运行所有这些机器的物理主机本身的一个故障点;它并没有消失。

Badoo 中存储和共享照片的架构

其次,SAN仍然存在问题,维护工作量大等问题仍然存在。 这并不是说它是一个关键因素,但我想尝试以某种方式在没有它的情况下生活。

我们制作了第三个版本(实际上是第二个版本)——保留版本。 它看起来像什么?

原来是这样的——

Badoo 中存储和共享照片的架构

我们的主要问题在于这是一个物理主机。

首先,我们正在删除 SAN,因为我们想要进行实验,我们想要尝试仅本地硬盘驱动器。

Badoo 中存储和共享照片的架构

这已经是2014-2015年了,那时磁盘及其在一台主机上的容量的情况变得好多了。 我们决定为什么不尝试一下。

然后我们只需将备份分区物理转移到一台单独的机器上即可。

Badoo 中存储和共享照片的架构

这样,我们就得到了这张图。 我们有两辆车存储相同的数据集。 它们完全相互备份,并通过同一个MySQL中的异步队列通过网络同步数据。

Badoo 中存储和共享照片的架构

为什么这很有效,因为我们的记录很少。 那些。 如果写作与阅读相当,也许我们会遇到某种网络开销和问题。 很少写作,大量阅读——这种方法效果很好,即我们很少在这两个服务器之间复制照片。

如果您更详细地了解一下,这是如何工作的。

Badoo 中存储和共享照片的架构

上传。 平衡器只需选择具有一对的随机主机并上传到它。 与此同时,他自然会进行健康检查并确保汽车不会掉下来。 那些。 他只将照片上传到实时服务器,然后通过异步队列将其全部复制到他的邻居。 通过上传,一切都变得非常简单。

任务有点困难。

Badoo 中存储和共享照片的架构

Lua 在这里帮助了我们,因为在普通 NGINX 上很难实现这样的逻辑。 我们首先向第一台服务器发出请求,查看照片是否在那里,因为它可能会被上传到例如邻居,但尚未到达这里。 如果有照片就好了。 我们立即将其提供给客户端,并可能将其缓存。

Badoo 中存储和共享照片的架构

如果不存在,我们只需向我们的邻居发出请求,并保证从那里收到它。

Badoo 中存储和共享照片的架构

那。 我们可以再次说:性能可能存在问题,因为存在不断的往返 - 照片已上传,但它不在这里,我们正在发出两个请求而不是一个,这应该会缓慢进行。

在我们的情况下,这并不缓慢。

Badoo 中存储和共享照片的架构

我们在这个系统上收集了一堆指标,这种机制的条件智能率大约是95%。 那些。 这个备份的延迟很小,因此我们几乎可以保证,照片上传后,我们会第一时间拍摄,而不必两次去任何地方。

那么我们还有什么真的很酷的呢?

以前,我们有主备份分区,我们按顺序读取它们。 那些。 我们总是先搜索主数据库,然后再搜索备份数据库。 这是一举一动。

现在我们同时利用两台机器的读取。 我们使用循环法分发请求。 在一小部分情况下,我们会提出两个请求。 但总体而言,我们现在的阅读量是以前的两倍。 而且发送机器和直接存储机器上的负载都大大减少了,我们当时也有这样的负载。

至于容错。 其实我们主要是为了这个而奋斗。 有了容错能力,这里一切都很好。

Badoo 中存储和共享照片的架构

一辆车坏了。

Badoo 中存储和共享照片的架构

没问题! 系统工程师可能晚上都起不来,等到早上,不会有什么不好的事情发生。

如果即使这台机器出现故障,队列乱了,也没有问题,日志会先在活的机器上累积,然后添加到队列中,然后再添加到要运行的车上。一段时间后即可投入运行。

Badoo 中存储和共享照片的架构

维护也是如此。 我们只需关闭其中一台机器,手动将其从所有池中拉出,它停止接收流量,我们进行某种维护,编辑一些内容,然后将其返回服务,并且此备份很快就能赶上。 那些。 每天,一辆车的停机时间会在几分钟之内赶上。 这实在是太少了。 有了容错能力,我再说一遍,这里一切都很酷。

从这个冗余方案中可以得出什么结论?

我们获得了容错能力。

便于使用。 由于机器具有本地硬盘驱动器,因此从操作角度来看,这对于使用它的工程师来说要方便得多。

我们获得了双倍的阅读津贴。

这是除了容错之外的一个非常好的加分。

但也存在问题。 现在我们对与此相关的一些功能进行了更加复杂的开发,因为系统已经变得 100% 最终一致。

Badoo 中存储和共享照片的架构

例如,在某些后台工作中,我们必须不断地思考:“我们现在在什么服务器上运行?”、“这里真的有当前照片吗?” ETC。 当然,这一切都是封装起来的,对于编写业务逻辑的程序员来说,它是透明的。 但是,尽管如此,这个巨大的复杂层已经出现了。 但我们已经准备好忍受这一点,以换取我们从中获得的好处。

这里又出现了一些冲突。

我一开始就说过,将所有内容存储在本地硬盘上是不好的。 现在我说我们喜欢它。

是的,确实,随着时间的推移,情况发生了很大的变化,现在这种做法有很多优点。 首先,我们的操作变得更加简单。

其次,它的生产力更高,因为我们没有这些自动控制器或与磁盘架的连接。

那里有大量的机器,而这些只是在机器上组装成一个raid的几个磁盘。

但也有缺点。

Badoo 中存储和共享照片的架构

即使按照今天的价格,这也比使用 SAN 贵大约 1,5 倍。 因此,我们决定不再大胆地将整个大型集群改装为带有本地硬盘的汽车,并决定留下混合解决方案。

我们一半的机器使用硬盘驱动器(好吧,不是一半 - 可能是 30%)。 其余的都是以前有优先预订计划的老车。 我们只是重新安装它们,因为我们不需要新数据或其他任何东西,我们只是将安装从一台物理主机移至两台。

我们现在有大量的阅读材料,并且我们扩大了它。 如果之前我们在一台机器上安装了一个存储,那么现在我们在一对机器上安装四个存储。 而且效果很好。

让我们简单总结一下我们所取得的成就、我们为之奋斗的目标以及我们是否成功。

结果

我们的用户数量高达 33 万。

我们有三个办事处 - 布拉格、迈阿密、香港。

它们包含一个缓存层,由具有快速本地磁盘 (SSD) 的汽车组成,NGINX 的简单机械、其 access.log 和 Python 守护进程在其上运行,处理所有这些并管理缓存。

如果您愿意,您在您的项目中,如果照片对您来说不像对我们那么重要,或者如果权衡控制与开发速度和资源成本对您来说是相反的方向,那么您可以安全地替换它有了 CDN,现代 CDN 就做得很好了。

接下来是存储层,在该层上我们有相互备份的成对机器集群,只要文件发生变化,文件就会从一台机器异步复制到另一台机器。

此外,其中一些机器可以使用本地硬盘。

其中一些机器连接到 SAN。

Badoo 中存储和共享照片的架构

而且,一方面,它使用起来更方便,生产效率更高一些,另一方面,它在放置密度和每 GB 价格方面也很方便。

这是对我们所获得的架构及其发展方式的简要概述。

船长还有一些提示,非常简单。

首先,如果您突然决定迫切需要改进照片基础设施中的所有内容,请先进行测量,因为也许没有任何内容需要改进。

Badoo 中存储和共享照片的架构

让我举一个例子。 我们有一组机器,可以从聊天中的附件中发送照片,该计划自 2009 年以来一直在那里运行,没有人受到影响。 每个人都很好,每个人都喜欢一切。

为了衡量,首先挂一堆指标,看看它们,然后决定哪些是你不满意的,哪些是需要改进的。 为了衡量这一点,我们有一个很酷的工具,叫做 Pinba。

它允许您从 NGINX 收集每个请求和响应代码以及时间分布的非常详细的统计数据 - 无论您想要什么。 它绑定到各种不同的分析系统,然后您可以精美地查看这一切。

首先我们测量它,然后我们改进它。

更远。 我们用缓存优化读取,用分片优化写入,但这是一个显而易见的点。

Badoo 中存储和共享照片的架构

更远。 如果您刚刚开始构建系统,那么最好将照片制作为不可变文件。 因为您立即就失去了缓存失效、逻辑如何找到照片的正确版本等一系列问题。

Badoo 中存储和共享照片的架构

假设您上传了一百个文件,然后对其进行旋转,使其成为物理上不同的文件。 那些。 无需思考:现在我将节省一点空间,将其写入同一个文件,更改版本。 这总是效果不佳,并且会在以后引起很多麻烦。

下一点。 关于动态调整大小。

以前,当用户上传照片时,我们立即针对各种场合、不同的客户剪切一大堆尺寸,并将它们都放在磁盘上。 现在我们已经放弃了这个。

我们只留下了三种主要尺寸:小号、中号和大号。 我们只是简单地缩小 Uport 要求的尺寸后面的所有其他尺寸,我们只需缩小尺寸并将其提供给用户即可。

事实证明,这里缓存层的 CPU 比我们在每个存储上不断重新生成这些大小要便宜得多。 假设我们想要添加一个新的,这将需要一个月的时间 - 到处运行一个脚本,可以整齐地完成所有这些操作,而不会破坏集群。 那些。 如果您现在有机会选择,最好制作尽可能少的物理尺寸,但至少有一些分布是,例如,三个。 其他所有内容都可以使用现成的模块即时调整大小。 现在一切都变得非常简单且方便。

而且增量异步备份也不错。

正如我们的实践所表明的,该方案对于延迟复制已更改的文件非常有效。

Badoo 中存储和共享照片的架构

最后一点也很明显。 如果你的基础设施现在没有这样的问题,但是有一个东西可以坏掉,当它变得多一点的时候,它肯定会坏掉。 因此,最好提前考虑一下,不要遇到问题。 这就是我想说的。

名片

» 博0rsh201
» Badoo 博客

本报告是高负载系统开发人员会议上最好的演讲之一的文字记录 高负荷++。 距离 HighLoad++ 2017 大会还有不到一个月的时间。

我们已经准备好了 会议日程目前,日程正在积极制定中。

今年我们继续探讨架构和扩展的主题:

我们还在开发高负载系统的在线培训课程中使用其中一些材料 高负载指南 是一系列精选的信件、文章、材料、视频。 我们的教科书已包含 30 多种独特的材料。 连接!

来源: habr.com

添加评论