原文:
zh.annas-archive.org/md5/937685F0CEE189D5B83741D8ADA1BFEE
译者:飞龙
第十四章:监视 KVM 虚拟化平台
当你从只有几个对象需要管理的环境(例如 KVM 主机)转移到需要管理数百个对象的环境时,你会开始问自己一些非常重要的问题。其中一个最突出的问题是,“我要如何在不做大量手动工作并且有一些 GUI 报告选项的情况下监视我的数百个对象?”这个问题的答案就是 Elasticsearch、Logstash、Kibana(ELK)堆栈。在本章中,我们将看到这些软件解决方案对你和基于 KVM 的环境能做些什么。
这些晦涩的名字背后是一些技术,它们可以解决在运行多个服务器时可能遇到的许多问题。虽然你可以运行 ELK 堆栈来监视一个服务,但这样做是没有意义的。本章提供的建议和解决方案适用于涉及多个设备和服务器的所有项目,不仅仅是在 KVM 上运行的项目,而是任何能够产生任何类型日志的项目。我们将从如何监视 KVM 作为虚拟化平台的基础知识开始。然后,我们将继续讨论 ELK 堆栈,包括其构建模块和安装,然后再进行高级配置和定制。
在本章中,我们将涵盖以下主题:
-
监视 KVM 虚拟化平台
-
开源 ELK 解决方案简介
-
设置和集成 ELK 堆栈
-
配置数据收集器和聚合器
-
创建自定义利用报告
-
让我们开始吧!
监视 KVM 虚拟化平台
当我们谈论运行任何类型的处理系统时,我们很快就会遇到监视和确保我们的系统在给定的一组参数内运行的问题。
当我们创建一个运行工作负载的系统时,它将不可避免地产生一些关于正在发生的一切的数据。这些数据的范围几乎是无限的——一个只在线而没有单个“有用”任务运行的服务器将创建一些日志或服务数据,比如已使用的内存量、正在启动或停止的服务、剩余的磁盘空间量、连接和断开的设备等。
当我们开始运行任何有用的任务时,日志只会变得越来越大。
拥有一个良好且详细的日志意味着我们可以找到系统当前的运行情况;它是否正常运行,我们是否需要做一些事情让它运行得更好?如果发生了意外情况,日志可以帮助我们确定实际出了什么问题,并指引我们找到解决方案的方向。正确配置的日志甚至可以帮助我们在问题开始制造麻烦之前发现错误。
假设你有一个系统,每周都在变得越来越慢。让我们进一步假设我们的问题出在我们在系统上安装的应用程序的内存分配上。但也让我们假设这个内存分配是不固定的,而是随着使用系统的用户数量而变化的。如果你在任何时间点看一下,你可能会注意到用户数量和分配的内存。但如果你只在不同的时间测量,你会很难理解内存和用户数量之间有什么样的相关性——分配的内存量是否与用户数量成线性关系,还是呈指数增长?如果我们能看到 100 个用户使用 100MB 内存,那是否意味着 1000 个用户将使用 1000MB?
但假设我们正在记录内存量和用户数量在等间隔时间内的情况。
我们并没有做什么复杂的事情;每隔几秒,我们都会记录测量时间、分配的内存量和使用系统的用户数量。我们正在创建一个称为数据点的数据集。使用数据点与我们在前面的例子中所做的没有什么不同,但一旦我们有了数据集,我们就可以进行趋势分析。基本上,我们可以分析不同的时间段,比较用户数量以及他们实际使用的内存量。即使我们现在没有问题,这将为我们提供有关我们的系统实际如何使用内存以及我们何时出现问题的重要信息。
这种方法甚至可以帮助我们找到和解决那些不明显的问题,比如每个月备份花费太长时间才能完成,而其他时间都正常工作。这种能力使我们能够发现趋势并分析数据和系统性能,这就是日志记录的全部意义。
简而言之,任何类型的监控都归结为两件事:从我们试图监控的事物中收集数据,然后分析这些数据。
监控可以是在线的,也可以是离线的。在线监控在我们试图创建某种警报系统或者试图建立能够响应过程变化的自我纠正系统时非常有用。然后,我们可以尝试纠正问题或关闭或重新启动系统。在线监控通常由运维团队使用,以确保一切运行顺利,并记录系统可能出现的问题。
离线监控要复杂得多。离线监控使我们能够将所有数据收集到日志中,稍后分析这些日志,并推断趋势,找出如何改进系统。但事实是,它总是延迟的,因为离线方法要求我们下载然后分析日志。这就是为什么我们更喜欢实时日志摄入,这是需要在线完成的事情。这就是为什么学习 ELK 堆栈如此重要。
通过将所有这些小组件-实时日志摄入、搜索、分析和报告-组合成一个更大的堆栈,ELK 使我们能够更容易地实时监控我们的环境。让我们来学习一下。
开源 ELK 解决方案简介
我们之前提到 ELK 代表 Elasticsearch、Logstash 和 Kibana,因为这三个应用程序或系统是完整监控和报告解决方案的基本组成部分。每个部分都有自己的目的和功能-Logstash 将所有数据收集到一个一致的数据库中,Elasticsearch 能够快速浏览 Logstash 存储的所有数据,而 Kibana 则将搜索结果转化为信息丰富且视觉上吸引人的内容。说了这么多,ELK 最近更改了其名称。尽管它仍然被称为 ELK 堆栈,几乎整个互联网都会这样称呼它,但 ELK 堆栈现在被称为 Elastic Stack,原因是在撰写本文时,堆栈中还包括另一个第四个组件。这个组件被称为 Beats,它代表整个系统的重要补充。
但让我们从头开始,尝试以其创建者描述的方式描述整个系统。
Elasticsearch
首先创建并在社区中获得关注的组件是 Elasticsearch,它被创建为一个灵活、可扩展的系统,用于索引和搜索大型数据集。Elasticsearch 被用于成千上万种不同的用途,包括在文档、网站或日志中搜索特定内容。它的主要卖点和许多人开始使用它的原因是它既灵活又可扩展,同时速度极快。
当我们考虑搜索时,我们通常会考虑创建某种查询,然后等待数据库给我们一些形式的答案。在复杂的搜索中,问题通常是等待,因为不断调整我们的查询并等待它们产生结果是很累人的。由于许多现代数据科学依赖于非结构化数据的概念,这意味着我们需要搜索的许多数据没有固定的结构,或者根本没有结构,因此在这些数据池中创建快速搜索的方法是一个棘手的问题。
想象一下,你需要在图书馆里找到一本特定的书。再想象一下,你没有所有书籍、作者、出版信息和其他一切正常图书馆都有的数据库;你只被允许搜索所有的书籍。
拥有一种能够识别这些书中的模式并告诉您答案的工具,比如*谁写了这本书?或在所有超过 200 页的书中 KVM 被提到了多少次?*是一件非常有用的事情。这就是一个好的搜索解决方案所做的事情。
如果我们想要快速有效地管理一个集群或多个集群的物理和虚拟服务器,那么能够搜索运行 Apache web 服务器并且在某个 IP 地址请求的某个页面上出现问题的机器是至关重要的。
当我们监控系统信息时,即使是单个数据点,比如跨数百台主机的内存分配,也是一个问题,即使是呈现这些数据也是一个问题,而在实时搜索中查找这些数据几乎是不可能的,没有正确的工具。
Elasticsearch 确实做到了这一点:它为我们快速浏览大量几乎没有结构的数据创造了一种方式,然后得出有意义的结果。Elasticsearch 的不同之处在于其可扩展性,这意味着您可以使用它在笔记本电脑上创建搜索查询,然后在多节点实例上运行这些查询,搜索 PB 级的数据。
Elasticsearch 也很快,这不仅节省时间。能够更快地获取搜索结果的能力使您能够通过创建和修改查询,然后理解其结果来更多地了解您的数据。
由于这只是对 ELK 实际做的事情的简单介绍,我们将转到下一个组件 Logstash,并稍后回到搜索。
Logstash
Logstash 有一个简单的目的。它旨在能够消化任意数量的生成数据的日志和事件,并将它们存储以备将来使用。存储后,它可以以多种格式导出,如电子邮件、文件、HTTP 等。
Logstash 的重要之处在于它的多功能性,可以接受不同的输入流。它不仅限于使用日志;甚至可以接受诸如 Twitter feeds 之类的东西。
Kibana
旧 ELK 堆栈的最后一部分是 Kibana。如果 Logstash 是存储,Elasticsearch 是计算,那么 Kibana 就是输出引擎。简而言之,Kibana 是一种利用 Elasticsearch 查询结果创建视觉上令人印象深刻且高度可定制布局的方法。尽管 Kibana 的输出通常是某种仪表板,但其输出可以是许多东西,取决于用户创建新布局和可视化数据的能力。说了这么多,不要害怕-互联网提供了几乎每种想象的场景的至少部分,如果不是全部的解决方案。
接下来,我们将介绍 ELK 堆栈的基本安装,展示它的功能,指导您正确的方向,并演示最受欢迎的beats之一-metricbeat。
使用 ELK 堆栈在许多方面与运行服务器相同-你需要做什么取决于你实际想要实现什么;只需几分钟就可以让 ELK 堆栈运行起来,但真正的努力却是从那时开始。
当然,为了充分理解 ELK 堆栈在实际环境中的使用方式,我们需要先部署和设置它。我们接下来就要做这件事。
建立和集成 ELK 堆栈
值得庆幸的是,几乎我们需要安装的所有东西都已经由 Elasticsearch 团队准备好了。除了 Java,其他所有东西都在他们的网站上得到了很好的整理和记录。
您需要做的第一件事是安装 Java - ELK 依赖于 Java 运行,因此我们需要安装它。Java 有两种不同的安装候选项:来自 Oracle 的官方安装和开源的 OpenJDK。由于我们试图留在开源生态系统中,我们将安装 OpenJDK。在本书中,我们使用 CentOS 8 作为我们的平台,因此将广泛使用yum
软件包管理器。
让我们从先决条件软件包开始。我们安装 Java 所需的唯一先决条件软件包是java-11-OpenJDK-devel
软件包(用当前的 OpenJDK 版本替换“11”)。因此,在这里,我们需要运行以下命令:
yum install java-11-openjdk-devel
发出该命令后,您应该会得到如下结果:
图 14.1 - 安装主要先决条件之一 - Java
安装完成后,我们可以通过运行以下命令来验证安装是否成功以及 Java 是否正常工作:
java -version
这是预期的输出:
图 14.2 - 检查 Java 的版本
输出应该是当前的 Java 版本和没有错误。除了验证 Java 是否正常工作之外,这一步还很重要,以便验证 Java 的路径是否设置正确 - 如果您在其他发行版上运行,可能需要手动设置路径。
现在 Java 已经安装并准备就绪,我们可以继续安装 ELK 堆栈。下一步是配置 Elasticsearch 和其他服务的安装源:
- 我们需要在
/etc/yum.repos.d/
中创建一个名为elasticsearch.repo
的文件,其中将包含有关我们存储库的所有信息:
[Elasticsearch-7.x]
name=Elasticsearch repository for 7.x packages
baseurl=https://artifacts.elastic.co/packages/7.x/yum
gpgcheck=1
gpgkey=https://artifacts.elastic.co/GPG-KEY-Elasticsearch
enabled=1
autorefresh=1
type=rpm-md
保存文件。这里重要的是仓库是 GPG 签名的,所以我们需要导入它的密钥并应用它,以便在下载时可以验证软件包。
您要安装的文件不是免费软件。Elasticsearch 有两个不同的免费版本和一个付费订阅模型。使用此存储库中的文件将获得基于订阅的安装,该安装将在basic模式下运行,该模式是免费的。在撰写本文时,Elastic 有四种订阅模型 - 一种是基于 Apache License 2.0 的开源模型,免费;其余的都是闭源的,但提供额外的功能。目前,这些订阅被命名为 Basic、Gold 和 Platinum。Basic 是免费的,而其他模型需要每月付费订阅。
你肯定会问为什么你应该选择开源而不是 Basic,或者反过来,因为它们都是免费的。虽然它们都有相同的核心,但 Basic 更先进,因为它提供了核心安全功能和更多在日常使用中可能很重要的东西,特别是如果你追求 Kibana 可视化。
- 让我们继续安装并导入必要的 GPG 密钥:
rpm --import https://artifacts.elastic.co/GPG-KEY-elasticsearch
- 现在,我们准备在系统端进行一些维护工作,并获取存储库系统中的所有更改:
elasticsearch by running this command:
elasticsearch 或任何其他服务都不会自动启动或启用。我们必须为它们中的每一个手动执行此操作。现在让我们来做这件事。
- 启动和启用服务的过程是标准的,对所有三个服务都是相同的:
sudo systemctl daemon-reload
sudo systemctl enable elasticsearch.service
sudo systemctl start elasticsearch.service
sudo systemctl status elasticsearch.service
sudo yum install kibana
sudo systemctl status kibana.service
sudo systemctl enable kibana.service
sudo systemctl start kibana.service
sudo yum install logstash
sudo systemctl start logstash.service
sudo systemctl enable logstash.service
最后要做的就是安装beats,这些服务通常安装在受监视的服务器上,并且可以配置为创建和发送系统上的重要指标。现在让我们来做这件事。
- 为了演示目的,我们将安装它们所有,尽管我们不会使用它们所有:
sudo yum install filebeat metricbeat packetbeat heartbeat-elastic auditbeat
完成后,我们应该有一个功能齐全的系统。让我们快速回顾一下。
Kibana 和 Elasticsearch 都作为 Web 服务运行在不同的端口上。我们将通过 Web 浏览器与 Kibana 进行交互(使用 URL http://localhost:9200
和http://localhost:5601
),因为这是可视化发生的地方:
图 14.3 – 检查 Elasticsearch 服务
现在,我们可以在端口5601
上连接到 Kibana:
图 14.4 – 成功连接到 Kibana
部署过程已经成功完成。我们的下一个逻辑步骤将是创建一个工作流程。让我们现在就做。
工作流程
在本节中,我们将建立一个工作流程 – 我们将创建日志和指标,这些日志和指标将被摄入 Logstash,通过 Elasticsearch 查询,然后在 Kibana 中进行可视化呈现。
默认情况下,Kibana 运行在端口5601
上,这可以在配置中更改。
但这对我意味着什么?这对 KVM 意味着什么?
使用 Elastic Stack 的最大卖点是灵活性和简单的展示方式。无论我们在几十个 KVM 主机内运行一台、10 台还是 1,000 台机器,我们都可以在生产中以相同的方式对待它们,并建立稳定的监控工作流程。使用极其简单的脚本,我们可以创建完全定制的指标并快速显示它们,我们可以观察趋势,甚至可以创建一个几乎实时的监控系统。所有这些,基本上都是免费的。
让我们创建一个简单的监视器,用于为运行 ELK 的主机系统转储系统指标。我们已经安装了 Metricbeat,所以唯一剩下的就是配置服务将数据发送到 Elasticsearch。数据发送到 Elasticsearch,而不是 Logstash,这仅仅是因为服务之间的相互操作方式。可以将数据同时发送到 Logstash 和 Elasticsearch,因此我们需要在这里做一点快速的解释。
Logstash 从定义上来说是一个存储发送到它的数据的服务。Elasticsearch 搜索该数据并与 Logstash 通信。如果我们将数据发送到 Logstash,我们并没有做错什么;我们只是为以后的分析转储数据。但是,将数据发送到 Elasticsearch 还给了我们一个功能 – 我们不仅可以发送数据,还可以以模板的形式发送关于数据的信息。
另一方面,Logstash 具有在接收数据后并在数据存储之前执行数据转换的能力,因此,如果我们需要执行诸如解析 GeoIP 信息、更改主机名称等操作,我们可能会将 Logstash 作为我们的主要目的地。牢记这一点,不要设置 Metricbeat 以便将数据同时发送到 Elasticsearch 和 Logstash;否则,您将只会在数据库中获得重复的数据。
使用 ELK 很简单,我们已经在安装过程中毫不费力地进行了这一步。当我们开始分析数据时,真正的问题就开始了。即使是来自 Metricbeat 的简单且完全格式良好的数据,也可能很难可视化,特别是如果我们是第一次这样做的话。为 Elasticsearch 和 Kibana 准备的预制模板可以节省大量时间。
看一下以下的屏幕截图:
图 14.5 – Metricbeat 仪表板
只需不到 10 分钟的设置,就可以获得一个像这样的完整仪表板。让我们一步一步地进行。
我们已经安装了 Metricbeat,只需要配置它,但在此之前,我们需要配置 Logstash。我们只需要定义一个pipeline。
那么,数据如何被转换?
到目前为止,我们还没有详细介绍 Logstash 的功能,但是为了创建我们的第一组数据,我们需要了解 Logstash 的一些内部工作原理。Logstash 使用管道的概念来定义数据在接收到数据后发生的情况,以及在将数据发送到 Elasticsearch 之前。
每个管道都有两个必需的元素和一个可选的元素:
-
输入始终是管道中的第一个,并且旨在从源接收数据。
-
输出是管道中的最后一个元素,并且输出数据。
-
过滤器是一个可选元素,位于输入和输出之间,以便根据我们可以定义的规则修改数据。
所有这些元素都可以从插件列表中选择,以便我们创建一个针对特定目的调整的最佳管道。让我们一步一步地进行。
我们需要做的就是取消注释配置文件中定义的一个管道,该文件位于/etc/logstash
文件夹中。
整个堆栈使用 YAML 作为配置文件结构的标准,因此每个配置文件都以.yml
扩展名结尾。这一点很重要,以便理解所有没有此扩展名的文件都在这里作为样本或某种配置模板;只有带有.yml
扩展名的文件才会被解析。
要配置 Logstash,只需打开logstash.yml
并取消注释与第一个管道main
相关的所有行。我们不需要做其他事情。该文件本身位于/etc/logstash
文件夹中,在您进行这些更改后应该看起来像这样:
图 14.6 - logstash.yml 文件
我们需要做的下一件事是配置 Metricbeat。
配置数据收集器和聚合器
在之前的步骤中,我们成功部署了 Metricbeat。现在,我们需要开始实际的配置。因此,让我们一步一步地进行配置过程:
- 转到
/etc/metricbeat
并打开metricbeat.yml
。
取消注释定义elasticsearch
为 Metricbeat 目标的行。现在,我们需要改变一件事。找到包含以下内容的行:
setup.dashboards.enabled: false
将前面的行更改为以下内容:
setup.dashboards.enabled: true
我们需要这样做来加载仪表板,以便我们可以使用它们。
- 其余的配置都是通过命令行完成的。Metricbeat 有几个可以运行的命令,但最重要的是以下命令:
metricbeat setup
这个命令将通过初始设置。设置的这一部分可能是整个初始配置中最重要的事情 - 将仪表板模板推送到 Kibana。这些模板将使您能够在几次点击之内启动和运行,而不是学习如何进行可视化和从头开始配置。您最终将不得不这样做,但是对于这个示例,我们希望尽快让事情运行起来。
- 您现在需要的另一个命令是以下命令:
logstash and kvm:
metricbeat 模块启用 kvm
metricbeat 模块启用 logstash
logstash
模块的命名令人困惑,因为它并不打算将数据推送到 Logstash;相反,它的主要目的是报告 Logstash 服务,并使您能够通过 Logstash 监视它。听起来困惑吗?让我们重新表达一下:这个模块使 Logstash 能够监视自己。或者更准确地说,它使 beats 能够监视 Elastic 堆栈的一部分。
KVM 模块是一个模板,将使您能够收集不同的与 KVM 相关的指标。
就是这样。作为预防措施,键入以下命令以检查 Metricbeat 的配置:
metricbeat test config
如果前面的命令运行正常,请使用以下命令启动 Metricbeat 服务:
systemctl start metricbeat
您现在有一个正在运行的服务,正在收集您主机上的数据 - 与运行 KVM 并将数据转储到 Elasticsearch 的主机相同。这是至关重要的,因为我们将使用所有这些数据来创建可视化和仪表板。
在 Kibana 中创建图表
现在,在浏览器中使用localhost:5601
作为地址打开 Kibana。屏幕左侧应该有一个基于图标的菜单。转到堆栈管理,查看Elasticsearch 索引管理。
应该有一个名为metricbeat-
*的活动索引。在这个特定的例子中,*将是 metricbeat 的当前版本和日志文件中第一个条目的日期。这完全是任意的,只是一个默认值,确保您知道此实例何时启动。
与此名称相同的一行中应该有一些数字:我们感兴趣的是文档计数 - 数据库持有的对象数量。暂时来说,如果不是零,我们就没问题。
现在,转到仪表板页面,打开Metricbeat 系统概览 ECS仪表板。它将显示许多可视化小部件,代表 CPU、内存、磁盘和网络使用情况:
图 14.7 - ECS 仪表板概览
现在,您可以点击“最近 15 分钟”。在您点击刷新按钮之后,新数据应该显示在页面上。
有了这些,您现在已经了解了足够的关于 Kibana 的知识,但我们仍然无法可视化 KVM 数据。下一步是创建一个覆盖这一点的仪表板。
但在我们这样做之前,想想我们到目前为止学到的东西可以做什么。您不仅可以监视安装了 KVM 堆栈的本地系统,还可以监视任何能够运行 Metricbeat 的系统。您唯一需要知道的是 ELK 堆栈的 IP 地址,以便您可以向其发送数据。Kibana 将自动处理来自不同系统的所有不同数据的可视化,我们稍后将看到。
创建自定义利用率报告
自版本 7 以来,Elastic stack 引入了强制性检查,旨在确保最低安全性和功能合规性,特别是一旦我们开始在生产中使用 ELK。
乍一看,这些检查可能会让您困惑 - 我们引导您完成的安装将正常工作,突然间,当您尝试配置一些设置时,一切都会失败。这是有意的。
在以前的版本中,这些检查是执行的,但如果错过或配置错误了配置项,它们会被标记为警告。从第 7 版开始,如果系统处于生产状态且配置不正确,这些检查将触发错误。这种状态自动意味着如果配置不正确,您的安装将无法工作。
ELK 有两种不同的操作模式:开发和生产。在第一次安装时,假定您处于开发模式,因此大多数功能都可以直接使用。
一旦进入生产模式,事情就会发生很大变化 - 安全设置和其他配置选项需要明确设置,以使堆栈正常运行。
诀窍在于没有明确的模式更改 - 与之相关的生产设置和检查是由配置中的一些设置触发的。这个想法是一旦您重新配置了一些可能从安全角度重要的东西,您需要正确地重新配置一切。这将防止您忘记一些在生产中可能成为大问题的东西,并迫使您至少有一个稳定的配置作为起点。有一个关闭检查的开关,但在任何情况下都不建议使用。
需要注意的主要事项是绑定接口——默认安装将所有内容绑定到localhost
或本地环回接口,这对于生产完全没问题。一旦您的 Elasticsearch 能够形成集群,并且可以通过简单地重新配置 HTTP 和传输通信的网络地址来触发,您必须注意检查并重新配置整个系统以使其正常工作。请参阅 https://www.elastic.co/上提供的文档以获取更多信息,从www.elastic.co/guide/index.html
开始。
例如,在 Elastic stack 中配置集群以及所有相关内容远远超出了本书的范围——我们将在我们的配置中保持在单节点集群的范围内。这个解决方案专门针对可以使用单个节点或更准确地说,覆盖堆栈所有功能的单个机器实例的情况而创建的。在正常部署中,您将在集群中运行 Elastic stack,但实施细节将由您的配置和其需求决定。
我们需要警告您两个关键点——防火墙和 SELinux 设置由您决定。所有服务使用标准的 TCP 进行通信。不要忘记,为了使服务运行,网络必须正确配置。
既然我们已经解决了这个问题,让我们回答一个简单的问题:要使 Elastic stack 与多个服务器一起工作,我们需要做些什么?让我们逐步讨论这种情况。
Elasticsearch
转到配置文件(/etc/elasticsearch/elasticsearch.yml
)并在发现部分中添加一行:
discovery.type: single-node
使用此部分不是强制性的,但在以后必须返回到配置时会有所帮助。
此选项将告诉 Elasticsearch,您的集群中只有一个节点,并且它将使 Elasticsearch 忽略与集群及其网络相关的所有检查。此设置还将使此节点自动成为主节点,因为 Elasticsearch 依赖于具有控制集群中所有内容的主节点。
更改network.host:
下的设置,使其指向 Elasticsearch 将要在其上可用的接口的 IP 地址。默认情况下,它指向 localhost,并且从网络上不可见。
重新启动 Elasticsearch 服务,并确保它正在运行且没有生成错误:
sudo systemctl restart elasticsearch.service
一旦它正常工作,检查服务是否从本地机器正常运行。最简单的方法是这样做:
curl -XGET <ip_address>:9200
响应应该是一个以.json
格式的文本,包含有关服务器的信息。
重要提示
Elastic stack 有三(或四)部分或服务。在我们所有的示例中,其中三个(Logstash、Elasticsearch 和 Kibana)都在同一台服务器上运行,因此不需要额外的配置来适应网络通信。在正常配置中,这些服务可能会在独立的服务器上运行,并且根据我们尝试监视的服务的工作负载和配置,可能会运行多个实例。
Logstash
Logstash 的默认安装文件名为logstash-sample.conf
,位于/etc/logstash
文件夹中。这包含了一个简单的 Logstash 管道,用于在 Logstash 作为 beats 的主要目的地时使用。稍后我们会讨论这一点,但目前,将此文件复制到/etc/logstash/conf.d/logstash.conf
,并在刚刚复制的文件中更改 Elasticsearch 服务器的地址。它应该看起来像这样:
hosts => ["http://localhost:9200"].
将localhost
更改为服务器的正确 IP 地址。这将使 Logstash 侦听端口5044
并将数据转发到 Elasticsearch。重新启动服务并验证其运行:
sudo systemctl restart logstash.service
现在,让我们学习如何配置 Kibana。
Kibana
Kibana 也有一些需要更改的设置,但在这样做时,有几件事情需要记住:
-
单独来说,Kibana 是一个通过 HTTP 协议(或根据配置的情况是 HTTPS)提供可视化和数据的服务。
-
同时,Kibana 使用 Elasticsearch 作为其后端,以便获取和处理数据。这意味着我们必须关心两个 IP 地址:
a) 第一个是用于显示 Kibana 页面的地址。默认情况下,这是 localhost 的端口5601
。
b) 另一个 IP 地址是将处理查询的 Elasticsearh 服务。这个的默认值也是 localhost,但它需要更改为 Elasticsearch 服务器的 IP 地址。
包含配置详细信息的文件是/etc/kibana/kibana.yml
,您至少需要进行以下更改:
-
server.host
:这需要指向 Kibana 将拥有其页面的 IP 地址。 -
elasticsearch.hosts
:这需要指向将执行查询的主机(或集群,或多个主机)。
重新启动服务,就可以了。现在,登录 Kibana 并测试一切是否正常。
为了让您更加熟悉 Kibana,我们将尝试建立一些基本的系统监控,并展示如何监控多个主机。我们将配置两个beats:Metricbeat 和 Filebeat。
我们已经配置了 Metricbeat,但是它是为本地主机配置的,所以让我们先解决这个问题。在/etc/metricbeat/metricbeat.yml
文件中,重新配置输出以将数据发送到elasticsearch
地址。您只需要更改主机 IP 地址,因为其他所有内容保持不变:
# Array of hosts to connect to
Hosts: ["Your-host-IP-address:9200"]
确保将Your-host-IP-address
更改为您正在使用的 IP 地址。
配置 filebeat 基本上是相同的;我们需要使用/etc/filebeat/filebeat.yml
进行配置。由于所有的 beats 都使用相同的概念,filebeat 和 metricbeat(以及其他 beats)都使用模块来提供功能。在两者中,核心模块都被命名为system
,因此在 filebeat 中使用以下命令启用它:
filebeat modules enable system
使用以下命令进行 metricbeat:
metricbeat modules enable system
我们之前提到过,在第一个示例中,但是您可以通过运行以下命令来测试您的配置:
filebeat test config
您还可以使用以下命令:
metricbeat test config
两个 beats 都应该显示配置为ok
。
此外,您还可以检查输出设置,这将显示输出设置实际上是什么以及它们是如何工作的。如果您只使用本书来配置系统,您应该会收到一个警告,提醒您连接没有 TLS 保护,但除此之外,输出应该在配置文件中设置的 IP 地址上工作。
要测试输出,请使用以下命令:
filebeat test output
您还可以使用以下命令:
metricbeat test output
对于您打算监视的每个系统都要重复所有这些步骤。在我们的示例中,我们有两个系统:一个正在运行 KVM,另一个正在运行 Kibana。我们还在另一个系统上设置了 Kibana,以测试 syslog 以及它通知我们注意到的问题的方式。
我们需要配置 filebeat 和 metricbeat 以将数据发送到 Kibana。我们将编辑filebeat.yml
和metricbeat.yml
文件,通过更改两个文件的以下部分来实现这一目的:
setup.kibana
host: "Your-Kibana-Host-IP:5601"
在运行 beats 之前,在新安装中,您需要将仪表板上传到 Kibana。您只需要为每个 Kibana 安装执行一次此操作,并且您只需要从要监视的系统中的一个系统执行此操作 - 模板将起作用,无论它们是从哪个系统上传的;它们只会处理进入 Elasticsearch 的数据。
要做到这一点,请使用以下命令:
filebeat setup
您还需要使用以下命令:
metricbeat setup
这将需要几秒钟甚至一分钟,这取决于您的服务器和客户端。一旦它说它创建了仪表板,它将显示所有创建的仪表板和设置。
现在,您几乎可以开始查看 Kibana 将显示的所有数据了:
图 14.8 - 来自 Kibana 仪表板的摘录
在我们开始之前,还有一件事情您需要了解有关时间和时间戳。右上角的日期/时间选择器将让您选择自己的时间跨度或预定义的间隔之一:
图 14.9-日期/时间选择器
重要提示
始终记住显示的时间是从您访问 Kibana 的浏览器/机器的时区本地时间。
日志中的所有时间戳都是发送日志的机器的本地时间。Kibana 将尝试匹配时区并转换生成的时间戳,但如果您监视的机器上的实际时间设置不匹配,那么在尝试建立事件时间线时就会出现问题。
假设您已经运行了 filebeat 和 metricbeat。您可以用这些做什么?事实证明,很多:
-
首先要做的是发现您的数据中有什么。在 Kibana 中按下发现按钮(看起来像一个小指南针)。如果一切正常,右侧应该显示一些数据。
-
在您刚刚单击的图标右侧,将填充一个垂直空间,其中包含 Kibana 从数据中获取的所有属性。如果您没有看到任何内容或缺少某些内容,请记住您选择的时间跨度会缩小在此视图中显示的数据。尝试重新调整间隔到最近 24 小时或最近 30 天。
一旦属性列表显示出来,您可以快速确定每个属性在您刚刚选择的数据中出现了多少次-只需单击任何属性并选择可视化。还要注意,一旦单击属性,Kibana 会显示最近 500 条记录中前五个不同的值。如果您需要知道例如哪些主机显示数据,或者有多少不同的操作系统版本,这是一个非常有用的工具。
特定属性的可视化只是一个开始-注意一旦悬停在属性名称上,一个名为添加的按钮会出现?尝试单击它。右侧将开始形成一个表,其中只包含您选择的属性,按时间戳排序。默认情况下,这些值不会自动刷新,因此时间戳将被固定。您可以选择任意数量的属性,并保存此列表或稍后打开它。
我们需要查看的下一件事是单独的可视化。我们不会详细介绍,但您可以使用预定义的可视化类型从数据集中创建自己的可视化。同时,您不仅限于使用预定义的内容-还可以使用 JSON 和脚本进行更多的自定义。
我们需要了解的下一件事是仪表板。
根据特定数据集,或者更准确地说,根据您正在监视的特定一组机器,其中一些将具有仅涵盖特定机器执行或具有的属性。一个例子是 AWS 上的虚拟机-它们将具有一些仅在 AWS 上下文中有用的信息。这在我们的配置中并不重要,但您需要了解数据中可能存在一些特定机器集的唯一属性。首先,选择一个系统指标;要么选择System Navigation ECS用于 metricbeat,要么选择Dashboards ECS用于 filebeat。
这些仪表板以多种方式显示有关系统的大量信息。尝试点击并查看您能推断出什么。
metricbeat 仪表板更侧重于运行系统并关注内存和 CPU 分配情况。您可以单击并过滤大量信息,并以不同的方式呈现。以下是 metricbeat 的屏幕截图,以便您对其外观有一个大致的了解:
图 14.10-metricbeat 仪表板
filebeat 仪表板更多地面向分析发生了什么并建立趋势。让我们从 filebeat 仪表板中的一些摘录开始检查,首先是 syslog 条目部分:
图 14.11 - filebeat syslog 条目部分
乍一看,您可以注意到一些事情。我们正在显示两个系统的数据,而且数据是部分的,因为它覆盖了我们设置的一部分时间间隔。此外,我们可以看到一些进程比其他进程更频繁地运行并生成日志。即使我们对特定系统一无所知,我们现在也可以看到一些进程出现在日志中,而它们可能不应该出现:
图 14.12 - filebeat 交互式圆环图
让我们来看看setroubleshoot
。点击进程名称。在打开的窗口中,点击放大镜。这将隔离只有这个进程,并在屏幕底部显示它的日志。
我们可以快速看到setroubleshoot
在哪个主机上 - 包括频率和原因 - 写入日志。这是发现潜在问题的快速方法。在这种特殊情况下,显然应该在这个系统上采取一些行动,重新配置 SELinux,因为它生成异常并阻止一些应用程序访问文件。
让我们沿着垂直导航栏继续,并指出一些其他有趣的功能。
从上到下,下一个重要功能是Canvas - 它使我们能够使用我们正在收集的数据创建实时演示文稿。界面类似于其他演示程序所期望的,但重点是直接在幻灯片中使用数据并几乎实时生成幻灯片。
接下来是地图。这是 7.0 版本的一个新功能,它允许我们创建数据的地理演示。
机器学习是下一个功能 - 它使您能够操纵数据并使用它来“训练”过滤器,并从中创建管道。
基础设施也很有趣 - 当我们提到仪表板时,我们谈论的是灵活性和定制。基础设施是一个模块,它使我们能够以最小的努力进行实时监控并观察重要的指标。您可以将重要数据显示为表格、气球状界面或图表。数据可以被平均或以其他方式呈现,所有这些都是通过一个非常直观的界面完成的。
Heartbeat 是另一个高度专业化的仪表板 - 正如其名称所示,这是跟踪和报告正常运行时间数据的最简单方法,并迅速注意到是否有什么东西已经离线。库存主机需要安装 Heartbeat 服务,以便监视我们打算监视的每个系统。
SIEM值得更深入的解释:如果我们把仪表板看作是多功能的,那么 SIEM 恰恰相反;它被创建为能够跟踪所有可以归类为安全相关的系统上的所有事件。当搜索 IP、网络事件、源、目的地、网络流和所有其他数据时,这个模块将解析数据,并创建简单易懂的报告,报告了您正在监视的机器上发生了什么。它甚至提供异常检测,这是一项付费功能,需要最高付费等级才能使用。
堆栈监视器是另一个值得注意的仪表板,因为它使您实际上可以看到 Elastic 堆栈的所有不同部分发生了什么。它将显示所有服务的状态、它们的资源分配和许可证状态。日志功能特别有用,因为它跟踪堆栈生成了多少种类型的日志,并且如果有任何问题,它可以快速指出问题。
该模块还为服务生成统计信息,使我们能够了解系统如何进行优化。
管理,底部的最后一个图标已经提到过了 - 它使集群及其部分的管理成为可能。这是我们可以看到是否有我们期望的任何索引,数据是否流入,我们是否可以优化某些内容等的地方。这也是我们可以管理许可证并创建系统配置快照的地方。
ELK 和 KVM
最后但同样重要的是,让我们创建一个系统仪表,它将向我们显示来自 KVM hypervisor 的参数,然后以几种方式进行可视化。这需要运行的 KVM hypervisor,安装了 KVM 模块的 metricbeat 和支持从 metricbeat 接收数据的 Elastic stack 配置。让我们详细了解 ELK 针对这个特定用例的配置:
- 首先,转到 hypervisor 并打开
virsh
shell。列出所有可用的域,选择一个域,并使用dommemstat –-domain <domain_name>
命令。
结果应该是这样的:
图 14.13 – 用于域的 dommemtest
- 打开 Kibana 并登录,转到
metric*
作为我们正在使用的索引。左侧列应该填充有 metricbeat 发送到此 Kibana 实例的数据集中的属性。现在,查看属性并选择其中的一些:
图 14.14 – 在 Kibana 中选择属性
您可以使用一个按钮选择字段,只要将鼠标光标悬停在任何字段上,该按钮就会显示出来。取消选择它们也是一样的:
图 14.15 – 在 Kibana 中添加属性
- 现在,让我们坚持我们选择的那些。在列的右侧,形成了一个表,其中只包含您选择的字段,使您能够检查系统正在接收的数据。您可能需要向下滚动以查看实际信息,因为此表将显示接收到的所有数据,其中至少有一个具有值的项目。由于其中一个字段始终是时间戳,因此将有许多行不包含任何对我们的分析有用的数据:
图 14.16 – 检查所选字段
在这里我们可以看到的是,我们得到了在监视服务器上运行命令行的结果相同的数据。
我们需要的是一种方法来使用这些结果作为数据来显示我们的图表。点击dommemstat
。保存搜索。
- 现在,让我们构建一个仪表,它将向我们显示实时数据和一个值的快速可视化。转到
area
图。然后,在下一个屏幕上,找到并选择我们的数据源:
图 14.18 – 选择可视化源
这将创建一个窗口,左侧显示所有设置,右侧显示最终结果。目前,我们看到的东西毫无意义,因此让我们配置我们需要的内容以显示我们的数据。有几种方法可以实现我们想要的内容:我们将使用直方图和过滤器快速显示我们的未使用内存随时间的变化。
- 我们将配置y轴以显示
kvm.dommemstat.stat.value
的平均数据,这是保存我们数据的属性。选择kvm.dommemstat.stat.value
作为我们正在聚合的字段。如果需要,您可以创建自定义标签:
图 18.19 – 选择度量属性
这还不对,我们需要添加一个时间戳以查看我们的数据随时间的变化。我们需要在x轴上添加日期直方图类型并使用它:
图 14.20 - 选择聚合类型
- 在完成此可视化之前,我们需要添加一个过滤器。从 KVM metricbeat 模块接收的数据的问题是,它使用一个属性来保存不同的数据 - 如果我们想知道我们正在显示的文件中的数字实际上意味着什么,我们需要从
kvm.dommemstat.stat.name
中读取其名称。为了实现这一点,只需创建一个名为kvm.dommemstat.stat.name:"unused"
的过滤器。
在我们刷新可视化后,我们的数据应该正确显示在右侧:
图 14.21 - 正确的可视化
- 我们需要使用“保存”按钮保存此可视化,为其命名,以便以后能够找到它,并重复此过程,但是不是过滤“未使用”,而是过滤“可用”。将所有设置保持与第一个可视化相同。
让我们构建一个仪表板。打开仪表板选项卡,然后在第一个屏幕上单击添加新仪表板。现在,将我们的两个可视化添加到此仪表板。您只需要找到正确的可视化并单击它;它将显示在仪表板上。
因此,我们有几个简单的仪表板正在运行:
图 14.22 - 显示可用内存的完成仪表板
第二个仪表板 - 在 UI 中,实际上就在第一个仪表板旁边 - 是未使用的内存仪表板:
图 14.23 - 显示未使用内存的完成仪表板
- 保存此仪表板,以便以后使用。仪表板的所有元素都可以自定义,并且仪表板可以包含任意数量的可视化。Kibana 让您几乎可以自定义您看到的一切,并将大量数据组合在一个屏幕上进行轻松监视。我们只需要更改一件事情,使其成为一个良好的监控仪表板,那就是使其自动刷新。单击屏幕右侧的日历图标,并选择自动刷新间隔。我们决定使用
5 秒
:
图 14.24 - 选择与时间相关的参数
现在我们已经完成了这个,我们可以反思一下,构建这个仪表板真的非常简单和容易。这只花了我们几分钟,而且很容易阅读。想象一下,以文本模式查看数百兆字节的日志文件与这种方式相比。真的没有可比性,因为我们能够使用先前部署的 ELK 堆栈来监视有关 KVM 的信息,这正是本章的重点。
总结
Kibana 让您可以创建自定义仪表板,可以并排显示不同机器的数据,因此 KVM 只是我们的许多选项之一。根据您的需求,您可以显示,例如,KVM 超级管理程序的磁盘使用情况以及运行在其上的所有主机,或者其他一些指标。弹性堆栈是一个灵活的工具,但与所有事物一样,它需要时间来掌握。本章仅涵盖了弹性配置的基础知识,因此我们强烈建议在此主题上进行进一步阅读 - 除了 KVM 之外,ELK 可以用于监视几乎所有产生任何类型数据的东西。
下一章将全面讨论 KVM 虚拟机的性能调优和优化,这是我们并没有真正涉及的一个主题。有很多内容需要讨论 - 虚拟机计算大小、性能优化、磁盘、存储访问和多路径、优化内核和虚拟机设置等等。所有这些主题在我们的环境变得越来越大时将变得更加重要。
问题
-
我们使用 metricbeat 做什么?
-
我们为什么使用 Kibana?
-
在安装 ELK 堆栈之前的基本先决条件是什么?
-
我们如何向 Kibana 添加数据?
进一步阅读
有关本章涵盖的内容的更多信息,请参考以下链接:
-
ELK stack:
www.elastic.co/what-is/elk-stack
-
ELK stack 文档:
www.elastic.co/guide/index.html
-
Metricbeat 文档:
www.elastic.co/guide/en/beats/metricbeat/current/index.html
第十五章:KVM VM 性能调优和优化
当我们思考虚拟化时,总会有一些问题不断出现。其中一些可能很简单,比如我们从虚拟化中能得到什么?它是否简化了事情?备份是否更容易?但是一旦我们使用虚拟化一段时间后,也会出现更复杂的问题。我们如何在计算层面加速?有没有更多的优化方法?我们可以调整什么来从存储或网络中获得更快的速度?我们可以引入一些配置更改,使我们能够在不在其中投入大量资金的情况下从现有基础设施中获得更多?
这就是为什么性能调优和优化对我们的虚拟化环境如此重要。正如我们将在本章中发现的那样,有许多不同的参数需要考虑-特别是如果我们从一开始就没有正确设计事物,这通常是情况。因此,我们将首先涵盖设计的主题,解释为什么它不应该只是一个纯粹的试错过程,然后继续通过不同的设备和子系统来解构这种思维过程。
在本章中,我们将涵盖以下主题:
-
调整 VM CPU 和内存性能- NUMA
-
内核同页合并
-
Virtio 设备调优
-
块 I/O 调优
-
网络 I/O 调优
一切都关乎设计
在我们生活的许多其他方面,我们不断重复一些基本模式。在 IT 中,我们通常也会这样做。当我们刚开始做某件事时,通常我们并不擅长。例如,当我们开始进行任何一种运动训练时,通常不如我们坚持几年后的水平。当我们开始音乐训练时,通常在参加音乐学校几年后我们会更擅长。同样的原则也适用于 IT-当我们开始从事 IT 时,我们远不如随着时间和主要是经验的积累变得更加擅长。
我们人类在学习过程中很擅长在智力防御方面设置障碍。我们很擅长说“我会通过我的错误学习”-而且我们通常会将其与“别打扰我”结合起来。
事实是-已经有这么多的知识存在,不去利用它就太愚蠢了。已经有这么多人经历了与我们相同或类似的过程;不利用这种经验来谋取我们的利益将是毫无意义的。此外,为什么要浪费时间在这个“我会通过我的错误学习”的事情上,当我们可以从比我们经验更丰富的人那里学到更多呢?
当我们开始使用虚拟化时,通常会从小处开始。例如,我们开始安装托管虚拟化解决方案,如 VMware Player,Oracle VirtualBox 或类似的解决方案。随着时间的推移,我们会转向具有一对虚拟机(VMs)的 hypervisor。随着我们周围的基础设施增长,我们开始遵循线性模式,试图使基础设施的工作方式与以前小型时相同,这是一个错误。IT 中没有任何线性的东西-增长、成本、管理所花费的时间…绝对没有。实际上,解构这一点非常简单-随着环境的增长,存在更多的相互依赖关系,这意味着一件事会影响另一件事,进而影响另一件事,依此类推。这种无尽的影响矩阵是人们经常忘记的东西,特别是在设计阶段。
重要提示:
这很简单:线性设计将使你一事无成,而正确的设计是性能调优的基础,这样在性能调优方面就要做的工作就少得多了。
在本书的早期(在第二章中,KVM 作为虚拟化解决方案),我们提到了非一致性内存访问(NUMA)。具体来说,我们提到了 NUMA 配置选项是 VM 配置的一个非常重要的部分,特别是如果你正在设计一个承载大量虚拟化服务器的环境。让我们用一些例子来进一步阐述这一点。这些例子将为我们提供一个很好的基础,以从一个“里程高度”的视角来看待性能调优和优化中最大的问题,并描述如何使用良好的设计原则来摆脱许多不同类型的麻烦。我们故意使用微软的解决方案作为例子 - 不是因为我们对使用它们有宗教信仰,而是因为一个简单的事实。我们有很多广泛可用的文档,我们可以利用它们 - 设计文档,最佳实践,简短的文章等。所以,让我们使用它们。
通用硬件设计
假设你刚开始设计你的新虚拟化环境。当你今天从你的渠道合作伙伴那里订购服务器时,无论他们是谁,你需要从一个很长的列表中选择一个型号。品牌并不重要 - 有很多型号供选择。你可以选择 1U(所谓的“披萨盒”)服务器,大多数情况下有一个或两个 CPU,具体取决于型号。然后,你可以选择 2U 服务器,3U 服务器……列表呈指数级增长。假设你选择了一个带有一个 CPU 的 2U 服务器。
在下一步中,你选择内存的数量 - 比如 96GB 或 128GB。你下订单,几天或几周后,你的服务器就送到了。你打开它,然后意识到一些事情 - 所有的 RAM 都连接到 CPU1 的内存通道。你把它放在你的内存库里,忘记它,然后继续下一个阶段。
然后,问题变成了一些非常普通设置的微观管理。服务器的 BIOS 版本,hypervisor 级别的驱动程序和 BIOS 设置(电源管理,C 状态,Turbo Boost,超线程,各种与内存相关的设置,不允许核心关闭自己等)对我们在 hypervisor 上运行的 VM 的性能有着巨大的影响。因此,最佳实践肯定是首先检查我们的硬件是否有任何更新的 BIOS/固件版本,并检查制造商和其他相关文档,以确保 BIOS 设置尽可能优化。然后,只有在这之后,我们才能开始勾选一些物理和部署程序 - 在机架中部署我们的服务器,安装操作系统和我们需要的一切,然后开始使用它。
假设过了一段时间,你意识到需要进行一些升级,并订购了一些 PCI Express 卡 - 两个单端口光纤通道 8 Gbit/s 主机适配器,两个单端口 10 Gbit/s 以太网卡,以及两个 PCI Express NVMe 固态硬盘。例如,通过订购这些卡,你想增加一些功能 - 访问光纤通道存储,并通过将这两个功能从 1 Gbit/s 切换到 10 Gbit/s 网络来加快备份过程和虚拟机迁移的速度。你下订单,几天或几周后,你的新 PCI Express 卡送到了。你打开它们,关闭服务器,将其从机架中取出,并安装这些卡。2U
服务器通常有空间可以安装两甚至三个 PCI Express 延长线卡,用于连接额外的 PCI Express 设备。假设你使用第一个 PCI Express 延长线来部署前两张卡 - 光纤通道控制器和 10 Gbit/s 以太网卡。然后,注意到你没有足够的 PCI Express 连接器将所有东西连接到第一个 PCI Express 延长线,你使用第二个 PCI Express 延长线来安装你的两个 PCI Express NVMe 固态硬盘。你将所有东西固定好,关闭服务器盖,将服务器放回机架,并重新开机。然后,你回到笔记本电脑上,试图格式化 PCI Express NVMe 固态硬盘并将其用于新的虚拟机存储,却发现服务器无法识别这些固态硬盘。你问自己 - 这到底是怎么回事?我的服务器出了问题吗?
图 15.1 - 适用于 DL380p G8 的 PCI Express 延长线 - 您必须将 PCI Express 卡插入其插槽
你给销售代表打电话,告诉他们你认为服务器出现故障,因为它无法识别这些新的固态硬盘。销售代表将你转接到售前技术支持;你听到对面传来一阵轻笑,然后得到以下信息:“嗯,你看,你不能那样做。如果你想在服务器上使用第二个 PCI Express 延长线,你必须在第二个 CPU 插槽中安装一个 CPU 套件(CPU 加散热器),以及为第二个 CPU 安装内存。订购这两样东西,安装到你的服务器上,你的 PCI Express NVMe 固态硬盘就能正常工作了。”
你结束了电话会话,脑海中留下了一个问号 - 这到底是怎么回事?为什么我需要连接第二个 CPU 和内存到其内存控制器才能使用一些 PCI Express 卡?
这实际上与两件事有关:
-
你不能在未安装的 CPU 上使用内存插槽,因为该内存需要内存控制器,而内存控制器位于 CPU 内部。
-
你不能在未安装的 CPU 上使用 PCI Express,因为连接 PCI Express 延长线卡到 CPU 的 PCI Express 通道并不一定由芯片组提供 - CPU 也可以用于 PCI Express 通道,而且通常是这样,特别是对于最快速的连接,你一会儿就会了解到。
我们知道这很令人困惑;我们能感受到你的痛苦,因为我们也曾经历过。不幸的是,你必须再和我们待一会儿,因为情况会变得更加混乱。
在第四章中,Libvirt 网络,我们学习了如何通过使用 Intel X540-AT2 网络控制器来配置 SR-IOV。我们提到在配置 SR-IOV 时我们使用了 HP ProLiant DL380p G8 服务器,所以让我们在这里也使用该服务器作为我们的示例。如果您查看该服务器的规格,您会注意到它使用了Intel C600芯片组。然后,如果您前往 Intel 的 ARK 网站(ark.intel.com
)并搜索有关 C600 的信息,您会注意到它有五个不同的版本(C602、C602J、C604、C606 和 C608),但其中最耐人寻味的部分是所有这些版本都只支持 8 条 PCI Express 2.0 通道。考虑到服务器规格清楚地说明该服务器支持 PCI Express 3.0,这变得非常令人困惑。这是怎么回事,这里使用了什么样的诡计?是的,PCI Express 3.0 卡几乎总是可以以 PCI Express 2.0 的速度工作,但最好不要直接说这台服务器支持 PCI Express 3.0,然后发现它通过提供 PCI Express 2.0 级别的性能(每个 PCI Express 通道的速度减慢一倍)来支持它。
只有当您查看 HP ProLiant DL380p G8 QuickSpecs 文档并找到该文档的特定部分(扩展槽部分,其中描述了三种不同类型的 PCI Express 扩展槽)时,我们才能找到我们实际需要的所有信息。让我们使用所有 PCI Express 扩展槽的详细信息作为参考和解释。基本上,主要扩展槽由处理器 1 提供两个 PCI Express v3.0 槽(x16 加 x8),第三个槽(PCI Express 2.0 x8)由芯片组提供。对于可选扩展槽,它表示所有槽都由 CPU 提供(x16 加 x8 乘以 2)。实际上,有一些型号可以有三个 PCI Express 扩展槽,对于第三个扩展槽,所有 PCI Express 通道(x16 乘以 2)也由处理器 2 提供。
这一切都非常重要。对于许多情景来说,这是性能瓶颈的一个巨大因素,这也是为什么我们的示例围绕着两个 PCI Express NVMe 固态硬盘的想法展开的。我们希望与您一起完成整个旅程。
因此,此时我们可以就我们示例服务器的实际标准硬件设计进行有根据的讨论。如果我们的意图是将这些 PCI Express NVMe 固态硬盘用作我们的 VM 的本地存储,那么大多数人会将这视为优先事项。这意味着我们绝对希望将这些设备连接到 PCI Express 3.0 槽,以避免受到 PCI Express 2.0 速度的限制。如果我们有两个 CPU,我们可能最好在我们的 PCI Express 扩展槽的第一个 PCI Express 槽中使用这个特定目的。原因很简单-它们是PCI Express 3.0 兼容,并且它们是由 CPU 提供。再次强调,这是非常重要的-这意味着它们是直接连接到 CPU,而不需要通过芯片组的额外延迟。因为,归根结底,CPU 是一切的中心枢纽,从 VM 到固态硬盘再返回的数据都将通过 CPU。从设计的角度来看,我们应该绝对利用我们知道的这一点,并将我们的 PCI Express NVMe 固态硬盘本地连接到我们的 CPU。
下一步与光纤通道控制器和 10 Gbit/s 以太网控制器有关。大部分 8 Gbit/s 光纤通道控制器都兼容 PCI Express 2.0。同样的情况也适用于 10 Gbit/s 以太网适配器。因此,这又是一个优先考虑的问题。如果您从我们的示例服务器大量使用光纤通道存储,那么逻辑推断您会希望将新的光纤通道控制器放在尽可能快的位置。这将是我们的两个 PCI Express 扩展槽中的第二个 PCI Express 槽。同样,第二个 PCI Express 槽都由 CPU 提供-处理器 1 和处理器 2。现在,我们只剩下 10 Gbit/s 以太网适配器。在我们的示例场景中,我们说我们将使用这些适配器进行备份和 VM 迁移。如果通过芯片组上的网络适配器进行备份,备份不会受到太大影响。VM 迁移可能对此有些敏感。因此,您将第一个 10 Gbit/s 以太网适配器连接到主扩展槽上的第三个 PCI Express 槽(用于备份,由芯片组提供)。然后,您还将第二个 10 Gbit/s 以太网适配器连接到次级扩展槽上的第三个 PCI Express 槽(由处理器 2 提供的 PCI Express 通道)。
我们刚刚开始讨论硬件方面的设计问题,现在我们已经有了如此丰富的信息要处理。现在让我们继续进行我们设计的第二阶段-与 VM 设计相关。具体来说,我们将讨论如何从头开始创建正确设计的新 VM。但是,如果我们要这样做,我们需要知道这个 VM 将为哪个应用程序创建。为此,我们将创建一个场景。我们将使用正在创建的 VM 来托管运行 Windows Server 2019 的 VM 上的 Microsoft SQL 数据库集群中的一个节点。当然,该 VM 将安装在 KVM 主机上。这是客户交给我们的任务。由于我们已经完成了一般的硬件设计,现在我们将专注于 VM 设计。
VM 设计
创建 VM 很容易-我们只需转到virt-manager
,点击几次,就可以了。oVirt、RedHat Enterprise Virtualization Manager、OpenStack、VMware 和 Microsoft 虚拟化解决方案也是如此……几乎在任何地方都是一样的。问题在于正确设计 VM。具体来说,问题在于创建一个将预先调整为在非常高的水平上运行应用程序的 VM,然后只留下一小部分配置步骤,我们可以在服务器或 VM 端采取来提高性能-前提是后续的大部分优化过程将在操作系统或应用程序级别完成。
因此,人们通常以两种方式之一开始创建 VM-要么从头开始创建 VM 并向 VM 添加XYZ数量的资源,要么使用模板,正如我们在第八章中解释的那样,创建和修改 VM 磁盘、模板和快照,这将节省大量时间。无论我们使用哪种方式,都会为我们的 VM 配置一定数量的资源。然后,我们记住我们将使用这个 VM(SQL),所以我们将 CPU 的数量增加到,例如,四个,内存的数量增加到 16 GB。我们将该 VM 放在服务器的本地存储中,启动它,并开始部署更新,配置网络,重新启动,通常准备 VM 进行最终安装步骤,即实际安装我们的应用程序(SQL Server 2016)和一些相关更新。完成后,我们开始创建我们的数据库,并继续进行需要完成的下一组任务。
接下来,让我们从设计和调优的角度来看这个过程。
调整 VM CPU 和内存性能
上述过程中有一些非常直接的问题。有些只是工程问题,而有些则更多是程序问题。让我们讨论一下:
-
在 IT 领域几乎没有一刀切的解决方案。每个客户的每个虚拟机都有不同的情况,并处于不同的环境中,包括不同的设备、服务器等等。不要试图加快流程以给人留下印象,因为这肯定会在以后成为问题。
-
当你完成部署后,停下来。学会深呼吸,停下来思考一秒钟,或者等一个小时甚至一天。记住你设计虚拟机的目的。
-
在允许虚拟机投入生产使用之前,检查其配置。虚拟 CPU 的数量、内存、存储位置、网络选项、驱动程序、软件更新——一切都要检查。
-
在安装阶段或模板阶段之前,可以进行大量的预配置。如果你正在将现有环境迁移到新环境,收集有关旧环境的信息。了解数据库的大小、使用的存储以及人们对其数据库服务器和使用它们的应用程序的性能满意程度。
在整个过程结束时,学会对你所做的与 IT 相关的工作采取高层视角。从质量保证的角度来看,IT 应该是一种高度结构化的、程序化的工作。如果你以前做过某事,学会记录你在安装过程中所做的事情和你所做的更改。文档——就目前而言——是 IT 的最大软肋之一。撰写文档将使你在未来面对相同(较少)或类似(更多)的情况时更容易重复这个过程。向伟人学习——举个例子,如果贝多芬没有详细记录他日复一日所做的事情,我们对他的了解就会少得多。是的,他生于 1770 年,今年将是他诞辰 250 周年,那是很久以前的事了,但这并不意味着 250 年前的惯例是不好的。
现在,你的虚拟机已经配置并投入生产使用,几天或几周后,你会接到公司的电话,他们会问为什么性能并不那么好。为什么它的工作效果不像物理服务器一样?
作为一个经验法则,当你在寻找 Microsoft SQL 的性能问题时,它们大致可以分为四类:
-
你的 SQL 数据库受内存限制。
-
你的 SQL 数据库受存储限制。
-
你的 SQL 数据库配置错误。
-
你的 SQL 数据库受 CPU 限制。
根据我们的经验,第一和第二类问题很容易占据 SQL 性能问题的 80-85%。第三类可能占 10%,而最后一类相对较少,但仍然会发生。记住,从基础设施的角度来看,当你设计数据库虚拟机时,你应该首先查看虚拟机内存和存储配置,因为它们是最常见的原因。问题会逐渐积累并不断恶化。具体来说,导致 SQL 虚拟机性能不佳的一些最常见的关键原因是内存位置、从 CPU 角度看待它,以及存储问题——延迟/IOPS 和带宽成为问题。所以,让我们逐一描述这些问题。
我们需要解决的第一个问题与——有趣的是——地理有关。对于数据库来说,将其内存内容尽可能靠近分配给其虚拟机的 CPU 核心非常重要。这就是 NUMA 的意义所在。我们可以通过一些配置轻松地解决这个特定问题。假设我们选择我们的虚拟机使用四个虚拟 CPU。我们的测试服务器配备了英特尔至强 E5-2660v2 处理器,每个处理器都有 10 个物理核心。考虑到我们的服务器有两个这样的至强处理器,我们总共有 20 个核心可供使用。
我们有两个基本问题要回答:
-
我们的虚拟机的四个核心如何与下面的 20 个物理核心相关?
-
这与 VM 的内存有什么关系,我们如何优化它?
对这两个问题的答案是取决于我们的配置。默认情况下,我们的 VM 可能会从两个物理处理器中使用两个核心,并在内存方面分布在两者之间或 3+1。这些配置示例都不好。你想要的是将所有虚拟 CPU 核心放在一个物理处理器上,并且你希望这些虚拟 CPU 核心使用与这四个物理核心相连的内存 - 直接连接到基础物理处理器的内存控制器。我们刚刚描述的是 NUMA 背后的基本思想 - 为你的 VM 提供作为本地内存的构建计算块的节点(由 CPU 核心组成)。
如果可能的话,你希望为该 VM 保留所有内存,这样它就不会在 VM 之外的某个地方交换。在 KVM 中,VM 之外将在 KVM 主机交换空间中。始终访问真正的 RAM 内存是性能和 SLA 相关的配置选项。如果 VM 使用一些基础交换分区作为其内存,它的性能将不同。请记住,交换通常是在某种本地 RAID 阵列、SD 卡或类似介质上进行的,与真正的 RAM 内存相比,这些介质在带宽和延迟方面慢得多。如果你想对此做出高层次的陈述 - 不惜一切代价避免 KVM 主机上的内存过度承诺。对于 CPU 也是如此,这是任何其他虚拟化解决方案上常用的最佳实践,而不仅仅是在 KVM 上。
此外,对于关键资源,比如数据库 VM,将 vCPU 固定到特定的物理核心确实是有意义的。这意味着我们可以使用特定的物理核心来运行一个 VM,并且我们应该配置在同一主机上运行的其他 VM不使用这些核心。这样,我们就可以保留这些 CPU 核心专门用于单个 VM,从而配置一切以获得最大性能,不受运行在物理服务器上的其他 VM 的影响。
是的,有时经理和公司所有者不会喜欢你因为这个最佳实践(好像是你的错),因为这需要适当的规划和足够的资源。但这是他们必须接受的事情 - 或者不接受,看他们的选择。我们的工作是尽可能使 IT 系统运行得最好。
VM 设计有其基本原则,如 CPU 和内存设计、NUMA 配置、配置设备、存储和网络配置等。让我们逐步地逐个讨论所有这些主题,从一个高级的基于 CPU 的功能开始,如果正确使用,它确实可以帮助我们的系统尽可能地运行得最好 - CPU 固定。
CPU 固定
CPU 固定只是设置 vCPU 和主机物理 CPU 核心之间亲和性的过程,以便 vCPU 只在该物理 CPU 核心上执行。我们可以使用virsh vcpupin
命令将 vCPU 绑定到物理 CPU 核心或物理 CPU 核心的子集。
在进行 vCPU 固定时有一些最佳实践:
-
如果客人 vCPU 的数量超过单个 NUMA 节点的 CPU 数量,则不要使用默认的固定选项。
-
如果物理 CPU 分布在不同的 NUMA 节点上,最好创建多个虚拟机,并将每个虚拟机的 vCPU 固定到同一 NUMA 节点中的物理 CPU。这是因为访问不同的 NUMA 节点,或者跨多个 NUMA 节点运行,对性能有负面影响,特别是对于内存密集型应用程序。
让我们来看看 vCPU 固定的步骤:
- 执行
virsh nodeinfo
以收集有关主机 CPU 配置的详细信息:
图 15.2 - 关于我们的 KVM 节点的信息
- 下一步是通过执行
virsh capabilities
命令并检查标记为<topology>
的部分来获取 CPU 拓扑结构:
图 15.3 – 具有所有可见物理 CPU 核心的 virsh capabilities 输出
一旦我们确定了主机的拓扑结构,下一步就是开始固定 vCPU。
- 让我们首先检查名为
SQLForNuma
的客户端的当前亲和力或固定配置,该客户端有四个 vCPU:
图 15.4 – 检查默认的 vcpupin 设置
让我们通过使用 CPU 固定来改变这一点。
- 让我们将
vCPU0
固定到物理核心 0,vCPU1
固定到物理核心 1,vCPU2
固定到物理核心 2,vCPU3
固定到物理核心 3:
图 15.5 – 配置 CPU 固定
通过使用virsh vcpupin
,我们改变了此 VM 的固定虚拟 CPU 分配。
- 让我们在此 VM 上使用
virsh dumpxml
来检查配置更改:
图 15.6 – CPU 固定 VM 配置更改
注意virsh
命令中列出的 CPU 亲和力以及运行客户端的 XML 转储中的<cputune>
标记。正如 XML 标记所说,这属于客户端的 CPU 调整部分。还可以配置一组物理 CPU 用于特定 vCPU,而不是单个物理 CPU。
有几件事情要记住。 vCPU 固定可以提高性能;但是,这取决于主机配置和系统上的其他设置。确保进行足够的测试并验证设置。
您还可以使用virsh vcpuinfo
来验证固定。virsh vcpuinfo
命令的输出如下:
图 15.7 – 用于我们的 VM 的 virsh vcpuinfo
如果我们在繁忙的主机上进行此操作,将会产生后果。有时,我们可能无法启动我们的 SQL 机器,因为这些设置。因此,为了更大的利益(SQL VM 能够工作而不是不想启动),我们可以将内存模式配置从strict
更改为interleave
或preferred
,这将放宽对于为此 VM 严格使用本地内存的坚持。
现在让我们探讨内存调整选项,因为这是下一个逻辑要讨论的事情。
内存调整
对于大多数环境来说,内存都是宝贵的资源,不是吗?因此,应通过调整来实现对内存的有效使用。优化 KVM 内存性能的第一条规则是在设置期间不要为客户端分配比其使用的资源更多的资源。
我们将更详细地讨论以下内容:
-
内存分配
-
内存调整
-
内存支持
让我们从解释如何为虚拟系统或客户端配置内存分配开始。
内存分配
为了使分配过程简单,我们将再次考虑virt-manager
libvirt 客户端。内存分配可以从以下截图中显示的窗口中完成:
图 15.8 – VM 内存选项
正如您在前面的截图中所看到的,有两个主要选项:当前分配和最大分配:
-
最大分配:客户端的运行时最大内存分配。这是客户端在运行时可以分配的最大内存。
-
当前分配:客户端始终使用的内存量。出于内存球形原因,我们可以将此值设置为低于最大值。
virsh
命令可用于调整这些参数。相关的virsh
命令选项是setmem
和setmaxmem
。
内存调整
内存调整选项添加在客户端配置文件的<memtune>
下。
其他内存调整选项可以在libvirt.org/formatdomain.html#elementsMemoryTuning
找到。
管理员可以手动配置客户机的内存设置。如果省略了<memtune>
配置,那么默认的内存设置将适用于客户机。这里使用的virsh
命令如下:
# virsh memtune <virtual_machine> --parameter size parameter
它可以具有以下任何值;这个最佳实践在 man 页面中有很好的记录:
--hard-limit The maximum memory the guest can use.
--soft-limit The memory limit to enforce during memory contention.
--swap-hard-limit The maximum memory plus swap the guest can use. This has to be more than hard-limit value provided.
--min-guarantee The guaranteed minimum memory allocation for the guest.
可以获取为memtune
参数设置的默认/当前值,如下所示:
图 15.9 - 检查 VM 的 memtune 设置
在设置hard_limit
时,不应将此值设置得太低。这可能导致虚拟机被内核终止。这就是为什么确定虚拟机(或任何其他进程)的正确资源量是一个设计问题。有时,正确设计东西似乎就像黑暗艺术一样。
要了解如何设置这些参数,请参阅以下截图中memtune
命令的帮助输出:
图 15.10 - 检查 virsh 帮助 memtune
在我们讨论了内存分配和调整之后,最后一个选项是内存后备。
内存后备
以下是内存后备的客户机 XML 表示:
<domain> ...
<memoryBacking>
<hugepages>
<page size="1" unit="G" nodeset="0-3,5"/>
<page size="2" unit="M" nodeset="4"/>
</hugepages>
<nosharepages/>
<locked/>
</memoryBacking> ...
</domain>
您可能已经注意到内存后备有三个主要选项:locked
、nosharepages
和hugepages
。让我们逐一介绍它们,从locked
开始。
locked
在 KVM 虚拟化中,客户机内存位于 KVM 主机中的qemu-kvm
进程的进程地址空间中。这些客户机内存页面可以根据主机的需求随时被 Linux 内核交换出去,这就是locked
可以帮助的地方。如果将客户机的内存后备选项设置为locked
,主机将不会交换属于虚拟系统或客户机的内存页面。当启用此选项时,主机系统内存中的虚拟内存页面将被锁定:
<memoryBacking>
<locked/>
</memoryBacking>
我们需要使用<memtune>
来设置hard_limit
。计算很简单 - 我们需要为客户机加上开销的内存量。
nosharepages
以下是来自客户机配置文件的nosharepages
的 XML 表示:
<memoryBacking>
<nosharepages/>
</memoryBacking>
有不同的机制可以在内存页面相同的情况下实现内存共享。诸如nosharepages
选项之类的技术指示了虚拟化程序禁用此客户机的共享页面 - 也就是说,设置此选项将阻止主机在客户机之间进行内存去重。
hugepages
第三个也是最后一个选项是hugepages
,可以用 XML 格式表示如下:
<memoryBacking>
</hugepages>
</memoryBacking>
HugePages 是在 Linux 内核中引入的,以改善内存管理的性能。内存以称为页面的块进行管理。不同的架构(i386、ia64)支持不同的页面大小。对于 x86 CPU(4 KB 内存页面)来说,我们不一定要使用默认设置,因为我们可以使用更大的内存页面(2 MB 到 1 GB),这个功能称为 HugePages。CPU 的一个部分称为内存管理单元(MMU)通过使用列表来管理这些页面。页面通过页表引用,并且每个页面在页表中都有一个引用。当系统想要处理大量内存时,主要有两种选项。其中一种涉及增加硬件 MMU 中的页表条目数。第二种方法是增加默认页面大小。如果我们选择增加页表条目的第一种方法,那么成本就会很高。
处理大量内存的第二种更有效的方法是使用 HugePages 或通过使用 HugePages 增加页面大小。每台服务器的不同内存量意味着需要不同的页面大小。默认值对大多数情况都可以,而巨大的内存页面(例如 1 GB)在我们有大量内存(数百 GB 甚至 TB)时更有效。这意味着在引用内存页面方面需要更少的管理工作,而实际上花费更多时间获取这些内存页面的内容,这可能会导致显著的性能提升。大多数已知的 Linux 发行版都可以使用 HugePages 来管理大量内存。进程可以使用 HugePages 内存支持通过增加 CPU 缓存命中来提高性能,这是在第二章中解释的,KVM 作为虚拟化解决方案。您已经知道,客户系统只是 Linux 系统中的进程,因此 KVM 客户也有资格执行相同的操作。
在我们继续之前,我们还应该提到MADV_HUGEPAGE
区域(以避免消耗更多的内存资源),或者在整个系统中启用。系统中配置 THP 有三个主要选项:always
,madvise
和never
。
# cat/sys/kernel/mm/transparent_hugepage/enabled [always] madvise never
从前面的输出中,我们可以看到我们服务器中当前的 THP 设置为madvise
。其他选项可以通过使用以下命令之一来启用:
echo always >/sys/kernel/mm/transparent_hugepage/enabled
echo madvise >/sys/kernel/mm/transparent_hugepage/enabled
echo never >/sys/kernel/mm/transparent_hugepage/enabled
简而言之,这些值的含义如下:
-
always
:始终使用 THP。 -
madvise
:仅在MADV_HUGEPAGE
中使用 HugePages。 -
never
:禁用该功能。
THP 会自动优化性能设置。通过将内存用作缓存,我们可以获得性能优势。当 THP 存在时,可以使用静态 HugePages,或者换句话说,THP 不会阻止使用静态方法。如果我们不配置 KVM hypervisor 来使用静态 HugePages,它将使用 4 KB 的透明 HugePages。使用 HugePages 来管理 KVM 客户端内存的优势在于,用于页表的内存更少,TLB 缺失减少;显然,这会提高性能。但请记住,当为客户端内存使用 HugePages 时,您将无法再交换或收缩客户端内存。
让我们快速看一下如何在 KVM 设置中使用静态 HugePages。首先,让我们检查当前的系统配置 - 很明显,这个系统中的 HugePages 大小目前设置为 2 MB:
图 15.11 - 检查 HugePages 设置
我们主要讨论以 HugePages 开头的所有属性,但值得一提的是AnonHugePages
属性。AnonHugePages
属性告诉我们系统级别上当前 THP 的使用情况。
现在,让我们配置 KVM 以使用自定义的 HugePages 大小:
- 通过运行以下命令查看当前显式的
hugepages
值或从sysfs
中获取它,如下所示:
# cat /proc/sys/vm/nr_hugepages
0
- 我们还可以使用
sysctl -a |grep huge
命令:
图 15.12 - sysctl hugepages 设置
- 由于 HugePage 大小为 2 MB,我们可以按 2 MB 的增量设置 hugepages。要将 hugepages 的数量设置为 2,000,请使用以下命令:
# echo 2000 > /proc/sys/vm/nr_hugepages
巨大页面分配的总内存不能被不了解巨大页面的应用程序使用 - 也就是说,如果你过度分配了巨大页面,主机系统的正常操作可能会受到影响。在我们的例子中,2048*2 MB 将等于 4096 MB 的内存,在进行此配置时我们应该有这么多可用的内存。
- 我们需要告诉系统这种类型的配置实际上是可以的,并配置
/etc/security/limits.conf
以反映这一点。否则,系统可能会拒绝给我们访问 2,048 个 2 MB 内存的巨大页面。我们需要在该文件中添加两行:
<value> parameter will depend on the configuration we want to do. If we want to configure everything according to our 2048*2 MB example, <value> would be 4,194,304 (or 4096*1024).
- 要使其持久化,您可以使用以下命令:
# sysctl -w vm.nr_hugepages=<number of hugepages>
- 然后,挂载
fs
大页,重新配置虚拟机,并重新启动主机:
# mount -t hugetlbfs hugetlbfs /dev/hugepages
通过在虚拟机配置文件中添加以下设置来重新配置已配置大页的虚拟机:
<memoryBacking>
</hugepages>
</ memoryBacking>
现在是关闭虚拟机并重新启动主机的时候。在虚拟机内执行以下操作:
# systemctl poweroff
在主机上,执行以下操作:
# systemctl reboot
主机重新启动并重新启动虚拟机后,它现在将开始使用大页。
下一个主题与在多个虚拟机之间共享内存内容有关,称为 KSM。这项技术被广泛用于节省内存。在任何给定时刻,当虚拟化主机上启动多个虚拟机时,这些虚拟机有很大的统计机会具有相同的内存内容块(它们具有相同的内容)。然后,没有理由多次存储相同的内容。通常,我们将 KSM 称为应用于内存的去重复过程。让我们学习如何使用和配置 KSM。
熟悉 KSM
KSM 是一个允许不同进程之间共享相同页面的功能。我们可能会认为相同的页面存在是由于某些原因,例如,如果有多个进程从相同的二进制文件生成,或者类似的情况。但实际上并没有这样的规则。KSM 扫描这些相同的内存页面,并合并一个写时复制的共享页面。写时复制是一种机制,当试图更改一个被多个进程共享的内存区域时,请求更改的进程会得到一个新的副本,并将更改保存在其中。
尽管所有进程都可以访问合并的写时复制共享页面,但每当一个进程尝试更改内容(向该页面写入)时,该进程都会得到一个带有所有更改的新副本。到目前为止,您可能已经了解到,通过使用 KSM,我们可以减少物理内存消耗。在 KVM 环境中,这确实可以增加价值,因为客户端系统是系统中的qemu-kvm
进程,并且所有虚拟机进程很可能具有大量相似的内存。
为了使 KSM 工作,进程/应用程序必须向 KSM 注册其内存页面。在 KVM 环境中,KSM 允许客户端共享相同的内存页面,从而提高内存消耗。这可能是某种应用程序数据、库或其他经常使用的内容。这个共享的页面或内存被标记为“写时复制”。简而言之,KSM 避免了内存重复,当 KVM 环境中存在相似的客户端操作系统时,它非常有用。
通过使用预测理论,KSM 可以提供增强的内存速度和利用率。大多数情况下,这些共享数据存储在缓存或主内存中,这会导致 KVM 客户端的缓存未命中减少。此外,KSM 可以减少客户端内存占用,从某种程度上允许用户在 KVM 设置中进行内存超额分配,从而提供更大的资源利用率。然而,我们必须记住,KSM 需要更多的 CPU 资源来识别重复页面并执行共享/合并等任务。
之前,我们提到进程必须标记页面,以表明它们是 KSM 操作的合格候选者。这种标记可以由基于MADV_MERGEABLE
标志的进程完成,我们将在下一节中讨论。您可以在madvise
手册页中了解有关此标志的用法:
# man 2 madvise
MADV_MERGEABLE (since Linux 2.6.32)
Enable Kernel Samepage Merging (KSM) for the pages in the range specified by addr and length. The kernel regularly scans those areas of user memory that have been marked as mergeable, looking for pages with identical content. These are replaced by a single write-protected page (that is automatically copied if a process later wants to update the content of the page). KSM merges only private anonymous pages (see mmap(2)).
The KSM feature is intended for applications that generate many instances of the same data (e.g., virtualization systems such as KVM). It can consume a lot of processing power; use with care. See the Linux kernel source file Documentation/ vm/ksm.txt for more details.
The MADV_MERGEABLE and MADV_UNMERGEABLE operations are available only if the kernel was configured with CONFIG_KSM.
因此,内核必须配置 KSM,如下所示:
图 15.13 - 检查 KSM 设置
KSM 作为qemu-kvm
软件包的一部分部署。可以从sysfs
文件系统中的/sys
目录中获取有关 KSM 服务的信息。在这个位置有不同的文件,反映了当前 KSM 的状态。这些文件由内核动态更新,并且它有 KSM 使用和统计的精确记录:
图 15.14 - sysfs 中的 KSM 设置
在接下来的部分中,我们将讨论ksmtuned
服务及其配置变量。由于ksmtuned
是一个控制 KSM 的服务,其配置变量类似于我们在sysfs
文件系统中看到的文件。有关更多详细信息,请查看www.kernel.org/doc/html/latest/admin-guide/mm/ksm.html
。
还可以使用virsh
命令调整这些参数。virsh node-memory-tune
命令可以为我们完成这项工作。例如,以下命令指定在共享内存服务进入休眠之前要扫描的页面数:
# virsh node-memory-tune --shm-pages-to-scan number
与任何其他服务一样,ksmtuned
服务也有日志存储在日志文件/var/log/ksmtuned
中。如果我们在/etc/ksmtuned.conf
中添加DEBUG=1
,我们将从任何类型的 KSM 调整操作中获得日志记录。有关更多详细信息,请参阅www.kernel.org/doc/Documentation/vm/ksm.txt
。
一旦我们启动了 KSM 服务,如下所示,您可以观察值的变化,具体取决于 KSM 服务的操作:
# systemctl start ksm
然后我们可以像这样检查ksm
服务的状态:
图 15.15 - ksm 服务命令和 ps 命令输出
一旦 KSM 服务启动并且我们的主机上有多个虚拟机正在运行,我们可以使用以下命令多次查询sysfs
来检查变化:
cat /sys/kernel/mm/ksm/*
让我们更详细地探讨ksmtuned
服务。ksmtuned
服务被设计成经历一系列动作并调整 KSM。这个动作循环会不断地工作。每当创建或销毁一个客户系统时,libvirt 都会通知ksmtuned
服务。
/etc/ksmtuned.conf
文件是ksmtuned
服务的配置文件。以下是可用的配置参数的简要说明。您可以看到这些配置参数与sysfs
中的 KSM 文件相匹配:
# Configuration file for ksmtuned.
# How long ksmtuned should sleep between tuning adjustments
# KSM_MONITOR_INTERVAL=60
# Millisecond sleep between ksm scans for 16Gb server.
# Smaller servers sleep more, bigger sleep less.
# KSM_SLEEP_MSEC=10
# KSM_NPAGES_BOOST - is added to the `npages` value, when `free memory` is less than `thres`.
# KSM_NPAGES_BOOST=300
# KSM_NPAGES_DECAY - is the value given is subtracted to the `npages` value, when `free memory` is greater than `thres`.
# KSM_NPAGES_DECAY=-50
# KSM_NPAGES_MIN - is the lower limit for the `npages` value.
# KSM_NPAGES_MIN=64
# KSM_NPAGES_MAX - is the upper limit for the `npages` value.
# KSM_NPAGES_MAX=1250
# KSM_THRES_COEF - is the RAM percentage to be calculated in parameter `thres`.
# KSM_THRES_COEF=20
# KSM_THRES_CONST - If this is a low memory system, and the `thres` value is less than `KSM_THRES_CONST`, then reset `thres` value to `KSM_THRES_CONST` value.
# KSM_THRES_CONST=2048
KSM 旨在提高性能并允许内存超额分配。在大多数环境中,它都能够实现这一目的;然而,在某些设置或环境中,KSM 可能会引入性能开销 - 例如,如果您有一些虚拟机在启动时具有相似的内存内容,然后进行大量的内存密集型操作。这将会导致问题,因为 KSM 首先会非常努力地减少内存占用,然后浪费时间来处理多个虚拟机之间的所有内存内容差异。此外,有人担心 KSM 可能打开一个潜在的渠道,可能被用于在客户之间泄露信息,这在过去几年中已经有充分的记录。如果您有这些担忧,或者如果您看到/经历 KSM 没有帮助提高工作负载的性能,可以将其禁用。
要禁用 KSM,通过执行以下命令停止系统中的ksmtuned
和ksm
服务:
# systemctl stop ksm
# systemctl stop ksmtuned
我们已经研究了 CPU 和内存的不同调优选项。接下来我们需要讨论的下一个重要主题是 NUMA 配置,其中 CPU 和内存配置成为更大故事或背景的一部分。
使用 NUMA 调整 CPU 和内存
在我们开始为 NUMA 可用系统调整 CPU 和内存之前,让我们看看 NUMA 是什么以及它是如何工作的。
将 NUMA 视为一个系统,其中有多个系统总线,每个总线为一小组处理器和关联内存提供服务。每组处理器都有自己的内存,可能还有自己的 I/O 通道。可能无法阻止或阻止运行的 VM 跨越这些组。这些组中的每一个称为NUMA 节点。
在这个概念中,如果一个进程/线程在一个 NUMA 节点上运行,同一节点上的内存称为本地内存,而驻留在不同节点上的内存称为外部/远程内存。这种实现与对称多处理系统(SMP)不同,SMP 中所有内存的访问时间对所有 CPU 都是相同的,因为内存访问是通过一个集中的总线进行的。
讨论 NUMA 的一个重要主题是 NUMA 比率。NUMA 比率是衡量 CPU 访问本地内存相对于访问远程/外部内存的速度的指标。例如,如果 NUMA 比率为 2.0,则 CPU 访问远程内存的时间是访问本地内存的两倍。如果 NUMA 比率为 1,这意味着我们正在使用 SMP。比率越大,VM 内存操作在获取必要数据(或保存数据)之前必须支付的延迟成本(开销)就越大。在更深入地探讨调优之前,让我们讨论一下系统的 NUMA 拓扑。显示当前 NUMA 拓扑的最简单方法之一是通过numactl
命令:
图 15.16 - numactl -H 输出
前面的numactl
输出表明系统中有 10 个 CPU,它们属于单个 NUMA 节点。它还列出了与每个 NUMA 节点关联的内存和节点距离。当我们讨论 CPU 固定时,我们使用virsh
功能显示了系统的拓扑结构。要获得 NUMA 拓扑的图形视图,可以使用一个名为lstopo
的命令,该命令在基于 CentOS-/Red Hat 的系统中与hwloc
软件包一起提供:
图 15.17 - 使用 lstopo 命令可视化 NUMA 拓扑
此截图还显示了与 NUMA 节点关联的 PCI 设备。例如,ens*
(网络接口)设备连接到 NUMA 节点 0。一旦我们了解了系统的 NUMA 拓扑,就可以开始调整它,特别是针对 KVM 虚拟化设置。
NUMA 内存分配策略
通过修改 VM XML 配置文件,我们可以进行 NUMA 调优。调优 NUMA 引入了一个名为numatune
的新元素标签:
<domain> ...
<numatune>
<memory mode="strict" nodeset="1-4,³"/>
</numatune> ...
</domain>
这也可以通过virsh
命令进行配置,如下所示:
图 15.18 - 使用 virsh numatune 配置 NUMA 设置
此标签的 XML 表示如下:
<domain>
…
<numatune>
<memory mode="strict" nodeset="1-4,³"/>
<memnode cellid="0" mode="strict" nodeset="1"/>
<memnode cellid="2" mode="preferred" nodeset="2"/>
</numatune> ...
</domain>
尽管名为numatune
的元素是可选的,但它是用来通过控制域进程的 NUMA 策略来调整 NUMA 主机性能的。此可选元素的主要子标签是memory
和nodeset
。有关这些子标签的一些说明如下:
memory
:此元素描述了 NUMA 节点上的内存分配过程。有三种策略来管理 NUMA 节点的内存分配:
a) Strict
:当虚拟机尝试分配内存并且内存不可用时,分配将失败。
b) Interleave
:在 NUMA 节点之间进行循环分配。
c) Preferred
:虚拟机尝试从首选节点分配内存。如果该节点没有足够的内存,它可以从剩余的 NUMA 节点分配内存。
nodeset
:指定服务器上可用的 NUMA 节点列表。
这里的一个重要属性是placement,在以下 URL 中有解释 - libvirt.org/formatdomain.html
:
“属性放置可用于指示域进程的内存放置模式,其值可以是"static"或"auto”,默认为 vCPU 的放置,或者如果指定了 nodeset,则为"static"。“auto"表示域进程将仅从查询 numad 返回的建议 nodeset 分配内存,如果指定了属性 nodeset 的值将被忽略。如果 vCPU 的放置是’auto’,并且未指定 numatune,则将隐式添加一个默认的 numatune,其放置为’auto’,模式为’strict’。”
我们需要小心这些声明,因为有适用的继承规则。例如,如果我们指定了<nodeset>
元素,<numatune>
和<vcpu>
元素默认为相同的值。因此,我们绝对可以配置不同的 CPU 和内存调优选项,但也要意识到这些选项可以被继承。
在考虑 NUMA 上下文中的 CPU 固定时,还有一些要考虑的事情。我们在本章的早些时候讨论了 CPU 固定的基础,因为它可以为我们的虚拟机提供更好、更可预测的性能,并且可以提高缓存效率。举个例子,假设我们想尽可能快地运行一个虚拟机。明智的做法是在固定 CPU 核心的 CPU 插槽上运行它,这样可以在最快的存储上运行,这将在 PCI Express 总线上。如果我们没有使用 NVMe SSD 本地运行虚拟机,我们可以使用存储控制器来实现相同的效果。但是,如果我们用来访问虚拟机存储的存储控制器物理连接到另一个 CPU 插槽,那将导致延迟。对于延迟敏感的应用程序,这将意味着性能大幅下降。
然而,我们也需要意识到另一个极端——如果我们进行过多的固定,将来可能会产生其他问题。例如,如果我们的服务器在架构上不同(具有相同数量的核心和内存),迁移虚拟机可能会变得棘手。我们可能会出现这样的情况,即迁移过程中将 CPU 核心固定到目标服务器上不存在的核心。因此,我们在配置环境时总是需要小心,以免走得太远。
我们列表上的下一个主题是emulatorpin
,它可以用来将我们的qemu-kvm
模拟器固定到特定的 CPU 核心,以便它不影响我们虚拟机核心的性能。让我们学习如何配置它。
理解 emulatorpin
emulatorpin
选项也属于 CPU 调优类别。其 XML 表示如下:
<domain> ...
<cputune> ….. <emulatorpin cpuset="1-3"/> …..
</cputune> ...
</domain>
emulatorpin
元素是可选的,用于将模拟器(qemu-kvm
)固定到主机物理 CPU。这不包括来自 VM 的 vCPU 或 IO 线程。如果省略此项,模拟器将默认固定到主机系统的所有物理 CPU。
重要提示:
请注意,当您调整支持 NUMA 的系统时,应该一起配置<vcpupin>
、<numatune>
和<emulatorpin>
,以实现最佳的确定性性能。
在我们离开这一部分之前,还有一些事情需要涵盖:客户端系统 NUMA 拓扑和 NUMA 的大页内存支持。
可以使用<numa>
元素在客户端 XML 配置中指定客户端 NUMA 拓扑结构;有些人称之为虚拟 NUMA:
<cpu> ...
<numa>
<cell id='0' cpus='0-3' memory='512000' unit='KiB'/>
<cell id='1' cpus='4-7' memory='512000' unit='KiB' /> </numa> ...
</cpu>
cell id
元素告诉虚拟机使用哪个 NUMA 节点,而cpus
元素配置特定的核心(或核心)。memory
元素为每个节点分配内存量。每个 NUMA 节点都以数字索引,从0
开始。
之前,我们讨论了memorybacking
元素,可以在客户端配置中指定使用大页。当 NUMA 存在于设置中时,nodeset
属性可用于配置每个 NUMA 节点的特定大页大小,这可能会很有用,因为它将给定客户端的 NUMA 节点与某些大页大小联系起来:
<memoryBacking>
<hugepages>
<page size="1" unit="G" nodeset="0-2,4"/>
<page size="4" unit="M" nodeset="3"/>
</hugepages>
</memoryBacking>
这种配置可以优化内存性能,因为客户端 NUMA 节点可以根据需要移动到主机 NUMA 节点,同时客户端可以继续使用主机分配的大页。
NUMA 调整还必须考虑 PCI 设备的 NUMA 节点局部性,特别是当从主机向客户端传递 PCI 设备时。如果相关的 PCI 设备隶属于远程 NUMA 节点,这可能会影响数据传输,从而影响性能。
显示 NUMA 拓扑和 PCI 设备关联的最简单方法是使用我们之前讨论过的lstopo
命令。同样命令的非图形形式也可以用来发现这个配置。请参考前面的章节。
KSM 和 NUMA
我们在前面的章节中详细讨论了 KSM。KSM 是 NUMA 感知的,它可以管理发生在多个 NUMA 节点上的 KSM 进程。如果你还记得,当我们从 sysfs 获取 KSM 条目时,遇到了一个名为merge_across_node
的sysfs
条目。这是我们可以用来管理这个进程的参数:
# cat /sys/kernel/mm/ksm/merge_across_nodes
1
如果这个参数设置为0
,KSM 只会合并来自同一 NUMA 节点的内存页面。如果设置为1
(就像这里的情况一样),它将跨越 NUMA 节点进行合并。这意味着运行在远程 NUMA 节点上的 VM CPU 在访问合并的 KSM 页面时会遇到延迟。
显然,你知道客户端 XML 条目(memorybacking
元素)用于要求虚拟机监视程序为客户端禁用共享页面。如果你不记得了,请参考内存调整部分,了解这个元素的详细信息。尽管我们可以手动配置 NUMA,但还有一种叫做自动 NUMA 平衡的东西。我们之前提到过它,但让我们看看这个概念涉及了什么。
自动 NUMA 平衡
自动 NUMA 平衡的主要目的是提高在 NUMA 感知系统中运行的不同应用程序的性能。其设计背后的策略很简单:如果一个应用程序使用本地内存到 vCPU 所在的 NUMA 节点,它将具有更好的性能。通过使用自动 NUMA 平衡,KVM 尝试将 vCPU 移动到本地(尽可能多)的内存地址,以便 vCPU 使用。这一切都是在自动 NUMA 平衡激活时由内核自动完成的。当在具有 NUMA 属性的硬件上引导时,将启用自动 NUMA 平衡。主要条件或标准如下:
-
numactl --hardware
:显示多个节点 -
cat /sys/kernel/debug/sched_features
:在标志中显示 NUMA
为了说明第二点,看下面的代码块:
# cat /sys/kernel/debug/sched_features
GENTLE_FAIR_SLEEPERS START_DEBIT NO_NEXT_BUDDY LAST_BUDDY CACHE_HOT_BUDDY
WAKEUP_PREEMPTION ARCH_POWER NO_HRTICK NO_DOUBLE_TICK LB_BIAS NONTASK_
POWER TTWU_QUEUE NO_FORCE_SD_OVERLAP RT_RUNTIME_SHARE NO_LB_MIN NUMA
NUMA_FAVOUR_HIGHER NO_NUMA_RESIST_LOWER
我们可以通过以下方法检查系统中是否启用了这个功能:
# cat /proc/sys/kernel/numa_balancing
1
显然,我们可以通过以下方式禁用自动 NUMA 平衡:
# echo 0 > /proc/sys/kernel/numa_balancing
自动 NUMA 平衡机制基于多种算法和数据结构。这种方法的内部基于以下内容:
-
NUMA 提示页面错误
-
NUMA 页面迁移
-
伪交错
-
故障统计
-
任务放置
-
任务分组
KVM 客户端的最佳实践或建议之一是将其资源限制在单个 NUMA 节点上的资源量。简而言之,这可以避免将 VMs 不必要地分割到 NUMA 节点上,从而降低性能。让我们从检查当前的 NUMA 配置开始。有多种可用的选项来执行此操作。让我们从numactl
命令、NUMA 守护程序和numastat
开始,然后再回到使用一个众所周知的命令virsh
。
numactl 命令
确认 NUMA 可用性的第一个选项使用numactl
命令,如下所示:
图 15.19 - numactl 硬件输出
这只列出一个节点。即使这表明了 NUMA 的不可用性,也可以通过运行以下命令进行进一步澄清:
# cat /sys/kernel/debug/sched_features
如果系统不支持 NUMA,这将不列出 NUMA 标志。
通常,不要使虚拟机宽于单个 NUMA 节点所能提供的范围。即使 NUMA 可用,vCPU 也绑定到 NUMA 节点,而不是特定的物理 CPU。
了解 numad 和 numastat
numad
手册页中指出:
numad 是一个守护程序,用于控制具有 NUMA 拓扑的系统上 CPU 和内存的有效使用。
numad
也被称为自动numad
手册页中指出:
“numad 是一个用户级守护程序,为具有 NUMA 拓扑的系统上的 CPU 和内存的有效使用提供放置建议和进程管理。”
numad
是一个系统守护程序,用于监视 NUMA 拓扑和资源使用情况。它将尝试定位进程以实现有效的 NUMA 局部性和亲和性,并根据系统条件的变化进行动态调整。numad
还提供指导,以帮助管理应用程序为其进程的 CPU 和内存资源进行初始手动绑定。请注意,numad
主要用于服务器整合环境,可能在同一服务器系统上运行多个应用程序或多个虚拟客户机。当进程可以在系统的 NUMA 节点子集中定位时,numad
可能会产生积极的影响。例如,如果整个系统专用于大型内存数据库应用程序,特别是如果内存访问可能保持不可预测,numad
可能不会提高性能。
为了根据 NUMA 拓扑自动调整和对齐 CPU 和内存资源,我们需要运行numad
。要将numad
用作可执行文件,只需运行以下命令:
# numad
您可以检查是否已启动如下所示:
图 15.20 - 检查 numad 是否处于活动状态
一旦执行numad
二进制文件,它将开始对齐,如下截图所示。在我们的系统中,我们有以下正在运行的虚拟机:
图 15.21 - 列出正在运行的虚拟机
您可以使用numastat
命令来监视运行numad
服务之前和之后的差异,该命令将通过以下命令持续运行:
# numad -i 0
我们可以随时停止它,但这不会改变numad
配置的 NUMA 亲和状态。现在让我们转到numastat
。
numactl
软件包提供numactl
二进制/命令,numad
软件包提供numad
二进制/命令:
图 15.22 - qemu-kvm 进程的 numastat 命令输出
重要提示:
在将虚拟机移至生产环境之前,必须对我们使用的众多内存调整选项进行全面测试。
在我们转到下一个主题之前,我们想提醒您本章前面提到的一个观点。迁移具有固定资源的虚拟机可能会很复杂,因为您必须在目标主机上拥有某种兼容资源(及其数量)。例如,目标主机的 NUMA 拓扑结构不必与源主机的 NUMA 拓扑结构对齐。在调整 KVM 环境时,您应考虑这一事实。自动 NUMA 平衡可能在一定程度上有所帮助,减少手动固定客户资源的需求。
Virtio 设备调整
在虚拟化世界中,总是将其与裸机系统进行比较。半虚拟化驱动程序增强了客户机的性能,并尝试保持接近裸机的性能。建议为完全虚拟化的客户机使用半虚拟化驱动程序,特别是当客户机运行 I/O 密集型任务和应用程序时。lguest
。Virtio 被引入以实现 IO 虚拟化的一种通用框架。
简而言之,当我们使用半虚拟化驱动程序时,VM 操作系统知道其下面有一个 hypervisor,因此使用前端驱动程序来访问它。前端驱动程序是客户系统的一部分。当存在模拟设备并且有人想要为这些设备实现后端驱动程序时,hypervisor 会执行此工作。前端和后端驱动程序通过基于 virtio 的路径进行通信。 Virtio 驱动程序是 KVM 用作半虚拟化设备驱动程序的。基本架构如下:
图 15.23 – Virtio 架构
主要有两层(virt 队列和虚拟环)来支持客户和 hypervisor 之间的通信。
Virt 队列和虚拟环(vring)是 virtio 中的传输机制实现。 Virt 队列(virtio)是连接前端和后端驱动程序的队列接口。每个 virtio 设备都有自己的 virt 队列,并且来自客户系统的请求被放入这些 virt 队列中。每个 virt 队列都有自己的环,称为 vring,这是 QEMU 和客户之间映射内存的地方。在 KVM 客户中有不同的 virtio 驱动程序可供使用。
这些设备在 QEMU 中是模拟的,驱动程序是 Linux 内核的一部分,或者是 Windows 客户的额外软件包。以下是一些设备/驱动程序对的示例:
-
virtio-net
:virtio 网络设备是一个虚拟以太网卡。virtio-net
为此提供驱动程序。 -
virtio-blk
:virtio 块设备是一个简单的虚拟块设备(即磁盘)。virtio-blk
为虚拟块设备提供块设备驱动程序。 -
virtio-balloon
:virtio 内存气球设备是用于管理客户内存的设备。 -
virtio-scsi
:virtio SCSI 主机设备将一个或多个磁盘组合在一起,并允许使用 SCSI 协议与它们通信。 -
virtio-console
:virtio 控制台设备是用于客户和主机用户空间之间的数据输入和输出的简单设备。 -
virtio-rng
:virtio 熵设备为客户提供高质量的随机性,并供客户使用等等。
一般来说,您应该在 KVM 设置中使用这些 virtio 设备以获得更好的性能。
块 I/O 调整
回到基础知识-VM 的虚拟磁盘可以是块设备,也可以是镜像文件。为了获得更好的 VM 性能,首选基于块设备的虚拟磁盘,而不是位于远程文件系统(如 NFS、GlusterFS 等)上的镜像文件。但是,我们不能忽视文件后端有助于 virt 管理员更好地管理客户磁盘,并且在某些情况下非常有帮助。根据我们的经验,我们注意到大多数用户在性能不是太大问题时使用磁盘镜像文件。请记住,可以附加到 VM 的虚拟磁盘的总数有限。同时,可以混合和使用块设备和文件,并将它们用作同一客户的存储磁盘,没有限制。
客户将虚拟磁盘视为其存储。当客户操作系统内的应用程序将数据写入客户系统的本地存储时,它必须通过几个层。也就是说,这个 I/O 请求必须通过存储上的文件系统和客户操作系统的 I/O 子系统。之后,qemu-kvm
进程将其从客户操作系统传递给 hypervisor。一旦 I/O 在 hypervisor 的范围内,它就开始像主机操作系统中运行的任何其他应用程序一样处理 I/O。在这里,您可以看到 I/O 必须通过的层数,以完成 I/O 操作。因此,块设备后端的性能优于镜像文件后端。
以下是我们对磁盘后端和基于文件或镜像的虚拟磁盘的观察:
-
文件镜像是主机文件系统的一部分,并且与块设备后端相比,它对 I/O 操作创建了额外的资源需求。
-
使用稀疏镜像文件有助于超额分配主机存储,但使用它会降低虚拟磁盘的性能。
-
在使用磁盘镜像文件时,不正确的分区可能会导致不必要的 I/O 操作。在这里,我们提到了标准分区单元的对齐。
在本章的开头,我们讨论了 virtio 驱动程序,它可以提供更好的性能。因此,建议在配置磁盘时使用 virtio 磁盘总线,而不是 IDE 总线。virtio_blk
驱动程序使用 virtio API 为存储 I/O 设备提供高性能,从而提高存储性能,特别是在大型企业存储系统中。我们在第五章中讨论了可用的不同存储格式;然而,主要的是raw
和qcow
格式。当使用raw
格式时将获得最佳性能。当使用qcow
时,格式层会带来一些性能开销。因为格式层有时必须执行一些操作,例如,如果要扩展qcow
镜像,它必须分配新的簇等。但是,如果要使用快照等功能,qcow
将是一个选择。这些额外的功能是由镜像格式qcow
提供的。一些性能比较可以在www.Linux-kvm.org/page/Qcow2
找到。
有三种可以考虑的 I/O 调优选项,我们在第七章中讨论过,虚拟机-安装、配置和生命周期管理:
-
缓存模式
-
I/O 模式
-
I/O 调优
让我们简要地浏览一些 XML 设置,以便我们可以在我们的虚拟机上实施它们。
缓存选项设置可以在虚拟机 XML 中反映如下:
<disk type='file' device='disk'>
<driver name='qemu' type='raw' cache='writeback'/>
I/O 模式配置的 XML 表示类似于以下内容:
<disk type='file' device='disk'>
<driver name='qemu' type='raw' io='threads'/>
在 I/O 调优方面,还有一些额外的说明:
-
可能需要限制每个虚拟机的磁盘 I/O,特别是在我们的设置中存在多个虚拟机时。
-
如果一个虚拟机通过生成的磁盘 I/O 数量使主机系统繁忙(嘈杂的邻居问题),这对其他虚拟机是不公平的。
一般来说,系统/虚拟管理员有责任确保所有正在运行的虚拟机获得足够的资源来工作,换句话说,这就是服务质量(QOS)。
虽然磁盘 I/O 并不是唯一需要考虑以保证 QoS 的资源,但它也很重要。调整 I/O 可以防止虚拟机系统垄断共享资源并降低在同一主机上运行的其他虚拟机的性能。这确实是一个要求,特别是当主机系统正在执行virsh blkdeviotune
命令时。可以使用该命令设置的不同选项如下所示:
图 15.24-摘自 virsh blkdeviotune –help 命令
关于参数的详细信息,如total-bytes-sec
、read-bytes-sec
、writebytes-sec
、total-iops-sec
等,可以从前面的命令输出中很容易理解。它们也在virsh
命令手册页中有记录。
例如,要限制名为SQLForNuma
的 VM 上的vdb
磁盘的 I/O 操作为每秒 200 次,吞吐量为每秒 50MB,运行以下命令:
# virsh blkdeviotune SQLForNuma vdb --total-iops-sec 200 --total-bytes-sec 52428800
接下来,我们将看一下网络 I/O 调优。
网络 I/O 调优
在大多数 KVM 环境中,我们看到的是来自客户机的所有网络流量都会经过单一的网络路径。不会有任何流量隔离,这会导致大多数 KVM 设置中的拥塞。作为网络调优的第一步,我们建议尝试不同的网络或专用网络用于管理、备份或实时迁移。但是,当您有多个网络接口用于流量时,请尽量避免多个网络接口用于相同的网络或段。如果这种情况确实存在,请应用一些常见的网络调优设置;例如,使用arp_filter
来控制 ARP Flux。当虚拟机具有多个网络接口并且正在使用它们积极地回复 ARP 请求时,就会发生 ARP Flux,因此我们应该执行以下操作:
echo 1 > /proc/sys/net/ipv4/conf/all/arp_filter
然后,您需要编辑/etc/sysctl.conf
以使此设置持久化。
有关 ARP Flux 的更多信息,请参阅linux-ip.net/html/ether-arp.html#ether-arp-flux
。
在驱动程序级别可以进行额外的调优;也就是说,现在我们知道 virtio 驱动程序与模拟设备 API 相比提供了更好的性能。因此,显然,应考虑在客户系统中使用virtio_net
驱动程序。当我们使用virtio_net
驱动程序时,它在qemu
中有一个后端驱动程序来处理来自客户网络的通信。即使这样性能更好,该领域的一些增强引入了一个称为vhost_net
的新驱动程序,为 KVM 提供了内核中的 virtio 设备。尽管 vhost 是一个可以被不同驱动程序使用的常见框架,但网络驱动程序vhost_net
是最早的驱动程序之一。以下图表将使这一点更清晰:
图 15.25 – vhost_net 架构
正如您可能已经注意到的那样,通过新的通信路径,上下文切换的数量确实减少了。好消息是,支持 vhost 不需要在客户系统中进行额外的配置,因为前端驱动程序没有变化。
vhost_net
减少了复制操作,降低了延迟和 CPU 使用率,从而提高了性能。首先,系统中必须加载名为vhost_net
的内核模块(请参阅下一节中的屏幕截图)。由于这是主机系统中的字符设备,它在主机上创建了一个名为/dev/vhost-net
的设备文件。
如何打开它
当使用-netdev tap,vhost=on
启动 QEMU 时,它将通过使用ioctl()
调用来实例化vhost-net
接口。此初始化过程将qemu
与vhost-net
实例绑定在一起,以及其他操作,如特性协商等等:
图 15.26 – 检查 vhost 内核模块
vhost_net
模块可用的参数之一是experimental_ zcopytx
。它是做什么的?此参数控制称为桥接零拷贝传输的内容。让我们看看这意味着什么(如www.google.com/patents/US20110126195
所述):
“用于在虚拟化环境中提供零拷贝传输的系统包括一个接收与客户应用程序相关的数据包的客户操作系统(OS)请求的超级监视程序,其中数据包位于客户 OS 的缓冲区或客户应用程序的缓冲区中,并且在网络堆栈处理期间创建了至少部分标头。超级监视程序进一步向网络设备驱动程序发送请求,以通过网络设备将数据包传输到网络上,其中请求标识了位于客户 OS 的缓冲区或客户应用程序的缓冲区中的数据包,并且超级监视程序避免将数据包复制到超级监视程序缓冲区。”
如果您的环境使用大数据包大小,则配置此参数可能会产生显着影响。当客户端与外部网络通信时,通过配置此参数可以减少主机 CPU 开销。这不会影响以下情况的性能:
-
客户端到客户端的通信
-
客户端到主机的通信
-
小数据包工作负载
此外,通过启用多队列virtio-net
也可以获得性能改进。有关更多信息,请访问fedoraproject.org/wiki/Features/MQ_virtio_net
。
使用virtio-net
时的一个瓶颈是其单个 RX 和 TX 队列。即使有更多的 vCPUs,网络吞吐量也受到此限制的影响。virtio-net
是一种单队列类型的队列,因此开发了多队列virtio-net
。在引入此选项之前,虚拟网卡无法利用 Linux 内核中可用的多队列支持。
通过在前端和后端驱动程序中引入多队列支持来解决这个瓶颈。这也有助于客户端使用更多 vCPUs 进行扩展。要启动具有两个队列的客户端,可以将queues
参数指定为tap
和virtio-net
,如下所示:
# qemu-kvm -netdev tap,queues=2,... -device virtio-net-pci,queues=2,...
等效的客户端 XML 如下:
<interface type='network'>
<source network='default'/>
<model type='virtio'/>
<driver name='vhost' queues='M'/>
</interface>
在这里,M
可以是1
到8
,因为内核支持多达八个队列的多队列 tap 设备。一旦为qemu
配置了这个参数,在客户端内部,我们需要使用ethtool
命令启用多队列支持。通过ethtool
启用多队列(其中K
的值从1
到M
),如下所示:
# ethtool -L eth0 combined 'K'
您可以查看以下链接,了解多队列virtio-net
何时提供最大的性能优势:access.redhat.com/documentation/en-us/red_hat_enterprise_linux/7/html/virtualization_tuning_and_optimization_guide/sect-virtualization_tuning_optimization_guide-networking-techniques
。
不要盲目使用上述 URL 中提到的选项-请测试对您的设置的影响,因为在这种情况下,即使网络吞吐量令人印象深刻,CPU 消耗也会更大。
KVM 客户端时间保持最佳实践
有不同的时间保持机制。其中最著名的技术之一是网络时间协议(NTP)。通过使用 NTP,我们可以使时钟同步到很高的精度,即使在具有抖动(可变延迟)的网络上也可以。在虚拟化环境中需要考虑的一件事是,客户端时间应与 hypervisor/host 同步,因为它会影响很多客户端操作,如果它们不同步可能会导致不可预测的结果。
有不同的方法可以实现时间同步,但这取决于您的设置。我们已经看到人们使用 NTP,使用hwclock –s
从硬件时钟设置系统时钟等。这里需要考虑的第一件事是尝试使 KVM 主机时间同步和稳定。您可以使用类似 NTP 的协议来实现这一点。一旦设置好,客户端时间必须保持同步。尽管有不同的机制可以做到这一点,但最好的选择是使用kvm-clock
。
kvm-clock
kvm-clock
也被称为虚拟化感知(半虚拟化)时钟设备。当使用kvm-clock
时,客户端询问宿主机当前时间,保证了稳定和准确的时间记录。这一功能是通过客户端注册一个页面并与宿主机共享地址来实现的。这是客户端和宿主机之间的共享页面。宿主机不断更新此页面,除非被要求停止。客户端可以在需要时间信息时简单地读取此页面。但请注意,宿主机应支持kvm-clock
供客户端使用。有关更多详细信息,您可以查看lkml.org/lkml/2010/4/15/355
。
默认情况下,大多数较新的 Linux 发行版都使用kvm_clock
通过以下方法在客户端进行配置:
[root@kvmguest ]$ cat /sys/devices/system/clocksource/clocksource0/current_clocksource
tsc
您还可以在 Linux 上使用ntpd
或chrony
作为时钟源,这需要最少的配置。在您的 Linux 虚拟机中,编辑/etc/ntpd.conf
或/etc/chronyd.conf
,并修改server配置行,将其指向 NTP 服务器的 IP 地址。然后,只需启用并启动您正在使用的服务(这里我们使用chrony
作为示例):
systemctl enable chronyd
systemctl start chronyd
还有另一种比较新的协议被大力推广用于时间同步,称为ntpd
或chronyd
。它使用网络接口上的时间戳和外部来源以及计算机的系统时钟进行同步。
安装所有必要的先决条件只需要一个yum
命令来启用和启动服务:
yum -y install linuxptp
systemctl enable ptp4l
systemctl start ptp4l
默认情况下,ptp4l
服务将使用/etc/sysconfig/ptp4l
配置文件,通常绑定到第一个网络接口。如果您想使用其他网络接口,最简单的方法就是编辑配置文件,更改接口名称,然后通过systemctl
重新启动服务。
现在,从 VM 的角度来看,我们可以通过进行一些配置来帮助它们进行时间同步。我们可以将ptp_kvm
模块添加到全局 KVM 主机配置中,这将使我们的 PTP 作为服务可用于chronyd
作为时钟源。这样,我们就不必进行大量额外的配置。因此,只需将ptp_kvm
作为字符串添加到默认的 KVM 配置中,如下所示:
echo ptp_kvm > /etc/modules-load.d/kvm-chrony.conf
modprobe ptp_kvm
通过这样做,将在/dev
目录中创建一个ptp
设备,然后我们可以将其用作chrony
的时间源。将以下行添加到/etc/chrony.conf
并重新启动chronyd
:
refclock PHC /dev/ptp0 poll 3 dpoll -2 offset 0
systemctl restart chronyd
通过使用 API 调用,所有 Linux 虚拟机都能从运行它们的物理主机获取时间。
现在,我们已经涵盖了大量关于 VM 配置选项的性能调整和优化,现在是时候最终摆脱所有这些微小的步骤,关注更大的画面。到目前为止,我们所涵盖的所有 VM 设计(与 CPU、内存、NUMA、virtio、块、网络和时间配置相关)只有在我们使用它时才重要。回到我们最初的场景——一个 SQL VM——让我们看看我们将如何根据我们将在其上运行的软件来正确配置我们的 VM。
基于软件的设计
还记得我们最初的场景吗,涉及一个应该是 Microsoft SQL Server 集群中的节点的基于 Windows Server 2019 的 VM 吗?我们在调整方面涵盖了很多设置,但还有更多要做——要做的事情更多。我们需要问一些问题。我们越早问这些问题越好,因为它们将对我们的设计产生关键影响。
我们可能会问的一些问题如下:
-
对不起,亲爱的客户,当您说集群时,您具体指的是什么,因为有不同的 SQL Server 集群方法学?
-
您有哪些 SQL 许可证,或者您打算购买哪些?
-
您需要主动-主动、主动-被动、备份解决方案还是其他什么?
-
这是一个单站点还是多站点集群?
-
您确切需要哪些 SQL 功能?
-
你有哪些许可证,你愿意为它们花多少钱?
-
你的应用程序是否能够与 SQL 集群一起工作(例如,在多站点场景中)?
-
你有什么样的存储系统?
-
你的存储系统可以提供多少 IOPS?
-
你的存储的延迟如何?
-
你有不同层次的存储子系统吗?
-
这些层次的服务水平在 IOPS 和延迟方面是多少?
-
如果你有多个存储层,我们是否可以根据最佳实践创建 SQL VMs,例如将数据文件和日志文件放在单独的虚拟磁盘上?
-
你有足够的磁盘容量来满足你的需求吗?
这些只是许可、集群和存储相关的问题,它们不会消失。我们需要毫不犹豫地提出这些问题,并在部署之前得到真实的答案。我们刚刚提到了 14 个问题,但实际上还有更多。
此外,我们需要考虑 VM 设计的其他方面。询问一些问题是明智的,比如:
-
你可以为 SQL VM 提供多少内存?
-
你有哪些服务器,它们使用哪些处理器,每个插槽有多少内存?
-
你是否正在使用任何最新一代技术,比如持久内存?
-
你有关于你正在为这个 SQL 基础架构设计的规模和/或查询量的任何信息吗?
-
在这个项目中,金钱是一个重要的决定因素吗(因为它将影响许多设计决策,因为 SQL 是按核心许可的)?还有标准与企业定价的问题。
这一系列问题实际上指向了 VM 设计中非常重要的一部分,与内存、内存位置、CPU 和内存之间的关系以及数据库设计中最基本的问题之一——延迟有关。其中很大一部分与正确的 VM 存储设计有关——正确的存储控制器、存储系统、缓存设置等,以及 VM 计算设计——这一切都与 NUMA 有关。我们在本章中解释了所有这些设置。因此,为了正确配置我们的 SQL VM,这里是我们应该遵循的高级步骤清单:
-
配置具有正确 NUMA 设置和本地内存的 VM。出于许可原因,从四个 vCPU 开始,然后找出是否需要更多(例如,如果你的 VM 变得受限于 CPU,你将从性能图表和基于 SQL 的性能监控工具中看到)。
-
如果你想保留 CPU 容量,利用 CPU 固定,以便物理服务器 CPU 上的特定 CPU 核心始终用于 SQL VM,而且只用于它。将其他 VM 隔离到剩余核心。
-
为 SQL VM 保留内存,以防止交换,因为只有使用真正的 RAM 内存才能保证性能平稳,不受到嘈杂的邻居的影响。
-
如有必要,为每个 VM 配置 KSM,并避免在 SQL VM 上使用它,因为它可能引入延迟。在设计阶段,确保购买尽可能多的 RAM 内存,以免内存成为问题,因为如果服务器没有足够的内存,这将是一个非常昂贵的性能问题。绝对不要过度分配内存。
-
配置具有多个虚拟硬盘的 VM,并将这些硬盘放在可以提供所需服务水平的存储中,包括延迟、开销和缓存。记住,操作系统磁盘不一定需要写缓存,但数据库和日志磁盘将受益于它。
-
使用主机到存储设备的单独物理连接,并调整存储以尽可能提高性能。不要过度订阅——无论是在链路级别(太多 VM 通过相同的基础设施连接到相同的存储设备)还是数据存储级别(不要将一个数据存储放在一个存储设备上并将所有 VM 存储在其中,因为这会对性能产生负面影响——隔离工作负载,通过多个链接创建多个目标,并使用掩码和分区)。
-
配置多路径、负载平衡和故障转移-以获得尽可能多的存储性能,同时也具有冗余性。
-
安装正确的 virtio 驱动程序,如有必要使用 vhost 驱动程序或 SR-IOV,并尽量减少每个级别的开销。
-
调整 VM 客户操作系统-关闭不必要的服务,将电源配置文件切换到“高性能”(大多数 Microsoft 操作系统出于某种原因将电源配置文件设置为“平衡”模式)。调整 BIOS 设置并检查固件和操作系统更新-从上到下的所有内容。做笔记,测量,进行基准测试,并在更新和更改配置时使用以前的基准测试作为基线,以便了解自己的方向。
-
在使用 iSCSI 时,配置巨帧,因为在大多数情况下,这将对存储性能产生积极影响,并确保您查看存储设备供应商的文档以了解相关的最佳实践。
本章的要点是-不要仅仅因为客户要求安装应用程序而盲目安装。这将在以后困扰你,并且解决任何问题和投诉将会更加困难。花时间并且做对。通过阅读文档来为整个过程做好准备,因为文档是广泛可用的。
总结
在本章中,我们深入探讨了 KVM 性能调优和优化的领域。我们讨论了许多不同的技术,从简单的 CPU 固定到更复杂的 NUMA 和适当的 NUMA 配置。不要被吓到,因为学习设计是一个过程,正确设计是一门可以通过学习和经验不断改进的技艺。想想这样的事情-当建筑师设计世界上最高的摩天大楼时,他们是否每次建造新的最高建筑物时都将目标进一步推进?
在下一章-本书的最后一章中-我们将讨论如何排除环境中的故障。这至少部分与本章相关,因为我们将排除一些与性能相关的问题。在切换到故障排除章节之前,多次阅读本章对您的整体学习过程将非常有益。
问题
-
什么是 CPU 固定?
-
KSM 是做什么的?
-
我们如何增强块设备的性能?
-
我们如何调整网络设备的性能?
-
我们如何在虚拟化环境中同步时钟?
-
我们如何配置 NUMA?
-
我们如何配置 NUMA 和 KSM 一起工作?
进一步阅读
有关更多信息,请参考以下链接:
-
RedHat Enterprise Linux 7-在 RHEL 物理机上安装、配置和管理 VM:
access.redhat.com/documentation/en-us/red_hat_enterprise_linux/7/html/virtualization_deployment_and_administration_guide/index
-
自动 NUMA 平衡:
www.redhat.com/files/summit/2014/summit2014_riel_chegu_w_0340_automatic_numa_balancing.pdf
-
Virtio 1.1 规范:
docs.oasis-open.org/virtio/virtio/v1.1/virtio-v1.1.html
-
RHEL 7 上的 libvirt NUMA 调优:
access.redhat.com/documentation/en-us/red_hat_enterprise_linux/7/html/virtualization_tuning_and_optimization_guide/sect-virtualization_tuning_optimization_guide-numa-numa_and_libvirt
第十六章:KVM 平台的故障排除指南
如果您从《第一章》《理解 Linux 虚拟化》一直跟着这本书走到现在,那么您会知道在这本书中我们一起经历了很多 - 数百页的概念和实际方面,包括配置示例、文件和命令 - 一切。大约 700 页。到目前为止,我们几乎完全忽略了故障排除作为旅程的一部分。我们并不是基于 Linux 中一切都只是“工作”,我们根本没有任何问题,而且我们在阅读全书的过程中达到了一种“涅槃”的状态。
这是一段充满各种问题的旅程。其中一些不值一提,因为它们是我们自己的错误。我们犯的错误(而且您肯定也会犯更多)大多来自于我们输入错误(在命令或配置文件中)。基本上,人类在 IT 中扮演着重要角色。但其中一些问题确实令人沮丧。例如,实施 SR-IOV 需要很多时间,因为我们不得不在硬件、软件和配置层面找到不同类型的问题才能使其正常工作。oVirt 相当古怪,我们很快会解释。Eucalyptus 有点有趣,姑且这么说。尽管我们之前经常使用它,但 cloudbase-init 真的很复杂,需要我们花费很多时间和注意力,结果证明这并不是由于我们做了什么 - 它只是 cloudbase-init 的版本。但总的来说,这进一步证明了我们上一章的一个普遍观点 - 在书籍、文章和博客文章中阅读各种 IT 主题,是一个确实不错的方法,可以从一开始就正确配置很多东西。但即便如此,您仍然需要一些故障排除来使一切完美。
一旦安装了一个服务并开始使用它,一切都很棒和令人惊讶,但第一次很少会这样。我们在本书中使用的一切实际上都是为了测试不同的配置并抓取必要的截图而安装的,但与此同时,我们也希望确保它们实际上可以以更有结构、程序化的方式安装和配置。
因此,让我们从与服务、软件包和日志记录相关的一些简单事物开始。然后,我们将继续介绍更高级的故障排除概念和工具,通过我们一路涵盖的各种示例进行描述。
在本章中,我们将涵盖以下主题:
-
验证 KVM 服务状态
-
KVM 服务日志记录
-
启用调试模式日志记录
-
高级故障排除工具
-
KVM 问题的最佳实践
验证 KVM 服务状态
我们将从最简单的示例开始 - 验证 KVM 服务状态及其对主机配置的一些正常影响。
在《第三章》《安装 KVM Hypervisor、libvirt 和 ovirt》中,我们通过安装virt module
并使用dnf
命令部署各种软件包,对整个 KVM 堆栈进行了基本安装。有几个原因可能导致这不是一个好主意:
- 许多服务器、台式机、工作站和笔记本电脑在出厂时都预先配置为关闭 BIOS 中的虚拟化。如果您使用基于英特尔的 CPU,请确保找到所有基于 VT 的选项并启用它们(VT、VT-d、VT I/O)。如果您使用基于 AMD 的 CPU,请确保打开 AMD-V。您可以进行一个简单的测试来检查虚拟化是否已启用。如果您启动任何 Linux 实时发行版,进入 shell 并输入以下命令:
cat /proc/cpuinfo | egrep "vmx|svm"
如果您已经安装了 Linux 主机和我们在《第三章》《安装 KVM Hypervisor、libvirt 和 ovirt》中提到的适当软件包,您也可以使用以下命令:
virt-host-validate
如果您从这个命令中没有得到任何输出,那么您的系统要么不支持虚拟化(可能性较小),要么没有打开虚拟化功能。确保您检查您的 BIOS 设置。
-
您的网络配置和/或软件包存储库配置可能没有正确设置。正如我们在本章中反复强调的,请从最简单的事情开始——不要试图找出某些超级复杂的原因,为什么某些东西不起作用。保持简单。对于网络测试,请尝试使用
ping
命令对一些知名服务器进行测试,比如 google.com。对于存储库问题,请确保您检查/etc/yum.repos.d
目录。尝试使用yum clean all
和yum update
命令。存储库问题更有可能发生在一些其他发行版而不是 CentOS/Red Hat 上,但仍然可能发生。 -
部署过程成功完成后,请确保使用以下命令启动和启用 KVM 服务:
libvirt-guests service, and then we get very surprised after we reboot our host. The result of libvirt-guests not being enabled is simple. When started, it suspends your virtual machines when you initiate shutdown and resumes them on the next boot. In other words, if you don't enable them, your virtual machines won't resume after the next reboot. Also, check out its configuration file, /etc/sysconfig/libvirt-guests. It's a simple text configuration file that enables you to configure at least three very important settings: ON_SHUTDOWN, ON_BOOT, and START_DELAY. Let's explain these:a) By using the `ON_SHUTDOWN` setting, we can select what happens with the virtual machine when we shut down your host since it accepts values such as `shutdown` and `suspend`.b) The `ON_BOOT` option does the opposite – it tells `libvirtd` whether it needs to start all the virtual machines on host boot, whatever their autostart settings are. It accepts values such as `start` and `ignore`.c) The third option, `START_DELAY`, allows you to set a timeout value (in seconds) between multiple virtual machine power-on actions while the host is booting. It accepts numeric values, with `0` being the value for parallel startup and *all other (positive) numbers* being the number of seconds it waits before it starts the next virtual machine.
考虑到这一点,至少有三件事需要记住:
- 确保这两个服务实际上正在运行,通过输入以下命令:
libvirtd needs to be started for us to be able to create or run a KVM virtual machine.
-
如果您正在配置更高级的设置,比如 SR-IOV,请确保阅读服务器的手册,选择一个与 SR-IOV 兼容的正确插槽。此外,请确保您有兼容的 PCI Express 卡和正确配置的 BIOS。否则,您将无法使其工作。
-
当您启动 libvirt 服务时,它通常会带有某种预定义的防火墙配置。记住这一点,以防您决定禁用 libvirt 服务,因为防火墙规则几乎总是还在那里。这可能需要一些额外的配置。
您故障排除旅程的下一步将是检查一些日志文件。有很多选择——KVM 有自己的,oVirt 有自己的,Eucalyptus 也有自己的,ELK 等等。因此,请确保您对这些服务非常了解,以便您可以检查正确的日志文件,以解决您要解决的情况。让我们从 KVM 服务日志开始。
KVM 服务日志
在讨论 KVM 服务日志时,有一些位置是我们需要注意的:
-
假设您以 root 用户身份登录到 GUI,并启动了 virt-manager。这意味着您在
/root/.cache/virt-manager
目录中有一个virt-manager.log
文件。它非常冗长,所以在阅读时请耐心等待。 -
/etc/libvirt/libvirtd.conf
文件是 libvirtd 的配置文件,包含了许多有趣的选项,但一些最重要的选项实际上位于文件的末尾,并与审计相关。您可以选择注释掉的选项(audit_level
和audit_logging
)来满足您的需求。 -
/var/log/libvirt/qemu
目录包含了在我们的 KVM 主机上创建的所有虚拟机的日志和旋转日志。
此外,请务必查看一个名为auvirt
的命令。它非常方便,因为它可以告诉您有关 KVM 主机上的虚拟机的基本信息——仍然存在和/或成功运行的虚拟机,以及我们尝试安装但失败的虚拟机。它从审计日志中获取数据,您也可以使用它来显示我们需要的特定虚拟机的信息。它还有一个非常调试级别的选项叫做--all-events
,如果您想检查关于 KVM 主机上的任何虚拟机的每一个细节。
启用调试模式日志记录
在 KVM 中还有另一种日志记录方法:配置调试日志记录。在我们刚提到的 libvirtd 配置文件中,有其他设置可以用来配置这个选项。因此,如果我们滚动到Logging controls
部分,这些是我们可以使用的设置:
-
log_level
-
log_filters
-
log_outputs
让我们一步一步地解释它们。第一个选项 - log_level
- 描述了日志详细程度。自从 libvirt 版本 4.4.0 起,此选项已被弃用。在文件的日志控制
部分中,还有额外的文档硬编码到文件中,以使事情变得更容易。对于这个特定的选项,文档中是这样说的:
图 16.1 - libvirtd.conf 中的日志控制
人们通常会看到此输出的第一部分(日志级别描述),转到最后一行(Iog_level
),将其设置为 1,保存,重新启动libvirtd
服务,然后完成。问题在于中间的文本部分。它明确表示journald
进行速率限制,以便它不会被来自一个服务的日志淹没,并指示我们改用log_filters
设置。
那么让我们这样做 - 让我们使用log_filters
。在配置文件的稍低处,有一个看起来像这样的部分:
图 16.2 - libvirtd.conf 中的日志过滤器选项
这为我们提供了各种选项,我们可以使用不同的日志选项来设置不同的对象类型,这很棒。它为我们提供了增加我们感兴趣的事物的详细程度的选项,同时将其他对象类型的详细程度保持在最低水平。我们需要做的是删除最后一行的注释部分(#log_filters="1:qemu 1:libvirt 4:object 4:json 4:event 1:util"
应该变成log_filters="1:qemu 1:libvirt 4:object 4:json 4:event 1:util"
),并配置其设置以使其符合我们的要求。
第三个选项涉及我们想要将调试日志输出文件放在哪里:
图 16.3 - libvirtd.conf 中的日志输出选项
重要提示
更改任何这些设置后,我们需要确保通过键入systemctl restart libvirtd
命令来重新启动libvirtd
服务。
如果我们只对客户端日志感兴趣,我们需要设置一个名为LIBVIRT_LOG_OUTPUTS
的环境变量为类似于这样的内容(假设我们想要 DEBUG 级别的日志):
export LIBVIRT_LOG_OUTPUTS="1:file:/var/log/libvirt_guests.log"
所有这些选项都有效,直到下一次libvirtd
服务重启,这对于永久设置非常方便。但是,当我们需要临时调试而不需要使用永久配置时,还有一个运行时选项可以使用。这就是为什么我们有一个名为virt-admin
的命令。我们可以使用它来设置我们自己的设置。例如,让我们看看如何使用它来获取我们当前的设置,然后如何使用它来设置临时设置:
图 16.4 - Runtime libvirtd 调试选项
我们还可以通过发出以下命令来删除这些设置:
virt-admin daemon-log-filters ""
这绝对是在我们完成调试后推荐的事情。我们不想把我们的日志空间用于无用的事情。
就纯粹调试虚拟机而言 - 除了这些日志选项之外 - 我们还可以使用串行控制台仿真来连接到虚拟机控制台。如果我们无法以其他方式访问虚拟机,尤其是在我们的环境中不使用 GUI 的情况下,这通常是在生产环境中的情况。访问控制台可以按以下方式完成:
virsh console kvm_domain_name
在上述命令中,kvm_domain_name
是我们想要通过串行控制台连接的虚拟机的名称。
高级故障排除工具
根据主题 - 网络、硬件和软件问题,或特定应用程序问题 - 我们可以使用不同的工具来排除我们环境中的问题。让我们简要地回顾一些这些方法,同时牢记本书的章节,以便我们排除故障:
-
oVirt 问题
-
快照和模板问题
-
虚拟机定制问题
-
Ansible 问题
-
OpenStack 问题
-
Eucalyptus 和 AWS 组合问题
-
ELK 堆栈问题
有趣的是,当我们处理 KVM 虚拟化时,通常不会遇到网络问题。这些都有很好的文档支持——从 KVM 桥接到 open vSwitch——只需要按照文档进行操作。唯一的例外是与防火墙规则相关的问题,特别是在处理 oVirt 和远程数据库连接时,同时保持最小的安全性。如果你对此感兴趣,请确保查看以下链接:www.ovirt.org/documentation/installing_ovirt_as_a_standalone_manager_with_remote_databases/#dns-requirements_SM_remoteDB_deploy
。
在文章的后面有一个大表格描述了每个端口用于什么以及它们使用的协议。此外,还有一个需要在 oVirt 主机级别配置的端口表。如果你要将 oVirt 投入生产,我们建议你使用这篇文章。
oVirt
在处理 oVirt 时,我们经常遇到两个常见问题:
-
安装问题:当我们在引擎设置中输入安装选项并正确配置事物时,我们需要放慢速度。
-
更新问题:这些问题可能与不正确地更新 oVirt 或底层系统有关。
安装问题通常很容易排除故障,因为它们通常发生在我们刚开始部署 oVirt 时。这意味着我们可以奢侈地停止安装过程,从头开始。其他一切都会变得太混乱和复杂。
然而,更新问题值得特别一提。让我们处理 oVirt 更新问题的两个子集并对它们进行更详细的解释。
更新 oVirt Engine 本身需要做的事情是我们大多数人都不喜欢做的——阅读大量的文档。我们需要首先检查我们正在运行的 oVirt 版本。例如,如果我们正在运行 4.3.0 版本,想要升级到 4.3.7 版本,这是一个相对简单的次要更新路径。我们需要首先备份我们的 oVirt 数据库:
engine-backup --mode=backup --file=backupfile1 --log=backup.log
我们这样做只是作为一种预防措施。然后,如果以后出现问题,我们可以使用以下命令:
engine-backup --mode=restore --log=backup.log --file=backupfile1 --provision-db --provision-dwh-db --no-restore-permissions
如果你没有部署 DWH 服务及其数据库,可以忽略--provision-dwh-db
选项。然后,我们可以执行标准程序:
engine-upgrade-check
yum update ovirt\*setup\*
engine-setup
这应该大约需要 10 分钟,不会造成任何伤害。但最好还是小心为妙,在这之前备份数据库。
然而,如果我们从旧版本的 oVirt 迁移到最新版本——比如从 4.0.0 版本、4.1.0 版本或 4.2.0 版本迁移到 4.3.7 版本——那就是一个完全不同的过程。我们需要去 ovirt.org 网站阅读文档。例如,假设我们要从 4.0 升级到 4.3。ovirt.org 上有描述所有这些过程的文档。你可以从这里开始:www.ovirt.org/documentation/upgrade_guide/
。
这将给我们大约 20 个子步骤,我们需要完成才能成功升级。请小心和耐心,因为这些步骤是按照非常清晰的顺序编写的,需要按照这种方式实施。
现在我们已经涵盖了升级方面的 oVirt 故障排除,让我们深入研究操作系统和软件包升级,因为这是一个完全不同的讨论,需要考虑的事情更多。
考虑到 oVirt 有自己的先决条件,从 CPU、内存和存储需求到防火墙和存储库需求,我们不能盲目地使用系统范围的命令,比如以下命令:
yum -y update
我们不能指望 oVirt 对此感到满意。它不会,这在生产环境和写作本书时都发生过很多次。我们需要检查将部署哪些软件包,并检查它们是否与 oVirt 存在某种相互依赖关系。如果有这样的软件包,你需要确保按照本章前面提到的进行引擎备份过程。这将避免给你带来很多问题。
不仅 oVirt Engine 可能会出问题-更新 oVirt 库存中的 KVM 主机也可能会相当戏剧化。oVirt 引擎或我们的手动安装程序部署在主机上的 oVirt 代理(vdsm
)及其组件,也有它们自己的相互依赖关系,可能会受到系统范围内的yum -y update
命令的影响。因此,在接受升级之前,要先拉手刹,因为它可能会带来很多痛苦。确保你检查vdsm
日志(通常位于/var/log/vdsm
目录中)。当你试图解释vdsm
出了什么问题时,这些日志文件非常有帮助。
oVirt 和 KVM 存储问题
我们遇到的大多数存储问题通常与 LUN 或共享向主机的呈现有关。特别是当你处理块存储(光纤通道或 iSCSI)时,我们需要确保不要从主机中排除或屏蔽 LUN,否则主机将看不到它。相同的原则也适用于 NFS 共享、Gluster、CEPH 或我们正在使用的任何其他类型的存储。
除了这些预配置问题之外,最常见的问题与故障转移有关-即路径指向存储设备失败的情况。这时,如果我们扩展了存储或存储网络基础设施一点-增加了额外的适配器、额外的交换机、配置了多路径(MPIO)等,我们会感到非常高兴。确保你查阅存储设备供应商的文档,并按照特定存储设备的最佳实践进行操作。相信我们说的- iSCSI 存储配置及其默认设置与配置光纤通道存储有天壤之别,特别是涉及多路径时。例如,使用 iSCSI 的 MPIO,如果正确配置,它会更加愉快和敏捷。你将在本章末尾的进一步阅读部分找到更多关于这个过程的细节。
如果你正在使用基于 IP 的存储,请确保通向存储设备的多个路径使用单独的 IP 子网,因为其他一切都是一个坏主意。类似 LACP 的技术和 iSCSI 不应该出现在同一个句子中,否则你将会对一个不适用于存储连接并且正常工作的技术进行故障排除,而你却认为它没有正常工作。我们需要知道我们在进行故障排除的是什么;否则,故障排除就毫无意义。为 iSCSI 创建 LACP 等同于仍然使用一个路径进行 iSCSI 连接,这意味着浪费了网络连接,除了在故障转移的情况下,它并没有被主动使用。而你实际上并不需要 LACP 或类似的技术。唯一的例外可能是刀片服务器,因为在刀片上的升级选项确实有限。但即使是这样,解决我们需要更多带宽从主机到存储的问题的方法是获得更快的网络或光纤通道适配器。
快照和模板的问题-虚拟机定制
老实说,多年来在各种虚拟化技术上工作,涵盖了 Citrix、微软、VMware、Oracle 和 Red Hat,我们看到了许多不同的快照问题。但只有当你开始在企业 IT 中工作,看到操作、安全和备份程序有多么复杂时,你才意识到创建快照这样一个简单的过程可能有多危险。
我们见过以下情况:
-
备份应用程序不想启动,因为虚拟机有快照(常见情况)。
-
快照不想删除和组装。
-
多个快照不想删除和组装。
-
快照因古怪的原因使虚拟机崩溃。
-
快照因为存储空间不足而使虚拟机崩溃(常见情况)。
-
快照使虚拟机中运行的应用程序崩溃,因为该应用程序不知道如何在快照之前进行整理,进入脏状态(VSS,同步问题)。
-
快照被轻微滥用,发生了一些事情,我们需要进行故障排除
-
快照被严重滥用,总是发生一些事情,我们需要进行故障排除
这种情况比预期的要频繁得多,因为人们确实倾向于在获得许可的情况下大量使用快照。我们曾看到在生产环境中运行的虚拟机拥有 20 多个快照,人们抱怨它们运行缓慢。在这种情况下,您只能深呼吸,深呼吸,耸耸肩,然后问:“你期望什么,20 多个快照会增加虚拟机的速度吗”?
在所有这些问题中,帮助我们度过所有这些问题的是三个基本原则:
-
真正了解在任何给定技术上快照的工作原理。
-
确保每次我们甚至考虑使用快照时,首先检查虚拟机所在数据存储中的可用存储空间量,然后检查虚拟机是否已经有快照。
-
不断重复这句口头禅:“快照不是备份”,一遍又一遍地对我们的所有客户进行灌输,并用额外的文章和链接向他们解释为什么他们需要停止使用快照,即使这意味着拒绝某人甚至拍摄快照的许可。
实际上,最后一个情况已经成为我们遇到的许多环境中的事实政策。我们甚至看到一些公司在处理快照时实施了一项明确的政策,规定公司政策是在有限的时间内最多拥有一两个快照。例如,在 VMware 环境中,您可以分配一个虚拟机高级属性,设置最大快照数为 1(使用名为snapshot.maxSnapshots
的属性)。在 KVM 中,您将不得不针对这些情况使用基于存储的快照,并希望存储系统具有基于策略的功能来设置快照数量。然而,在许多环境中,这有点违背了使用基于存储的快照的想法。
模板化和虚拟机定制是另一个完全不同的故障排除世界。模板化很少会引起问题,除了我们在[第八章](B14834_08_Final_ASB_ePub.xhtml#_idTextAnchor143)中提到的警告之外,创建和修改 VM 磁盘、模板和快照,与在 Windows 机器上串行使用sysprep
相关的警告。创建 Linux 模板现在非常简单,人们使用virt-sysprep
、sys-unconfig
或自定义脚本来执行。但与虚拟机定制相关的下一步是完全不同的事情。特别是在使用 cloudbase-init 时,因为多年来 cloud-init 一直是预配置 Linux 虚拟机在云环境中的标准方法。
以下是一个简短的列表,列出了我们在 cloudbase-init 中遇到的一些问题:
-
Cloudbase-init 由于“无法加载用户配置文件:设备尚未准备好”而失败。
-
域加入不可靠。
-
网络设置期间出现错误。
-
通过 cloudbase-init 重置 Windows 密码。
-
使 cloudbase-init 从指定目录执行 PowerShell 脚本。
这些和其他问题的绝大多数都与 cloudbase-init 的文档非常糟糕有关。它确实有一些配置文件示例,但其中大部分更多与 API 或编程方法相关,而不是通过示例来解释如何创建某种配置。此外,我们在第十章中提到的不同版本也存在各种问题,自动化 Windows 客户端部署和自定义。然后,我们选择了一个预发布版本,它可以直接使用配置文件,而在稳定版本上无法正常工作。但总的来说,我们在尝试使其正常工作时遇到的最大问题是与 PowerShell 正确配合。如果我们能够正确执行 PowerShell 代码,我们几乎可以在 Windows 系统上配置任何我们想要的东西,所以这是一个大问题。有时,它不想从 Windows 系统磁盘上的随机目录执行 PowerShell 脚本。
确保您在本书中使用示例作为起点。我们故意将第十章中的示例尽可能简单化,其中包括执行的 PowerShell 代码。之后,展开你的翅膀,做任何需要做的事情。当您使用基于 Microsoft 的解决方案时,无论是本地还是混合解决方案,PowerShell 都会使一切变得更容易和更自然。
使用 Ansible 和 OpenStack 的问题
我们与 Ansible 和 OpenStack 的第一次互动发生在多年前 - Ansible 于 2012 年推出,OpenStack 于 2010 年推出。我们一直认为它们都是非常酷的工具,尽管存在一些问题。其中一些小问题与开发速度快(OpenStack)有关,大量的错误从一个版本到另一个版本得到解决。
在 Ansible 方面,我们与人们进行了大量的争论 - 一天,主题与“我们习惯使用 Puppet,为什么需要 Ansible?!”有关;第二天是“啊,这个语法太复杂了”;第三天是其他事情,还有其他事情……通常都与 Ansible 架构更简单,语法在一开始至少更复杂有关。对于 Ansible 来说,一切都取决于语法,我们相信您要么已经知道,要么很快就会发现。
故障排除 Ansible playbook 通常是一个过程,有 95%的机会是我们在配置文件中拼写错误或输入错误。我们谈论的是您已经有机会使用 Ansible 一段时间的初始阶段。确保重新检查 Ansible 命令的输出,并将其用于此目的。在这方面,它真的很出色。您不需要进行复杂的配置(例如libvirtd
)来从执行的过程和 playbook 中获得可用的输出。这使我们的工作变得更加容易。
故障排除 OpenStack 是完全不同的一桩麻烦。有一些充分记录的 OpenStack 问题,这些问题也可能与特定设备有关。让我们举一个例子 - 查看以下链接,了解在使用 NetApp 存储时出现的问题:netapp-openstack-dev.github.io/openstack-docs/stein/appendices/section_common-problems.html
。
以下是一些例子:
-
创建卷失败
-
克隆卷失败
-
卷附加失败
-
卷上传到镜像操作失败
-
卷备份和/或恢复失败
然后,例如,查看这些链接:
正如你可能已经推断出的那样,OpenStack 在存储方面非常挑剔。这就是为什么存储公司通常为他们自己的存储设备创建参考架构,以在基于 OpenStack 的环境中使用。查看 HPE 和戴尔 EMC 的这两份文件,作为这种方法的良好示例:
最后要警告的是,最难克服的障碍与 OpenStack 版本升级有关。关于这个主题,我们可以告诉你很多恐怖故事。话虽如此,我们在这里也有部分责任,因为我们作为用户部署了各种第三方模块和实用程序(基于供应商的插件、分支、未经测试的解决方案等),忘记使用它们,然后当升级过程失败时,我们真的感到惊讶和恐惧。这可以追溯到我们在整本书中一直讨论的关于记录环境的多个讨论。这是一个我们将在本章稍后再次讨论的主题。
依赖关系
每个管理员都完全意识到几乎每个服务都有一些依赖关系 - 要么是依赖于运行此特定服务的服务,要么是我们的服务需要工作的服务。在处理软件包时,依赖关系也是一个重要因素 - 软件包管理器的整个目的是严格注意需要安装的内容以及依赖它的内容,以便我们的系统正常工作。
大多数管理员犯的错误是忘记了,在更大的系统中,依赖关系可能延伸到多个系统、集群,甚至数据中心。
每个涵盖 OpenStack 的课程都有一个专门的课程,介绍如何启动、停止和验证不同的 OpenStack 服务。其原因很简单 - OpenStack 通常在大量节点上运行(数百,有时数千)。一些服务必须在每个节点上运行,一些服务需要一组节点,一些服务在每个节点实例上都是重复的,一些服务只能存在一个实例。
了解每个服务的基础知识以及它如何融入整个 OpenStack 架构不仅在安装整个系统时至关重要,而且在调试为什么某些东西在 OpenStack 上不起作用时也是最重要的。至少阅读一次文档以“串联起点”。同样,在本章末尾的“进一步阅读”部分包含了指向 OpenStack 正确方向的链接。
OpenStack 是那些在文档中包括“如何正确地重新启动运行 X 的机器?”的系统之一。其原因就像整个系统一样复杂 - 系统的每个部分既有它所依赖的东西,也有一些依赖它的东西 - 如果某些东西出了问题,你不仅需要了解系统的这个特定部分是如何工作的,还需要了解它如何影响其他一切。但是在所有这些中有一线希望 - 在一个正确配置的系统中,很多东西都是冗余的,所以有时,修复某些东西最简单的方法是重新安装它。
这可能总结了整个故障排除的故事 - 试图修复一个简单的系统通常比修复一个复杂的系统更复杂和耗时。了解它们各自的工作原理是最重要的部分。
故障排除 Eucalyptus
说我们开始安装过程后一切都按照手册进行是不真实的 - 大部分是,我们相当肯定,如果您按照我们记录的步骤进行,您最终会得到一个可用的服务或系统,但在任何时候,都会有事情可能会出错。这时候你需要做的是最难以想象的事情 - 故障排除。但你该怎么做呢?信不信由你,有一种更或多或少系统化的方法可以让你解决几乎任何问题,不仅仅是 KVM/OpenStack/AWS/Eucalyptus 相关的问题。
收集信息
在我们做任何事情之前,我们需要做一些研究。这是大多数人做错事情的时刻,因为显而易见的答案是去互联网上搜索问题。看看这个屏幕截图:
图 16.5 - Eucalyptus 日志,第一部分 - 清晰、简洁、易读 - Eucalyptus 中已完成的每个过程在日志中清晰可见
如果你还没有注意到,互联网上充满了几乎任何想象问题的现成解决方案,其中很多是错误的。这是因为有两个原因:大多数解决方案的人并不了解问题是什么,所以一旦他们找到了解决他们特定问题的任何解决方案,他们就停止解决它。换句话说 - 许多 IT 人员试图将从 A 点(问题)到 B 点(解决方案)的路径描绘成一束激光束 - 超级平坦,最短可能的路径,沿途没有障碍。一切都很好,设计得很干净,旨在在激光束原则停止工作时干扰我们的故障排除思维过程。这是因为,在 IT 领域,事情很少那么简单。
例如,由 DNS 配置错误引起的任何问题。其中大多数可以通过在hosts文件中创建一个条目来“解决”。这个解决方案通常有效,但同时在几乎任何层面上都是错误的。这个解决方案只在一个机器上解决了问题 - 那个特定的主机文件所在的机器。而 DNS 仍然配置错误;我们只是创建了一个快速的、未记录的解决方法,它在我们的特定情况下有效。每台其他有相同问题的机器都需要以这种方式进行修补,而我们的修复可能会在未来产生更多问题的真正可能性。
真正的解决方案显然是找到问题的根源并解决 DNS 的问题,但在互联网上很少有这样的解决方案。这主要是因为互联网上的大多数评论者对许多服务不熟悉,快速修复基本上是他们能够应用的唯一方法。
互联网大部分错误的另一个原因是因为著名的“重新安装解决了问题”的解决方案。Linux 在这方面的记录更好,因为使用它的人不太倾向于通过擦除和重新安装系统来解决所有问题,但你会发现大多数 Windows 问题的解决方案至少会有一个简单的“重新安装解决了问题”。与仅仅给出一个随机的解决方案作为总是有效的解决方案相比,这种“重新安装”方法要糟糕得多。这不仅意味着你将浪费大量时间重新安装所有东西;它还意味着你的问题最终可能会或可能不会得到解决,这取决于问题实际上是什么。
因此,我们将给出的第一个简短建议是,“不要盲目相信互联网”。
好了,但你实际上应该做什么呢?让我们来看看:
- 收集关于问题的信息。阅读错误消息,阅读日志(如果应用程序有日志),并尽可能打开调试模式。获取一些实际数据。找出是什么导致了崩溃,以及是如何崩溃的,以及是什么问题导致了崩溃。看一下下面的截图:
图 16.6 - 桉树日志,第二部分 - 再次,干净,清晰,易于阅读 - 有关更新内容和位置的信息消息
- 阅读文档。你正在尝试的事情是否得到支持?功能系统的先决条件是什么?你是否遗漏了什么?缓存磁盘?一些内存?你特定系统的依赖基本服务?一个库或额外的软件包的依赖?固件升级?
有时,你会遇到一个更大的问题,特别是在文档写得很糟糕的情况下 - 可能会在次要提到一些关键的系统依赖项,并可能导致整个系统崩溃。例如,外部识别服务 - 也许你的目录使用了错误的字符集,导致当特定用户以特定方式使用时系统崩溃。始终确保你了解你的系统是如何相互连接的。
接下来,检查你的系统。如果你正在安装一个新系统,请检查先决条件。你有足够的磁盘空间和内存吗?你的应用程序需要的所有服务是否都可用并正常工作?
搜索互联网。我们之前提到过,互联网对所有可能的问题都有一个简单而不正确的解决方案,但通常也会在错误的解决方案中隐藏着正确的解决方案。当你武装自己拥有关于你特定系统和特定问题的大量数据后,互联网很快就会成为你的朋友。因为你了解问题是什么,你将能够理解提供给你的解决方案中哪些是错误的。
现在,让我们谈谈我们故意在安装桉树时制造的一个现实世界的问题,只是为了向你展示文档有多重要。
我们在第十三章中向你展示了如何安装桉树,使用 AWS 扩展 KVM - 我们不仅经历了安装过程,还学会了如何使用这个令人惊叹的服务。如果你想学习一些关于如何不做的东西,继续阅读。我们将向你展示一个故意创建的桉树安装失败的场景,因为我们创造性地忘记了一些我们知道需要做的步骤。让我们这样说 - 我们表现得像人类一样,使用了浏览文档的方法,而不是实际坐下来阅读文档。这听起来熟悉吗?
安装桉树应该是一项简单的任务,因为它的安装本质上是一个应用脚本的练习。桉树甚至在项目的首页上都这样说:只需运行这个脚本。
但事实要复杂得多 - 桉树确实可以只使用这个脚本进行安装,但必须满足一些先决条件。当然,在你急于测试新服务时,你可能会忽略阅读文档,就像我们一样,因为我们已经有了桉树的经验。
我们配置了系统,启动了安装,然后遇到了问题。在确认了初始配置步骤后,我们的安装失败了,错误消息显示无法解析特定地址:192.168.1.1.nip.io
。
DNS 是 IT 基础设施中的主要问题之一,我们迅速开始调试 - 我们想要看到的第一件事是这个特定地址是什么。实际上,在 IT 中有一句话 - 总是 DNS。它看起来像一个本地地址,所以我们开始 ping 它,看起来还好。但为什么 DNS 甚至与 IP 地址有关?DNS 应该解析域名,而不是 IP 地址。然后,我们转向文档,但没有得到太多信息。我们唯一发现的是 DNS 必须为整个系统工作。
然后,是时候尝试调试 DNS 了。首先,我们尝试从我们正在安装的机器上解析它。DNS 返回超时。我们在另一台机器上尝试了一下,得到了我们没有预期的响应 - 127.0.0.1.nip.io
解析为127.0.0.1
,这意味着本地主机。基本上,我们向互联网上的 DNS 请求一个地址,它将我们引导到我们的本地系统。
所以,我们遇到了一个我们不理解的错误,一个解析为我们没有预期的 IP 地址的地址,以及两个不同的系统对相同命令表现出完全不同的行为。我们把注意力转向我们正在安装的机器,意识到它配置错误 - 没有配置 DNS。这台机器不仅无法解析我们奇怪的 IP 地址,而且无法解析任何东西。
我们通过指向正确的 DNS 服务器来解决了这个问题。然后,按照真正的 IT 方式,我们重新启动了安装,以便我们能够继续进行这一部分,一切都还好,或者看起来是这样。但发生了什么?为什么一个本地服务解析如此奇怪的名称,为什么它们会被解析?
我们转向互联网,看了一下我们神秘名称末尾的域名。我们发现服务nip.io
实际上就是我们观察到的事情 - 当要求返回本地子网范围内 IP 地址形成的特定名称时(由RFC 1918
定义),它返回相同的 IP。
我们接下来的问题是 - 为什么?
经过更多阅读,您会意识到这里的诀窍是什么 - 桉树使用 DNS 名称与其所有组件进行通信。作者非常明智地选择不将单个地址硬编码到应用程序中,因此系统的所有服务和节点都必须具有真实的 DNS 注册名称。在正常的多节点,多服务器安装中,这就像魅力一样 - 每个服务器和每个节点首先都要在适当的 DNS 服务器上注册,桉树将尝试解析它们以便与机器通信。
我们正在安装一个拥有所有服务的单个机器,这使得安装更容易,但节点没有单独的名称,甚至我们的机器可能没有在 DNS 中注册。因此,安装程序做了一个小技巧。它将本地 IP 地址转换为完全有效的域名,并确保我们可以解析它们。
所以,现在我们知道发生了什么(解析过程不起作用)以及为什么会发生(我们的 DNS 服务器设置出了问题),但我们也理解了为什么首先需要 DNS。
这带我们到下一个点 - 不要假设任何事情。
在我们排除故障并跟进我们的 DNS 问题时,我们的安装崩溃了。桉树是一个复杂的系统,它的安装是一件相当复杂的事情 - 它会自动更新您运行它的机器,然后安装似乎有成千上万的软件包,然后下载,配置和运行一小部分镜像和虚拟软件包。为了保持整洁,用户看不到发生的一切,只能看到最重要的部分。安装程序甚至有一个漂亮的 ASCII 图形屏幕让你忙碌。一切都还好,但突然之间,我们的安装完全崩溃了。我们得到的只是一个看起来像属于 Python 语言的巨大堆栈跟踪。我们重新运行了安装,但它再次失败了。
此时的问题是,我们不知道为什么会发生这一切,因为安装要求对 CentOS 7 进行最小安装。我们在虚拟机上运行测试,并确实进行了最小安装。
我们重新尝试从头安装。重新安装整个机器只花了几分钟,然后我们重新尝试安装。结果是一样的 - 一个失败的安装,让我们得到了一个无法使用的系统。但有一个可能的解决方案 - 或者更准确地说,是了解发生了什么。
与 IT 宇宙中所有伟大的安装程序一样,这个安装程序也为这种可能性准备了特别的东西:一个日志文件。看一下下面的截图:
图 16.7 - 当你不阅读 Eucalyptus 的文档时,安装过程会花费很长时间。然后还需要更多的时间…还有更多…
这是安装屏幕。我们看不到关于正在发生的事情的任何真实信息,但从顶部的第三行中可以找到最重要的线索 - 日志文件的位置。为了防止屏幕被信息淹没,安装程序显示了这个非常漂亮的 figlet-coffee 图形(所有在 20 世纪 90 年代和 2000 年代使用 IRC 的人现在可能会微笑),但也将正在发生的一切都转储到日志中。这里的一切,是指每个命令、每个输入和每个输出。这使得调试变得容易 - 我们只需要滚动到文件的末尾,然后尝试从那个点开始向后查看是什么出了问题。一旦我们这样做了,解决方案就很简单 - 我们忘记为机器分配足够的内存。我们给了它 8GB 的 RAM,而官方上应该至少有 16GB 才能顺利运行。有报道称有机器只有 8GB 的 RAM 也能运行,但这完全没有意义 - 毕竟我们正在运行一个虚拟化环境。
AWS 及其冗长,这并不有助于解决问题
我们想提到的另一件事是 AWS 以及如何对其进行故障排除。AWS 是一个了不起的服务,但它有一个巨大的问题 - 就是它的规模。有这么多服务、组件和服务部分,你需要使用它们来在 AWS 上运行一些东西,简单的任务可能会变得非常复杂。我们的情景涉及尝试建立一个我们用作示例的 EC2 实例。
这个任务相对简单,演示了一个简单的问题可以有一个简单的解决方案,同时也可能完全不明显。
让我们回到我们试图做的事情。我们有一台机器在本地磁盘上。我们必须将它转移到云端,然后创建一个正在运行的虚拟机。这可能是最简单的事情之一。
为此,我们创建了一个 S3 存储桶,并将我们的机器从本地机器转移到了云端。但在我们尝试运行机器后,我们得到的只是一个错误。
像 AWS 这样的服务最大的问题是它的庞大,没有办法一次性理解所有东西 - 你必须一块一块地建立你的知识。所以,我们回到了文档。AWS 有两种文档 - 广泛的帮助,涵盖了每个服务的每个命令和每个选项,以及引导示例。帮助是令人惊叹的,但如果你不知道自己在找什么,它将毫无用处。这种形式的帮助只有在你对概念有基本的理解时才有效。如果你是第一次做某事,或者你遇到了以前没有遇到过的问题,我们建议你找到一个你正在尝试做的任务的示例,并进行练习。
在我们的情况下,这很奇怪,因为我们只需要运行一个简单的命令。但我们的导入仍然失败。在我们碰头几个小时后,我们决定表现得像我们什么都不知道,然后做了*如何将 VM 导入 AWS?*的示例。一切都很顺利。然后,我们尝试导入我们自己的机器;那不起作用。命令被复制/粘贴,但仍然不起作用。
然后我们意识到最重要的一点是我们需要注意细节。如果没有正确实施和执行这种思维方式,我们将给自己带来一系列问题。
注意细节
长话短说,我们做错的是错误配置了身份服务。在 AWS 等云环境中,每个服务都作为独立的域运行,与其他服务完全分开。当需要执行某项任务时,执行任务的服务必须具有某种授权。有一个服务负责处理这个问题-IAM-每个服务的每个请求的明显默认值是拒绝一切。一旦我们决定需要做什么,我们就有责任配置适当的访问和授权。我们知道这一点,所以我们为 EC2 访问 S3 中的文件创建了所有角色和权限。尽管这听起来可能有些奇怪,但我们必须授予我们正在使用的服务获取我们上传的文件的权限。如果你是新手,你可能期望这是自动的,但事实并非如此。
查看以下摘录,这是 AWS 预定义的角色列表中的一小部分。请记住,完整列表要长得多,我们只是触及了所有可用角色的表面。这些只是以字母A开头的角色:
图 16.8 - AWS 预定义角色
我们错误配置的是角色的名称-为了将 VM 导入 EC2 实例,需要有一个名为vmimport
的安全角色授予 EC2 正确的权限。我们匆忙配置了一个名为importvm
的角色。当我们完成示例时,我们粘贴了示例,一切都很好,但一旦我们开始使用我们的安全设置,EC2 就无法完成其工作。因此,始终检查产品文档并仔细阅读。
解决 ELK 堆栈的问题
ELK 堆栈可以有效地用于监视我们的环境。它确实需要一些手动操作,额外的配置,并且需要有点诡计,但它仍然可以提供报告、自动报告、通过电子邮件发送报告以及许多其他有价值的东西。
开箱即用,你不能直接发送报告-你需要再做一些调查。你可以使用 Watcher,但你需要的大部分功能是商业化的,所以你需要在上面花一些钱。还有其他一些方法:
-
使用 Kibana/Grafana 的快照-查看此网址:
github.com/parvez/snapshot
-
使用 ElastAlert-查看此网址:
github.com/Yelp/elastalert
-
使用 Elastic Stack 功能(以前称为 X-Pack)-查看此网址:
www.elastic.co/guide/en/x-pack/current/installing-xpack.html
这里还有一个建议:你可以通过rsyslog
来集中日志,因为这是一个内置功能。如果你创建一个集中式日志服务器,那里有免费的应用程序可以浏览日志文件(例如 Adiscon LogAnalyzer)。如果处理 ELK 似乎有点难以应付,但你意识到你需要一些东西,那就从这样的东西开始。它非常容易安装和配置,并提供一个带有正则表达式支持的免费 Web 界面,以便你可以浏览日志条目。
KVM 问题的故障排除最佳实践
在解决 KVM 问题时,有一些常识最佳实践。让我们列出其中一些:
-
保持简单,进行配置:部署了 50 个 OpenStack 主机跨三个子网在一个站点中的情况有什么好处呢?仅仅因为你可以将子网划分到 IP 范围的极限并不意味着你应该这样做。仅仅因为你的服务器有八个可用连接并不意味着你应该将它们全部连接到 iSCSI 存储。考虑端到端的配置(例如,iSCSI 网络的巨帧配置)。简单的配置几乎总是意味着更简单的故障排除。
-
在故障排除中保持简单:不要首先追求超复杂的场景。从简单开始。从日志文件开始。检查那里写了什么。随着时间的推移,使用你的直觉,因为它会发展,你将能够信任它。
-
使用监控工具,如 ELK 堆栈:使用某种工具不断监视你的环境。投资一些大屏幕显示器,将其连接到一台独立的计算机,挂在墙上,并花时间为你的环境配置重要的仪表板。
-
使用报告工具创建关于环境状态的多个自动报告:例如,Kibana 支持以 PDF 格式生成报告。当你监视你的环境时,你会注意到你的环境中一些更敏感的部分,比如存储。监视可用空间的数量。监视路径活动和从主机到存储的网络连接断开。创建报告并自动发送到你的电子邮件。那里有很多选择,所以利用它们。
-
在配置环境时创建笔记:如果没有别的,至少这样做,这样你就有了一些起点和/或未来的参考,因为经常会有许多即兴的更改。当记笔记的过程结束时,创建文档。
-
创建文档:使其永久,可读,并尽可能简单。不要记住事情,把事情写下来。使写下一切成为一项使命,并试图在你周围传播这种文化。
习惯于随时拥有大量的<插入你最喜欢的饮料>,并且经常熬夜,如果你想成为 IT 管理员、工程师或 DevOps 工程师。咖啡、百事可乐、可口可乐、柠檬汁、橙汁……无论什么能让你的智力活力充沛。有时,学会暂时远离问题。解决方案通常会在你思考与工作完全相反的事情时在你脑海中闪现。
最后,记住在工作时要尽量享受乐趣。否则,与 KVM 或任何其他 IT 解决方案一起工作的整个过程只会成为无休止的挫败感。挫折从来不是一件有趣的事情。我们更喜欢对着计算机或服务器大喊大叫。这是一种治疗方法。
总结
在本章中,我们试图描述一些基本的故障排除步骤,这些步骤通常适用于故障排除 KVM。我们还讨论了在处理本书的各种主题时我们不得不处理的一些问题——Eucalyptus,OpenStack,ELK 堆栈,cloudbase-init,存储等。这些问题大多是由于错误配置引起的,但也有一些严重缺乏文档的问题。无论发生什么,不要放弃。排除故障,让它工作,并在你做到时庆祝。
问题
-
在部署 KVM 堆栈之前,我们需要检查什么?
-
在部署 KVM 堆栈后,我们需要配置什么,以确保虚拟机在重新启动后能够运行?
-
我们如何检查 KVM 客户端日志文件?
-
我们如何永久打开和配置 KVM 调试日志?
-
我们如何在运行时打开和配置 KVM 调试日志?
-
解决 oVirt 安装问题的最佳方法是什么?
-
解决 oVirt 的小版本和大版本升级问题的最佳方法是什么?
-
管理 oVirt Engine 和主机更新的最佳方法是什么?
-
我们为什么需要小心快照?
-
模板和 cloudbase-init 的常见问题是什么?
-
安装 Eucalyptus 时我们的第一步应该是什么?
-
我们可以使用 ELK 堆栈的哪些高级监控和报告功能?
-
在故障排除基于 KVM 的环境时有哪些最佳实践?
更多阅读
有关本章涵盖内容的更多信息,请参考以下链接:
-
使用 KVM 调试日志:
wiki.libvirt.org/page/DebugLogs
-
oVirt 节点和 oVirt Engine 的防火墙要求:
www.ovirt.org/documentation/installing_ovirt_as_a_standalone_manager_with_remote_databases/#dns-requirements_SM_remoteDB_deploy
-
oVirt 升级指南:
www.ovirt.org/documentation/upgrade_guide/
-
NetApp 和 Openstack 集成的常见问题:
netapp-openstack-dev.github.io/openstack-docs/stein/appendices/section_common-problems.html
-
在 OpenStack 中集成 IBM Storwize 家族和 SVC 驱动程序:
docs.openstack.org/cinder/queens/configuration/block-storage/drivers/ibm-storwize-svc-driver.html
-
集成 IBM Storwize 和 OpenStack:
www.ibm.com/support/knowledgecenter/STHGUJ_8.2.1/com.ibm.storwize.v5100.821.doc/storwize_openstack_matrix.html
-
HPE Synergy 上 Red Hat OpenStack 平台与 Ceph 存储的参考架构:
www.redhat.com/cms/managed-files/cl-openstack-hpe-synergy-ceph-reference-architecture-f18012bf-201906-en.pdf
-
集成 Dell EMC Unity 和 OpenStack:
docs.openstack.org/cinder/rocky/configuration/block-storage/drivers/dell-emc-unity-driver.html
-
Red Hat Enterprise Linux 7 的 DM-multipath 配置:
access.redhat.com/documentation/en-us/red_hat_enterprise_linux/7/html/dm_multipath/mpio_setup
-
Red Hat Enterprise Linux 8 的 DM-multipath 配置:
access.redhat.com/documentation/en-us/red_hat_enterprise_linux/8/pdf/configuring_device_mapper_multipath/Red_Hat_Enterprise_Linux-8-Configuring_device_mapper_multipath-en-US.pdf
-
使用 Kibana/Grafana 的快照:
github.com/parvez/snapshot
-
使用 ElastAlert:
github.com/Yelp/elastalert
-
使用 Elastic Stack 功能(以前称为 X-Pack):
www.elastic.co/guide/en/elasticsearch/reference/current/setup-xpack.html
-
OpenStack 网络故障排除:
docs.openstack.org/operations-guide/ops-network-troubleshooting.html
-
OpenStack Compute 故障排除:
docs.openstack.org/ocata/admin-guide/support-compute.html
-
OpenStack 对象存储故障排除:
docs.openstack.org/ocata/admin-guide/objectstorage-troubleshoot.html
-
OpenStack 块存储故障排除:
docs.openstack.org/ocata/admin-guide/blockstorage-troubleshoot.html
-
OpenStack 共享文件系统故障排除:
docs.openstack.org/ocata/admin-guide/shared-file-systems-troubleshoot.html
-
故障排除裸金属 OpenStack 服务:
docs.openstack.org/ocata/admin-guide/baremetal.html#troubleshooting