我们只需4/30即可调整Futureestack注册。条款和条件适用。 现在注册

在新的遗物中容用数据库,第1部分:我们学到了什么

10分钟阅读

(这篇文章是两部分系列的一部分。第二部分 -建造梅格萨斯-从技术上看我们是如何使用微服务架构在容器中部署数据库的,我们称之为“Megabase”。)

作为一个早期的容器,新遗物开始使用Docker.在项目的测试版中。现在我们已经运营Docker生产将近4年了,我们建立了深入的组织知识,了解集装箱基础架构的益处和限制。我们的大部分生产服务现在在部署目标上运行,我们指定了“集装箱面料”,这有助于我们的工程师始终如一地达到越来越多的规模和速度目标。

集装箱结构从我们的无状态应用程序中摘要我们的硬件(这不需要服务器保留有关会话或通信请求的信息),并允许我们大大简化每个管理。首先经历了许多容器的好处,我们希望继续利用Docker为我们的有状态应用程序(类似的应用程序,例如保留和存储信息的数据库)。我们使用大量数据库,用于内部工程项目和用于存储客户数据,我们希望能够更快地部署数据库,更加一致性和更高的资源效率。

容器化数据库的四个固有挑战

不幸的是,将数据库放在容器中提出了许多固有的挑战。数据库表现出一些关键属性,使它们难以有效地集装箱:

  • 它们需要高吞吐量和低延迟的网络功能。
  • 在我们使用中,他们需要处理持久数据存储的能力。
  • 它们需要复杂的配置层。
  • 它们需要磁盘空间来存储大量数据,从而不那么便携。

挑战1:建立合适的网络条件

Docker容器是围绕两个Linux内核特性构建的抽象:控制组(常见于cgroups)和名称空间。这些功能提供资源限制对于内存和CPU,但遗憾的是,他们并不是在他们自己的既有问题上提供有效隔离存储和网络资源,这对于数据库至关重要。

目前有四个用于Docker的本机网络驱动程序:主机,桥接,叠加和麦克风。我们考虑了每个人的好处和减数:

  • 主机网络是最简单和最快的选择,因为它将容器放置在与运行它们的主机相同的Linux网络名称空间中。主机网络没有开销,但没有提供与底层硬件或其他容器的隔离。
  • 码头工人创造了一个默认Linux桥梁命名为Docker0.在主机上用于使用的容器。在桥接模式下,容器的接口通过虚拟以太网接口连接到桥梁。使用Linux桥接和网络命名空间隔离容器网络,但它可以添加一个可测量的开销量到CPU绑定的工作负载。
  • 覆盖网络使用Linux桥接和内核虚拟可扩展LAN(VXLAN)将容器的网络从物理网络抽象出来的特性。覆盖网络是强大的,并提供了丰富的特性集,但实现细节可能导致性能问题强调cpu。
  • MACVLAN驱动程序为容器提供对主机接口的访问,而没有开销网络地址转换(NAT)。然而,与桥接和覆盖驱动程序使用的内部网络不同,MacVLan可以在外部物理网络上分配容器的地址,这可以使便携性非常棘手。

考虑到数据库容器项目的隔离,性能和可移植性之间的权衡后,我们选择了主机网络。我们使用随机端口分配和仔细的容器放置,以避免在同一物理主机上施加多个高吞吐量服务。(我推荐了对影响我们决定的因素的更深入的分析Docker网络选项的此参考)。

挑战2:处理持久数据存储

New Relic数据库团队对于是否使用Docker卷来保存数据几乎没有争论。根据设备映射器存储文档:“卷为写负荷大的工作提供了最好的和最可预测的性能……因为它们绕过了存储驱动程序,并且不会引起任何由精简配置和写时复制带来的潜在开销。”

我们所有的内部项目用于有状态集装箱使用卷。虽然这是一种从性能角度来看,但它可以使容器可移植性更具挑战性(我们将在此帖子之后介绍该问题)。

在一些项目中,我们使用逻辑卷管理器(LVM)提供额外的存储隔离层。在部署数据库时,我们从精简池创建一个新的逻辑卷,并将其分配给一个容器。如果容器偶然填满了它的卷,它不会影响任何相邻的容器,因为我们将每个卷作为一个单独的资源来监视。我们可以扩展包含任何容器的持久数据的逻辑卷,并在不中断服务的情况下调整文件系统的大小。

与网络一样,我们仔细地将高吞吐量的服务放在我们避免的位置“吵闹的邻居”问题在有多个租户的主机上。最终,我们必须在足够的资源隔离和资源效率之间保持仔细的平衡。为了保持平衡,满足我们的成本效率目标和我们的服务级别协议,我们密切监控网络可观察性是关键。事实上,本系列中的第二部分显示了我们如何使用New Relic的基础设施新的遗物见解满足这些需求。

挑战3:配置数据库

普遍的智慧持有容器图像应该是从特定版本的代码和配置衍生的不可变的工件。但是,为每个数据库配置更改构建新图像可能会导致容器图像蔓延。

数据库高性能需求的一个副作用是,它们需要复杂的配置调优层。在New Relic,我们调优存储控制器、Linux内核和操作系统参数、语言运行时和数据库参数,以满足我们的性能需求。这使得我们很难从数据库部署中抽象底层硬件。实际上,这意味着我们的数据库团队仍然必须拥有其硬件的管理权。

在配置主机时,硬件,内核和操作系统调整通常会发生。在部署时,我们大小的容器内存限制和CPU共享以保证为每个工作负载授予足够的资源,并帮助避免争用。我们还在部署时传递环境变量,以确保容器内的服务可以解析任何外部依赖项。

数据库通常有数百个调优参数。这些参数中的许多都可以动态更改,因此将动态更改反映在磁盘上非常重要,这样在重新部署或重新启动数据库时就不会将它们还原。

此问题的一个常见解决方案是将数据库配置转移到环境变量中(用于根据数据库将在其中运行的上下文指定配置;一个基本的例子包括为开发、登台和产品化设置环境)。环境变量使得在部署时很容易更改配置,并确保在重新启动运行它的容器时配置保持不变。将数据库参数映射到环境变量是有帮助的,但是这会使识别容器的最终配置变得困难。

要绕过这些障碍,我们将数据库配置文件与我们的版本控制系统同步到对象存储,并将其拉入部署时间(我们会用它来说明第二部分本系列的)。我们发现,在我们解决方案中剩余的收益,我们之间的不可变节性和知名度与集装箱图像蔓延之间的这种权衡可以接受。

挑战4:大数据不是便携式

应用程序可移植性是容器的一个关键优势。如果主机体验问题,则应相对速度且易于将Containized应用程序重新部署到另一个主机。然而,迁移大数据集的物理学使得难以困难。我们发现为数据库有一个容错无共享架构,放弃容器级可移植性是可以接受的,因为我们在应用程序级别解决数据冗余和高可用性(HA)。

对于传统的关系数据库管理系统(RDBMS),需要其他服务来提供数据冗余和HA等保证。我们考虑的一个解决方案是将状态的维护推向较低级别的“存储结构”,该较低级别的“存储结构”将处理跨越多余主机集的数据复制。不幸的是,这征收了表现罚款。另一种选择是备份和恢复来自对象商店的数据,但可能会产生负面影响恢复平均时间(MTTR)在一个失败。

从长远来看,我们对大数据问题的最佳解决方案只是为了接受“小数据” - otherwise称为微服务。

微服务体系结构要求狭义定义的服务,这些服务拥有对其状态的访问权。将单个数据库分解成更小、更易于管理的组件实现了这一理念。它缩小了数据库问题的“爆炸半径”,并使站点可靠性工程师(SREs)能够执行操作工作,而导致重大服务中断的风险更低。当然,缺点是微服务可能需要对现有应用程序进行根本的更改。它们还会使跨域数据访问模式复杂化,并增加网络负载。

拥抱微服务架构意味着我们现在正在管理大量的小型数据库,这要求我们建立一组新的工具。在新的遗物中,我们正在建立一个名为Megabase的项目的工具,我在更大的技术中描述细节第二部分

以功能增量提供值

我们在集装箱化数据库中取得成功的关键部分是我们在阶段提供了系统。我们没有必要采用全尺寸的集装业务编制系统,以便开始提供价值。我们的主要目标是提供一致的数据库服务,我们希望它快速,资源效率很高。

我们现在在Docker容器中部署所有新数据库实例,无论其类型和版本如何。这使我们能够达到数据库层的新级别的一致性和再现性。具有单个部署过程意味着我们可以更快,更可靠地向内部团队提供新数据库。即使没有完全资源隔离,我们的资源效率也大大提高。通过构建新图像,我们还能够通过构建数据库层来添加对新的备份解决方案,监控和操作系统的支持。有关此信息,请参阅本系列的第二篇文章

正如我们向前迈进的时候,我们将密切关注上游开源努力,特别是对于那些处理资源管理和编排的人。虽然支持有状态容器的上游工作仍然是新生,但我们觉得这是有前途的。特定的注意是支持有关的工作KubernetesDC / OS.项目。

现在,查看本系列的第二部分,建造梅格萨斯我仔细研究了兆级的微服务体系结构。