# 阿尔及利亚通往全球 API 步骤的愤怒之路第 2 部分

> 原文： [http://highscalability.com/blog/2015/7/20/algolias-fury-road-to-a-worldwide-api-steps-part-2.html](http://highscalability.com/blog/2015/7/20/algolias-fury-road-to-a-worldwide-api-steps-part-2.html)

![](img/914d4bdf9db5c148d642dcbfb590ddac.png)

我们为开发人员和开发人员回答的最常见问题是关于[我们的体系结构](http://highscalability.com/blog/2015/3/9/the-architecture-of-algolias-distributed-search-network.html)以及我们如何实现如此高的可用性。 他们中的一些人对裸机服务器的高可用性持怀疑态度，而另一些人则对我们如何在全球范围内分发数据持怀疑态度。 但是，我更喜欢的问题是“初创企业如何建立这样的基础架构”。 的确，对于一个年轻的公司，我们当前的架构令人印象深刻：

*   我们的高端专用计算机在全球 13 个地区托管，拥有 25 个数据中心

*   我们的主从设置会在至少 3 台不同的计算机上复制我们的搜索引擎

*   我们每个月处理超过 60 亿个查询

*   我们每个月接收和处理超过 200 亿次写操作

就像罗马不是一天建成的，我们的基础架构也不是很好。 本系列文章将探讨我们在构建基础架构时采取的 15 个工具步骤。 我什至将讨论我们的中断和错误，以便您了解我们如何使用它们来改进我们的体系结构。

该系列的 [第一篇博客文章](http://highscalability.com/blog/2015/7/13/algolias-fury-road-to-a-worldwide-api.html) 专注于我们 Beta 的早期。 这篇博客文章将重点介绍从 2013 年 9 月到 2014 年 12 月我们服务的前 18 个月，甚至包括我们的首次停机！

## 步骤 4：2014 年 1 月

### 部署是高可用性的大风险

目前，我们的主要关注之一是确保我们的发展敏捷，同时又不以牺牲稳定性为代价。 因此，我们开发了一个包含 6,000 多个单元测试和 200 多个非回归测试的测试套件，以确保代码更改不会引入新的错误。 不幸的是，这还不够。 通过我们所有测试的一项新功能引入了一个生产错误，该错误导致 [八分钟的索引停机时间](https://blog.algolia.com/postmortem-todays-8min-indexing-downtime/) 。 值得庆幸的是，由于我们的体系结构旨在将搜索查询与索引分开，因此不会影响搜索查询。

此问题帮助我们确定了高可用性设置中的几个问题：

*   回滚需要很快，因此我们开发了使用单个命令行执行回滚的功能。

*   部署脚本需要执行完整性检查，并在出现错误时自动回滚，因此我们将其添加到了部署过程中。

*   我们不应该仅仅因为测试通过 而部署到所有生产集群。 在此问题之后，我们对集群进行了一系列部署。 我们从测试集群开始，然后是社区集群（免费客户），最后是付费用户集群。

今天，当要测试一项新功能时，我们的部署有所不同。 我们选择一组集群进行测试，然后使用以下步骤进行部署：

1.  部署到所选集合的所有群集中的第一台计算机。

2.  监视 24 小时，然后部署到所选集中所有群集中的第二台计算机。

3.  监视 24 小时，然后部署到所选集中所有群集中的第三台计算机。

4.  几天后，我们部署到了所有生产集群。

使用这种方法，我们能够在几个小时内检测到几乎不可能通过单元测试发现的错误。 由于我们每月有数十亿的查询，因此这种检测是可能的。

# 第 5 步：2014 年 3 月

### 管理大量写操作

当我们在加拿大/东部和欧洲/西部的集群很好地处理了我们的增长时，我们开始解决一个新问题：延迟。 来自亚洲的集群的延迟太高，无法获得令人满意的性能。 我们决定首先通过在 AWS 中部署计算机来测试市场。 我们不愿意做出选择，因为即使使用 AWS 提供的最佳 CPU（当时的 E5-2680），搜索查询的性能也比 E5-2687W CPU 低 15％！ 我们这样做是为了减少启动实验的时间，但要确保不引入对 AWS 的任何依赖关系。 如果测试成功，这使我们可以轻松地迁移到其他提供商。 在纸上，一切看起来都不错。 当我们发现他们的虚拟化不支持 AVX 指令时，我们遇到了一个问题，这对我们来说是重要的功能。 我们必须生成没有 AVX 指令集的二进制文件（这再次降低了搜索查询的性能）。

在享受我们最近在新加坡推出的服务时，我们开始收到一些来自欧洲客户的投诉，他们抱怨他们的搜索查询延迟时间增加。 我们很快发现它与大量的索引操作相关联，这很奇怪，因为我们确信索引和搜索 CPU 使用率之间的体系结构划分正常工作。 经过调查，我们发现用于处理写操作的整个集群的分布式一致性的共识算法存在潜在的瓶颈。 当出现瓶颈时，它将阻塞 HTTP 服务器线程。 然后，这将导致搜索查询需要等待线程。 我们是无意中设计造成的！

我们通过在达成共识之前实施队列来解决此问题。 它使我们能够收到大量的写操作，进行批处理，然后将其发送给共识。 共识不再存在于 HTTP 服务器的序列中，因此写操作无法再冻结 HTTP 服务器线程。 在正常操作期间，除了将作业传递给共识以外，队列什么都不做。 在出现峰值的情况下，它允许我们在达成共识之前进行缓冲和批量处理。 进行此更改后，我们没有冻结任何群集。

## 步骤 6：2014 年 4 月

### 一个数据中心几乎无法实现网络高可用性

从 2014 年 4 月开始，我们开始收到使用在加拿大/东部使用集群的美国东部客户的投诉。 我们在美国西部的用户没有受到影响。 我们立即怀疑加拿大和美国东部之间存在网络问题，并发现我们的提供商正在报告同一问题。 一场车祸使蒙特利尔和纽约之间的一根含 120 根纤维的管道破裂。 所有的交通都在经过芝加哥的不同路径上进行。 不幸的是，带宽不足以防止数据包丢失。 中断不仅影响了我们的提供商，而且影响了加拿大和美国东部之间的所有流量。 这类事故可能会破坏我们经常忘记的互联网，但仍然可能发生。 那天我们除了帮助每个客户并通知他们当前的情况外，无能为力。

就在这一天，我们开始了一场大型基础设施讨论。 我们需要依靠更多的提供商，数据中心和网络提供商来提高高可用性。 更重要的是，我们需要在美国拥有基础设施。 通过从加拿大为美国服务，我们可以削减成本，但高可用性受到了影响。 我们需要真正分布我们的基础架构。 我们不能再在一个提供商上拥有多个可用区！

## 步骤 7：2014 年 7 月

### 首次在两个数据中心中部署

我们发现在单个数据中心中进行部署是不够的。 我们决定从最大的客户之一开始，在两个不同的数据中心（它们之间相距 100 公里以上）部署一台机器。 这两个数据中心使用的是同一提供程序（相同的自治系统），并且已经提供了高可用性级别，比云提供程序的多个可用性区域略高一点。 这是由于两个数据中心位置在网络链接和电源单元方面完全不同。

根据我们过去的经验，我们花了这段时间来设计具有下一代 CPU 和 SSD 的硬件的下一版本：

*   Xeon E5-1650v2（6 核，12 线程，3.5Ghz-3.9Ghz）

*   128G RAM

*   英特尔 SSD S3500（2x480G）或 S3700（2x400G）。 我们将 intel S3700 用于每天写入量较高的计算机，因为它们更耐用

我们所做的更改主要围绕 CPU。 我们从未在 E5-2687W 上使用 100％的 CPU。 E5-1650v2 是下一代 CPU，并提供了更高的时钟速度。 结果是，与以前的 CPU 相比，我们的服务速度提高了近 15％。 毫秒很重要！

## 步骤 8：2014 年 9 月

### 在美国的存在！

在与数家提供商进行了数月的讨论之后，我们于 2014 年 9 月在美国东部（弗吉尼亚州）和美国西部（加利福尼亚州）与一家新提供商一起启动了该服务。 由于更好的延迟和带宽，第一步是改善我们在美国搜索体验的好方法。 高可用性方面的改进并不大，但是确实有助于我们更灵活地应对加拿大和美国东部之间过去的问题。 我们使用的方法与以前的位置相同：一家提供商内的可用区域不同（不同的网络设备和电源单元）。

## 步骤 9：2014 年 10 月

### 通过厨师进行自动化

随着我们需要管理的计算机数量的大量增加，我们将管理迁移到了 Chef。 以前，我们使用 Shell 脚本管理计算机，但是与 Chef 进行自动化相比，修复 Heartbleed（OpenSSL 漏洞）等安全问题非常耗时。

Chef 所提供的自动化功能在配置数百台机器时非常有用，但它也有缺点。 迁移到 Chef 几个月后，菜谱中的错字导致某些生产服务器崩溃。 幸运的是，我们能够尽早发现问题。 由于推出了厨师客户的 CRON 工作具有非侵略性，因此对生产没有太大影响。 我们有足够的时间来做出反应并解决问题。

我们非常幸运遇到此问题，因为该错误可能会破坏生产。 为了避免再次发生此类问题，我们决定将生产手册分为两个版本：

*   第一个版本（稳定版）已部署到所有集群的第一台和第二台计算机上

*   第二个版本（生产版本）已部署在所有集群的第 3 台计算机上

对我们的菜谱进行任何修改时，我们首先将修改应用于生产版本。 经过几天的测试，我们将修改应用于稳定的食谱版本。 高可用性需要在所有级别上应用！

## 第 10 步：2014 年 11 月

### DNS 是体系结构中的 SPoF

随着时间的流逝，我们开始收到越来越多的用户反馈，指出我们的服务间歇性地变慢，尤其是在亚洲。 经过调查，我们发现.io TLD 的使用是造成此问题的原因。 事实证明，.io TLD 的任意播网络的位置少于主要 TLD（.net，.com 和.org）的位置，并且 DNS 服务器超载。 用户有时在 DNS 解析期间会遇到超时。

我们与 CDN 提供程序讨论了此问题，他们都告诉我们最佳实践是使用.net TLD。 我们需要从.io 迁移到.net！ 在准备发布分布式搜索网络时，我们决定迁移到另一个 DNS 提供商。 该新提供商提供了链接域功能，这意味着它们将处理 [algolia.io](http://algolia.io) 和 [algolia 之间的同步。 net](http://algolia.net) ，这样我们就可以轻松地保持向后兼容性。

我们从不同的位置对该迁移进行了广泛的测试，并感到一切正常。 不幸的是，在完成迁移之后，我们发现了一些影响我们某些用户的问题。 您可以在 [此博客文章](https://blog.algolia.com/black-thursday-dns-issue/) 中阅读详细的报告。 DNS 比我们意识到的要复杂得多。 DNS 提供程序有许多不同的行为，我们的测试并未涵盖所有这些行为（例如，首先使用 IPv6 解析，在 TTL 上使用不同行为等）

这个问题也改变了我们识别 SPoF 的想法。 只有一个 DNS 提供程序是 SPoF，由于没有回退，因此迁移非常关键。 我们开始制定一项计划，以删除架构中的任何 SPoF。

## 下一个

至此，我们已经涵盖了本系列 15 个步骤中的 10 个。 正如您所看到的，我们推出后的头 18 个月并非一帆风顺。 我们经历了几次故障，不得不重新考虑基础架构的几个部分。 这些改进的目的是始终确保我们的基础架构将来几乎不可能面临类似的问题。

本博客系列的下一部分和最后一部分将重点介绍 DSN（分布式搜索网络），它是我们最引以为傲的功能，并提高了我们的高可用性。 两者都有一个目标：在可靠性和性能方面满足大型上市公司的期望。

*以下是该系列的所有三个部分：[第 1 部分](http://highscalability.com/blog/2015/7/13/algolias-fury-road-to-a-worldwide-api.html)，[第 2 部分](http://highscalability.com/blog/2015/7/20/algolias-fury-road-to-a-worldwide-api-steps-part-2.html)，[第 3 部分](http://highscalability.com/blog/2015/7/27/algolias-fury-road-to-a-worldwide-api-part-3.html)*