在 Kubernetes 上管理云原生数据——云原生数据基础设施简介:持久化、流处理与批量分析

177 阅读34分钟

您是否在解决数据问题时,发现自己面临现代化的需求?您的云原生应用程序是否仅限于使用微服务和服务网格?如果您在 Kubernetes(有时缩写为“K8s”)上部署应用程序时没有包括数据管理,那么您还没有完全拥抱云原生。应用程序的每一个元素,包括数据处理,都应体现云原生的原则,如可扩展性、弹性、自愈能力和可观测性。

从事数据工作的工程师主要关注有状态的服务,而这将是我们的重点:提升您在 Kubernetes 上管理数据的技能。通过阅读本书,我们的目标是丰富您向云原生数据进发的旅程。如果您刚刚开始接触云原生应用程序,现在正是将堆栈的每一个方面都包括进来的最佳时机。这种融合是我们未来使用云资源的方式。

那么,我们正在共同创造的未来是什么样的呢?

长久以来,数据一直存在于 Kubernetes 之外,这给工作带来了大量的额外工作和复杂性。尽管这种做法有其合理的原因,但现在是时候将整个堆栈结合起来,以更快地构建符合所需规模的应用程序了。基于当前的技术,这一目标完全可以实现。我们已经从过去部署单个服务器的时代,迈向了能够部署整个虚拟数据中心的未来。曾经需要数月甚至数年完成的开发周期,现在可以在几天或几周内管理完成。开源组件现在可以组合成一个单一的部署在 Kubernetes 上,从您的笔记本电脑到最大的云服务提供商都可以无缝迁移。

开源贡献在这一过程中也扮演了重要角色。除非另有说明,本书讨论的 Kubernetes 和相关项目都遵循 Apache 2.0 许可证,这是有充分理由的。如果我们构建的基础设施能够在任何地方运行,那么我们需要一种赋予我们选择自由的许可模式。开源既是“免费的”(就像免费啤酒),也是“自由的”(就像言论自由),这两者在构建基于 Kubernetes 的云原生应用程序时都至关重要。开源一直是基础设施许多革命的动力,这次也不例外。

这就是我们正在构建的:完全实现 Kubernetes 应用程序的近未来现实。而最终的组成部分,也是最重要的,就是您。作为本书的读者,您将是创造这一未来的人之一。作为工程师,创造是我们所做的工作。我们不断重新发明部署复杂基础设施的方式,以应对日益增长的需求。1960 年,当美国航空公司上线第一个电子数据库系统时,一小群工程师确保它全天候在线并正常工作。从大型机到小型机,再到微型计算机,直到今天的集群管理,这一进程从未停止。如今,这种进程正在向云原生和 Kubernetes 继续推进。

本章将探讨云原生应用程序的组成部分、运行有状态工作负载的挑战,以及本书涵盖的关键领域。要开始的话,让我们先来看看构成数据基础设施的基本构件。

基础设施类型

在过去的20年中,基础设施的构建方式逐渐分化为两大领域,反映了我们如何部署分布式应用程序(如图1-1所示):

无状态服务

无状态服务是指那些只在活跃请求的即时生命周期内维护信息的服务。例如,将格式化的购物车信息发送到移动客户端的服务。一个典型的例子是执行购物车业务逻辑的应用服务器。然而,关于购物车内容的信息存储在这些服务之外。这些服务只需要在线一段很短的时间,从请求到响应完成即可。用于提供此类服务的基础设施可以轻松扩展和缩减,对整个应用程序的影响很小,可以根据需要按需扩展计算和网络资源。由于我们并不在单个服务中存储关键数据,因此这些数据可以快速创建和销毁,且无需太多协调。无状态服务是分布式系统中一个至关重要的架构元素。

有状态服务

有状态服务则需要在多个请求之间保持信息。磁盘和内存用于跨多个请求存储和使用数据。一个例子是数据库或文件系统。扩展有状态服务更为复杂,因为这些信息通常需要进行复制以确保高可用性。这就需要保持一致性并使用机制在副本之间保持数据同步。这些服务通常具有不同的扩展方法,包括垂直扩展和水平扩展。因此,它们比无状态服务需要不同的一组操作任务。

image.png

除了信息存储方式的变化,我们还看到了系统开发逐渐向自动化基础设施部署方向的转变。最近的进展包括以下几个方面:

  • 物理服务器逐渐被虚拟机(VM)取代,虚拟机更易于部署和维护。
  • 虚拟机已经被简化,并专注于特定的应用程序,发展为容器。
  • 容器使基础设施工程师能够将应用程序的操作系统需求打包成一个可执行文件。

容器的使用无疑提高了部署的一致性,使得批量部署和运行基础设施变得更加容易。随着容器数量的爆炸式增长,出现了一些系统来进行编排,其中以 Kubernetes 为代表,其显著增长表明它在解决这一问题方面的出色表现。官方文档对 Kubernetes 的描述如下:

“Kubernetes 是一个可移植的、可扩展的开源平台,用于管理容器化的工作负载和服务,促进声明式配置和自动化。它拥有一个庞大且快速增长的生态系统。Kubernetes 服务、支持和工具广泛可用。”

Kubernetes 最初是为无状态工作负载设计的,并且在传统上这一点做得最好。Kubernetes 已经建立了作为“构建平台的平台”的声誉,并以云原生的方式实现这一目标。然而,也有一种合理的观点认为,完整的云原生解决方案必须考虑到数据处理。这正是本书的目标:探索如何在 Kubernetes 上构建云原生的数据解决方案。但首先,让我们拆解一下“云原生”究竟意味着什么。

什么是云原生数据?

让我们开始定义云原生数据的各个方面,以帮助我们给出最终的定义。首先,让我们从云原生计算基金会(CNCF)对云原生的定义开始:

“云原生技术使组织能够在现代动态环境中(如公有云、私有云和混合云)构建和运行可扩展的应用程序。容器、服务网格、微服务、不可变基础设施和声明式 API 是这种方法的典型例子。

这些技术使得松散耦合的系统具有弹性、可管理性和可观测性。结合强大的自动化,它们允许工程师频繁且可预测地进行高影响力的变更,同时减少工作负担。”

请注意,这一定义描述了目标状态、理想特性以及体现这些特性的技术实例。基于这个正式定义,我们可以总结出在处理数据方面,将云原生应用程序与其他类型部署区分开的特质。让我们更仔细地看看这些特质:

可扩展性

如果一个服务能够为单位资源产生一个单位的工作量,那么增加更多的资源应当能增加服务能够执行的工作量。可扩展性描述了服务应用额外资源以产生额外工作的能力。理想情况下,服务应该能够在无限的计算、网络和存储资源的支持下无限制地扩展。对于数据而言,这意味着在不需要停机的情况下扩展。传统系统在添加新资源时需要一个维护期,在此期间所有服务必须关闭。而对于云原生应用程序而言,停机时间已不再是可接受的。

弹性

与可扩展性指增加资源以满足需求不同,弹性是指在资源不再需要时释放这些资源。图1-2强调了可扩展性与弹性的区别。弹性也可以被称为按需基础设施。在一个如私有数据中心这样的受限环境中,这是共享有限资源的关键。对于按资源使用收费的云基础设施而言,这是防止为不需要的运行服务付费的一种方式。在数据管理方面,这意味着我们需要具备回收存储空间和优化使用的能力,例如将较旧的数据移动到较便宜的存储层。

image.png

自愈能力

不好的事情总会发生。当它们发生时,您的基础设施将如何响应?自愈基础设施会重新路由流量、重新分配资源并保持服务水平。随着越来越多、更复杂的分布式应用程序被部署,自愈能力成为云原生应用程序越来越重要的属性。这也是避免您凌晨3点被叫醒的关键。对于数据来说,这意味着我们需要具备检测数据问题(如数据丢失和数据质量)的能力。

可观测性

如果某个系统出现故障,而您没有监控它,那故障是否真的发生了?不幸的是,答案是肯定的,甚至可能会导致更糟糕的情况。分布式应用程序高度动态,对每个服务的可见性对于维护服务水平至关重要。相互依赖关系可能会导致复杂的故障场景,这就是为什么可观测性是构建云原生应用程序的关键部分。在数据系统中,大量数据的流动和状态需要有效的监控方式。在大多数情况下,提前预警问题可以帮助操作人员避免昂贵的停机时间。

定义云原生数据

结合前面的定义,我们可以尝试提出一个表达这些特性的定义:

云原生数据方法使采用云原生应用程序方法论的组织能够全面地整合数据,而不是依赖传统的人员、流程和技术,从而使数据可以弹性地扩展或收缩,并促进可观测性和自愈能力。容器化数据、声明式数据、数据 API、数据网格以及云原生数据基础设施(如本身架构为云原生应用程序的数据库、流处理和分析技术)都是这种方法的典型例子。

为了使数据基础设施与我们应用程序的其他部分保持同步,我们需要整合每一个部分。这包括自动化的扩展、弹性和自愈能力。需要 API 来解耦服务并提高开发者的速度,同时使您能够观察应用程序的整个堆栈,以做出关键决策。整体来看,您的应用程序和数据基础设施应该作为一个整体单元呈现。

更多的基础设施,更多的问题

无论您的基础设施是在云上、本地,还是两者兼有(通常称为混合模式),您都可能需要花费大量时间进行手动配置。通过编辑器输入内容并进行非常详细的配置工作,需要对每项技术有深入的了解。在过去的20年里,DevOps 社区在代码和基础设施部署方式上都取得了重大进展。这是现代基础设施演进的关键一步。DevOps 使我们能够应对应用程序所需的规模,尽管仅仅是勉强应对。可以说,要完全编写一个数据库服务器的部署脚本,所需的知识量几乎是相同的。只不过现在我们可以通过模板和脚本,将其重复执行数百万次(如果需要的话)。然而,缺乏的是组件之间的连通性以及对整个应用程序堆栈的整体视图。让我们一起来解决这个问题。(前瞻:这是一个亟待解决的问题。)

正如任何优秀的工程问题一样,我们将其分解为可管理的部分。第一部分是资源管理。不论我们开发了多少种大规模工作的方式,根本上我们都在尝试尽可能高效地管理三件事:计算、网络和存储,如图 1-3 所示。这些是每个应用程序都需要的关键资源,也是增长过程中消耗的燃料。毫不意外,这些也是运行应用程序时与金钱挂钩的资源。如果我们能明智地使用这些资源,将会获得回报;如果不然,则会付出高昂的代价。无论您在哪里运行应用程序,这些都是最基本的单位。在本地,一切都是购买和拥有的;在云中,我们是在租用这些资源。

image.png

DevOps 提供了许多工具来管理各个组件,但这些组件之间的连接才真正提供了实现极高效率的潜力——就像应用程序被打包到桌面上,但工作在数据中心的规模一样。这种潜力催生了围绕云原生应用程序的整个社区。这些应用程序与我们一直部署的应用程序相似,不同之处在于,现代的云应用程序不再是一个带有业务逻辑的单一进程。它们是许多需要安全且可靠通信的容器化进程的复杂协调。存储必须与应用程序的当前需求相匹配,同时还需意识到它对应用程序稳定性的贡献。

当我们考虑在不管理数据的同一控制平面上部署无状态应用程序时,听起来总是不完整,因为确实如此。将应用程序组件分解到不同的控制平面会增加更多的复杂性,因此违背了云原生的理念。

Kubernetes 引领潮流

如前所述,DevOps 自动化使我们在应对规模需求方面始终处于前沿。容器化带来了对更好编排的需求,而 Kubernetes 回应了这一需求。对于运维人员来说,在部署文件中描述完整的应用程序堆栈可以实现可重复且可移植的基础设施。这是因为 Kubernetes 远远超越了 DevOps 工具包中流行的简单部署管理。Kubernetes 控制平面将部署要求应用于底层的计算、网络和存储资源,以管理整个应用程序基础设施的生命周期。即使底层硬件发生变化,您的应用程序的期望状态仍然能够得到保持。现在,我们不再仅仅是部署虚拟机,而是将整个虚拟数据中心作为一个完整的定义来部署,如图 1-4 所示。

Kubernetes 的流行已经超越了 DevOps 中使用的所有其他容器编排工具。它已经取代了我们部署基础设施的其他方式,并且没有任何减缓的迹象。然而,早期的大部分采用主要集中在无状态服务上。

在迁移到容器和 Kubernetes 之前,大规模管理数据基础设施早已是一个难题。像数据库这样的有状态服务走上了一条与 Kubernetes 采用曲线平行的不同路径。许多专家建议,Kubernetes 并不适合运行有状态服务,这些工作负载应当保持在 Kubernetes 之外。这种方法在某种程度上有效,直到它不再奏效。现在,其中许多专家正推动 Kubernetes 中所需的变革,以融合整个堆栈。

image.png

那么,有状态服务面临哪些挑战?为什么在 Kubernetes 上部署数据基础设施如此困难呢?让我们逐一考虑基础设施的每个组件。

在 Kubernetes 上管理计算资源

在数据基础设施中,依赖摩尔定律使得硬件升级成为常规事件。摩尔定律预测计算能力每18个月就会翻一番。如果您的需求每18个月翻一番,那么通过更换硬件可以跟上增长步伐。最终,原始计算能力开始趋于平稳。供应商开始增加更多的处理器和核心,以继续遵循摩尔定律,这导致了使用虚拟机(VM)和容器进行单服务器资源共享,使我们能够利用分散在物理服务器孤岛中的巨大计算资源池。Kubernetes 通过将整个数据中心视为一个跨多个物理设备的大型资源池,扩展了计算资源管理的范围。

在数据领域,与其他服务共享计算资源有点像禁忌。数据工作负载通常资源密集,而一个服务影响另一个服务的潜力(称为“嘈杂邻居问题”)导致了将它们与其他工作负载隔离的政策。这种一刀切的方法消除了获得更多显著好处的可能性。首先是假设所有数据服务的资源需求都是相同的。例如,Apache Pulsar 代理所需的资源远少于 Apache Spark 工作节点,且两者都不同于用于在线分析处理(OLAP)报告的大型 MySQL 实例。其次,将底层硬件与运行的应用程序解耦的能力为运维人员提供了许多被低估的灵活性。需要扩展性、弹性和自愈能力的云原生应用程序正是 Kubernetes 能够提供的,而数据基础设施也不例外。

在 Kubernetes 上管理网络

构建分布式应用程序本质上需要可靠且安全的网络。云原生应用程序增加了添加和移除服务的复杂性,使动态网络配置成为一种新需求。Kubernetes 自动管理这些内容,就像在您的虚拟数据中心中有一个虚拟网络团队在行动。当新服务上线时,就像有一个虚拟网络团队开始工作。IP 地址被分配,路由被创建,DNS 条目被添加,虚拟安全团队确保防火墙规则到位,并且在需要时,传输层安全协议(TLS)证书提供端到端加密。

相比之下,数据基础设施往往比微服务等更少动态化。数据库使用带有主机名的固定 IP 是常态。像 Apache Flink 这样的分析系统在处理过程中是动态的,但硬件地址分配是固定的。服务质量通常是需求列表的首位,因此对专用硬件和专用网络的需求使得管理员对 Kubernetes 敬而远之。

在 Kubernetes 上运行数据基础设施的优势不在于过去的需求,而在于未来的需求。动态扩展资源可能会产生一系列依赖关系。自动化是保持网络清洁和高效的唯一途径,而网络是分布式无状态系统的命脉。云原生应用程序的未来将包括更多的组件和新的挑战,例如应用程序将运行在何处。我们可以将监管合规性和数据主权加入到之前对延迟和吞吐量的关注中。Kubernetes 网络的声明式特性使其非常适合数据基础设施。

在 Kubernetes 上管理存储

任何提供大数据量持久性或分析服务的系统都需要合适的存储设备。早期版本的 Kubernetes 将存储视为堆栈的基本商品部分,并假设大多数工作负载都是短暂的。对于数据而言,这是一个巨大的不匹配——您不能每次容器迁移时都删除 Postgres 数据文件。此外,最初的底层块存储从高性能的 NVMe 磁盘到老旧的 5400 RPM 机械硬盘不等,而您无法总是确定会得到哪种类型的硬件。值得庆幸的是,这在过去几年中已成为 Kubernetes 的重点关注领域,并且得到了显著改进。

随着 StorageClasses 等功能的增加,现在可以满足特定的性能、容量或两者的要求。通过自动化,我们可以避免资源不足的情况。避免意外是容量管理的领域——既要初始化所需的容量,也要在需要时扩展容量。当您的存储容量耗尽时,一切都会停滞。

将 Kubernetes 的分布式特性与数据存储结合起来,开辟了更多自愈的可能性。自动备份和快照让您随时准备应对潜在的数据丢失场景。将计算和存储放在一起,可以最大限度地减少硬件故障风险,并在不可避免的故障发生时自动恢复到期望状态。所有这些都使得 Kubernetes 的数据存储方面更加有吸引力。

云原生数据组件

现在我们已经定义了云原生应用程序中消耗的资源,让我们来明确支持这些应用程序的数据基础设施类型。我们不会列出所有可能的产品,而是将它们分为具有相似特征的几大类:

持久化存储

当我们谈论数据基础设施时,这可能是您首先想到的类别。这些系统存储数据并通过某种查询方法提供访问,例如 MySQL 和 Postgres 等关系数据库,以及 Apache Cassandra 和 MongoDB 等 NoSQL 系统。由于它们对资源的严格要求和对高可用性的需求,这些系统通常是最后迁移到 Kubernetes 的。数据库通常是运行应用程序的关键部分,也是系统中其他所有部分的核心。

流处理

流处理的最基本功能是促进数据在不同点之间的高速传输。流处理系统根据用例提供各种传递语义。在某些情况下,数据可以传递给多个客户端,或者在需要严格控制时,仅传递一次。流处理的进一步增强是在传输过程中对数据进行处理或增强。对数据更快洞察的需求已将流处理分析推向了与持久化系统同等重要的关键地位。移动数据的流处理系统的例子包括 Apache Flink 和 Apache Kafka,而处理系统的例子则包括 Apache Flink 和 Apache Storm。

批量分析

大数据的第一个问题之一是分析大型数据集以获取洞察或将其重新用于生成新数据。Apache Hadoop 是第一个用于批量分析的大规模系统,它设定了使用大容量计算和存储来协调并生成复杂分析过程结果的预期。通常,这些任务会像 Spark 那样分布在整个集群中。由于所需资源的巨大数量,成本问题在这些系统中往往更加突出。编排系统通过智能分配来帮助降低成本。

展望未来

云原生数据的未来充满吸引力。我们今天所拥有的与未来可能拥有的之间的路径取决于我们——负责数据基础设施的社区。正如我们一贯所做的那样,我们看到了新的挑战,并迎接了它。这里有很多事情要做,但结果可能会非常惊人,再次提升我们的标准。

呼吁数据库在 Kubernetes 上实现现代化

由 Western Digital 高级总监 Rick Vasquez 撰写

这段话是为在 2020 年代与数据库打交道的任何人准备的。Kubernetes 在构建云原生和分布式系统方面处于领先地位。如果数据系统能够更好地与 Kubernetes 集成,它们就能充分利用可能的容量和功能。我从“绝不应该在容器中运行数据库”的思想转变为现在认为我们应该推动大家在 Kubernetes 上进行主要部署。我一直从事企业级用例的规模化工作。我不认为这只是一时的潮流。我关注的是其在全球规模上一些世界最大公司中的适用性。

我们需要克服的一种思维方式是将 Kubernetes 视为一种操作系统,用于运行其他应用程序。这种看待数据工作负载的方式是错误的。如果您的系统在容器中运行,那么它当然可以在 Kubernetes 上运行,对吗?不!它将对控制平面如何部署和运行您的应用程序做出反应,而结果可能会也可能不会是您想要的。假如数据系统与 Kubernetes 更紧密集成,并能够将功能卸载给 Kubernetes 控制平面来处理,会怎样呢?服务发现、负载均衡、存储编排、自动化部署和回滚、自动 bin packing、自愈能力、秘密和配置管理,所有这些强大的功能都可以让您获得一致的开发人员和 SRE(站点可靠性工程师)体验。Kubernetes 的关键在于驱动一致性。您可以使用 Kubernetes 在所有部署中实现全球一致性,并以相同的方式反复进行这些部署。但这需要包括数据库系统。想象一下,如果您有 Postgres、MongoDB、MySQL 或 Cassandra,并且它们是原生构建在 Kubernetes 上的,您会怎么做?

能够访问不同的存储层,无论是本地磁盘还是远程磁盘——所有这些都是在一些配置对象中声明的。我希望在配置数据库时进行配置。如果我使用 MySQL,我希望日志在本地磁盘上,因为我不希望有任何瓶颈。我希望某些表位于可能通过网络访问的较慢磁盘上。我希望最近七天的数据存储在热的本地 NVMe 磁盘上,使用您所拥有的每一位容量,副本实际上在做事情——例如卸载读取或多个写入节点——以及一个用于分析的大型汇总。这些所有事情都应该通过基于 Kubernetes 的部署和云原生数据库来实现。

数据库不会考虑或对它们的大小有任何意见。如果您让数据库变大,它只需要更多资源。您可以设置自动扩展以变大,或进行水平扩展。当您想要使用 Kubernetes 提供的真正弹性时会发生什么?不仅仅是向上和向外扩展。还包括缩减和收回!为什么数据库不这样做呢?在基于 Kubernetes 的部署或更广泛的云原生部署中最大化您的价值非常重要。我们还有很多工作要做,但未来值得期待。

Rick 的观点专门针对数据库,但我们可以将他的行动呼吁推广到在 Kubernetes 上运行的数据基础设施上。与在物理服务器上部署数据应用程序不同,Kubernetes 控制平面的引入需要与其运行的服务进行对话。

准备迎接革命

作为创建和运行数据基础设施的工程师,我们必须为即将到来的进步做好准备,这不仅包括操作方式的改进,还包括我们对数据基础设施角色的心态转变。以下部分描述了您可以采取的措施,以应对 Kubernetes 中运行云原生数据的未来。

采用 SRE 心态

随着云原生方法论的普及,站点可靠性工程(SRE)的角色也在不断发展。如果我们希望基础设施实现融合,作为数据基础设施工程师,我们必须学习新技能并采用新的实践方法。让我们从 Wikipedia 对 SRE 的定义开始:

站点可靠性工程是一套原则和实践,将软件工程的某些方面应用于基础设施和运维问题。其主要目标是创建可扩展且高度可靠的软件系统。站点可靠性工程与 DevOps 密切相关,后者是一套结合了软件开发和 IT 运维的实践,而 SRE 也被描述为 DevOps 的一种具体实现。

部署数据基础设施主要关注于部署的具体组件——即“是什么”。例如,您可能会专注于大规模部署 MySQL 或使用 Spark 分析大数据量。采用 SRE 心态意味着超越您部署的内容,而更关注“如何”部署。这些组件将如何协同工作以满足应用程序的目标?整体部署视图考虑了每个组件的交互方式、所需的访问权限(包括安全性)以及每个方面的可观测性,以确保服务水平得以满足。

如果您当前的主要或次要角色是数据库管理员(DBA),现在是转型的最佳时机。LinkedIn 的趋势显示,DBA 角色逐年减少,而 SRE 的需求则大幅增加。那些学习了运行关键数据库基础设施所需技能的工程师具备了管理云原生数据所需的基本条件。这些需求包括以下几个方面:

  • 可用性
  • 延迟
  • 变更管理
  • 紧急响应
  • 容量管理

要更好地适应整个应用程序的重大责任,需要在这个列表中添加新技能。您可能已经具备了这些技能,但它们包括以下几个方面:

CI/CD 流水线

掌握从代码库到生产环境的全局视角,是加速组织中应用程序开发的最有效方式。持续集成(CI)将新代码构建到应用程序堆栈中,并自动化所有测试以确保质量。持续交付(CD)则将完全测试和认证的构建自动部署到生产环境中。结合使用(流水线),组织可以显著提高开发人员的速度和生产力。

可观测性

DevOps 从业者喜欢区分“是什么”(您正在部署的实际服务)和“如何做”(部署该服务的方法)。监控是任何有基础设施经验的人都熟悉的东西。在 DevOps 的“是什么”部分,您监控的属性告诉您服务是否健康,并提供诊断问题所需的信息。可观测性将监控扩展到应用程序的“如何做”,通过将所有内容作为一个整体来考虑——例如,通过跟踪数据在系统中每一次跳转的延迟来深入了解高度分布式应用程序中延迟的根源。

了解代码

在一个大型分布式应用程序中,当事情出错时,原因并不总是进程故障。在许多情况下,问题可能是代码中的错误或细微的实现细节。作为对整个应用程序健康负责的人,您需要了解在所提供环境中执行的代码。适当实施的可观测性将帮助您发现问题,这包括软件仪表化。SRE 和开发团队需要清晰且定期的沟通,而代码则是双方的共同基础。

接受分布式计算

在 Kubernetes 中部署应用程序意味着接受分布式计算提供的一切。当您习惯于单系统思维时,这种转变可能很难,尤其是在期望和理解问题出在哪里方面的思维转变。例如,在每个进程都包含在一个系统中时,延迟几乎为零。这并不是您需要管理的问题。CPU 和内存资源才是主要关注点。在 1990 年代,Sun Microsystems 在分布式计算领域领先,并发布了以下八条常见的分布式计算谬论:

  1. 网络是可靠的。
  2. 延迟为零。
  3. 带宽是无限的。
  4. 网络是安全的。
  5. 拓扑不会改变。
  6. 只有一个管理员。
  7. 传输成本为零。
  8. 网络是同质的。

在每个这些谬论背后,肯定都有一个开发人员做了错误的假设,得到了意想不到的结果,并花费无数时间试图解决错误的问题。从长远来看,接受分布式方法是值得的。它们使我们能够构建大规模应用程序,并将继续在很长一段时间内发挥作用。挑战是值得的,对于我们这些每天都在做这件事的人来说,这也非常有趣!由于 Kubernetes 的默认分布式特性,它的应用将测试这些谬论中的每一个。在规划部署时,考虑从一个地方到另一个地方的传输成本或延迟影响等问题。这将为您节省大量时间,并避免返工。

云原生数据基础设施的原则

作为工程专业人员,我们寻求标准和最佳实践来构建我们的系统。为了使数据尽可能“云原生”,我们需要充分利用 Kubernetes 提供的一切。真正的云原生方法意味着采用 Kubernetes 设计范式的关键要素,并在此基础上进行构建。一个完整的包含数据的云原生应用程序必须能够在 Kubernetes 上有效运行。让我们探索一些指引方向的 Kubernetes 设计原则。

原则 1:将计算、网络和存储作为通用 API 使用

云计算成功的关键之一是将计算、网络和存储商品化,使它们成为我们可以通过简单 API 提供的资源。考虑一下 AWS 服务的示例:

  • 计算:我们通过 Amazon Elastic Compute Cloud (EC2) 和 Auto Scaling 组(ASG)分配虚拟机。
  • 网络:我们使用 Elastic Load Balancers (ELB)、Route 53 和虚拟私有云 (VPC) 对等连接来管理流量。
  • 存储:我们使用诸如 Simple Storage Service (S3) 的长期对象存储选项或 Elastic Block Store (EBS) 卷来持久化计算实例的数据。

Kubernetes 提供了自己的 API,为容器化应用程序的世界提供类似的服务:

  • 计算:Pods、Deployments 和 ReplicaSets 管理容器在计算硬件上的调度和生命周期。
  • 网络:Services 和 Ingress 用于暴露容器的网络接口。
  • 存储:PersistentVolumes (PVs) 和 StatefulSets 使容器与存储的关联更加灵活。

Kubernetes 资源促进了应用程序在 Kubernetes 发行版和服务提供商之间的可移植性。这对数据库意味着什么?它们只是利用计算、网络和存储资源来提供数据持久性和检索服务的应用程序:

  • 计算:数据库需要足够的处理能力来处理传入的数据和查询。每个数据库节点都作为一个 Pod 部署,并被分组到 StatefulSets 中,使 Kubernetes 能够管理扩展和缩减。
  • 网络:数据库需要暴露数据和控制的接口。我们可以使用 Kubernetes Services 和 Ingress 控制器来暴露这些接口。
  • 存储:数据库使用指定 StorageClass 的 PersistentVolumes 来存储和检索数据。

将数据库视为它们的计算、网络和存储需求有助于减少在 Kubernetes 上部署时的复杂性。

原则 2:分离控制平面和数据平面

Kubernetes 鼓励将控制平面和数据平面分离。Kubernetes API 服务器是控制平面的入口,提供了数据平面请求计算资源时使用的接口,而控制平面则管理将这些请求映射到底层基础设施即服务 (IaaS) 平台的细节。

我们可以将这一模式应用于数据库。例如,数据库数据平面包括暴露给客户端的端口,以及分布式数据库之间用于节点通信的端口。控制平面包括数据库提供的用于管理和收集指标的接口以及执行运维任务的工具。大部分这种能力可以也应该通过 Kubernetes 操作器模式实现。操作器定义自定义资源(CRD)并提供控制循环,观察这些资源的状态,并采取行动将它们朝向期望的状态移动,从而通过领域特定逻辑扩展 Kubernetes。

原则 3:简化可观测性

可观测系统的三个支柱是日志记录、指标和追踪。Kubernetes 提供了一个很好的起点,通过暴露每个容器的日志给第三方日志聚合解决方案。对于指标、追踪和可视化,有多种解决方案可用,我们将在本书中探索其中的几种。

原则 4:确保默认配置的安全性

Kubernetes 网络默认是安全的:端口必须明确暴露才能从 Pod 外部访问。这为数据库部署设置了一个有价值的先例,迫使我们仔细考虑每个控制平面和数据平面接口将如何暴露,以及哪些接口应该通过 Kubernetes Service 暴露。Kubernetes 还提供了管理机密的功能,可以用于共享加密密钥和配置管理账户。

原则 5:优先选择声明式配置

在 Kubernetes 的声明式方法中,您指定资源的期望状态,而控制器则操纵底层基础设施以实现该状态。数据基础设施的操作器可以智能地管理如何扩展的细节——例如,决定在扩展额外节点时如何重新分配分片或分区,或者选择移除哪些节点以实现弹性缩减。

下一代操作器应该能够让我们指定存储数据的大小、每秒事务数量或两者的规则。也许我们将能够指定最大和最小集群大小,以及何时将不常使用的数据移动到对象存储。这将允许在我们的数据基础设施中实现更多的自动化和效率。

总结

到此为止,我们希望您已经准备好迎接接下来激动人心的旅程。向云原生应用程序的转变必须包括数据,为此,我们将利用 Kubernetes 来涵盖无状态和有状态服务。本章讨论了能够弹性扩展并抵抗系统故障导致的任何停机的云原生数据基础设施,以及如何构建这些系统。作为工程师,我们必须接受云原生基础设施的原则,并在某些情况下学习新技能。恭喜您——您已经开始了构建云原生应用程序的奇妙旅程。翻开下一页,让我们继续前行吧!