Linux 架构实用手册(一)

原文:zh.annas-archive.org/md5/7D24F1F94933063822D38A8D8705DDE3

译者:飞龙

协议:CC BY-NC-SA 4.0

前言

欢迎阅读《架构师的 Linux 实战》,深入了解架构师在处理基于 Linux 的解决方案时的思维过程。本书将帮助您达到架构和实施不同 IT 解决方案所需的知识水平。

此外,它将向您展示开源软件的灵活性,通过演示行业中最广泛使用的一些产品,为您提供解决方案并分析每个方面,从设计阶段的最开始,一直到实施阶段,在那里我们将从零开始构建我们设计中提出的基础设施。

深入探讨设计解决方案的技术方面,我们将详细剖析每个方面,以实施和调整基于 Linux 的开源解决方案。

这本书是为谁写的

本书面向 Linux 系统管理员、Linux 支持工程师、DevOps 工程师、Linux 顾问以及任何其他类型的希望学习或扩展基于 Linux 和开源软件的架构、设计和实施解决方案的技术专业人士。

本书涵盖了什么

第一章,设计方法论简介,通过分析提出的问题以及在设计解决方案时应该提出的正确问题,来提取必要的信息以定义正确的问题陈述。

第二章,定义 GlusterFS 存储,介绍了 GlusterFS 是什么,并定义了存储集群。

第三章,设计存储集群,探讨了使用 GlusterFS 及其各种组件实施集群存储解决方案的设计方面。

第四章,在云基础设施上使用 GlusterFS,解释了在云上实施 GlusterFS 所需的配置。

第五章,分析 Gluster 系统的性能,详细介绍了先前配置的解决方案,解释了所采取的配置以及对性能进行测试的实施。

第六章,创建高可用的自愈架构,讨论了 IT 行业是如何从使用单片应用程序发展为基于云的、容器化的、高可用的微服务的。

第七章,理解 Kubernetes 集群的核心组件,探讨了核心 Kubernetes 组件,展示了每个组件以及它们如何帮助我们解决客户的问题。

第八章,设计 Kubernetes 集群,深入探讨了 Kubernetes 集群的要求和配置。

第九章,部署和配置 Kubernetes,介绍了 Kubernetes 集群的实际安装和配置。

第十章,使用 ELK Stack 进行监控,解释了弹性堆栈的每个组件以及它们的连接方式。

第十一章,设计 ELK Stack,涵盖了部署弹性堆栈时的设计考虑。

第十二章,使用 Elasticsearch、Logstash 和 Kibana 管理日志,描述了弹性堆栈的实施、安装和配置。

第十三章,使用 Salty 解决管理问题,讨论了业务需要具有用于基础设施的集中管理实用程序的需求,例如 Salt。

第十四章,Getting Your Hands Salty,介绍了如何安装和配置 Salt。

第十五章,设计最佳实践,介绍了设计具有弹性和防故障解决方案所需的一些不同最佳实践。

充分利用本书

需要一些基本的 Linux 知识,因为本书不解释 Linux 管理的基础知识。

本书中给出的示例可以在云端或本地部署。其中一些设置是在微软的云平台 Azure 上部署的,因此建议您拥有 Azure 帐户以便跟随示例。Azure 提供免费试用以评估和测试部署,更多信息可以在azure.microsoft.com/free/找到。此外,有关 Azure 的更多信息可以在azure.microsoft.com找到。

由于本书完全围绕 Linux 展开,因此连接到互联网是必需的。这可以从 Linux 桌面(或笔记本电脑)、macOS 终端或Windows 子系统WSL)中完成。

本书中所示的所有示例都使用可以轻松从可用存储库或各自的来源获得的开源软件,无需支付许可证。

一定要访问项目页面以表达一些爱意——开发这些项目需要付出很多努力:

下载示例代码文件

您可以从www.packt.com的帐户中下载本书的示例代码文件。如果您在其他地方购买了本书,可以访问www.packt.com/support并注册,以便直接通过电子邮件接收文件。

您可以按照以下步骤下载代码文件:

  1. 请登录或注册www.packt.com

  2. 选择“支持”选项卡。

  3. 单击“代码下载和勘误”。

  4. 在搜索框中输入书名,然后按照屏幕上的说明操作。

下载文件后,请确保使用最新版本的解压缩软件解压缩文件夹:

  • Windows 上的 WinRAR/7-Zip

  • Mac 上的 Zipeg/iZip/UnRarX

  • Linux 上的 7-Zip/PeaZip

该书的代码包也托管在 GitHub 上,网址为github.com/PacktPublishing/-Hands-On-Linux-for-Architects。如果代码有更新,将在现有的 GitHub 存储库上进行更新。

我们还有来自丰富书籍和视频目录的其他代码包,可以在**github.com/PacktPublishing/**上找到。去看看吧!

下载彩色图像

我们还提供了一个 PDF 文件,其中包含本书中使用的屏幕截图/图表的彩色图像。您可以在此处下载:www.packtpub.com/sites/default/files/downloads/9781789534108_ColorImages.pdf

使用的约定

本书中使用了许多文本约定。

CodeInText:表示文本中的代码词、数据库表名、文件夹名、文件名、文件扩展名、路径名、虚拟 URL、用户输入和 Twitter 用户名。这是一个例子:“该命令中的两个关键点是address-prefix标志和subnet-prefix标志。”

代码块设置如下:

apiVersion: v1
kind: PersistentVolumeClaim
metadata:
 name: gluster-pvc  
spec:
 accessModes:
 - ReadWriteMany      
 resources:
    requests:
      storage: 1Gi  

当我们希望引起您对代码块的特定部分的注意时,相关行或项目会以粗体显示:

 SHELL ["/bin/bash", "-c"]
 RUN echo "Hello I'm using bash" 

任何命令行输入或输出都会以以下方式编写:

yum install -y zfs

粗体:表示一个新术语,一个重要单词,或者您在屏幕上看到的单词。例如,菜单或对话框中的单词会以这种方式出现在文本中。这里有一个例子:“要确认数据是否被发送到集群,请转到 kibana 屏幕上的 Discover”。

警告或重要说明会显示为这样。

提示和技巧会显示为这样。

联系我们

我们始终欢迎读者的反馈。

一般反馈:如果您对本书的任何方面有疑问,请在邮件主题中提及书名,并发送电子邮件至customercare@packtpub.com

勘误:尽管我们已经尽一切努力确保内容的准确性,但错误确实会发生。如果您在这本书中发现了错误,我们将不胜感激,如果您能向我们报告。请访问www.packt.com/submit-errata,选择您的书,点击勘误提交表格链接,并输入详细信息。

盗版:如果您在互联网上发现我们作品的任何形式的非法副本,我们将不胜感激,如果您能向我们提供位置地址或网站名称。请通过链接copyright@packt.com与我们联系。

如果您有兴趣成为作者:如果您在某个专题上有专业知识,并且有兴趣撰写或为一本书做出贡献,请访问authors.packtpub.com

评论

请留下评论。一旦您阅读并使用了这本书,为什么不在购买它的网站上留下评论呢?潜在的读者可以看到并使用您的客观意见来做出购买决定,我们在 Packt 可以了解您对我们产品的看法,我们的作者可以看到您对他们的书的反馈。谢谢!

有关 Packt 的更多信息,请访问packt.com

第一部分:使用 GlusterFS 的高性能存储解决方案

在本节中,读者将能够了解在使用 GlusterFS 部署高性能存储解决方案时需要做出的决策。

本节包括以下章节:

  • 第一章,设计方法论简介

  • 第二章,定义 GlusterFS 存储

  • 第三章,设计存储集群

  • 第四章,在云基础架构上使用 GlusterFS

  • 第五章,在 Gluster 系统中分析性能

第一章:设计方法论简介

如今,IT 解决方案需要更高的性能和数据可用性,设计一个满足这些要求的强大实施方案是许多 IT 专家每天都要面对的挑战。

在本章中,你将学习从鸟瞰 IT 解决方案架构的基础知识,无论是在任何类型的环境中,还是虚拟化基础设施、裸金属甚至公共云,解决方案设计的基本概念都适用于任何环境。

你将探讨以下主题:

  • 定义解决方案设计的阶段及其重要性

  • 分析问题并提出正确的问题

  • 考虑可能的解决方案

  • 实施解决方案

充分理解在构建解决方案时需要考虑的方面对于项目的成功至关重要,因为这将决定哪些软件、硬件和配置将帮助你实现符合客户需求的期望状态。

定义解决方案设计的阶段及其重要性

像许多事情一样,设计解决方案是一个逐步的过程,不仅涉及技术方面,也不一定涉及技术方面的人员。通常情况下,你将受到一个客户经理、项目经理或者如果你很幸运的话,一个懂得技术需求的 CTO 的委托。他们正在寻找一个能够帮助他们向客户提供解决方案的专家。这些请求通常不包含你需要提供解决方案所需的所有信息,但这是了解你的目标的一个开始。

例如,想象一下,你收到了一个项目经理的电子邮件,其中包含以下陈述。

我们需要一个能够承受至少 10,000 个网站访问量并在更新期间保持可用以及在故障期间存活的解决方案。我们的预算相当有限,所以我们需要尽可能少地花费,几乎没有前期成本。我们还预计在项目的生命周期中这个解决方案会获得动力。

从上面的陈述中,你只能得到一个大致的要求,但没有给出具体的细节。因此,你只知道基本信息:我们需要一个能够承受至少 10,000 个网站访问量的解决方案,这对于设计来说是不够的,因为你需要尽可能多的信息来解决客户暴露出的问题。这就是你必须尽可能多地询问细节,以便为客户提供准确的提案,这将是客户对项目的第一印象。这部分非常关键,因为它将帮助你了解你是否理解了客户的愿景。

同样重要的是要理解,你需要为客户提供几种不同的解决方案,因为客户是决定哪种最符合他们业务需求的人。记住,每种解决方案都有其优点和缺点。客户决定后,你将有必要继续实施你的提案,这可能会引发更多的挑战。通常情况下,这将需要一些最终的定制调整或在最初的概念验证(POC)中没有考虑到的变化。

从我们之前的分析中,你可以看到你需要遵循的过程的四个明确定义的阶段,以达到下图所示的最终交付:

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

我们可以涵盖许多更多的阶段和设计方法,但由于它们不在本书的范围内,我们将专注于这四个一般阶段,以帮助你了解你将在其中构建解决方案的过程。

分析问题并提出正确的问题

在获得初始前提之后,您需要将其分解成较小的部分,以便了解所需的内容。每个部分都会引发不同的问题,您稍后将向客户提出这些问题。这些问题将有助于填补 POC 的空白,确保您的问题涵盖所有业务需求,从所有视角来看:业务视角、功能视角,最后是技术视角。跟踪出现的问题以及它们将解决的业务需求的一个好方法是拥有一个清单,询问问题是从哪个视角提出的,并解决或回答了什么。

重要的是要注意,随着问题变成答案,它们也可能伴随着约束或其他障碍,这些也需要在 POC 阶段进行解决和提及。客户将不得不同意这些约束,并在选择最终解决方案时起决定性作用。

从我们之前的例子中,您可以通过将其分解为不同的视角来分析前提。

我们需要一个可以承受至少 10,000 次网站点击并且在更新期间保持可用以及在停机期间幸存的解决方案。我们的预算相当有限,因此我们需要尽可能少地花费,几乎没有预付成本。我们还期望在项目的生命周期中获得动力。

技术视角

从这个角度来看,我们将分析前提的所有技术方面-这是您需要提供解决方案的初始技术要求。

我们将以以下方式进行分析:

  • 您可以从前提中了解到,您的客户需要一种可以承受一定数量的网站点击的解决方案,但您无法确定 Web 服务器是否已经设置好,以及客户是否只需要一个负载平衡解决方案。或者,客户可能需要一个 Web 服务器,即 NGINX、Apache 或类似的服务器,以及负载平衡解决方案。

  • 客户提到他们的网站至少有 10,000 次点击,但他们没有提到这些点击是每秒、每天、每周,甚至每月的并发点击。

  • 您还可以看到,他们需要在更新期间保持可用,并且能够在公司出现故障时继续为其网站提供服务,但所有这些陈述都非常一般,因为可用性是以 9s 来衡量的。您拥有的 9s 越多,就越好(实际上,这是一年中停机时间的百分比测量;99%的可用性意味着每年只能有 526 分钟的停机时间)。停机也很难预测,几乎不可能说您永远不会出现停机,因此,您需要为此做好计划。在发生灾难时,您必须为您的解决方案设定恢复点目标RPO)和恢复时间目标RTO)。客户没有提到这一点,了解企业可以承受多长时间的停机时间至关重要。

  • 在预算方面,这通常是从业务角度来看的,但技术方面受到直接影响。项目预算似乎很紧张,客户希望尽可能少地花费在他们的解决方案上,但他们没有提到确切的数字,您需要这些数字来调整您的提案。几乎没有预付成本?这是什么意思?我们是否正在重新利用现有资源并构建新的解决方案?如何实施没有预付成本的设计?克服低预算或没有预付成本的一种方法,至少在软件方面,是利用开源软件OSS),但这是我们需要向客户询问的事情。

  • 获得动力只能意味着他们预测他们的用户群最终会增长,但您需要估计他们预测这种增长的规模和速度,因为这将意味着您必须使解决方案准备好进行垂直或水平扩展。垂直扩展,通过留出空间最终增加资源,并考虑业务的采购流程,如果您需要购买更多资源,如 RAM、CPU 或存储。水平扩展也将涉及采购流程,并需要相当长的时间将新节点/服务器/VM/容器集成到解决方案中。这些都不包括在前提中,这是至关重要的信息。

这里我们对水平和垂直扩展进行了比较。水平扩展增加了更多的节点,而垂直扩展增加了现有节点的更多资源:

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

以下是一些示例问题的列表,您可以询问以澄清不清楚的地方:

  • 这个解决方案是为新的/现有的网站或 Web 服务器吗?

  • 当您说 10,000 次点击时,这是每秒同时发生的还是每天/每周/每月发生的?

  • 您是否有关于用户群规模有多大的估计或当前数据?

  • 考虑到预算有限,我们可以使用 OSS 吗?

  • 您是否有技术资源来支持解决方案,如果我们使用 OSS?

  • 您是否已经有任何更新基础设施,或者已经实施了版本控制软件?

  • 当您说几乎没有前期成本时,这是否意味着您已经拥有硬件、资源或基础设施(虚拟或云)可供我们回收和/或重用于我们的新解决方案?

  • 是否有任何灾难恢复站点可以使用,以提供高可用性?

  • 如果您的用户群增长,这会产生更多的存储需求还是只需要计算资源?

  • 您是否计划执行任何备份?您的备份方案是什么?

从技术角度来看,一旦开始设计您的 POC,将会根据解决方案中将使用的软件或硬件产生更多问题。您需要知道它们如何适应或需要什么来调整到客户的现有基础设施(如果有的话)。

业务角度

在这里,我们将从业务角度分析该声明,考虑可能影响我们设计的所有方面:

  • 一个主要的要求是性能,因为这会影响解决方案可以承受多少点击。由于这是解决方案的主要目标之一,它需要根据业务期望进行规模化。

  • 预算似乎是影响项目设计和范围的主要约束。

  • 没有提及实际可用的预算。

  • 可用性要求影响业务在发生故障时应该如何应对。由于没有具体的服务级别协议(SLA),这需要澄清以适应业务需求。

  • 一个主要的问题是前期成本。通过利用 OSS,可以大大降低这一成本,因为没有许可费用。

  • 已经提到解决方案需要在维护操作期间保持运行。这可能表明客户愿意投资于维护操作以进行进一步的升级或增强。

  • 声明中提到,我们也希望这会带来动力,表明解决方案所需资源的数量将发生变化,从而直接影响其消耗的资金数量。

以下是澄清业务疑问时要问的问题:

  • 根据性能要求,当性能低于预期基线时,业务会受到什么影响?

  • 项目的实际预算是多少?

  • 预算是否考虑了维护操作?

  • 考虑到可能的非计划中断和维护,您的网站每年确切可以停机多长时间?这会影响业务连续性吗?

  • 如果发生故障,应用程序可以容忍多长时间不接收数据?

  • 我们是否有任何数据可以估计您的用户群体将增长多少?

  • 您是否有任何采购流程?

  • 批准新硬件或资源采购需要多长时间?

功能角度

在功能角度,您将审查解决方案的功能方面:

  • 您知道客户需要 10,000 次点击,但是什么类型的用户将使用这个网站?

  • 您可以看到它需要 10,000 次点击,但是假设并未指定用户将如何使用它。

  • 假设陈述指出他们需要在更新期间可用的解决方案。由此,我们假设应用程序将被更新,但是如何更新?

为了澄清功能角度的差距,我们可以要求以下信息:

  • 什么类型的用户将使用您的应用程序?

  • 您的用户在您的网站上会做什么?

  • 这个应用程序会经常更新或维护吗?

  • 谁将维护和支持这个解决方案?

  • 这个网站是为内部公司用户还是外部用户?

需要注意的是,功能角度与业务角度有很大的重叠,因为它们都试图解决类似的问题。

一旦我们收集了所有信息,您可以建立一个文件总结您解决方案的要求;确保您与客户一起审查,并且他们同意所需的内容,以便考虑此解决方案为完成。

考虑可能的解决方案

一旦消除了最初假设中出现的所有疑问,您可以继续构建一个更加详细和具体的陈述,其中包括所有收集到的信息。我们将继续使用我们之前的陈述,并假设我们的客户回答了我们之前的所有问题,我们可以构建一个更详细的陈述,如下所示。

我们需要一个新的 Web 服务器,用于我们的金融应用程序,可以每秒承受至少 10,000 次网页点击,来自大约 2,000 个用户,以及另外三个将使用其数据的应用程序。它将能够通过使用至少四个节点的高可用性实现来承受维护和故障。该项目的预算将为初始实施提供 20,000 美元,并且该项目将利用 OSS,从而降低前期成本。解决方案将部署在现有的虚拟环境中,其支持将由我们的内部 Linux 团队处理,并且更新将由我们自己的更新管理解决方案在内部进行。用户群体将每两个月增长一次,这在我们的采购流程范围内,允许我们相当快速地获取新资源,而不会产生资源争用的长时间。用户增长将主要影响计算资源。

正如您所看到的,这是一个更完整的陈述,您可以开始工作。您知道它将利用现有的虚拟基础设施。 OSS 是可行的,还需要高可用性,并且将通过已经存在的更新和版本控制基础设施进行更新,因此可能只需要为您的新解决方案添加监控代理。

一个非常简化的概述,没有太多细节的可能设计如下:

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

在图表中,您可以看到这是一个 Web 服务器集群,为使用解决方案的客户和应用程序提供高可用性和负载均衡。

由于您已经利用了大部分现有基础设施,可能的 POC 选项较少,因此这个设计将非常直接。尽管如此,我们可以玩一些变量,为我们的客户提供几种不同的选择。例如,对于 Web 服务器,我们可以有一个使用 Apache 的解决方案,另一个使用 NGINX,或者两者结合,Apache 托管网站,NGINX 提供负载均衡。

POC

有了完整的陈述和已经定义的几个选项,我们可以继续提供基于可能路线之一的 POC。

POC 是演示一个想法或方法的过程,在我们的情况下是一个解决方案,旨在验证给定功能。此外,它提供了解决方案在环境中的行为的广泛概述,允许进一步测试以进行特定工作负载和用例的微调。

任何 POC 都有其优点和缺点,但主要重点是让客户和架构师探索实际工作环境的解决方案的不同概念。重要的是要注意,作为架构师,您对于使用哪个 POC 作为最终解决方案有很大的影响,但客户是选择哪些约束和优势更适合他们业务的人。

以选择 NGINX 作为负载均衡器以提供高可用性和性能改进给托管应用文件的 Apache Web 服务器为例,我们可以使用缩减资源来实现一个可行的解决方案。我们可以只部署两个节点来演示负载均衡功能,并故意关闭其中一个节点来演示高可用性。

以下是描述先前示例的图表:

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

这不需要在设计阶段设想的完整四节点集群,因为我们不测试整个解决方案的完整性能。对于性能或负载测试,可以通过较少的并发用户为应用程序提供接近实际工作负载。虽然较少的用户永远不会提供完整实施的精确性能数字,但它提供了一个基准数据,可以后续推断出实际性能的近似值。

例如,对于性能测试,我们可以只有四分之一的用户群和一半的资源来加载应用程序,而不是有 2,000 个用户。这将大大减少所需的资源量,同时提供足够的数据来分析最终解决方案的性能。

此外,在信息收集阶段,编写一个记录不同 POC 的文档是一个好主意,因为如果客户将来想构建类似的解决方案,它可以作为一个起点。

实施解决方案

一旦客户根据其业务需求选择了最佳路线,我们就可以开始构建我们的设计。在这个阶段,您将面临不同的障碍,因为在开发或 QA 环境中实施 POC 可能与生产环境不同。在 QA 或开发中有效的东西现在可能在生产中失败,并且可能存在不同的变量;所有这些问题只会在实施阶段出现,您需要意识到,在最坏的情况下,这可能意味着需要更改初始设计的大量内容。

这个阶段需要与客户和客户的环境进行实际操作,因此确保您所做的更改不会影响当前的生产是至关重要的。与客户合作也很重要,因为这将使他们的 IT 团队熟悉新解决方案;这样,当签署完成时,他们将对其及其配置有所了解。

在这个阶段,实施指南的制作是最重要的部分之一,因为它将记录解决方案的每一步和每一个小的配置。它还将有助于将来,如果出现问题,支持团队需要知道如何配置才能解决问题。

总结

设计解决方案需要不同的方法。本章介绍了设计阶段的基础知识以及它们的重要性。

第一阶段通过分析设计旨在解决的问题,同时提出正确的问题。这将有助于定义实际需求并将范围缩小到真正的业务需求。与初始问题陈述一起工作将在后续阶段带来问题,使得这个阶段非常重要,因为它将防止不必要地来回移动。

然后,我们考虑了解决已定义问题的可能路径或解决方案。通过在前一阶段提出正确的问题,我们应该能够构建几个选项供客户选择,并且稍后可以实施 POC。POC 有助于客户和架构师了解解决方案在实际工作环境中的行为。通常,POC 是最终解决方案的缩减版本,使实施和测试更加灵活。

最后,实施阶段涉及项目的实际配置和实际操作方面。根据 POC 期间的发现,可以进行更改以适应每个基础设施的具体情况。通过这个阶段提供的文档将有助于使各方保持一致,以确保解决方案得到预期的实施。

在下一章中,我们将着手解决影响每种实施的问题,无论是云提供商、软件还是设计,展示高性能冗余存储的必要性。

问题

  1. 解决方案设计的阶段是什么?

  2. 设计解决方案时提出正确问题为什么重要?

  3. 为什么我们应该提供几种设计选项?

  4. 可以提出哪些问题以获取有助于设计更好解决方案的信息?

  5. 什么是 POC?

  6. 实施阶段发生了什么?

  7. POC 如何帮助最终实施?

进一步阅读

在随后的章节中,我们将介绍为特定问题创建解决方案的过程。由于这些解决方案将在 Linux 中实施,我们建议阅读Oliver PelzLinux 基础 www.packtpub.com/networking-and-servers/fundamentals-linux.

第二章:定义 GlusterFS 存储

每天,应用程序需要更快的存储,可以支持成千上万个并发 I/O 请求。GlusterFS 是一个高度可扩展的冗余文件系统,可以同时向许多客户端提供高性能 I/O。我们将定义集群的核心概念,然后介绍 GlusterFS 如何发挥重要作用。

在前一章中,我们已经讨论了设计解决方案的不同方面,以提供高可用性和性能,以满足许多要求的应用程序。在本章中,我们将解决一个非常具体的问题,即存储。

在本章中,我们将涵盖以下主题:

  • 理解集群的核心概念

  • 选择 GlusterFS 的原因

  • 解释软件定义存储SDS

  • 探索文件、对象和块存储之间的区别

  • 解释对高性能和高可用存储的需求

技术要求

本章将重点介绍定义 GlusterFS。您可以参考项目的主页github.com/gluster/glusterfswww.gluster.org/

此外,项目的文档可以在docs.gluster.org/en/latest/找到。

什么是集群?

我们可以利用 SDS 的许多优势,它允许轻松扩展和增强容错能力。GlusterFS 是一款软件,可以创建高度可扩展的存储集群,同时提供最大性能。

在我们解决这个特定需求之前,我们首先需要定义集群是什么,为什么它存在,以及集群可能能够解决什么问题。

计算集群

简而言之,集群是一组计算机(通常称为节点),它们协同工作在相同的工作负载上,并可以将负载分布到集群的所有可用成员上,以增加性能,同时允许自我修复和可用性。请注意,在现实中,任何计算机都可以添加到集群中,因此术语服务器之前并未使用。从简单的树莓派到多 CPU 服务器,集群可以由一个小型的双节点配置制成,也可以由数据中心中的数千个节点制成。

这是一个集群的例子:

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

从技术上讲,集群允许工作负载通过添加具有相似资源特征的相同类型的服务器来扩展性能。理想情况下,集群将具有同质硬件,以避免节点具有不同性能特征的问题,并且同时使维护相对相同 - 这意味着具有相同 CPU 系列、内存配置和软件的硬件。向集群添加节点的想法允许您计算工作负载以减少其处理时间。根据应用程序,计算时间有时甚至可以线性减少。

为了进一步理解集群的概念,想象一下您有一个应用程序,它获取历史财务数据。然后,该应用程序接收这些数据并根据存储的信息创建预测。在单个节点上,预测过程(集群上的进程通常被称为作业)大约需要六天才能完成,因为我们处理了数 TB 的数据。添加具有相同特征的额外节点将处理时间缩短到四天。再添加第三个节点将进一步缩短完成时间至三天。

请注意,虽然我们增加了三倍的计算资源,但计算时间仅减少了大约一半。一些应用程序可以线性扩展性能,而其他应用程序则没有相同的可扩展性,需要更多的资源来获得更少的收益,直至收益递减的点。为了获得最小的时间收益,添加更多资源是不划算的。

考虑到所有这些,我们可以指出定义集群的几个特征:

  • 它可以通过添加计算资源来帮助减少处理时间

  • 它可以进行垂直和水平扩展

  • 它可以是冗余的,也就是说,如果一个节点失败,其他节点应该接管工作负载

  • 它可以允许增加资源以供应用程序使用

  • 它是一个资源池,而不是单独的服务器

  • 它没有单点故障

存储集群

现在我们已经了解了如何计算集群,让我们继续讨论集群的另一个应用。

存储集群的主要功能不是聚合计算资源以减少处理时间,而是聚合可用空间以提供最大的空间利用率,同时提供某种形式的冗余。随着存储大量数据的需求增加,需要以更低的成本进行存储,同时仍然保持增加的数据可用性。存储集群通过允许单个单片式存储节点一起工作,形成一个大型的可用存储空间池,来解决这个问题。因此,它允许存储解决方案在不需要部署专门的专有硬件的情况下达到 PB 级别。

例如,假设我们有一个单节点,可用空间为 500 TB,我们需要实现 1-PB标记,并提供冗余。这个单独的节点成为单点故障,因为如果它宕机,那么数据就无法访问。此外,我们已经达到了最大的硬盘驱动器HDD)容量。换句话说,我们无法进行水平扩展。

为了解决这个问题,我们可以添加两个具有相同配置的节点,因为已经存在的节点提供了总共 1 PB 的可用空间。现在,让我们在这里做一些数学运算,500 TB 乘以 3 应该大约是 1.5 PB,对吗?答案绝对是肯定的。然而,由于我们需要为这个解决方案提供高可用性,第三个节点充当备份,使解决方案能够容忍单节点故障而不中断客户端的通信。这种允许节点故障的能力完全归功于 SDS 和存储集群的强大功能,比如 GlusterFS,接下来我们将探讨它。

什么是 GlusterFS?

GlusterFS 是 Gluster 的一个开源项目,该项目于 2011 年被 Red Hat 公司收购。这个收购并不意味着您必须获取 Red Hat 订阅或支付 Red Hat 才能使用它,因为正如前面提到的,它是一个开源项目;因此,您可以自由安装它,查看其源代码,甚至为项目做出贡献。尽管 Red Hat 提供基于 GlusterFS 的付费解决方案,但我们将在本章中讨论开源软件OSS)和项目本身。

以下图表显示了 Gluster 项目中的贡献者提交数量:

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

要理解 GlusterFS,我们必须了解它与传统存储的区别。为了做到这一点,我们需要了解 SDS 背后的概念,包括 GlusterFS 是什么。

传统存储是一个行业标准的存储阵列,其中包含专有软件,与硬件供应商绑定。所有这些都限制了您遵循存储提供商设定的一组规则:

  1. 可扩展性限制

  2. 硬件兼容性限制

  3. 客户端操作系统限制

  4. 配置限制

  5. 供应商锁定

SDS

有了 SDS,许多,如果不是所有,前面的限制都消失了,因为它通过不依赖于任何硬件提供了令人印象深刻的可扩展性。您基本上可以从任何供应商那里获取包含您所需存储的行业标准服务器,并将其添加到您的存储池中。只需执行这一简单步骤,您就已经克服了前面四个限制。

成本降低

SDS部分的示例大大降低了运营费用OPEX)成本,因为你不必为现有供应商存储阵列购买昂贵的扩展架,这可能需要数周才能到货并安装。你可以快速获取存储在数据中心角落的服务器,并用它为现有应用程序提供存储空间。这个过程称为插件可扩展性,并且存在于大多数开源 SDS 项目中。从理论上讲,SDS 在可扩展性方面的潜力是无限的。

可扩展性

当你向存储池添加新服务器时,SDS 会扩展,并增加存储集群的弹性。根据你的配置,数据会分布在多个成员节点上,通过镜像或创建数据的奇偶校验提供额外的高可用性。

控制

你还需要明白,SDS 并不是从虚无中创造空间,也不会将存储的概念与硬件(如硬盘、固态硬盘SSD)或任何旨在存储信息的硬件设备)分离。这些硬件设备将始终是实际数据存储的地方。SDS 添加了一个逻辑层,允许你控制数据的存储位置和方式。它利用了最基本的组件,即应用程序编程接口API),允许你管理和维护存储集群和逻辑卷,为其他服务器、应用程序甚至自我修复集群的监控代理提供存储容量。

市场正在向 SDS 发展

SDS 是未来,这就是存储行业的发展方向。事实上,预测未来几年,大约 70%的当前存储阵列将作为纯软件解决方案或虚拟存储设备VSAs)提供。传统的网络附加存储NAS)解决方案比当前的 SDS 实施要贵 30%,中档磁盘阵列甚至更昂贵。考虑到每年企业数据消耗约增长 40%,成本仅下降 25%,你可以看到为什么我们在不久的将来会向 SDS 世界迈进。

随着在公共、私人和混合云中运行的应用数量不断增长,消费者和企业数据的消耗呈指数级增长。这些数据通常是使命关键的,并且需要高水平的弹性。以下是一些这些应用的列表:

  • 电子商务和在线商店

  • 金融应用

  • 企业资源规划

  • 医疗保健

  • 大数据

  • 客户关系管理

当公司存储这种类型的数据(称为大数据)时,他们不仅需要对其进行归档,还需要访问它,并且尽可能地降低延迟。想象一种情景,你在医生的预约中被要求进行 X 光检查,当你到达时,他们告诉你需要等一周才能得到你的扫描结果,因为他们没有存储空间来保存你的图像。当然,这种情况不会发生,因为每家医院都有一个高效的采购流程,他们可以根据存储消耗来预测使用情况,并决定何时开始购买和安装新的硬件,但你明白我的意思。在你的 SDS 层中安装一个符合 POSIX 标准的服务器并准备好使用,速度更快、更高效。

大规模存储

许多其他公司也需要数据湖作为辅助存储,主要是为了以原始形式存储数据以进行分析、实时分析、机器学习等。SDS 非常适合这种类型的存储,主要是因为所需的维护很少,还有我们之前讨论过的经济原因。

我们主要讨论了 SDS 的经济性和可扩展性,但也很重要提到它带来的高灵活性。SDS 可用于从存档数据和存储丰富媒体到为虚拟机(VM)提供存储,作为私有云中对象存储的端点,甚至在容器中。它可以部署在前面提到的任何基础设施上。它可以在您选择的公共云中运行,在您当前的本地虚拟基础设施中运行,甚至在 Docker 容器或 Kubernetes pod 中运行。事实上,它非常灵活,以至于您甚至可以使用称为 heketi 的 RESTful 管理接口将 Kubernetes 与 GlusterFS 集成,每当您需要为您的 pod 提供持久卷时,它都会动态分配卷。

块、文件和对象存储

现在我们已经了解了为什么 SDS 是下一代工作负载的未来,是时候深入了解使用 SDS 可以实现的存储类型了。

传统的存储区域网络(SAN)和 NAS 解决方案更常用的是使用诸如 Internet 小型计算机系统接口(iSCSI)、光纤通道(FC)、以太网上的光纤通道(FCoE)、网络文件系统(NFS)和服务器消息块(SMB)/通用互联网文件系统(CIFS)等协议提供存储。然而,由于我们更多地向云端迁移,我们的存储需求也发生变化,这就是对象存储发挥作用的地方。我们将探讨对象存储是什么,以及它与块和文件存储的比较。GlusterFS 也是一种文件存储解决方案,但它具有可以进一步配置的块和对象存储功能。

以下图表显示了块、文件和对象存储:

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

块存储、文件存储和对象存储在客户端存储数据的方式上有很大不同,因此它们的用途也完全不同。

块存储

SAN 主要是利用块存储的地方,使用诸如 FC 或 iSCSI 之类的协议,这些协议本质上是在 FC 和 TCP/IP 上映射 SCSI 协议。

典型的 FC SAN 如下图所示:

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

典型的 iSCSI SAN 如下图所示:

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

数据存储在逻辑块地址中。在检索数据时,应用程序通常会说:“我要从地址 XXYYZZZZ 获取 X 个块。”这个过程往往非常快(不到一毫秒),使得这种类型的存储在延迟上非常低,是一种非常事务性导向的存储形式,非常适合随机访问。然而,当涉及跨多个系统共享时,它也有其缺点。这是因为块存储通常以原始形式呈现,您需要在其上方使用一个文件系统,该文件系统可以支持在不同系统之间进行多次写入而不会损坏,换句话说,是一个集群文件系统。

当涉及到高可用性或灾难恢复时,这种类型的存储也有一些缺点;因为它以原始形式呈现,存储控制器和管理器因此不知道如何使用这种存储。因此,当涉及将其数据复制到恢复点时,它只考虑块,并且一些文件系统在回收或清零块时表现糟糕,这导致未使用的块也被复制,从而导致存储利用不足。

由于其优势和低延迟,块存储非常适合结构化数据库、随机读/写操作以及存储多个虚拟机镜像,这些镜像查询磁盘时可能有数百甚至数千次的 I/O 请求。为此,集群文件系统被设计为支持来自不同主机的多次读写。

然而,由于其优点和缺点,块存储需要相当多的维护和管理——您需要关注要放在块设备上的文件系统和分区。此外,您还需要确保文件系统保持一致和安全,具有正确的权限,并且在访问它的所有系统中没有损坏。虚拟机中还有其他文件系统存储在其虚拟磁盘中,这也增加了另一层复杂性——数据可以写入虚拟机的文件系统和超级管理程序的文件系统。两个文件系统都有文件的进出,它们需要适当地清零以便在薄量复制场景中回收块,正如我们之前提到的,大多数存储阵列并不知道实际写入它们的数据。

文件存储

另一方面,文件存储或 NAS 要简单得多。您不必担心分区,也不必担心选择和格式化适合多主机环境的文件系统。

NAS 通常使用 NFS 或 SMB/CIFS 协议,主要用于将数据存储在共享文件夹中作为非结构化数据。这些协议在扩展性或满足云中面临的高媒体需求方面并不是很好,比如社交媒体服务以及每天创建/上传成千上万张图片或视频。这就是对象存储发挥作用的地方,但我们将在本章后面讨论对象存储。

文件存储,顾名思义,是在文件级别的存储上工作,当您向 NAS 发出请求时,您请求的是文件或文件系统中的一部分,而不是一系列逻辑地址。对于 NAS,这个过程是从主机(存储被挂载的地方)中抽象出来的,您的存储阵列或 SDS 负责访问后端的磁盘并检索您请求的文件。文件存储还具有本地功能,如文件锁定、用户和组集成(当我们谈论 OSS 时,主要是指 NFS),安全性和加密。

尽管 NAS 为客户端提供了抽象和简化,但它也有其缺点,因为 NAS 在很大程度上,如果不是完全地,依赖于网络。它还有一个额外的文件系统层,延迟远高于块存储。许多因素可能导致延迟或增加往返时间(RTT)。您需要考虑诸如您的 NAS 距离客户端有多少跳、TCP 窗口缩放,或者设备访问文件共享时未启用巨帧。此外,所有这些因素不仅影响延迟,而且在涉及 NAS 解决方案的吞吐量时起着关键作用,这也是文件存储最擅长的地方。

以下图表展示了文件存储共享的多功能性:

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

对象存储

对象存储与 NAS(文件存储)和 SAN(块存储)完全不同。尽管数据仍然通过网络访问,但数据检索的方式是独特不同的。您不会通过文件系统访问文件,而是通过使用 HTTP 方法的 RESTful API 访问。

对象存储在一个扁平的命名空间中存储,可以存储数百万甚至数十亿个对象;这是其高可扩展性的关键,因为它不受节点数量的限制,就像常规文件系统(如 XFS 和 EXT4)一样。重要的是要知道,命名空间可以有分区(通常称为存储桶),但它们不能像文件系统中的常规文件夹那样嵌套,因为命名空间是扁平的:

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

在将对象存储与传统存储进行比较时,经常使用自动停车与代客泊车的类比。为什么这类似呢?因为在传统文件系统中,当你存储文件时,你将其存储在一个文件夹或目录中,你需要记住文件存储的位置,就像把车停在一个停车位上一样,你需要记住你的车停在哪个号码和楼层。另一方面,使用对象存储时,当你上传数据或将文件放入一个存储桶时,你会得到一个唯一的标识符,以后可以用来检索它;你不需要记住它存储在哪里。就像代客泊车员会为你取车一样,你只需要给他们你离开车时收到的票。

继续使用代客泊车的比喻,通常你会给代客泊车提供关于他们需要为你取车的信息,不是因为他们需要,而是因为这样可以更好地识别你的车,比如车的颜色、车牌号或车型将对他们有很大帮助。对象存储的过程也是一样的。每个对象都有自己的元数据、唯一 ID 和文件本身,这些都是存储对象的一部分。

下图显示了对象存储中包含的对象的组成部分:

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

正如我们已经多次提到的,对象存储是通过 RESTful API 访问的。因此,理论上,任何支持 HTTP 协议的设备都可以通过 HTTP 方法(如 PUT 或 GET)访问你的对象存储桶。这听起来不安全,但事实上,大多数软件定义的对象存储都有某种类型的身份验证方法,你需要一个身份验证令牌才能检索或上传文件。使用 Linux 的 curl 工具的简单请求可能如下所示:

curl -X PUT -T "${path_to_file}" \
  -H "Host: ${bucket_name}.s3.amazonaws.com" \
  -H "Date: ${date}" \
  -H "Content-Type: ${contentType}" \
  -H "Authorization: AWS ${s3Key}:${signature}" \
  https://${bucket}.s3.amazonaws.com/${file}

在这里,我们可以看到多个不同的设备如何通过 HTTP 协议连接到云中的对象存储桶:

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

为什么选择 GlusterFS?

现在我们了解了 SDS、存储集群以及块、文件和对象存储之间的区别,我们可以看一下企业客户选择 GlusterFS 作为他们存储需求的一些原因。

正如之前所述,GlusterFS 是一个 SDS,它是一个位于传统本地存储挂载点之上的层,允许将多个节点之间的存储空间聚合成单个存储实体或存储集群。GlusterFS 可以在私有、公共或混合云上运行。尽管其主要用途是文件存储(NAS),但几个插件允许它通过 gluster-block 插件用作块存储的后端,通过 gluster-swift 插件用作对象存储的后端。

定义 GlusterFS 的一些主要特点如下:

  • 商品硬件

  • 可以部署在私有、公共或混合云上

  • 没有单点故障

  • 可扩展性

  • 异步地理复制

  • 性能

  • 自愈

  • 灵活性

GlusterFS 特点

让我们逐个了解这些特点,以了解为什么 GlusterFS 对企业客户如此有吸引力。

商品硬件- GlusterFS 几乎可以运行在任何东西上

从树莓派上的 ARM(高级精简指令集计算机)到各种 x86 硬件,Gluster 只需要作为砖块使用的本地存储,为卷奠定基础存储。不需要专用硬件或专门的存储控制器。

在其最基本的配置中,可以使用单个格式为 XFS 的磁盘与单个节点一起使用。虽然不是最佳配置,但可以通过添加更多的砖块或更多的节点来实现进一步的增长。

GlusterFS 可以部署在私有、公共或混合云上

从容器镜像到专用于 GlusterFS 的完整 VM,对云客户来说,一个主要的吸引点是,由于 GlusterFS 仅仅是软件,它可以部署在私有、公共或混合云上。因为没有供应商,跨不同云提供商的卷是完全可能的。允许使用高可用性设置的多云提供商卷,这样当一个云提供商出现问题时,卷流量可以转移到完全不同的提供商,几乎没有或没有停机时间,这取决于配置。

无单点故障

根据卷配置,数据分布在集群中的多个节点上,消除了单点故障,因为没有headmaster节点控制集群。

可扩展性

GlusterFS 允许通过垂直添加新的砖块或通过水平添加新的节点来平稳扩展资源。

所有这些都可以在线完成,而集群提供数据,而不会对客户的通信造成任何中断。

异步地理复制

GlusterFS 采用无单点故障概念,提供地理复制,允许数据异步复制到完全不同地理数据中心的集群中。

以下图表显示了跨多个站点的地理复制:

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

性能

由于数据分布在多个节点上,我们还可以同时有多个客户端访问集群。从多个来源同时访问数据的过程称为并行性,GlusterFS 通过将客户端指向不同的节点来实现增加性能。此外,通过添加砖块或节点,可以增加性能,有效地通过水平或垂直扩展。

自愈

在意外停机的情况下,剩余节点仍然可以提供流量服务。如果在其中一个节点宕机时向集群添加了新数据,则需要在节点恢复后同步这些数据。

GlusterFS 将在访问这些新文件时自动自愈,触发节点之间的自愈操作并复制丢失的数据。这对用户和客户是透明的。

灵活性

GlusterFS 可以部署在现有硬件或虚拟基础设施上,也可以作为 VM 在云上部署,或作为容器。它的部署方式并不受限制,客户可以决定最适合他们需求的方式。

远程直接内存访问(RDMA)

RDMA 允许 Gluster 服务器和 Gluster 客户端之间进行超低延迟和极高性能的网络通信。GlusterFS 可以利用 RDMA 进行高性能计算(HPC)应用和高并发工作负载。

Gluster 卷类型

通过了解 GlusterFS 的核心特性,我们现在可以定义 GlusterFS 提供的不同类型的卷。这将有助于我们在接下来的章节中深入讨论 GlusterFS 解决方案的实际设计。

GlusterFS 提供了选择最适合工作负载需求的卷类型的灵活性;例如,对于高可用性要求,我们可以使用复制卷。这种类型的卷在两个或更多节点之间复制数据,导致每个节点的精确副本。

让我们快速列出可用的卷类型,稍后我们将讨论它们各自的优缺点:

  • 分布式

  • 复制

  • 分布式复制

  • 分散

  • 分布式分散

分布式

顾名思义,数据分布在卷和节点的砖块之间。这种类型的卷允许可用空间的无缝和低成本增加。主要缺点是没有数据冗余,因为文件分配在可能在同一节点或不同节点上的砖块之间。它主要用于高存储容量和并发应用。

将这种卷类型视为一堆磁盘(JBOD)或线性逻辑卷管理器(LVM),其中空间只是聚合而没有任何分割或奇偶校验。

以下图表显示了一个分布式卷:

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

复制

在复制卷中,数据被复制到不同节点上的砖块上。扩展复制卷需要添加相同数量的副本。例如,如果我有一个带有两个副本的卷,我想要扩展它,我需要总共四个副本。

复制卷可以与 RAID1 相比,其中数据在所有可用节点之间进行镜像。它的缺点之一是可扩展性相对有限。另一方面,它的主要特点是高可用性,因为即使在意外停机的情况下,数据也可以被访问。

对于这种类型的卷,必须实施机制来避免脑裂情况。当新数据被写入卷时,不同的节点集被允许分别处理写入时就会发生脑裂。服务器仲裁是这样一种机制,因为它允许存在一个决胜者。

以下图表显示了一个复制卷:

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

分布式复制

分布式复制卷类似于复制卷,其主要区别在于复制卷是分布式的。为了解释这一点,考虑有两个单独的复制卷,每个卷有 10TB 的空间。当两者都被分布时,卷最终拥有总共 20TB 的空间。

当需要高可用性和冗余性时,主要使用这种类型的卷,因为集群可以容忍节点故障。

以下图表显示了一个分布式复制卷:

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

分散

分散卷通过在所有可用的砖块上分割数据,并同时允许冗余性,兼具分布式和复制卷的优点。砖块应该是相同大小的,因为一旦最小的砖块满了,卷就会暂停所有写入。例如,想象一个分散卷,比如 RAID 5 或 6,数据被分割并创建奇偶校验,允许从奇偶校验中重建数据。虽然这个类比帮助我们理解这种类型的卷,但实际过程完全不同,因为它使用了数据被分成片段的纠错码。分散卷提供了性能、空间和高可用性的正确平衡。

分布式分散

在分布式分散卷中,数据分布在分散类型的卷中。冗余性是在分散卷级别提供的,具有与分布式复制卷相似的优势。

想象一下在两个 RAID 5 阵列之上的 JBOD 上存储数据——扩展这种类型的卷需要额外的分散卷。虽然不一定是相同的大小,但理想情况下,它应该保持相同的特性以避免复杂性。

对高度冗余存储的需求

随着应用程序可用空间的增加,对存储的需求也在增加。应用程序可能需要随时访问它们的信息,而不会出现任何可能导致整个业务连续性受到威胁的中断。没有公司希望出现停机,更不用说中央基础设施的中断导致损失、客户无法服务和用户因错误决策而无法登录到他们的帐户。

让我们考虑将数据存储在传统的单片存储阵列上——这样做可能会带来重大风险,因为一切都集中在一个地方。一个包含公司所有信息的大型存储阵列意味着操作风险,因为该阵列容易出现故障。每一种硬件——无论多么好——都会在某个时候出现故障。

单体阵列倾向于通过在磁盘级别使用传统的 RAID 方法来提供某种形式的冗余来处理故障。虽然这对为数百用户提供服务的小型本地存储来说是不错的,但是当我们达到 PB 级别并且存储空间和活跃并发用户大幅增加时,这可能不是一个好主意。在特定情况下,RAID 恢复可能导致整个存储系统崩溃或性能下降到应用程序无法正常工作的程度。此外,随着磁盘容量的增加和单个磁盘性能在过去几年内保持不变,现在恢复单个磁盘需要更长的时间;重建 1TB 磁盘不同于重建 10TB 磁盘。

存储集群,如 GlusterFS,通过提供最适合工作负载的方法来处理冗余。例如,当使用复制卷时,数据从一个节点镜像到另一个节点。如果一个节点宕机,那么流量会无缝地转向剩余的节点,对用户来说完全透明。一旦问题节点得到处理,它可以迅速重新加入集群,在那里它将进行数据的自我修复。与传统存储相比,存储集群通过将数据分发到集群的多个成员来消除单点故障。

提高可用性意味着我们可以达到应用程序服务级别协议并保持所需的正常运行时间。

灾难恢复

逃不过灾难——无论是自然灾害还是人为错误。重要的是我们为此做好了多少准备,以及我们能多快多高效地恢复。

实施灾难恢复协议对业务连续性至关重要。在继续之前,有两个术语我们需要了解:恢复时间目标RTO)和恢复点目标RPO)。让我们快速浏览一下每个术语。RTO 是从故障或事件导致中断开始恢复所需的时间。简单地说,它指的是我们可以多快将应用程序恢复正常。另一方面,RPO 指的是数据可以在不影响业务连续性的情况下回溯多远的时间,也就是说,你可以丢失多少数据。

RPO 的概念看起来像这样:

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

RTO

如前所述,这是在故障后恢复功能所需的时间。根据解决方案的复杂性,RTO 可能需要相当长的时间。

根据业务需求,RTO 可能只有几个小时。这就是设计高度冗余解决方案的作用所在——通过减少恢复所需的时间。

RPO

这是可以丢失的数据量,仍然可以返回到恢复点的时间,换句话说,这是恢复点被采取的频率;在备份的情况下,备份的频率(可以是每小时、每天或每周),以及在存储集群的情况下,更改的复制频率。

需要考虑的一点是变化可以被复制的速度,因为我们希望变化几乎可以立即被复制;然而,由于带宽限制,实时复制大多数时候是不可能的。

最后,需要考虑的一个重要因素是数据如何被复制。一般来说,有两种类型的复制:同步和异步。

同步复制

同步复制意味着数据在写入后立即复制。这对于最小化 RPO 是有用的,因为从一个节点到另一个节点的数据之间没有等待或漂移。GlusterFS 复制的卷提供了这种复制。带宽也应该被考虑,因为更改需要立即提交。

异步复制

异步复制意味着数据在时间片段内复制,例如,每 10 分钟。在设置过程中,根据业务需求和可用带宽等多个因素选择 RPO。

带宽是主要考虑因素;这是因为根据更改的大小,实时复制可能无法适应 RPO 窗口,需要更长的复制时间,直接影响 RPO 时间。如果有无限带宽可用,应选择同步复制。

回顾过去,作为 IT 架构师,我们花费了大量时间试图找出如何使我们的系统更具弹性。事实上,成功降低 RTO 和 RPO 时间可能标志着部分考虑周到的解决方案和完全设计良好的设计之间的差异。

高性能的需求

随着越来越多的用户访问相同的资源,响应时间变慢,应用程序开始处理时间变长。传统存储的性能在过去几年没有改变——单个 HDD 的吞吐量约为 150 MB/s,响应时间为几毫秒。随着闪存介质和诸如非易失性内存扩展(NVMe)之类的协议的引入,单个 SSD 可以轻松实现每秒几十亿字节的吞吐量和亚毫秒的响应时间;SDS 可以利用这些新技术提供增加的性能并显著减少响应时间。

企业存储被设计为处理数百个客户的多个并发请求,这些客户都希望尽快获取他们的数据,但当性能限制达到时,传统的单体存储开始变慢,导致应用程序失败,因为请求未能及时完成。提高这种类型存储的性能代价高,并且在大多数情况下,无法在存储仍在提供数据的情况下完成。

增加性能的需求来自存储服务器负载的增加;随着数据消费的激增,用户存储的信息量比以往更多,并且需要比以前更快地获取。

应用程序还需要尽快将数据传递给它们;例如,考虑股票市场,数千用户每秒多次请求数据。与此同时,另外一千用户不断地写入新数据。如果单个交易未能及时提交,人们将无法根据正确的信息做出买卖股票的决定。

前面的问题是架构师在设计能够提供应用所需性能的解决方案时必须面对的问题。花费适当的时间正确规划存储解决方案可以使整个流程更加顺畅,减少设计和实施之间的来回。

诸如 GlusterFS 之类的存储系统可以同时为数千个并发用户提供服务,而不会出现性能显著下降,因为数据分布在集群中的多个节点上。这种方法比访问单个存储位置(例如传统阵列)要好得多。

并行 I/O

I/O 是指向存储系统请求和写入数据的过程。该过程通过 I/O 流进行,数据一次请求一个块、文件或对象。

并行 I/O 是指多个流同时在同一存储系统上执行操作的过程。这增加了性能并减少了访问时间,因为各种文件或块同时读取或写入。

相比之下,串行 I/O 是执行单个 I/O 流的过程,这可能会导致性能降低和延迟或访问时间增加。

存储集群(如 GlusterFS)利用并行 I/O 的优势,因为数据分布在多个节点上,允许多个客户端同时访问数据,而不会出现延迟或吞吐量下降。

总结

在本章中,我们深入了解了集群的核心概念,并将其定义为一组计算机节点,它们一起处理相同类型的工作负载。计算集群的主要功能是执行运行 CPU 密集型工作负载的任务,旨在减少处理时间。存储集群的功能是将可用的存储资源聚合到一个单一的存储空间中,简化管理,并允许您有效地达到 PB 级别或超过 1PB 的可用空间。然后,我们探讨了 SDS 如何改变数据存储方式,以及 GlusterFS 是领导这一变革的项目之一。SDS 允许简化存储资源的管理,同时添加了传统的单片式存储阵列无法实现的功能。

为了进一步了解应用程序与存储的交互方式,我们定义了块、文件和对象存储之间的核心区别。主要地,块存储处理存储设备中的逻辑数据块,文件存储通过从存储空间读取或写入实际文件来工作,对象存储为每个对象提供元数据以进行进一步交互。有了这些不同存储交互方式的概念,我们继续指出了使 GlusterFS 对企业客户具有吸引力的特征,以及这些特性如何与 SDS 的定义联系起来。

最后,我们深入探讨了为什么高可用性和高性能对于每个存储设计都是必不可少的主要原因,以及如何执行并行或串行 I/O 会影响应用程序性能。

在下一章中,我们将深入探讨架构 GlusterFS 存储集群的实际过程。

问题

  1. 我如何优化我的存储性能?

  2. GlusterFS 更适合哪种工作负载?

  3. 哪些云提供商提供对象存储?

  4. GlusterFS 提供哪些类型的存储?

  5. 红帽是否拥有 GlusterFS?

  6. 我使用 GlusterFS 需要付费吗?

  7. Gluster 是否提供灾难恢复或复制?

进一步阅读

第三章:设计存储集群

软件定义的存储已经改变了我们存储数据的方式;随着功能的增加,设计正确解决方案时需要考虑的要求也在增加。在设计存储集群时需要考虑大量的变量。

本章探讨了使用 GlusterFS 及其各种组件实现软件定义存储解决方案的不同设计方面。

在本章中,我们将涵盖以下主题:

  • GlusterFS 计算需求

  • 选择合适的存储大小

  • 定义性能需求

  • 决定高可用性的正确方法

  • 确定工作负载如何联系在一起

技术要求

对于本章,我们将使用以下网址上提供的 GlusterFS 文档:

GlusterFS 计算需求

与任何软件一样,GlusterFS 有一组由开发人员定义的要求,以确保其按预期工作。文档中描述的实际要求相对较低,几乎每台在过去 10 年中销售的计算机都可以运行 GlusterFS。这可能不是最佳性能水平,但它仍然显示了在混合条件下运行的灵活性。

对于计算需求,我们主要有以下两个资源需要考虑在设计使用 GlusterFS 的解决方案时:

  • 内存

  • CPU

内存

对于内存,选择相对简单——尽可能多地使用。不幸的是,没有无限的内存,但尽可能多地使用内存这一说法是非常真实的,因为 GlusterFS 使用 RAM 作为每个节点的读取缓存,同时 Linux 内核使用内存作为预读缓存,以加快对频繁访问的文件的读取速度。

根据砖块布局和选择的文件系统,可用内存在读取性能中起着重要作用。以使用高级 ZFS 文件系统的砖块为例,它使用 RAM 作为其自适应替换缓存(ARC)。这增加了一个额外的缓存层,位于高速 RAM 上。缺点是它会消耗尽可能多的内存,因此选择提供大量内存的服务器会有很大帮助。

GlusterFS 并不需要大量的内存——每个节点拥有 32GB 或更多的内存可以确保缓存足够大,以分配频繁访问的文件,如果通过在每个节点上添加更多的砖块来扩展集群的规模,那么应该考虑增加更多的内存,以增加缓存的可用内存。

为什么缓存很重要?

考虑以下:即使是旧的 DDR2 内存技术也可以提供 GBps 级的吞吐量和几纳秒的延迟。另一方面,从常规旋转介质(硬盘驱动器)读取的吞吐量在大多数情况下峰值为 150MBps,延迟在几百毫秒。

从缓存中读取总是比访问磁盘快——等待磁盘移动其磁头,找到请求的数据块,然后将其发送回控制器并传递到应用程序。

需要记住的一件事是,缓存需要先预热;这是允许系统确定哪些文件经常被访问,然后将数据移动到缓存中的过程。在预热期间,请求会变慢,因为它们首先必须从磁盘中获取。

CPU

任何软件都需要 CPU 周期,GlusterFS 也不例外。CPU 要求相对较低,并且取决于所使用的卷的类型,例如,复制卷分散卷需要更少的 CPU。

CPU 需求也受到砖块使用的文件系统类型和其具有的功能的影响。回到 ZFS 的例子,如果启用了压缩,这会增加 CPU 的负载,而没有足够的 CPU 资源会大大降低性能。

对于简单的存储服务器和在 brick 级别没有高级功能的情况,任何四个 CPU 或更多的都足够了。当启用文件系统功能,比如压缩时,需要八个或更多的 CPU 以获得最佳性能。此外,更多的 CPU 允许对集群进行更多并发 I/O。这在为高性能计算(HPC)应用程序设计存储集群时至关重要,其中成千上万的用户同时进行 I/O 操作。

使用以下规则作为一般的经验法则:

  • 对于高并发工作负载,选择更多的 CPU,超过八个 CPU,取决于并发级别

  • 对于低性能要求和成本效益的解决方案,选择较少数量的 CPU,例如四个 CPU

云考虑

许多云提供商为其虚拟机大小提供了一组固定的资源,不允许自定义 vCPU 到 RAM 的比例。找到合适的平衡取决于哪种 VM 大小提供了必要的资源。

GlusterFS 在云中的概念将在接下来的章节中进一步探讨。然而,为了对这个概念有一个概述,让我们使用微软的 Azure 提供的 VM 大小来探索一下。

Azure VM 系列从通用计算到特定工作负载,如 GPU。对于 GlusterFS,我们真的很喜欢 L 系列 VM,这些 VM 针对存储工作负载进行了优化。这个 VM 系列具有良好的 vCPU 到 RAM 比例,并提供了任何系列中最高的存储性能与成本比。

这个一般的想法可以应用到其他云供应商。应选择提供优秀和具有成本效益的 vCPU 到 RAM 比例的 VM 大小。

你需要多少空间?

如果我们可以使用我们需要的空间,那不是很好吗?实际上,存储是有成本的,无限的存储是不存在的。

在确定可用存储空间时,必须考虑以下因素:

  • GlusterFS 卷类型

  • 应用程序需要的空间

  • 预期增长

GlusterFS 卷类型

让我们从一些技术考虑开始。每个 GlusterFS 卷在可用空间方面都有特点。根据卷类型,最终可用空间可能比您最初计算的要少。我们将探讨我们在第二章中描述的每种卷类型的空间考虑,定义 GlusterFS 存储

分布式

这种卷类型相当简单。每个节点的可用空间之和是全局命名空间(GlusterFS 卷挂载的另一个名称)上的总空间。

例如,一个 50TB 卷的请求,砖块所需的空间恰好是 50TB。这可以分成每个 10TB 的五个节点或每个 25TB 的两个节点。

复制

对于复制卷,一半的可用原始砖块空间用于数据的镜像或复制。这意味着在确定这种类型的卷的大小时,您需要至少将所请求的存储容量加倍。这取决于卷的具体配置。一个经验法则是可用容量是砖块上总空间的一半。

例如,如果请求的是 50TB 卷,节点配置应该至少在两个节点之间有 100TB 的砖块空间。

分散

分散卷的大小更难确定,因为它们的功能类似于 RAID 5,其中数据分布在节点上,并且一个节点的容量用于奇偶校验。这取决于卷的配置,但您可以预期随着节点数的增加,空间利用效率会提高。

进一步解释,对于一个 50 TB 的卷的请求,可以在 6 个节点上配置,每个节点有 10 TB。请注意额外考虑了一个节点。选择 5 个每个 10 TB 的节点会导致只有 40 TB 的卷,这不符合请求的大小。

应用程序所需的空间

每个应用程序都有自己的一套要求,存储要求和其他要求一样重要。

提供媒体文件需要的资源比用户较少且媒体文件不多的网站要多得多。准确了解存储系统的预期使用方式可以正确地确定解决方案的大小,并防止存储估算不足以满足最初需求的情况发生。

确保你了解应用程序开发人员推荐的最低要求,并了解它如何与存储交互,因为这有助于避免头疼的情况。

预期增长

作为架构师,你的工作是提出正确的问题。在涉及存储时,确保增长率或变化率被考虑在内。

考虑到数据增长是无法避免的,提前思考可以避免复杂的情况,即没有足够的空间,因此为未来的利用留出一些余地是一个好的做法。允许 10%或更多的空间应该是一个很好的起点,所以如果请求 50 TB 的空间,那么在解决方案中再增加 5 TB 的空间。

选择最具成本效益的路线。虽然 GlusterFS 允许无缝扩展,但尽量避免使用这个功能作为简单的解决方案,并确保从一开始就定义了正确的大小,并考虑了未来的增长。

性能考虑

性能差的应用程序可能比根本无法工作的应用程序更糟糕。让某些东西一半的时间工作是非常令人沮丧和对任何企业来说成本高昂的。

作为架构师,你需要设计满足规格或更好的解决方案,以避免由于性能不佳而导致问题的情况。

首先要做的是定义性能要求是什么。大多数情况下,应用程序开发人员在他们的文档中提到了性能要求。不满足这些最低要求意味着应用程序要么根本无法工作,要么几乎无法工作。这两种情况都是不可接受的。

设计面向性能的解决方案时需要注意以下几点:

  • 吞吐量

  • 延迟

  • IOPS

  • I/O 大小

吞吐量

吞吐量是在一定时间内传输的数据量的函数,通常以兆字节每秒(MBps)描述。这意味着每秒从存储系统发送或接收 X 数量的数据。

根据工作负载的不同,最高吞吐量可能无法实现,因为应用程序无法执行足够大或足够快的 I/O 操作。这里没有硬性建议的数字。尽量追求最高可能的吞吐量,并确保存储集群能够维持所需的并发级别所需的传输速率。

延迟

延迟是至关重要的,需要额外小心,因为一些应用程序对高延迟或响应时间非常敏感。

延迟是衡量 I/O 操作完成所需的时间的指标,通常以毫秒为单位(1 秒等于 1000 毫秒)。高延迟或响应时间会导致应用程序响应时间变长,甚至完全停止工作。

力求达到最低的延迟。这是一个情况,其中获得最低可能的数字总是最好的方法。在延迟方面,没有不够的情况,或者在这种情况下,响应时间不够短。考虑你使用的存储介质类型。传统的硬盘驱动器的响应时间(或寻道时间)在几百毫秒范围内,而新型固态硬盘可以达到亚毫秒甚至微秒的水平。

IOPS

每秒输入/输出操作是一定时间内(在本例中是秒)的一定数量的操作的函数。这是衡量每秒可以执行多少操作的指标,许多应用程序提供了关于 IOPS 的最低要求。

大多数应用程序提供了其所需的最低 IOPS 要求。确保满足这些要求,否则应用程序可能无法按预期运行。

在设计存储解决方案时,确保 IOPS 被视为在制定大小决策时的主要决定因素。

I/O 大小

I/O 大小是每个操作执行的数据量。这取决于工作负载类型,因为每个应用与存储系统的交互方式不同。I/O 大小直接影响了之前提到的性能方面。

较小的 I/O 会导致较低的吞吐量,但如果足够快,会导致更高的 IOPS 和较低的延迟。另一方面,较大的 I/O 提供更高的吞吐量,但通常会产生较低的 IOPS,因为在相同的时间内执行较少的操作。

关于 I/O 大小没有明确的建议。在理想的、不现实的世界中,I/O 足够大且足够快,这会导致高吞吐量和高 IOPS。但在现实中,要么是一个,要么是另一个。小的 I/O 在吞吐量方面较慢,但完成得足够快,因此 IOPS 似乎更高。而大的 I/O 则相反,吞吐量更高,但由于完成时间较长,IOPS 下降。

GlusterFS 性能

在设计 GlusterFS 存储集群时,需要考虑以下方面,以便提高性能:

  • 卷类型

  • 砖块布局

  • 节点数量

  • 调整参数

卷类型

所选的卷以不同的方式影响性能,因为 GlusterFS 为每种类型分配数据方式不同。

例如,复制卷在节点之间镜像数据,而分散卷试图最大化节点使用并并行使用它们。

如果性能是分散或分布式卷的主要目标,请考虑分布卷不提供冗余,而分散卷则以性能降级为代价提供冗余。

砖块布局

将所有磁盘都放在一个大的砖块中的节点与将磁盘分组在较小数量的砖块中的节点性能表现不同。砖块布局是性能的最大贡献因素,因为这直接决定了磁盘的使用方式。

如果所有磁盘最终都放在一个砖块中,性能会受到影响。通常,更多的砖块和较少的磁盘会带来更好的性能和更低的延迟。

考虑为构成砖块的磁盘配置软件 RAID0。例如,您可以有 10 个可用的磁盘,并且为了简单起见,可以在单个砖块上配置所有 10 个磁盘的 RAID0。或者,您可以选择更高效的方式,配置五个砖块,其中每个砖块由 RAID0 中的两个磁盘组成。

这也可以实现更平稳的增长,因为添加更多砖块并不需要添加大量的磁盘。您应该以更少的磁盘组成更多的砖块为目标。

在下图中,我们可以看到每个砖块由两个不同的磁盘组成:

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

节点数量

增加集群中节点的数量可以实现更高的并发性。虽然性能增益可能不是线性的,但增加节点可以允许更多的用户和应用程序访问卷。

目标是拥有足够的节点以实现可用空间和并发性的平衡。这里没有固定的数量,但作为架构师,您的工作是通过测试来定义特定解决方案的正确节点数量。在 POC 阶段,使用较少的节点进行测试,并检查性能是否可接受。

调整参数

文件系统可调参数,如块大小,可以发挥重要作用,目标是使工作负载 I/O 大小、GlusterFS 卷块大小和文件系统块大小相匹配。

通常,4K 是最常用的块大小,适用于一般工作负载。对于大量的小文件,选择较小的块大小。对于大文件,选择较大的块大小,例如 1M。

实现高可用性的最佳方法

使用 GlusterFS,高可用性可以通过卷配置实现;决定如何实现取决于应用程序需求、可用空间和所需性能。

由于 GlusterFS 处理高可用性,因此无需在存储单元级别配置任何形式的冗余。特别是在云实例和虚拟机中,没有可以出问题的物理磁盘。对于物理安装,通过为本地磁盘配置 RAID5 或 RAID6 来增加额外的冗余层总是更好,以实现性能和弹性的平衡。现在,让我们继续使用云部署。

使用 GlusterFS 时,只有两种卷类型提供高可用性:复制和分散。复制卷相对较简单,因为数据只是从一个节点复制到另一个节点。这提供了较低的性能,但配置、部署和维护都相对容易。

复制

当不需要极端性能时,请选择复制卷。根据卷应该容忍的节点或存储单元数量选择副本的数量。请考虑使用更高的副本数量将减少可用空间的数量,但会增加卷的可用性。

以下示例显示,丢失复制卷中的一个节点不会中断卷的运行:

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

分散

分散卷在高可用性和性能之间提供了良好的平衡;当两者都是要求时,这应该是首选卷。配置分散卷是一个更复杂的过程,因为冗余是像 RAID5 设置一样处理的,其中一个节点被用作奇偶校验。冗余值可以在卷创建时选择,这允许更大的灵活性。

在下图中,您可以看到丢失一个节点不会中断卷的运行:

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

当存在特定需求时,请计划高可用性。请记住,卷类型可以混合使用。例如,分布式复制卷将具有良好的可用空间和冗余性的混合。

地理复制

地理复制允许通过本地网络或互联网在不同站点之间进行数据的异步复制。这通过在不同地理位置拥有数据的副本来提供高可用性,并确保在发生故障时进行灾难恢复。

当存在需要额外冗余层的特定用例时,考虑使用地理复制路线。请记住,这是异步复制,因此在发生灾难时,请考虑前几章中解释的 RPO 和 RTO 时间。

以下图表让您对地理复制的工作原理有一个大致的了解——站点 A通过广域网复制到站点 B

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

工作负载如何定义需求

将视频文件传送到流媒体服务器与托管大型数据库不同。I/O 是以完全不同的方式进行的,了解工作负载与存储系统的交互方式对成功地确定和设计强大的存储解决方案至关重要。

文档

当尝试确定存储需求时,应用程序文档是您的最佳伙伴。当应用程序已经存在时,询问管理员软件对性能的期望以及当不满足最低要求时的反应。

系统工具

使用诸如iostat之类的工具可以很好地了解应用程序与存储的交互方式,例如通过使用以下命令:

iostat -dxctm 1

前面的代码显示了每个块设备的使用情况,areq-sz列(以前称为avgrq-sz)显示了以千字节为单位的平均请求大小,这是了解应用程序通常使用的 I/O 大小的良好起点。

输出看起来类似于以下截图:

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

在前面的图像中,我们可以欣赏到块设备及其相应的性能。

文件类型和大小

举例来说,为媒体流服务器设计存储解决方案需要使用大块大小,因为媒体文件往往比小文本文件大。如果你为砖块使用更大的块大小,GlusterFS 卷不仅会更有效地利用空间,还将允许更快的操作,因为事务大小与文件大小匹配。

另一方面,传感器日志记录的存储服务器通常会创建包含文本的大量小文件,因此需要较小的块大小来匹配正在创建的文件的大小。使用较小的块大小可以避免为仅有 1K 大小的文件分配整个块(例如 4K)。

提出正确的问题

作为架构师,您的目标是确保工作负载非常清晰。存储服务器的预期用途定义了需要分配多少资源。未能这样做可能导致资源浪费,这反过来意味着浪费金钱,或者在最坏的情况下,可能导致解决方案无法按规格执行,从而导致应用程序失败和用户无法工作。

从第一章中记住,设计方法论简介:提出正确的问题。在调整存储解决方案时,您可以问以下问题:

  • 当前实施消耗了多少空间(如果已经有一个)?

  • 应用程序的性能要求是什么?

  • 有多少用户与应用程序交互?

  • 是否需要高可用性?

  • 应用程序如何存储其数据?

  • 它是否创建大文件并向其附加数据?

  • 它是否创建大量小文件?

这些问题的可能答案可能是以下内容:

  • 目前,该应用程序消耗了 20TB,但我们预计每个月增长 5%,并稳定在 80TB。

  • 该应用程序需要至少 100MB/s 的吞吐量和不超过 10ms 的延迟。

  • 目前,大约有 300 个用户可以访问该应用程序;同时,我们已经看到了 150 个用户的高峰,但我们预计用户数量将显著增加。

  • 我们可以忍受一段时间无法访问存储,但我们确实需要能够相对快速地从故障中恢复,并且可能在外部有数据的副本。

  • 应用程序主要将其信息保存在小文件中。

  • 它不附加数据,如果需要更多空间,它只是创建更多小文件。

  • 是的,我们已经看到创建了数千个大小不超过 4KB 的文件。

从前面的例子中,您可以推断出该应用程序创建了大量小文件,并且可以容忍一段时间的停机,但需要外部复制以实现平稳的灾难恢复。性能要求似乎相对较高,因此我们可以选择启用地理复制的分散或分布式卷。

总结

设计存储解决方案的过程需要了解许多变量。在本章中,我们确定了决定需要多少空间取决于 GlusterFS 卷类型、应用程序要求和数据利用率的预估增长。

根据卷类型,可用空间会受到影响,分布式卷会聚合所有可用空间,使其成为最节省空间的卷,而复制卷使用一半可用原始空间进行镜像。

应用程序和用户群决定了需要多少空间。这是因为,根据所提供的数据类型,存储需求会发生变化。提前考虑并规划存储增长可以避免资源耗尽的潜在风险,并且在大小确定时至少留出 10%的缓冲区应该适应大多数情况。

通过性能要求,我们定义了吞吐量、延迟、IOPS 和 I/O 大小的概念,以及它们如何相互作用。我们定义了在为 GlusterFS 配置最佳性能时涉及的变量,每个卷都具有其性能特征,以及在尝试优化 GlusterFS 卷时砖块布局起着重要作用。

我们还定义了高可用性要求如何影响大小,以及每个卷提供不同级别的 HA。当需要灾难恢复时,GlusterFS 地理复制通过将数据复制到另一个物理区域提供所需的可用性级别,从而在发生灾难时平稳恢复服务。

最后,我们讨论了工作负载如何定义解决方案的设计,以及如何使用工具来验证应用程序与存储的交互方式,从而正确配置存储集群。我们还了解了文件类型和大小如何定义性能行为和空间利用率,以及如何提出正确的问题可以更好地理解工作负载,从而实现更高效和优化的解决方案。

最重要的是要始终询问应用程序和工作负载如何与其资源交互。这可以实现最高效的设计。

在下一章中,我们将介绍 GlusterFS 所需的实际配置。

问题

  1. GlusterFS 的计算要求是什么?

  2. GlusterFS 如何使用 RAM?

  3. 什么是缓存?

  4. 并发性如何影响 CPU 大小?

  5. GlusterFS 卷如何影响可用空间?

  6. 应用程序需要多少空间?

  7. 什么是预期增长?

  8. 什么是吞吐量、延迟 IOPS 和 I/O 大小?

  9. 什么是砖块布局?

  10. 什么是地理复制?

进一步阅读

  • 架构数据密集型应用 by Anuj Kumar

  • Microsoft Azure 存储基础 by Chukri Soueidi

  • Ritesh Modi 的 Azure 架构师

第四章:在云基础设施上使用 GlusterFS

在对 GlusterFS 的核心概念有了很好的理解之后,我们现在可以深入到存储集群的安装、配置和优化中。

我们将在 Azure 上使用云提供商搭建一个三节点集群的 GlusterFS,作为本示例的云提供商。然而,这些概念也可以应用于其他云提供商。

在本章中,我们将涵盖以下主题:

  • 配置 GlusterFS 后端存储

  • 安装和配置 GlusterFS

  • 设置卷

  • 优化性能

技术要求

本章的技术资源列表如下:

  • Azure 虚拟机(VM)大小的详细视图:

docs.microsoft.com/en-us/azure/virtual-machines/linux/sizes-storage

  • Azure 磁盘大小和类型的详细视图:

azure.microsoft.com/en-us/pricing/details/managed-disks/

  • ZFS on Linux 项目的主页:

github.com/zfsonlinux/zfs/wiki/RHEL-and-CentOS

  • CentOS 上的 GlusterFS 安装指南:

wiki.centos.org/HowTos/GlusterFSonCentOS

  • GlusterFS 在 Gluster 网站上的快速入门指南:

docs.gluster.org/en/latest/Quick-Start-Guide/Quickstart/

  • 在管理员指南上设置 GlusterFS 卷:

docs.gluster.org/en/latest/Administrator%20Guide/Setting%20Up%20Volumes/

  • GlusterFS 调整卷以获得更好的性能:

docs.gluster.org/en/latest/Administrator%20Guide/Managing%20Volumes/#tuning-options

设置用于后端存储的砖

以下是我们将使用的组件列表:

  • Azure L4s VM,具有 4 个 vCPU 和 32GB 的 RAM

  • 每个 VM 有四个 S10 128GB 的磁盘

  • CentOS 7.5

  • ZFS on Linux 作为砖的文件系统

  • 一个由四个磁盘组成的单个 RAID 0 组

  • GlusterFS 4.1

Azure 部署

在深入讨论如何配置砖之前,我们首先需要在 Azure 中部署节点。在本示例中,我们使用存储优化的 VM 系列,即 L 系列。值得一提的是,Azure 提供了一个 30 天的免费试用期,可以用于在承诺任何部署之前进行测试。

在 Azure 中,性能在几个级别上进行定义。第一级是 VM 限制,即 VM 允许的最大性能。L 系列家族提供了价格与性能的正确平衡,因为这些 VM 经过优化,提供了更高的 IOPS 和吞吐量,而不是提供高计算或内存资源。性能定义的第二级是通过连接到 VM 的磁盘。在本示例中,我们将使用标准的硬盘驱动器作为一种经济实惠的解决方案。如果需要更高的性能,磁盘可以随时迁移到高级的固态硬盘存储。

本示例的确切 VM 大小将是 L4s,提供四个 vCPU 和 32GB 的 RAM,足够用于一般用途的小型存储集群。在正确配置时,最大可达 125MB/s 和 5k IOPS,仍然保持可观的性能。

最近推出了一代新的面向存储优化的 VM,提供了一个本地可访问的 2 TB NVMe SSD。此外,它提供了增加的核心数和内存,使这些新的 VM 成为 GlusterFS 设置与Z 文件系统ZFS)的理想选择。新的 L8s_v2 VM 可以用于这个特定的设置,产品页面上可以看到大小和规格(docs.microsoft.com/en-us/azure/virtual-machines/linux/sizes-storage#lsv2-series)。

以下截图显示了可用性集、当前故障域和当前更新域的设置:

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

在 Azure 中部署 GlusterFS 设置时,请确保每个节点都落在不同的更新和故障域上。这是通过使用可用性集来实现的(参考前面的截图)。这样做可以确保如果平台重新启动一个节点,其他节点仍然保持运行并提供数据。

最后,对于 Azure 设置,我们需要每个节点512 GB,总共 1.5 TB 原始空间,或 1 TB 可用空间。实现这一点的最具成本效益的方法是使用单个S20 512 GB磁盘,因为每月每千兆字节的价格约为**$0.04**。选择单个磁盘会影响性能,因为单个标准磁盘只提供最大 500 IOPS 和 60 MB/s。考虑性能并接受我们在成本方面会失去一些效率的事实,我们将使用四个S10 128 GB 磁盘组成单个 RAID0 组。S10磁盘每月每千兆字节的价格为**$0.05**,而S20磁盘每月每千兆字节的价格为**$0.04**。您可以参考以下表格,其中计算是基于托管磁盘的成本除以其相应的大小进行的:

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

确保所有三个节点都部署在同一区域和相同的资源组中,以保持一致性。

ZFS 作为砖的后端

我们在第三章中讨论了 ZFS,构建存储集群。ZFS 是由 Sun Microsystems 开发的文件系统,后来被 Oracle 收购。该项目后来被开源,并移植到了 Linux。尽管该项目仍处于测试阶段,但大多数功能都运行良好,大部分问题已经排除,该项目现在专注于添加新功能。

ZFS 是一个软件层,将磁盘管理、逻辑卷和文件系统合而为一。诸如压缩、自适应替换缓存ARC)、重复数据删除和快照等高级功能使其成为与 GlusterFS 作为砖的后端一起使用的理想选择。

安装 ZFS

让我们从安装 ZFS 开始;有一些依赖项,比如动态内核模块DKMS),它们存放在 EPEL 存储库中。

请注意,这里运行的大多数命令都假定是以 root 身份运行的;可以在每个命令之前加上sudo作为非 root 帐户运行命令。

要安装所需的组件,我们可以使用以下命令:

yum install -y epel-release
yum install -y http://download.zfsonlinux.org/epel/zfs-release.el7_5.noarch.rpm

接下来,我们将使用以下命令:

yum install -y zfs

以下命令用于启用 ZFS 组件:

systemctl enable zfs.target
systemctl enable --now zfs-import-scan.service

配置 zpools

安装并启用 ZFS 后,我们现在可以创建 zpools。Zpool 是在 ZFS 中创建的卷的名称。

由于我们将使用由四个磁盘组成的单个 RAID 0 组,我们可以创建一个名为brick1的 zpool;这需要在所有三个节点上完成。此外,让我们创建一个名为bricks的目录,位于根目录(/)下;这个目录包含了一个带有砖名称的目录下的砖。执行此操作所需的命令如下:

mkdir -p /bricks/brick1

这将创建目录树,如下所示:

zpool create brick1 /dev/disk/by-id/scsi-360022480f0da979b536cde32a4a17406 \
 /dev/disk/by-id/scsi-360022480fb9d18bbdfb9175fd3e0bbf2 \
/dev/disk/by-id/scsi-360022480fb9d18bbdfb9175fd3e0bae4 \
/dev/disk/by-id/scsi-360022480fb9d18bbdfb9175fd3e049f2

进一步解释该命令,brick1是 zpool 的名称。然后,我们指示磁盘的路径。在本例中,我们使用磁盘的 ID,因为这样可以避免磁盘更改顺序时出现问题。虽然 ZFS 不受磁盘顺序不同的影响,但最好通过使用永远不会更改的 ID 来避免问题。

ZFS 可以使用整个磁盘,因为它会自动创建所需的分区。

创建zpool实例后,我们可以使用zpool status命令检查是否已正确完成:

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

让我们启用压缩并将池的挂载点更改为先前创建的目录。要执行此操作,请运行以下命令:

zfs set compression=lz4 brick1

您还需要运行以下命令:

zfs set mountpoint=/bricks/brick1 brick1

第一个命令使用lz4算法启用压缩,其 CPU 开销较低。第二个命令更改了 zpool 的挂载点。在更改设置时,请确保使用正确的池名称。

完成此操作后,我们应该在df命令中看到 ZFS 卷已挂载在/bricks/brick1下:

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

我们需要在最近添加的挂载点上创建一个目录以用作 brick;共识是使用卷的名称。在这种情况下,我们将卷命名为gvol1,然后简单地创建目录:

mkdir -p /bricks/brick1/gvol1

这需要在所有节点上完成。

将 ZFS 缓存添加到池中(可选)

在 Azure 中,每个 VM 都有一个临时资源驱动器。这个临时资源驱动器的性能比添加到它的数据磁盘要高得多。这个驱动器是临时的,这意味着一旦 VM 被取消分配,数据就会被擦除;由于不需要在重新启动时持续保留数据,这应该非常适合作为读取缓存驱动器。

由于驱动器在每次stop/deallocate/start周期中都会被擦除,因此我们需要调整一些 ZFS 的单元文件,以允许在每次重新启动时添加磁盘。驱动器将始终是/dev/sdb,并且由于不需要在其上创建分区,因此我们可以简单地告诉 ZFS 在系统引导时每次将其添加为新磁盘。

可以通过编辑位于/usr/lib/systemd/system/zfs-mount.service下的zfs-mount.servicesystemd单元来实现。这种方法的问题在于 ZFS 更新将覆盖对先前单元所做的更改。解决此问题的一种方法是运行sudo systemctl edit zfs-mount并添加以下代码:

[Service]
ExecStart=/sbin/zpool remove brick1 /dev/sdb
ExecStart=/sbin/zpool add brick1 cache /dev/sdb

要应用更改,请运行以下命令:

systemctl daemon-reload

现在,我们已确保缓存驱动器将在每次重新启动后添加,我们需要更改在 Azure VM 上运行的 Linux 代理的特定于 Azure 的配置。该代理负责创建临时资源驱动器,由于我们将用于其他目的,因此我们需要告诉代理不要创建临时磁盘。为实现此目的,我们需要编辑位于/etc/waagent.conf中的文件,并查找以下行:

ResourceDisk.Format=y

然后,您需要将其更改为以下行:

ResourceDisk.Format=n

完成此操作后,我们可以通过运行以下命令将缓存驱动器添加到池中:

zpool add brick1 cache /dev/sdb -f 

-f选项只能在第一次使用时使用,因为它会删除先前创建的文件系统。请注意,需要对 VM 进行stop/deallocate/start周期以阻止代理程序默认格式化资源磁盘,因为它默认会得到一个ext4文件系统。

先前的过程也可以应用于使用更快的 NVMe 驱动器的新 Ls_v2 VM,例如 L8s_v2;只需将/dev /sdb替换为/dev/nvme0n1

您可以验证缓存磁盘是否已添加如下:

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

由于我们将使用单个 RAID 组,因此这将用作整个 brick 的读取缓存,从而在读取 GlusterFS 卷的文件时提供更好的性能。

在节点上安装 GlusterFS

每个节点已经配置了砖块后,我们最终可以安装 GlusterFS。安装相对简单,只需要几个命令。

安装软件包

我们将使用 CentOS 提供的软件包。要安装 GlusterFS,我们首先安装存储库如下:

yum install -y centos-release-gluster41

然后,我们安装glusterfs-server软件包:

yum install -y glusterfs-server

然后,确保启用并启动glusterd服务:

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

这些命令需要在将成为集群一部分的每个节点上运行;这是因为每个节点都需要启用软件包和服务。

创建受信任的池

最后,我们需要创建一个受信任的池。受信任的池是将成为集群一部分的节点列表,其中每个 Gluster 节点都信任其他节点,从而允许创建卷。

要创建受信任的池,请从第一个节点运行以下代码:

gluster peer probe gfs2
gluster peer probe gfs3

您可以按以下方式验证节点是否显示:

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

该命令可以从任何节点运行,并且主机名或 IP 地址需要修改以包括其他节点。在这种情况下,我已将每个节点的 IP 地址添加到/etc/hosts文件中,以便进行简单的配置。理想情况下,主机名应该在 DNS 服务器上注册,以便在网络内进行名称解析。

安装完成后,gluster节点应允许创建卷。

创建卷

我们现在已经到达可以创建卷的阶段;这是因为我们已经配置了砖块并且安装了 GlusterFS 所需的软件包。

创建分散卷

我们将在三个节点之间使用分散卷类型,以实现高可用性和性能的良好平衡。所有节点的原始空间总共约为 1.5 TB;但是,分布式卷的可用空间将约为 1 TB。

要创建分散卷,请使用以下代码:

gluster volume create gvol1 disperse 3 gfs{1..3}:/bricks/brick1/gvol1

然后,使用以下代码启动卷:

gluster volume start gvol1

确保使用以下代码正确启动:

gluster volume status gvol1

现在应该显示卷如下:

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

挂载卷

卷现在已创建,并且可以在客户端上挂载;最好的方法是使用本机的glusterfs-fuse客户端进行此操作,它允许在其中一个节点宕机时自动进行故障转移。

要安装gluster-fuse客户端,请使用以下代码:

yum install -y glusterfs-fuse

然后,在根目录下创建一个名为gvol1的目录:

mkdir /gvol1

最后,我们可以按以下方式在客户端上挂载 GlusterFS 卷:

mount -t glusterfs gfs1:/gvol1 /gvol1

您指定的节点并不重要,因为可以从任何节点访问卷。如果其中一个节点宕机,客户端将自动将 I/O 请求重定向到剩余的节点。

优化性能

创建和挂载卷后,我们可以调整一些参数以获得最佳性能。主要是在文件系统级别(在本例中为 ZFS)和 GlusterFS 卷级别上进行性能调整。

GlusterFS 调优

在这里,主要变量是performance.cache-size。此设置指定要分配为 GlusterFS 卷的读取缓存的 RAM 量。默认情况下,它设置为 32 MB,这相当低。鉴于所选的 VM 具有足够的 RAM,可以使用以下命令将其提高到 4 GB:

gluster volume set gvol1 performance.cache-size 4GB

一旦集群开始增长,另一个重要的参数是performance.io-thread-count。这控制卷生成多少 I/O 线程。默认值为16个线程,对于中小型集群来说足够了。但是,一旦集群规模开始增大,可以将其加倍。要更改此设置,请使用以下命令:

gluster volume set gvol1 performance.io-thread-count 16

应该测试此设置,以检查增加计数是否改善性能。

ZFS

我们将主要更改两个设置:ARC 和 L2ARC feed 性能。

ARC

ZFS 的主要设置是其读取缓存,称为 ARC。允许分配更多的 RAM 给 ZFS 可以大大提高读取性能。由于我们已经为 Gluster 卷读取缓存分配了 4GB,并且 VM 有 32GB 可用,我们可以为 ZFS 分配 26GB 的 RAM,这将留下大约 2GB 给操作系统。

要更改 ARC 允许的最大大小,使用以下代码:

echo 27917287424 > /sys/module/zfs/parameters/zfs_arc_max

在这里,数字是以字节为单位的 RAM 数量,本例中为 26GB。这样做会即时更改设置,但不会使其持久化。要在引导时应用设置,创建一个名为/etc/modprobe.d/zfs.conf的文件,并添加以下值:

options zfs zfs_arc_max=27917287424

通过这样做,您可以使更改在引导时持久化。

L2ARC

L2ARC 是指第二级读取缓存;这是先前添加到 zpools 的缓存磁盘。改变数据馈送到缓存的速度有助于减少将常访问文件填充到缓存中所需的时间。该设置以每秒字节为单位指定。要更改它,可以使用以下命令:

echo 2621440000 > /sys/module/zfs/parameters/l2arc_max_write

与前面的设置一样,这适用于运行的内核。要使其持久化,将以下行添加到/etc/modprobe.d/zfs.conf文件中:

options zfs l2arc_write_max=2621440000

此设置允许最大 256MB/s 的 L2ARC feed;如果 VM 大小更改为更高级别,则应将设置至少增加一倍。

最后,您应该在每个节点上得到一个类似这样的文件:

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

关于 ZFS,在其他类型的文件系统上,改变块大小有助于提高性能。ZFS 具有可变的块大小,允许小文件和大文件实现类似的结果,因此无需更改此设置。

总结

安装 ZFS、创建 zpools、安装 GlusterFS 和创建卷后,我们得到了一个性能可观的解决方案,可以承受节点故障并仍然为其客户端提供数据。

对于设置,我们使用 Azure 作为云提供商。虽然每个提供商都有自己的一套配置挑战,但核心概念也可以在其他云提供商上使用。

然而,这种设计有一个缺点。当向 zpools 添加新磁盘时,条带不对齐,导致新的读取和写入产生较低的性能。通过一次添加整套磁盘可以避免这个问题;较低的读取性能大部分由 RAM 上的读取缓存(ARC)和缓存磁盘(L2ARC)覆盖。

对于 GlusterFS,我们使用了一个平衡性能和高可用性的分散布局。在这个三节点集群设置中,我们可以承受一个节点故障,而不会阻止来自客户端的 I/O。

主要的要点是在设计解决方案时要有批判性的思维。在这个例子中,我们利用现有的资源来实现一个符合规格并利用我们提供的配置的解决方案。确保您始终问自己这个设置将如何影响结果,以及如何更改它以使其更有效。

在下一章中,我们将测试和验证设置的性能。

问题

  • 什么是 GlusterFS 的 bricks?

  • 什么是 ZFS?

  • 什么是 zpool?

  • 什么是缓存磁盘?

  • 如何安装 GlusterFS?

  • 什么是受信任的池?

  • 如何创建 GlusterFS 卷?

  • 什么是 performance.cache-size?

  • 什么是 ARC?

进一步阅读

第五章:分析 Gluster 系统的性能

在第四章中,在云基础设施上使用 GlusterFS,我们已经完成了 GlusterFS 的工作实施,现在可以专注于解决方案的测试方面。我们将概述部署的情况,并解释选择组件背后的原因。

一旦配置被定义,我们可以通过测试性能来验证我们是否达到了预期的结果。然后,我们可以在执行 I/O 时故意关闭节点来进行可用性测试。

最后,我们将看到如何在垂直和水平两个方向上扩展解决方案。

在本章中,我们将涵盖以下主题:

  • 实施的高级概述

  • 进行性能测试

  • 性能可用性测试

  • 在垂直和水平两个方向上扩展解决方案

技术要求

本章的技术资源列表如下:

实施概述

在第四章中部署和配置了解决方案后,在云基础设施上使用 GlusterFS,我们可以验证实施的性能。主要目标是了解如何实现以及可用的工具。

让我们先退一步,看看我们实施了什么。

集群的概述

在第四章中,在云基础设施上使用 GlusterFS,我们在 Azure 的虚拟机VM)上部署了 GlusterFS 4.1 版本。我们使用 ZFS 作为砖块的存储后端,通过在三节点设置中每个节点使用四个磁盘。以下图表提供了这个分布的高级概述:

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

这个设置提供了 1TB 的可用空间。卷可以容忍整个节点宕机,同时仍然向客户端提供数据。

这个设置应该能够提供大约 375 兆字节每秒MB/s),同时处理数百个客户端,并且应该相当容易在垂直和水平两个方向上扩展。

性能测试

现在我们需要验证理论性能是否可以通过实际实施来实现。让我们将这个分解成几个部分。

性能理论

让我们根据设置的规格来确定应该获得多少性能。考虑到每个节点应该提供最大 125MB/s。磁盘子系统完全能够提供性能,因为每个磁盘产生 60MB/s。

总体可实现的性能应该在 375MB/s 左右,假设客户端可以通过发送或请求足够的数据到卷来跟上。

性能工具

我们将使用三种主要工具来验证和测试解决方案的性能:

  • zpool iostat

  • iostat

  • 灵活 I/O 测试工具FIO

这些工具每个都在不同的级别上工作。现在让我们详细说明每个工具的作用以及如何理解它们提供的信息。

ZFS zpool iostat 命令

ZFS 在后端卷级别上工作;zpool iostat -v命令为 ZFS 卷中的每个成员提供性能统计信息,并为整个 ZFS 卷提供统计信息。

该命令可以通过传递秒数来提供实时数据,它将在经过该时间段后迭代。例如,zpool iostat -v 1每秒报告磁盘统计信息。这里,-v选项显示池的每个成员及其各自的数据。

该工具有助于以尽可能低的级别呈现性能,因为它显示了来自每个磁盘、每个节点的数据:

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

请注意,我们使用了额外的-L-P选项,以便打印设备文件的绝对路径或通用唯一标识符UUID);这是因为我们使用每个磁盘的唯一标识符创建了池。

从前面的屏幕截图中,我们可以看到四个主要组,如下:

  • pool: 这是使用每个成员创建的。

  • capacity: 这是分配给每个设备的空间量。

  • operations: 这是在每个设备上执行的 IOPS 数量。

  • bandwidth: 这是每个设备的吞吐量。

在第一行中,该命令打印自上次启动以来的统计信息。请记住,该工具有助于从 ZFS 池级别呈现性能。

iostat

作为sysstat软件包的一部分,iostat提供了来自每个设备的低级性能统计数据。iostat绕过文件系统和卷,并呈现系统中每个块设备的原始性能数据。

iostat工具可以使用选项运行,以更改在屏幕上打印的信息,例如,iostat -dxctm 1。让我们探讨每个部分的作用:

  • iostat: 这是主要命令。

  • d: 这打印设备利用率。

  • x: 这显示扩展设备统计信息。

  • c: 这显示了 CPU 利用率。

  • t: 这显示每个报告打印的时间。

  • m: 这确保统计数据以 MB/s 显示。

  • 1: 这是iostat打印数据的时间,以秒为单位。

在下面的屏幕截图中,您可以看到iostat以不同的列显示信息:

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

没有必要浏览所有列,但最重要的列如下:

  • Device: 这显示系统上存在的块设备。

  • r/s: 这些是每秒的读取操作。

  • w/s: 这些是每秒的写入操作。

  • rMB/s: 这些是从设备读取的 MB/s。

  • wMB/s: 这些是写入设备的 MB/s。

  • r_await: 这是读取请求的平均时间(毫秒)。

  • w_await: 这是写请求的平均时间(毫秒)。

r_awaitw_await列与avg-cpu %iowait时间一起是必不可少的;这是因为这些指标可以帮助确定是否有一个设备的延迟增加超过其他设备。高 CPU iowait时间意味着 CPU 不断等待 I/O 完成,这反过来可能意味着块设备具有较高的延迟。

iostat工具可以在集群中的每个节点上运行,为组成 GlusterFS 卷的每个磁盘提供低级别统计信息。

有关其他列的详细信息可以在iostat的 man 页面上找到。

FIO 测试员

FIO 是一个基准测试工具,用于通过生成合成工作负载进行性能测试,并提供 I/O 指标摘要。

请注意,fio在 CentOS 上不是默认安装的,但它可以在基本存储库中找到,并且可以通过运行sudo yum install -y fio来安装。

这个工具非常有用,因为它允许我们执行接近系统实际工作负载的测试——通过允许用户更改块大小、文件大小和线程数量等参数。FIO 可以提供接近真实性能的数据。这种定制水平可能会让人感到困惑,因为它提供了许多工作负载模拟选项,一些选项一开始并不直观。

使用 FIO 进行测试的最简单方法是创建一个配置文件,告诉软件如何行为;配置文件看起来像这样:

[global]
name=rw-nocache-random
rw=randrw
rwmixread=50
rwmixwrite=50
group_reporting=1
bs=1M
direct=1
numjobs=4
time_based=1
runtime=180
ioengine=libaio
iodepth=64

[file1]
size=10G
filename=rw-nocache-random.1

让我们分解一下,以便了解配置文件的每个部分是如何工作的:

  • [global]:这表示影响整个测试的配置参数(可以设置单个文件的参数)。

  • name=:这是测试的名称;可以是任何有意义的名称。

  • rw=randrw:这告诉 FIO 要执行什么类型的 I/O;在这种情况下,它执行随机读写。

  • rwmixreadrwmixwrite:这告诉 FIO 执行读写的百分比或混合比例——在这种情况下,是 50-50 的混合比例。

  • group_reporting=1:这用于为整个测试提供统计信息,而不是为每个作业提供统计信息。

  • bs=1M:这是 FIO 在执行测试时使用的块大小;可以将其更改为模拟预期工作负载的值。

  • numjobs=4:这控制每个文件打开多少个线程。理想情况下,可以用来匹配将使用存储的用户或线程的数量。

  • runtime=180:这控制测试运行的时间,以秒为单位。

  • ioengine=libaio:这控制要使用的 I/O 引擎类型。最常见的是libaio,因为它最接近大多数工作负载。

  • iodepth=64:这控制测试的 I/O 深度;较高的数字允许存储设备充分利用。

最后,文件组控制创建测试文件的数量和它们的大小。可以向该组添加某些设置,例如iodepth,这些设置仅影响定义了该参数的文件。另一个考虑因素是,fio根据numjobs参数为每个文件打开一个线程。在前面的配置中,它将打开总共 16 个线程。

要运行 FIO,只需进入挂载点所在的目录,并将其指向配置文件,如下所示:

cd /gvol1
fio /root/test.fio

请注意,FIO 需要 root 权限,因此请确保使用sudo来运行 FIO。

在 FIO 运行时,它会显示吞吐量和 IOPS 等统计信息:

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

完成后,FIO 会在屏幕上报告测试统计信息。要查找的主要内容是读写操作的 IOPS 和带宽。

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

从测试结果中,我们可以看到 GlusterFS 卷可以同时维持约 150MB/s 的读写操作。我们与集群的理论最大性能相差 75MB/s;在这种特定情况下,我们达到了网络限制。

FIO 在验证性能和检测问题方面非常有效;fio可以在挂载 Gluster 卷的客户端上运行,也可以直接在每个节点的存储单元上运行。您可以使用 FIO 来测试现有解决方案,以验证性能需求;只需确保根据需要测试的内容更改 FIO 配置中的设置。

GlusterFS 提供了一些工具,可以从卷的角度监视性能。这些工具可以在 GlusterFS 的文档页面上找到,位于监视工作负载下。

可用性测试

确保集群能够容忍节点宕机是至关重要的,因为我们可以确认如果节点丢失,不会发生停机。

这可以通过强制关闭其中一个节点来完成,而其他节点继续提供数据。为了作为合成工作负载,我们可以使用 FIO 在关闭其中一个节点时执行连续测试。

在下面的屏幕截图中,我们可以看到gfs2节点不存在,但 FIO 测试继续按预期提供数据:

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

扩展

这种设置的扩展相对简单。如前所述,我们可以通过在每个节点上添加更多磁盘来纵向扩展,或者通过在集群中添加更多节点来横向扩展。

纵向扩展比横向扩展要简单得多,因为它需要更少的资源。例如,如果在每个节点上将单个磁盘添加到 ZFS 池中,则可以将可用空间增加 256 GB,如果添加了三个 128 GB 磁盘。

可以使用以下命令将磁盘添加到 ZFS 池中:

zpool add brick1 /dev/disk/by-id/<disk-id>

从前一个命令中,brick1是池的名称,disk-id是最近添加的磁盘的 UUID。

横向扩展需要在新节点上镜像完全相同的设置,然后将其添加到集群中。这需要一组新的磁盘。优点是可用空间和性能将相应增长。

摘要

在本章中,我们概述了前一章第四章中完成的实施,即在云基础架构上使用 GlusterFS,以便我们可以对实施的内容有一个新的理解,以便了解我们如何测试性能。根据先前的设置,实施应该能够实现理论上的 375 MB/s 吞吐量。我们可以使用几个在不同级别工作的工具来验证这个数字。

对于 ZFS 卷,我们可以使用zpool iostat命令,该命令提供 ZFS 卷的每个块设备的数据。iostat可用于确定系统中存在的所有块设备的性能。这些命令只能在集群的每个节点上运行。为了验证实现的实际性能,我们使用了 FIO 工具,该工具可以通过更改 I/O 执行方式的参数来模拟特定的工作负载。该工具可用于每个节点的砖级别,或者在 GlusterFS 卷上的每个 Gluster 客户端上,以获得集群可实现的性能的概述。

我们已经了解了如何通过有意关闭其中一个节点并通过 FIO 执行测试来执行可用性测试。最后,可以通过纵向扩展(在每个节点的每个卷中添加磁盘)或横向扩展(在集群中添加一个全新节点)来扩展解决方案。您从本章的主要收获是考虑如何使用广泛可用的工具来验证已实施的配置。这只是一组工具。可能还有许多其他工具可用,这些工具可能更适合您正在实施的解决方案。

在下一章中,我们将介绍创建高可用性自愈架构。

问题

  1. MB/s 是什么?

  2. zpool iostat是什么?

  3. 我在哪里可以运行zpool iostat

  4. iostat是什么?

  5. r_await是什么意思?

  6. CPU IOWAIT 时间是什么?

  7. FIO 是什么?

  8. 我怎样才能运行 FIO?

  9. FIO 配置文件是什么?

  10. 我怎样才能在 Gluster 集群中验证可用性?

  11. 我怎样才能纵向扩展?

进一步阅读

第二部分:使用 Kubernetes 构建高可用性 Nginx Web 应用程序

在本节中,读者将学习了解使用 Kubernetes 作为部署和管理容器化应用程序的编排器的优势,以及如何部署这样的解决方案。

本节包括以下章节:

  • [第六章],创建高可用性的自愈架构

  • [第七章],理解 Kubernetes 集群的核心组件

  • [第八章],设计 Kubernetes 集群

  • [第九章],部署和配置 Kubernetes

第六章:创建高可用的自愈架构

在本章中,我们将介绍 IT 行业是如何从使用单片应用程序发展到云原生、容器化和高可用的微服务的。

通过开源,我们可以提供解决方案,使我们能够根据用户消费量创建高可用性和按需扩展我们的应用程序。

我们将在本章中涵盖以下主题:

  • 描述微服务

  • 为什么容器是微服务的家园

  • 我们如何可以编排我们的容器

  • 探索开源中最常用的编排器 Kubernetes。

微服务

微服务用于以模块化方式设计应用程序,其中每个模块都独立部署,并通过 API 相互通信。所有这些模块共同工作,以交付一个单一应用程序,其中每个功能都有其自己的目的。

例如,让我们看看一个在线商店。我们只能看到主网站;然而,在后台有几个微服务起作用,一个服务用于接受订单,另一个根据您以前的浏览推荐物品,支付处理,评论处理等等。

以下图表是微服务应用程序的一个示例:

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

从本质上讲,微服务应用程序不需要一个庞大的团队来支持整个应用程序。一个团队只支持整体图景中的一个或两个模块,从而在支持和专业知识方面创造了更细粒度的方法。支持和开发不仅是细粒度的,还存在故障。在单个微服务故障的情况下,只有应用程序的那一部分会失败。

继续我们的在线商店示例,假设处理评论和评论的微服务失败了。这是因为我们的网站是使用微服务构建的,所以我们网站的只有那个组件将对我们的客户不可用。

然而,他们仍然可以继续购买和使用网站,而用户将无法看到他们感兴趣的产品的评论,这并不意味着我们整个网站的可用性受到损害。根据问题的原因,您可以修补微服务或重新启动它。不再需要为了修补或重新启动整个网站。

作为基础架构工程师,您可能会想,为什么我必须知道什么是微服务或它的好处?原因很简单。作为架构师或基础架构工程师,您正在为这种类型的应用程序构建基础架构。无论它们是在单个主机上运行的单片应用程序,还是在多个容器中分布的微服务,它肯定会影响您设计客户架构的方式。

Linux 将是您的好朋友,因为您将找到多个开源工具,将帮助您维护高可用性、负载平衡和持续集成CI)/持续交付CD),使用 Docker、Kubernetes、Jenkins、Salt 和 Puppet 等工具。因此,每当客户询问您应该从哪个操作系统环境开始设计他的微服务应用程序时,Linux 将是您的答案。

目前,Docker Swarm 和 Kubernetes 在容器编排方面处于领先地位。在微服务方面,当为客户设计基础架构时,容器也将是您的首选。

我们将在第七章中深入探讨 Kubernetes,了解 Kubernetes 集群的核心组件,并展示它如何帮助您编排和交付一个优雅而复杂的解决方案,用于托管微服务和其他类型的应用程序。

然而,在谈论 Kubernetes 或容器编排之前,我们需要解释容器的概念,以便理解为什么它们非常适合托管微服务应用程序。

Linux 中的容器已经有一段时间了,但直到几年前(随着 Docker Engine 的发布),它们才在所有技术社区中获得了动力和赞誉。容器在合适的时间出现了,并随着微服务架构的兴起而留了下来,并且正在塑造我们设计和执行它的方式。

让我们退一步,以便您了解这种技术的好处。想象一下,您有一个简单的单体应用程序,它正在运行一个 API,您可以从中查询用户列表以及他们从您托管的网站购买的商品。

过了一段时间,您的客户发现他们的 API 在其他应用程序中变得非常受欢迎,这些应用程序现在在高峰时段进行数千次 HTTP GET请求。当前的基础设施无法处理如此多的请求,因此您的客户要求您以一种可以处理更多请求的方式扩展他们的基础设施。问题在于,因为这是一个单体应用程序,您不仅需要计算 API 所需的资源,还需要考虑与 API 一起托管的网店前端,即使 API 是您实际上需要扩展的唯一内容。

这将是一种资源浪费,因为您还将包括不需要任何额外副本或资源的网店前端。您正在浪费宝贵的,有时是昂贵的(如果您在公共云中)存储、内存和 CPU 资源,用于一些实际上并不需要的东西。

因此,这就是微服务和为托管这种类型的应用程序而设计的容器发挥作用的地方。使用容器镜像中的微服务,您无需每次需要扩展服务以满足需求时都要提供新的服务器,也无需重新启动服务器,或者在执行应用程序或操作系统更新时每次都要处理软件包依赖关系。只需使用一个简单的命令(docker container run companyreg.io/storeapi:latest),您的应用程序就可以启动并准备好提供请求。同样,如果您的应用程序失败,只需重新启动容器或提供一个新的容器,您就可以继续进行。如果对微服务进行的更新存在错误,只需回滚到以前的镜像版本,您就可以重新启动;无需开始卸载更新的库或处理依赖关系问题。

容器还允许应用程序部署的一致性,因为您可能知道,有多种安装软件包的方式。您可以通过aptyumapk等软件包管理器进行安装,也可以通过git/curl/wgetpipjuju进行安装,取决于您的安装方式,也将定义您的维护方式。

想象一下,开发人员将其软件包发送给开放性分析标准OPS)团队进行部署,每个 OPS 工程师以不同的方式部署应用程序!这将变得难以支持和跟踪。具有您的应用程序的容器镜像将创建一致性,因为无论您将其部署为容器的位置在哪里,它都将在所有部署的地方具有相同的位置,用于所有配置文件、二进制文件、库和依赖项。所有内容都将被隔离到一个具有自己的进程命名空间PID 命名空间)、网络命名空间和挂载命名空间MNT 命名空间)的容器中。

将应用程序架构为微服务的目的是为了为应用程序中的每个微服务提供隔离,以便它们可以轻松管理和维护——容器正好实现了这一点。你甚至可以定义每次容器启动时如何启动应用程序——一致性在这里起着主导作用。

创建容器镜像

构建容器的方式是通过一个叫做Dockerfile的东西。Dockerfile 基本上是一组关于如何构建容器镜像的指令;一个典型的 Dockerfile 如下所示:

FROM ubuntu:latest
LABEL maintainer="WebAdmin@company.com"

RUN apt update
RUN apt install -y apache2
RUN mkdir /var/log/my_site

ENV APACHE_LOG_DIR /var/log/my_site
ENV APACHE_RUN_DIR /var/run/apache2
ENV APACHE_RUN_USER www-data
ENV APACHE_RUN_GROUP www-data

COPY /my_site/ /var/www/html/

EXPOSE 80

CMD ["/usr/sbin/apache2","-D","FOREGROUND"]

如你所见,这是一组非常易读的指令。即使不知道每个指令的作用,我们也可以假设它的功能,因为它非常类似于英语。这个 Dockerfile 只是一个例子,迄今为止是最有效的方法。

镜像本质上就像虚拟机VM)世界中的模板;它是一组只读层,包含了部署容器所需的所有信息——从单个镜像中,你可以部署多个容器,因为它们都在自己的可写层上运行。

例如,每当你拉取一个镜像,你会看到以下输出:

[dsala@redfedora ~]# docker pull httpd:latest
latest: Pulling from library/httpd
d660b1f15b9b: Pull complete
aa1c79a2fa37: Pull complete
f5f6514c0aff: Pull complete
676d3dd26040: Pull complete
4fdddf845a1b: Pull complete
520c4b04fe88: Pull complete
5387b1b7893c: Pull complete
Digest: sha256:8c84e065bdf72b4909bd55a348d5e91fe265e08d6b28ed9104bfdcac9206dcc8
Status: Downloaded newer image for httpd:latest

你看到的每个Pull complete实例对应着镜像的一个层。那么,这些层是什么,它们来自哪里呢?

当我们构建镜像时,我们在 Dockerfile 中定义的一些指令将创建一个新的层。文件中的每个指令都在容器中的读写层中执行,在构建结束时,将提交到最终层堆栈,形成最终镜像。需要注意的是,即使构建过程中的每个指令都在容器中执行,并非所有命令都会创建数据,使得镜像在大小和层面上变得更大——其中一些只会写入到所谓的镜像清单中,这本质上是一个包含所有镜像元数据的文件。

让我们更深入地探讨每个命令。

FROM

FROM指令指示了你的初始镜像是什么,基本上是你将开始构建自己镜像的基础。

你在这里放置的内容将取决于你的需求,例如,哪个镜像预先安装了我应用程序需要的库,哪个镜像已经安装了我需要编译应用程序的编译器,或者哪个镜像对我们最终大小的影响最小。例如,你的应用程序是基于 Python 2 构建的。你可以直接使用python:2.7镜像,而不是使用 CentOS 或 Ubuntu 作为初始镜像,然后手动安装 Python,因为它已经预先安装了 Python。

显然,这里还有更多需要考虑的事情,但我们将在本章后面讨论镜像构建的最佳实践时再详细介绍。

由于这个指令会使用另一个镜像作为基础,你的最终镜像将继承基础镜像的层;因此,最终层的总数将如下所示:

最终镜像层 = 基础镜像层 + 你创建的层

LABEL

LABEL指令非常直观——它使用键值对为你的镜像添加元数据标签,稍后可以通过docker inspect命令检索。你可以使用它来添加用户需要知道的数据。通常用于添加镜像作者的信息,比如他们的电子邮件或公司:

LABEL maintener="john.doe@company.com"

由于这个指令只是元数据,不会为你的镜像添加额外的层。

RUN

使用RUN,你将运行需要准备容器来运行你的应用程序的命令;例如,安装软件包、编译代码,创建用户或目录。RUN有两种运行命令的方式。

shell 形式如下:

 RUN <command>

在这种形式下,默认情况下所有命令都将使用/bin/sh -c shell 运行,尽管你可以使用SHELL指令来更改 shell,如下所示:

 SHELL ["/bin/bash", "-c"]
 RUN echo "Hello I'm using bash" 

SHELL关键字只能以 JSON 数组格式运行,这导致我们可以使用第二种形式来运行RUN指令。

执行形式如下:

RUN ["echo","hello world"]

这里的主要区别,除了格式之外,在执行形式中不会调用 shell,因此不会发生正常的变量替换——相反,您必须调用 shell 作为 shell 的命令,以便 shell 能够提供变量扩展:

 RUN ["/bin/bash","-c","echo $HOME"]

由于RUN关键字的性质,每个实例都将在新层上执行并提交到最终图像,因此,每次使用RUN都会向图像添加一个新层。

ENV

对于ENV,没有太多可说的——这个指令为环境设置变量。它们将在构建时使用,并在容器运行时可用。ENV不会为容器生成额外的层,因为它将环境变量存储在图像清单中作为元数据:

 ENV <key>=<value>

ENV的参数以<key> /<value>对的形式处理,其中<key>参数是变量名,<value>参数是其内容或值。您可以使用=符号声明它们,也可以不使用。引号和反斜杠可用于转义值字段中的空格。

以下所有变体都是有效的:


ENV USER="Jane Doe"  

ENV USER=Jane\ Doe

ENV USER Jane Doe

COPY

使用COPY,我们可以将文件或目录从本地主机(执行 Docker 构建的位置)复制到我们的图像中。这非常有用,因为您实际上正在将内容移动到图像中,以便您可以复制应用程序、文件或任何可能需要的内容以使容器工作。正如我们之前提到的,任何向容器添加实际数据的指令都将创建一个新层,因此会增加最终图像的存储占用。

此指令与RUN具有相同的形式;您可以使用 JSON 格式化,也可以将<src>源分开放置到<dst>目的地:

 COPY <src>  <dst>
 COPY ["<src1>","<src2>","<dst>"]

有几个陷阱我们需要经历。首先,如果任何文件名或目录名中有空格,您必须使用 JSON 数组格式。

其次,默认情况下,所有文件和目录都将以用户标识符UID)和组标识符GID0(root)复制。要覆盖此设置,可以使用--chown=<UID>:<GID>标志,如下所示:

 COPY --chown=JANE:GROUP <src> <dst> 

chown接受数字 ID 或用户或组的名称。如果只有其中一个,则定义如下:

COPY --chown=JANE <src> <dst> 

COPY将假定用户和组都是相同的。

如果要复制名称相似的文件,则可以始终使用通配符——COPY将使用 Go 的filepath.Match规则,该规则可以在golang.org/pkg/path/filepath#Match找到。

定义<src><dst>条目的方式非常重要,因为它们遵循以下三条规则:

  • <src>中定义的路径必须在构建的上下文中,基本上,所有位于您运行 Docker 构建PATH命令时指定的目录中的文件和目录。

  • 如果要复制目录,则始终以/结尾。这样,Docker 就知道这是一个目录,而不是要复制的单个文件。此外,如果是目录,则其中的所有文件也将被复制。

  • <dst>中定义的路径将始终是绝对路径,除非您使用WORKDIR指令指定相对于的工作目录。

最后要说的是COPY指令,我必须补充的是COPY只支持复制本地文件。如果要使用 URL 从远程服务器复制文件,必须使用ADD指令,它遵循与COPY相同的规则,但对于 URL 还有一些其他注意事项。这超出了本章的范围,但您可以在docs.docker.com了解更多信息。

EXPOSE

使用EXPOSE关键字,我们实际上并没有发布我们在这里指定的容器端口;相反,我们正在为容器的用户创建一个指南,让他们知道在启动容器时应该发布哪些端口。

因此,这只是在图像的清单中再次创建的元数据,稍后可以使用docker inspect检索。不会使用此关键字创建其他图层。

EXPOSE指令中定义的端口可以是用户数据报协议UDP)或传输控制协议TCP),但是,默认情况下,如果未指定协议,则假定为 TCP。

以下是一些EXPOSE指令的示例:

 EXPOSE 80
  EXPOSE 53/udp
  EXPOSE 80/tcp

CMD 和 ENTRYPOINT

这可能是 Dockerfile 中最重要的指令,因为它们告诉容器在启动时要运行什么。我们将逐个讨论它们,并探讨它们如何相互作用以及它们之间的区别。

让我们先从ENTRYPOINT开始。正如我们之前提到的,这个指令允许您定义启动容器时要运行的可执行文件。您可以在 Dockerfile 中添加多个ENTRYPOINT定义,但只有最后一个会在docker container run上执行。

当您使用run参数运行容器时,通常可以添加命令行参数。除非您在使用docker container run时使用--entrypoint标志覆盖ENTRYPOINT可执行文件,否则这些参数将被追加到ENTRYPOINT参数。

让我们看一些例子。假设我们正在使用一个具有以下 Dockerfile 的容器:

 FROM alpine
 ENTRYPOINT ["echo","Hello from Entrypoint"]

现在,假设我们构建了图像并将其标记为entrypointexample。当我们在不带额外命令行参数的情况下运行此容器时,它将显示如下:

[dsala@redfedora]# docker container run entrypointexample
Hello from Entrypoint

如果我们向run命令添加命令行参数,我们将看到类似这样的东西:

[dsala@redfedora]# docker container run entrypointexample /bin/bash
Hello from Entrypoint /bin/bash

正如您所看到的,它实际上并没有执行 BASH shell,而是将/bin/bash作为我们在 Dockerfile 中定义的echo命令的字符串。让我们考虑一个更明确的例子,因为前一个例子中,我只是想演示即使您传递了实际命令或尝试执行 shell,它仍然会将其作为ENTRYPOINT的参数传递。这是一个更清晰的例子,带有一个简单的字符串:

[dsala@redfedora]# docker container run entrypointexample I AM AN ARGUMENT
Hello from Entrypoint I AM AN ARGUMENT

现在,如果我们传递--entrypoint标志,我们将覆盖ENTRYPOINT可执行文件:

[dsala@redfedora]# docker container run --entrypoint /bin/ls entrypointexample -lath /var
total 0
drwxr-xr-x    1 root root           6 Aug 8 01:22 ..
drwxr-xr-x   11 root root         125 Jul 5 14:47 .
dr-xr-xr-x    2 root root           6 Jul 5 14:47 empty
drwxr-xr-x    5 root root          43 Jul 5 14:47 lib
drwxr-xr-x    2 root root           6 Jul 5 14:47 local
drwxr-xr-x    3 root root          20 Jul 5 14:47 lock
drwxr-xr-x    2 root root           6 Jul 5 14:47 log
drwxr-xr-x    2 root root           6 Jul 5 14:47 opt
lrwxrwxrwx    1 root root           4 Jul 5 14:47 run -> /run
drwxr-xr-x    3 root root          18 Jul 5 14:47 spool
drwxrwxrwt    2 root root           6 Jul 5 14:47 tmp
drwxr-xr-x    4 root root          29 Jul 5 14:47 cache

好的,那么为什么这个命令的格式是这样的呢?正如我们之前看到的,--entrypoint标志只替换可执行文件——所有额外的参数都必须作为参数传递。这就是为什么我们的ls在最后有-lath /var参数的原因。这里还有一些其他需要注意的地方,它们对应于ENTRYPOINT指令的形式。

与其他 Dockerfile 指令一样,ENTRYPOINT有两种形式,shell 和 exec:

 ENTRYPOINT command argument1 argument2 
 ENTRYPOINT ["executable", "param1", "param2"]

对于 exec 形式,适用于之前 Dockerfile 指令的相同规则也适用于这里。

在 exec 形式中不会调用 shell,因此$PATH变量不存在,您将无法在不提供完整路径的情况下使用可执行文件——这就是为什么我们使用/bin/ls而不是ls。此外,您可以看到您首先在 JSON 数组中定义可执行文件,然后是其参数,这个第一个字段是--entrypoint标志将替换的内容。在使用该标志时,任何额外的参数都必须作为docker container run命令参数传递,就像我们在示例中所做的那样。

另一方面,shell 形式将加载/bin/sh,以便环境变量可用。让我们看一个例子;这是一个使用 exec 形式的 Dockerfile 的容器:

FROM alpine
ENTRYPOINT ["echo", "$PATH"]

假设我们构建了图像并将其标记为pathexampleexec。当我们运行容器时,我们将看到以下内容:

[dsala@redfedora]#docker container run pathexampleexec
$PATH

这是一个使用 shell 形式的 Dockerfile 的容器:

FROM alpine
ENTRYPOINT echo $PATH

当我们运行容器时,我们将看到以下内容:

 [dsala@redfedora]# docker container run pathexampleshell
 /usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin

现在,假设您想为应用程序设置一些默认参数,但是您希望用户能够覆盖并使用不同的参数。这就是CMD的作用;使用CMD,您可以为可执行文件指定默认参数,但如果用户在docker container run上运行容器时使用命令参数,这些参数将被覆盖。您必须小心声明ENTRYPOINT,因为如果使用 shell 形式声明ENTRYPOINT,所有CMD定义将被忽略。

让我们看几个例子;以下是要运行的容器的 Dockerfile:

 FROM alpine
 ENTRYPOINT echo Hello
 CMD ["I'm Ignored"]

假设先前提到的容器已构建并标记为cmdexample,下面是其运行情况:

[dsala@redfedora]# docker container run cmdexample
Hello

现在,如果我们对ENTRYPOINT使用执行形式,CMD 参数将被附加到ENTRYPOINT。参考 Dockerfile:

 FROM alpine
  ENTRYPOINT ["echo", "hello from ENTRY"]
  CMD ["hello", "from CMD"]

假设镜像已构建并标记为execcmdexample,以下是输出:

[dsala@redfedora]# docker container run execcmdexmple
hello from ENTRY hello from CMD

请注意,这次CMD条目被附加到ENTRYPOINT作为参数。但是,请记住,CMD的内容只是默认值;如果我们在docker container run上指定参数,这些参数将覆盖CMD中的参数。

使用与前面示例相同的 Dockerfile,我们将得到类似以下的内容:

[dsala@redfedora]# docker container run execcmdexmple "hello" "from" "run"
 hello from ENTRY hello from run

CMDENTRYPOINT之间有几种组合,您可以在以下来自docs.docker.com的图表中看到所有这些组合:

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

使用最佳实践构建容器镜像

Dockerfiles are like recipes for your applications, but you can’t just throw in the ingredients and hope for the best. Creating an efficient image requires you to be careful about how you utilize the tools at your disposal.

容器的整个目的是占用空间小 - 对于 100 MB 应用程序来说,拥有 1 GB 以上的镜像并不代表占用空间小,也不高效。微服务也是如此;为微服务拥有小的容器镜像不仅提高了性能,而且存储利用率降低了安全漏洞和故障点,并且还能节省金钱。

容器镜像在主机本地和容器注册表中存储。公共云提供商根据注册表的存储利用率收取费用,而不是根据您在其中存储的镜像数量收费。想象一下注册表就像容器的 GitHub。假设您必须从云提供商的注册表中拉取镜像;您认为拉取 1 GB 镜像还是 100 MB 镜像会更快?镜像大小很重要。

构建镜像时要考虑的第一件事是要使用的基础镜像。不要使用大型镜像(如完整的 Linux 发行版,Ubuntu,Debian 或 CentOS),因为这些镜像有很多工具和可执行文件,您的应用程序不需要运行,而是使用较小的镜像,例如 Alpine:

**REPOSITORY **SIZE
centos200 MB
ubuntu83.5 MB
debian101 MB
alpine 4.41 MB

您会发现大多数镜像都有自己的精简版本,例如httpdnginx

REPOSITORYTAGSIZE
httpdalpine91.4 MB
httpdlatest178 MB
nginxalpine18.6 MB
nginxlatest109 MB

正如您所看到的,httpd:alpine几乎比httpd:latest小了 50%,而nginx:alpine小了 80%!

更小的镜像不仅会减少存储消耗,还会减少攻击面。这是因为较小的容器具有较小的攻击面;让我们看看最新的 Ubuntu 镜像与最新的 Alpine 镜像。

对于 Ubuntu,我们可以看到最新标签的漏洞数量增加了;以下是 Docker Hub 页面的截图:

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

对于 Alpine Linux,计数降至零,如下截图所示:

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

在上面的截图中,我们可以看到与 Ubuntu 相比的漏洞计数。即使在今天,最新的 Alpine 图像也没有任何漏洞。相比之下,Ubuntu 有七个不需要的组件存在漏洞,这些组件甚至不需要我们的应用程序运行。

另一件需要考虑的事情是图像的分层;每次在构建中运行RUN语句时,它都会添加一个更多的层和大小到最终图像中。减少RUN语句的数量以及在其中运行的内容将大大减少图像的大小。

让我们看看我们的第一个 Dockerfile,如下所示:

    FROM ubuntu:latest
    LABEL maintainer="WebAdmin@company.com"

    RUN apt update
    RUN apt install -y apache2
    RUN mkdir /var/log/my_site

    ENV APACHE_LOG_DIR /var/log/my_site
    ENV APACHE_RUN_DIR /var/run/apache2
    ENV APACHE_RUN_USER www-data
    ENV APACHE_RUN_GROUP www-data

    COPY /my_site/ /var/www/html/

    EXPOSE 80

    CMD ["/usr/sbin/apache2","-D","FOREGROUND"]

我们可以将RUN指令修改为以下方式:

RUN apt update && \
      apt install -y apache2 --no-install-recommends && \
      apt clean && \
      mkdir /var/my_site/ /var/log/my_site

现在,我们将不再创建三个层,而是通过在单个语句中运行所有命令来产生一个层。

请记住,在RUN中执行的所有操作都是使用/bin/sh -c或您在SHELL中指定的任何其他 shell 来执行的,因此&;\都会被接受,就像在常规 shell 中一样。

然而,我们不仅删除了额外的RUN指令;我们还添加了apt clean来清理容器的缓存,然后使用了--no-install-recommend标志来避免安装任何不必要的软件包,从而减少了存储空间和攻击面:

以下是原始图像的详细信息:

仓库大小
bigimage221 MB

以下是较小图像的详细信息:

仓库大小
smallerimage214 MB

当然,这并不是一个巨大的差异,但这只是一个例子,没有安装任何真正的应用程序。在生产图像中,您将不得不做的不仅仅是安装apache2

现在让我们使用我们学到的两种技术,来精简我们的图像:

FROM alpine

RUN apk update && \
      apk add mini_httpd && \
       mkdir /var/log/my_site

COPY /my_site/ /var/www/localhost/htdocs/
EXPOSE 80

CMD ["/usr/sbin/mini_httpd", "-D", "-d", "/var/www/localhost/htdocs/"]

这是图像的最终大小:

仓库大小
finalimage5.79 MB

现在,您可以看到大小上有很大的差异——我们从 221 MB 减少到 217 MB,最终得到了一个 5.79 MB 的图像!这两个图像都完成了完全相同的任务,即提供网页服务,但占用的空间完全不同。

容器编排

现在我们知道如何创建我们的图像,我们需要一种方法来维护我们应用程序的期望状态。这就是容器编排器的作用。容器编排器回答了以下问题:

  • 如何维护我的应用程序,使其具有高可用性?

  • 如何根据需求扩展每个微服务?

  • 如何在多个主机之间负载均衡我的应用程序?

  • 如何限制我的应用程序在主机上的资源消耗?

  • 如何轻松部署多个服务?

使用容器编排器,管理您的容器从未像现在这样简单或高效。有几种编排器可用,但最常用的是 Docker Swarm 和 Kubernetes。我们将在本章后面讨论 Kubernetes,并深入了解第七章中的核心组件。

所有编排器共同之处在于它们的基本架构是一个由一些主节点组成的集群,这些主节点监视您的期望状态,并将其保存在数据库中。主节点将根据工作节点的状态启动或停止容器,工作节点负责容器工作负载。每个主节点还负责根据您预定义的要求来指示哪个容器必须在哪个节点上运行,并根据需要扩展或重新启动任何失败的实例。

然而,编排器不仅通过重新启动和按需启动容器来提供高可用性,Kubernetes 和 Docker Swarm 还具有控制流量到后端容器的机制,以便为应用程序服务的传入请求提供负载均衡。

以下图表展示了流向编排集群的流量:

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

让我们更深入地探索 Kubernetes。

Kubernetes

Kubernetes 目前是迄今为止最受欢迎的容器编排器。许多公共云提供商现在将其作为事实上的容器编排器采用;例如,Azure 的Azure Kubernetes ServicesAKS),亚马逊网络服务的弹性容器服务 for KubernetesEKS),以及谷歌云的Google Kubernetes EngineGKE)。这些解决方案大多是托管的,为用户抽象出管理平面,以便使用,并采用与公共云负载均衡器和 DNS 服务集成的云原生解决方案。

Kubernetes 处于平台即服务PaaS)解决方案和基础设施即服务IaaS)解决方案之间,因为它为您提供了一个运行容器和管理数据的平台,但它仍然允许您提供软件定义的基础设施,如负载均衡器、网络管理、入口控制和资源分配。

通过 Kubernetes,我们可以自动化部署容器的过程,并在控制资源消耗的同时保持所需的状态,同时为不同的应用程序提供高可用性和隔离。

Kubernetes 具有我们之前提到的基本编排器组件;它有工作节点、主节点和保存集群状态的数据库。我们将在第七章中深入探讨 Kubernetes 的概念,理解 Kubernetes 集群的核心组件

以下图表显示了 Kubernetes 的基本架构:

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

总结

在本章中,我们讨论了 IT 是如何从单块设计演变为微服务的,并且容器如何帮助我们通过允许模块化基础架构来实现这种架构。我们以在线商店为例,演示了微服务如何允许特定组件的可伸缩性,而无需关闭整个应用程序。此外,我们探讨了相同示例如何通过讨论微服务方法允许应用程序的一部分失败而不影响整个解决方案的高可用性设计(即,只有评论部分失败而不会导致整个在线商店崩溃)。

随后,我们学习了容器是如何通过 Dockerfile 从镜像创建的,Dockerfile 使用可读的一组指令来创建基础镜像。在 VM 的背景下,镜像可以被视为模板的对应物。

从这个 Dockerfile 中,我们学到了FROM语句表示初始镜像是什么,LABEL指令如何向容器添加元数据,RUN如何执行需要准备容器运行应用程序的命令,以及ENV如何设置用于构建容器的环境变量。

此外,我们讨论了构建容器镜像时的一些最佳实践,例如使用更小的镜像(如 Alpine),以及选择更小的镜像如何帮助减少构建容器中存在的漏洞数量。

最后,我们简要地介绍了一些更受欢迎的编排工具,如 Docker Swarm 和 Kubernetes。

在下一章中,我们将深入探讨 Kubernetes 集群的核心组件。

问题

  1. Kubernetes 的组件是什么?

  2. GKE、EKS 和 AKS 之间有什么区别?

  3. 容器免受利用的安全性有多高?

  4. 在容器中部署应用程序有多容易?

  5. Docker 容器和 Kubernetes 是否专属于 Linux?

进一步阅读

参考文献/来源

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值