CentOS-高性能指南-全-
CentOS 高性能指南(全)
原文:
annas-archive.org/md5/1a6a6cc31871803eb86642497978ce1d译者:飞龙
前言
CentOS 是企业级 Linux 操作系统,100%与 Red Hat Enterprise Linux(RHEL)二进制兼容。它作为 RedHat 商业 Linux 版本的免费替代品,仅在品牌上有所不同。一个高性能集群由一组协同工作的计算机组成,这样可以最小化或消除关键服务的停机时间,并增强应用程序的性能。
本书涵盖的内容
第一章,集群基础与 CentOS 7 安装,回顾了集群的基本原理,并概述了用两台 CentOS 7 服务器安装集群的必要步骤。
第二章,安装集群服务与配置网络组件,介绍了如何设置和配置基本的网络基础设施和集群服务。
第三章,更深入了解高可用性,详细列出了集群的组件,并演示了如何通过配置故障转移并对集群整体及每个节点的法定人数进行围栏处理来解决分脑问题。
第四章,集群的实际应用,介绍了如何在集群中实现一个 Web 服务器和数据库服务器。
第五章,监控集群健康状况,讨论了如何监控集群的性能和可用性。
第六章,性能测量与提升,回顾了为你最近安装的高可用集群进行性能调优的技术。
本书所需的工具
要跟随本书的内容,你需要从项目网站下载一个 CentOS 7 最小安装镜像。根据每章的要求,你将被要求安装其他软件包(例如 pacemaker、corosync 和 pcs 等)。
本书的读者对象
本书面向两类系统管理员——一类是想要获得关于如何设置高性能和高可用性的 CentOS 7 集群的详细逐步指南的读者,另一类是希望获得参考书籍以帮助他们学习必要技能,从而确保系统和相应资源、服务能够得到最优利用的读者。开始阅读本书时不需要具备性能调优的相关知识,但读者需要至少对 Fedora 家族的 Linux 发行版有所了解,最好是 CentOS。
规范
本书中,你会看到多种文本样式,用于区分不同类型的信息。以下是一些样式的示例及其含义解释。
代码单词、数据库表名、文件夹名、文件名、文件扩展名、路径名、虚拟网址、用户输入和 Twitter 用户名的显示方式如下。要下载“Employees”表,请访问launchpad.net/testdb/:
代码块的设置如下:
HWADDR="08:00:27:C8:C2:BE"
TYPE="Ethernet"
BOOTPROTO="static"
NAME="enp0s3"
ONBOOT="yes"
IPADDR="192.168.0.2"
NETMASK="255.255.255.0"
新术语和重要词汇以粗体显示。在屏幕上看到的词汇,例如在菜单或对话框中出现的词汇,通常以这种方式呈现:"高亮安装 CentOS 7,使用上下箭头"。
注意
警告或重要的备注会以框的形式呈现。
提示
提示和技巧以这种方式呈现。
读者反馈
我们始终欢迎读者的反馈。请告诉我们你对本书的看法——你喜欢或不喜欢的部分。读者的反馈对我们开发能最大程度满足你需求的书籍至关重要。
要向我们发送一般反馈,只需发送电子邮件至<feedback@packtpub.com>,并在邮件主题中注明书名。
如果你在某个领域具有专业知识,并且有兴趣写书或为书籍做贡献,请查看我们的作者指南:www.packtpub.com/authors。
客户支持
现在你已经成为 Packt 书籍的骄傲拥有者,我们为你提供了许多帮助,确保你能从购买中获得最大的收益。
下载示例代码
你可以从你的帐户中下载你所购买的所有 Packt 书籍的示例代码文件,网址为:www.packtpub.com。如果你在其他地方购买了本书,可以访问www.packtpub.com/support,并注册以便直接通过电子邮件获取文件。
勘误
尽管我们已尽一切努力确保内容的准确性,但错误仍然会发生。如果您在我们的书籍中发现错误——无论是文本还是代码中的错误——我们将非常感激您向我们报告。通过这样做,您可以避免其他读者的困扰,并帮助我们改进该书的后续版本。如果您发现任何勘误,请通过访问www.packtpub.com/submit-errata,选择您的书籍,点击勘误 提交 表单链接,并输入勘误的详细信息。一旦您的勘误被验证,您的提交将被接受,勘误将上传到我们的网站,或者添加到该书标题下的现有勘误列表中。任何现有的勘误可以通过选择您的书籍标题访问www.packtpub.com/support查看。
盗版
网络上的版权盗版问题是一个跨媒体的持续性问题。在 Packt,我们非常重视版权和许可证的保护。如果您在网络上发现任何我们作品的非法复制,无论形式如何,请立即向我们提供相关地址或网站名称,以便我们采取必要的措施。
请通过<copyright@packtpub.com>与我们联系,并提供涉嫌盗版材料的链接。
我们感谢您为保护我们的作者以及帮助我们提供有价值内容所做的努力。
问题
如果您在本书的任何方面遇到问题,可以通过<questions@packtpub.com>与我们联系,我们会尽力解决。
第一章:集群基础和在 CentOS 7 上的安装
在本章中,我们将介绍集群的基本原理,并逐步展示如何将两台 Linux 服务器设置为集群的成员。
在这个过程中,我们将从零开始安装 CentOS 7 Linux 发行版,并安装必要的软件包,最后配置基于密钥的认证,以便从一台计算机通过 SSH 访问另一台计算机。所有命令,除非特别说明,必须以 root 身份执行,并且在本书中始终以 $ 符号开头。
集群基础知识
在计算机科学中,集群由一组计算机组成(每台计算机称为节点或成员),它们共同工作,使得外部看来这一组计算机就像一个单一的系统。
企业和科研环境通常需要强大的计算能力来分析每天产生的大量数据,并且需要冗余。为了确保结果始终可供使用这些服务或管理这些服务的人访问,我们依赖于计算机系统的高可用性和高性能。互联网网站,如银行和其他商业机构使用的网站,在承受较大负载时仍能良好运行,正是使用集群优势的一个明显例子。
有两种典型的集群设置。第一种是将不同的任务分配给每个节点,从而实现比单个成员独立执行多个任务时更高的性能。集群的另一个经典用途是通过提供故障转移功能来确保高可用性,使得一个节点在另一个节点出现故障时能自动替代它,从而最小化一个或多个关键服务的停机时间。在这两种情况下,集群的概念不仅仅是利用每个成员的计算功能,而是通过相互补充来最大化它。
这种类型的集群设置被称为高可用性(HA),它的目的是通过在节点出现故障并导致无法使用时将服务从一个节点故障转移到另一个节点,从而消除系统停机时间。与需要人工干预的切换操作不同,故障转移过程由集群自动执行,无需停机。换句话说,这一操作对集群外部的终端用户和客户是透明的。
第二种设置使用其节点执行并行操作,以增强一个或多个应用程序的性能,这种设置被称为高性能集群(HPC)。HPC 通常出现在涉及使用大量数据集合的应用程序和进程的场景中。
为什么选择 Linux 和 CentOS 7?
如前所述,我们将构建一个包含两台运行 Linux 的机器的集群。选择这种方式是因为它具有低成本和稳定性——不需要付费的操作系统或软件许可证,并且可以在资源较少的系统(如 Raspberry Pi 或相对较旧的硬件)上运行 Linux。因此,我们可以用非常少的资源或资金搭建集群。
我们将通过设置组成系统的独立节点开始我们的集群之旅。我们选择的操作系统是 Linux 和 CentOS 7 版本,因为这是当前可用的 CentOS 最新发行版。与 Red Hat Enterprise Linux ©(这是企业和科学环境中使用最广泛的发行版之一)的二进制兼容性,加上其经过验证的稳定性,是我们做出这一决定的原因。
注意
CentOS 7 可以从项目官网 www.centos.org/ 免费下载。除此之外,关于该版本的具体详情可以随时查阅 CentOS wiki 上的发布说明,地址为 wiki.centos.org/Manuals/ReleaseNotes/CentOS7。
下载 CentOS
要下载 CentOS,请访问 www.centos.org/download/ 并点击下图所示的三种选项之一:

-
DVD ISO:这是一个
.iso文件(约 4 GB),可以写入普通的 DVD 光盘,并包含常用工具。如果你有稳定的网络连接,并可以以后下载其他软件包和工具,可以选择下载这个文件。 -
Everything ISO:这是一个
.iso文件(约 7 GB),包含 CentOS 7 基础仓库中的完整软件包集。如果你没有持续的网络连接,或者你的计划需要安装或填充本地或网络镜像,请下载这个文件。 -
替代下载:此链接将带你到官方 CentOS 镜像的一个公共目录,其中包含前述选项以及其他版本,包括不同桌面版本的选择(GNOME 或 KDE),以及最小化的
.iso文件(约 570 MB),该文件包含发行版的核心或基本软件包。
虽然这三种下载选项都可以使用,但我们将使用最小化安装,因为它足以满足我们的需求,且以后可以通过 标准 CentOS 包管理器 yum 使用公共软件包仓库安装其他所需的软件包。推荐下载的 .iso 文件是从下载页面获取的最新版本,截至本文编写时为 CentOS 7.0 1406 x86_64 Minimal.iso。
设置 CentOS 7 节点
如果你没有专用硬件可以用来设置集群的节点,你仍然可以使用一些虚拟化软件,如 Oracle Virtualbox © 或 VMware © 等,创建虚拟机来设置这些节点。通过虚拟化,我们可以在设置第一个节点后,通过克隆轻松地设置第二个节点。唯一的限制是我们无法使用 STONITH 设备。Shoot The Other Node In The Head(STONITH)是一种机制,旨在防止两个节点在 HA 集群中同时作为主节点,从而避免数据损坏的可能性。
以下设置将在具有 1 GB RAM 和 30 GB 硬盘空间、以及两个网络卡接口的 Virtualbox 虚拟机上进行。第一个网络卡将允许我们访问互联网以下载其他软件包,而第二个则用于创建一个共享 IP 地址,以便整个集群能够访问。
我选择 VirtualBox 而不是 VMware 的原因是,前者是免费的,且可用于 Microsoft Windows、Linux 和 macOS,而后者的完整版需要付费。
要下载并安装 VirtualBox,请访问 www.virtualbox.org/ 并选择适用于你操作系统的版本。有关安装说明,你可以参考 www.virtualbox.org/manual/UserManual.html,特别是 1.7 创建你的第一个虚拟机 和 1.13 克隆虚拟机 部分。
此外,你还需要确保虚拟机有两个网络接口卡。第一个是默认创建的,第二个需要手动创建。
要显示虚拟机的当前网络配置,请在 Virtualbox 的主界面中点击该虚拟机,然后点击 设置 按钮。会弹出一个窗口,列出不同的硬件类别。选择 网络 并将 适配器 1 配置为 桥接适配器,如下图所示:

点击 适配器 2,勾选相应的复选框启用它,并将其配置为 内部网络,命名为 intnet,如下图所示:

我们将使用安装过程建议的默认分区方案(LVM)。
安装 CentOS 7
我们将通过一步步创建第一个节点,然后使用 Virtualbox 的克隆功能实例化一个相同的节点。这将减少安装所需的时间,因为只需要稍微修改主机名和网络配置。按照以下步骤在虚拟机中安装 CentOS 7:
-
以下截图中的启动画面是加载安装介质后安装过程的第一步。使用上下箭头高亮安装 CentOS 7,然后按回车键:
![Installing CentOS 7]()
-
选择英语(或你偏好的安装语言)并点击继续:
![Installing CentOS 7]()
-
在下一屏幕上,你可以设置当前的日期和时间,选择键盘布局和语言支持,选择硬盘安装目标以及分区方式,连接主要网络接口,并为节点分配一个唯一的主机名。我们将当前节点命名为node01,并将其他设置保持为默认(我们稍后会配置额外的网卡)。然后,点击开始安装按钮。
![Installing CentOS 7]()
-
在安装后台继续进行时,我们将被提示为 root 账户设置密码并创建一个管理用户。一旦这些步骤确认完成,相应的警告将不再出现:
![Installing CentOS 7]()
-
当过程完成后,点击完成配置,系统将完成配置系统和设备。当系统准备好自行启动时,你会被提示这么做。移除安装介质并点击重启。
-
在成功重启计算机并启动到 Linux 提示符后,我们的第一个任务将是更新我们的系统。然而,在此之前,我们首先需要设置基本的网络适配器来访问互联网,以便下载和更新包。之后,我们就可以继续配置我们的网络接口。
设置网络基础设施
由于我们的节点将通过网络进行互相通信,我们将首先定义我们的网络地址和配置。我们相当基础的网络基础设施将包括两台 CentOS 7 机器,它们具有静态 IP 地址和主机名node01 [192.168.0.2]和node02 [192.168.0.3],以及一个名为简单网关 [192.168.0.1]的网关路由器。
在 CentOS 中,所有的网络接口配置都使用位于/etc/sysconfig/network-scripts目录中的脚本。如果你按照之前的步骤创建了第二个网络接口,那么该目录下应该有ifcfg-enp0s3和ifcfg-enp0s8文件。第一个是我们用来访问互联网并通过外部客户端进行 SSH 连接的网络卡的配置文件,而第二个将在后面的章节中用作集群资源的一部分。请注意,网络接口的具体命名可能会稍有不同,但可以假设它们会遵循ifcfg-enp0sX的格式,其中X是一个整数。
这是在我们的第一个节点的/etc/sysconfig/network-scripts/ifcfg-enp0s3目录中所需的最小内容(当您稍后设置第二个节点时,只需将 IP 地址(IPADDR)更改为192.168.0.3):
HWADDR="08:00:27:C8:C2:BE"
TYPE="Ethernet"
BOOTPROTO="static"
NAME="enp0s3"
ONBOOT="yes"
IPADDR="192.168.0.2"
NETMASK="255.255.255.0"
GATEWAY="192.168.0.1"
PEERDNS="yes"
DNS1="8.8.8.8"
DNS2="8.8.4.4"
请注意,UUID和HWADDR的值会因为硬件的不同而有所不同。为了避免问题,可以将这些设置保留为默认值。此外,请注意,集群主机必须分配静态 IP 地址——绝不要将其交给 DHCP!在前面使用的配置文件中,我们使用的是 Google 的 DNS,但如果您愿意,也可以使用其他 DNS。
修改完成后,保存文件并重启网络服务以应用更改。由于 CentOS 从版本 7 开始使用 systemd 代替 SysVinit 进行服务管理,本书中我们将使用systemctl命令来重启服务,而不是使用/etc/init.d脚本,如下所示:
$ systemctl restart network.service # Restart the network service
您可以使用以下命令验证之前的更改是否生效:
$ systemctl status network.service # Display the status of the network service
您可以通过以下命令验证预期的更改是否已正确应用:
$ ip addr | grep 'inet' ''# Display the IP addresses

您可以忽略所有与回环接口相关的错误信息,如前面的截图所示。然而,您需要仔细检查与enp0s3相关的任何错误信息(如果有),并解决它们,以便继续进行后续操作。
第二个接口将被命名为enp0sX,其中X通常是8,正如我们在本例中所示。您可以通过以下命令验证这一点,正如下面的截图所示:
$ ip link show

至于enp0s8的配置文件,您可以安全地通过复制ifcfg-enp0s3的内容来创建它。不过,别忘了通过ip link show enp0s8命令获取网卡的硬件(MAC)地址,并将其更改,同时将 IP 地址字段留空,使用以下命令:
ip link show enp0s8
cp /etc/sysconfig/network-scripts/ifcfg-enp0s3 /etc/sysconfig/network-scripts/ifcfg-enp0s8
接下来,按照之前的说明重启网络服务。
请注意,您还需要设置至少一种基本的 DNS 解析方法。考虑到我们只会设置两个节点的集群,因此我们将在两个主机的/etc/hosts中使用该方法。
编辑/etc/hosts,内容如下:
192.168.0.2 node01
192.168.0.3 node02
192.168.0.1 gateway
一旦您按照后续部分的说明设置了两个节点,在继续操作之前,您可以进行一次 ping 测试,以确保两个主机之间的连接正常,确保它们能够互相访问。
首先,在node01中执行:
$ ping –c 4 node02
接下来,在node02上执行相同操作:
$ ping –c 4 node01
安装集群所需的软件包
一旦我们完成操作系统的安装和基本网络基础设施的配置,就可以开始安装将为每个节点提供集群功能的软件包。在这里我们要强调的是,没有这些核心组件,我们的两个节点将变成简单的独立服务器,在其中一个节点发生系统崩溃或其他重大问题时无法相互支持。
关键软件组件
每个节点都需要以下软件组件,以便作为集群的一员工作。这些包在 CentOS 7 中作为集群设置的一部分得到全面支持,而其他已被弃用的替代方案则不再支持:
-
Pacemaker:这是一个集群资源管理器,它会在启动时运行脚本,在各个节点启动或停止时,或者在相关资源故障时执行。此外,它还可以配置为定期检查每个集群成员的健康状态。换句话说,pacemaker 负责启动和停止服务(例如,经典的网页服务器或数据库服务器),并实施逻辑,确保所有必要的服务始终只在一个位置运行,以避免数据故障或损坏。
-
Corosync:这是一个消息服务,它将为节点之间提供通信通道。正如你所猜测的,corosync 对 pacemaker 完成其任务至关重要。
-
PCS:这是一个 corosync 和 pacemaker 配置工具,它将允许你轻松查看、修改并创建基于 pacemaker 的集群。这并非严格必需,而是可选的。我们选择安装它,因为它在后续阶段会派上用场。
要安装前述的三个软件包,请运行以下命令:
$ yum update && yum install pacemaker corosync pcs
Yum 将更新所有已安装的软件包到最新版本,以便更好地满足依赖关系,然后继续实际安装。
除了安装上述软件包外,我们还需要启用iptables,因为 CentOS 7 的默认防火墙是firewalld。我们选择iptables而非firewalld,是因为它的使用更为广泛,并且相比相对较新的firewalld,你更有可能熟悉它。我们将在此安装所需的包,并将配置留到下一章进行。
为了通过 systemd 工具管理iptables,您需要使用以下命令安装(如果尚未安装)iptables-services软件包:
yum update && yum install iptables-services
现在,您可以使用以下命令停止并禁用firewalld:
systemctl stop firewalld.service
systemctl disable firewalld.service
接下来,启用iptables,使其在启动时初始化,并在当前会话中启动:
systemctl enable iptables.service
systemctl start iptables.service
您可以参考以下截图,以查看此过程的逐步示例:

一旦第一个节点(node01)的安装成功完成,按照 Virtualbox 手册(第 1.13 节,“克隆虚拟机”)中的大纲克隆第一个节点。克隆虚拟机完成后,向第二个虚拟机添加以下小修改:
-
将机器命名为
node02。当您启动这个新创建的虚拟机时,它的主机名仍然设置为node01。要更改它,运行以下命令,然后重启机器以使更改生效:$ hostnamectl set-hostname node02 $ systemctl reboot -
在
node02的enp0s3配置文件中,输入192.168.0.3作为 IP 地址,并设置正确的HWADDR地址。 -
确保两个虚拟机都在运行,并且每个节点都能 ping 通另一个节点和网关,如下两张截图所示。
首先,我们将从 node01 向 node02 和网关发送 ping,并将看到以下输出:

然后,我们将从 node02 向 node01 和网关发送 ping:

如果有任何 ping 操作没有返回预期的结果,如前面截图所示,请检查 Virtualbox 和配置文件中的网络接口配置,具体步骤见本章前面部分。
设置基于密钥的 SSH 访问认证
虽然不是严格要求,但我们也会设置基于公钥的 SSH 认证,这样就可以在不输入帐户密码的情况下从一台主机访问另一台主机。这个功能在某些情况下会很有用,比如需要在某个节点上执行系统管理任务时。请注意,您需要在两个节点上都执行此操作。
为了提高安全性,我们在创建 RSA 密钥时也可以设置一个密码短语,如下图所示。此步骤是可选的,如果您希望,可以跳过它。事实上,我建议您留空,以便今后操作更方便,但这完全取决于您。
运行以下命令以创建 RSA 密钥:
$ ssh-keygen -t rsa

为了启用无密码登录,我们将把新创建的密钥复制到 node02,反之亦然,接下来两张图分别展示了这一过程。
$ cat .ssh/id_rsa.pub | ssh root@node02 'cat' >> .ssh/authorized_keys'
将密钥从node01复制到node02:

将密钥从 node02 复制到 node01:

接下来,我们需要验证能否从每个集群成员连接到其他节点,且不需要密码,而是使用我们之前输入的密码短语:

最后,如果无密码登录没有成功,您可能需要确保 SSH 守护进程在两台主机上都在运行:
$ systemctl status sshd
如果没有运行,请使用以下命令启动它:
$ systemctl start sshd
在尝试重新启动服务后,您可能需要再次检查服务的状态。如果有任何错误,systemctl status sshd的输出将为您提供有关服务问题的指示,帮助您了解为什么它无法正常启动。按照这些指示,您将能够轻松地排查问题。
总结
在本章中,我们回顾了如何安装操作系统,并安装了实现基本集群功能所需的软件组件。在继续进行第二章,安装集群服务并配置网络组件之前,请确保已按照本章前述内容安装好节点、基本的集群软件,并配置好网络和 SSH 访问,我们将在该章节中配置资源管理器、消息层和防火墙服务,以便开始构建我们的集群。
第二章:安装集群服务并配置网络组件
在本章中,你将学习如何设置和配置基本的网络基础设施,并配置我们在上一章中安装的集群组件。
除此之外,我们还将回顾防火墙和互联网协议的基本概念,并解释如何添加防火墙规则,以允许节点之间的通信,并确保每个节点上的集群服务能够正常运行。
如果你的母语不是英语,你必须已经上过英语课或像我一样自学过,才能阅读这本书。当两个人不说相同语言时,他们也面临同样的情况。至少其中一个人需要知道对方的语言,或者两人需要达成一致使用一种共同的语言,才能互相理解。
在网络中,以上类比中的语言对应的就是协议。为了使两台机器之间能够进行数据传输,必须有一种逻辑方式让它们能够相互沟通。这正是互联网协议套件的核心内容,也被称为互联网模型,它提供了一组通信协议或规则。
正是这一套协议使得在像互联网这样的网络中数据传输成为可能。在本章后面,我们将解释参与集群内部通信的协议和网络端口。
配置和启动集群服务
在回顾了之前概述的关键网络概念后,我们现在可以开始描述集群服务。
启动并启用集群服务
你可能还记得,在上一章中我们安装了以下集群组件:
-
Pacemaker:这是集群资源管理器
-
Corosync:这是消息传递服务
-
PCS:这是同步和配置工具
正如你从之前的列表中可能已经猜到的,这些组件应当作为守护进程运行,守护进程是一种特殊的后台进程,无需管理员直接干预或控制。尽管我们在第一章中安装了必要的软件包,集群基础与在 CentOS 7 上的安装,但我们并没有启动集群资源管理器或消息传递服务。因此,我们现在需要手动首次启动它们,并在下次系统启动时使其自动运行。
我们将首先配置pacemaker和corosync,并将 PCS 配置留到本章后面。
如下截图所示,在你完成第一章,集群基础和 CentOS 7 上的安装 中列出的所有任务后,第一次启动两个节点时,这些守护进程(也称为 systemd 系统中的单元)是非活动的(并且在重启时不会自动启动)。你可以使用以下命令检查它们当前的运行状态:
systemctl status pacemaker
systemctl status corosync

为了在每个节点上启动 corosync 和 pacemaker 并启用这两个服务在系统启动时自动启动,首先通过复制安装包中随附的示例文件来创建 corosync 配置文件。与 pacemaker 和 PCS 不同,corosync 不会为你自动创建配置文件:
要创建 corosync 配置文件,请执行以下操作:
cp /etc/corosync/corosync.conf.example /etc/corosync/corosync.conf
然后通过运行以下命令来重启并启用服务:
systemctl start pacemaker
systemctl enable corosync
systemctl enable pacemaker
在前面的命令中,请注意我们并没有手动启动 corosync,因为当 pacemaker 启动时,corosync 会自动启动。需要注意的是,在基于 systemd 的系统中,启用服务并不等同于启动它。一个单元可以被启用但未启动,反之亦然。如下所示,启用服务涉及创建一个指向单元配置文件的符号链接,该配置文件指定了系统启动和关机时需要执行的操作等内容。
在两个节点上执行以下操作:
[root@node01 ~]# systemctl enable pacemaker
ln -s '/usr/lib/systemd/system/pacemaker.service' '/etc/systemd/system/multi-user.target.wants/pacemaker.service'
[root@node01 ~]# systemctl enable corosync
ln -s '/usr/lib/systemd/system/corosync.service' '/etc/systemd/system/multi-user.target.wants/corosync.service'
[root@node01 ~]#
最后,在我们可以在后续阶段配置集群之前,我们需要执行以下步骤:
-
启动并启用 PCS 守护进程(
pcsd),该守护进程将负责保持node01和node02上的 corosync 配置同步。为了使pcsd守护进程按预期工作,corosync 和 pacemaker 必须先前已经启动。请注意,当你使用systemctl工具在基于 systemd 的系统中管理服务时,可以省略守护进程名称后面的.service(或者如果你愿意,也可以使用它,正如在第一章,集群基础和 CentOS 7 上的安装 中所示)。通过以下命令启动并启用 PCS 守护进程:systemctl start pcsd systemctl enable pcsd -
现在设置 hacluster Linux 账户的密码,该账户是在安装 PCS 时自动创建的。此账户由 PCS 守护进程用于设置节点之间的通信,最好在两个节点上使用相同的密码来管理此账户。要设置 hacluster 密码,请输入以下命令,并在两个节点上设置相同的密码:
passwd hacluster
故障排除
在正常情况下,启动 pacemaker 应该会自动启动 corosync。你可以通过运行 systemctl status corosync 命令来检查 corosync 的状态。如果出于某种原因 corosync 没有自动启动,你仍然可以运行以下命令手动启动消息服务:
systemctl start corosync
如果前面的命令返回错误,运行 systemctl -l status unit,其中 unit 可以是 corosync 或 pacemaker,将返回有关相应服务的详细状态。
这是另一个有用的故障排除命令:
journalctl -xn
这将查询 systemd 日志(systemd 的日志),并返回关于最近事件的详细消息。
这两个命令将提供有用的信息,帮助你找出出了什么问题,并指引你解决问题的正确方向。
提示
你可以在其手册页中阅读更多关于 systemd 日志的信息,man journalctl,或者在在线版本中查看,网址是www.freedesktop.org/software/systemd/man/journalctl.html。
安全基础
现在,我们准备讨论网络安全问题,以便仅允许节点之间正确的网络流量。在初始设置过程中以及执行第一次测试时,你可能希望禁用防火墙和 SELinux(稍后在本章中会介绍),然后在稍后的阶段再通过这两者——具体取决于你目前对它们的熟悉程度。
进出控制
在启动并启用前面提到的服务之后,我们可以更详细地了解集群配置和维护过程中涉及的网络进程。在 netstat 命令的帮助下,这是 CentOS 7 中 net-tools 包的一部分,我们将打印出当前的监听网络端口,并验证 corosync 是否正在运行并监听连接。在此之前,你需要安装 net-tools 包,因为它并未包含在 CentOS 7 的最小安装中,使用以下命令进行安装:
yum –y install net-tools && netstat -npltu | grep -i corosync
如下截图所示,Corosync 正在监听回环接口(127.0.0.1)的 UDP 端口 5404 和 5405,以及多播地址(默认设置为 239.255.1.1,提供一种逻辑方式来标识这一组节点)上的端口 5405:

注意
用户数据报协议(UDP)是互联网模型的核心协议之一。该协议允许应用程序向网络中的主机发送消息(也称为 数据报),以便在不进行完整握手(即不在网络中建立成功连接)的情况下设置数据传输路径。此外,UDP 不包含网络通信中的错误检查和修正(这些检查由目标应用程序本身执行)。
传输控制协议(TCP)是互联网模型的另一个核心协议。与 UDP 相对,它提供了数据流在网络中计算机之间的错误检测、传输、排序和重复检查。几个著名的应用层协议(如 HTTP、SMTP 和 SSH 等)都封装在 TCP 中。
互联网组管理协议(IGMP)是网络设备(无论是主机还是路由器)用于建立多播数据传输的通信协议,它允许网络中的一个主机将数据报发送到多个其他感兴趣的系统,供它们接收源内容。
在继续之前,我们需要在每个节点的防火墙上允许流量通过。默认情况下,以下列表中命名的端口是这些服务启动后监听的默认端口,正如我们之前所做的那样。具体来说,在两个节点中,我们需要执行以下步骤:
-
使用以下命令打开
corosync所需的网络端口(UDP端口5404和5405)和 PCS(通常是TCP 2224):iptables -I INPUT -m state --state NEW -p udp -m multiport --dports 5404,5405 -j ACCEPT iptables -I INPUT -p tcp -m state --state NEW --dport 2224 -j ACCEPT注意
请注意,使用
-m多端口选项可以将多个不同的端口组合成一条规则,而无需编写几乎相同的多个规则。这将减少规则数量,并简化iptables的维护。 -
使用以下命令允许 IGMP 和多播流量:
iptables -I INPUT -p igmp -j ACCEPT iptables -I INPUT -m addrtype --dst-type MULTICAST -j ACCEPT -
将
INPUT链的默认iptables策略更改为DROP。因此,任何不符合我们刚刚添加的规则的数据包将被丢弃。请注意,与REJECT策略不同,DROP不会向调用客户端发送任何响应,只是保持“无线电静默”并主动丢弃数据包:iptables -P INPUT DROP -
添加必要规则后,我们的防火墙配置如下所示,在以下代码中可以清楚地看到,除了我们在前两步中添加的规则外,还有一些是我们启动并启用
iptables时默认初始化的,如在第一章中所解释的,集群基础与 CentOS 7 的安装。运行以下命令以列出防火墙规则及其对应的编号:[root@node01 ~]# iptables -L -v --line-numbers Chain INPUT (policy DROP 0 packets, 0 bytes) num pkts bytes target prot opt in out source destination 1 423 48645 ACCEPT all -- any any anywhere anywhere ADDRTYPE match dst-type MULTICAST 2 0 0 ACCEPT igmp -- any any anywhere anywhere 3 0 0 ACCEPT tcp -- any any anywhere anywhere state NEW tcp dpt:efi-mg 4 1200 124K ACCEPT udp -- any any anywhere anywhere state NEW multiport dports hpoms-dps-lstn,netsupport 5 86 7152 ACCEPT all -- any any anywhere anywhere state RELATED,ESTABLISHED 6 0 0 ACCEPT icmp -- any any anywhere anywhere 7 387 41151 ACCEPT all -- lo any anywhere anywhere 8 0 0 ACCEPT tcp -- any any anywhere anywhere state NEW tcp dpt:ssh 9 65 10405 REJECT all -- any any anywhere anywhere reject-with icmp-host-prohibited Chain FORWARD (policy ACCEPT 0 packets, 0 bytes) num pkts bytes target prot opt in out source destination 1 0 0 REJECT all -- any any anywhere anywhere reject-with icmp-host-prohibited Chain OUTPUT (policy ACCEPT 1149 packets, 127K bytes) num pkts bytes target prot opt in out source destination -
如果
INPUT链中的最后一条默认规则执行了对不符合要求的数据包的REJECT操作,我们将删除它,因为我们已经通过修改链的默认策略来解决这个需求:iptables -D INPUT [rule number] -
最后,我们必须保存防火墙规则,以确保在系统重启时规则能保持持久性。如以下截图所示,这包括将更改保存到
/etc/sysconfig/iptables中:service iptables save![Letting in and letting out]()
如果我们使用首选的文本编辑器或分页程序查看/etc/sysconfig/iptables文件,我们会发现该文件以一种较易阅读的格式呈现了相同的防火墙规则,如以下代码所示:
[root@node02 ~]# cat /etc/sysconfig/iptables
# Generated by iptables-save v1.4.21 on Sat Dec 5 10:09:24 2015
*filter
:INPUT DROP [0:0]
:FORWARD ACCEPT [0:0]
:OUTPUT ACCEPT [263:28048]
-A INPUT -m addrtype --dst-type MULTICAST -j ACCEPT
-A INPUT -p igmp -j ACCEPT
-A INPUT -p tcp -m state --state NEW -m tcp --dport 2224 -j ACCEPT
-A INPUT -p udp -m state --state NEW -m multiport --dports 5404,5405 -j ACCEPT
-A INPUT -m state --state RELATED,ESTABLISHED -j ACCEPT
-A INPUT -p icmp -j ACCEPT
-A INPUT -i lo -j ACCEPT
-A INPUT -p tcp -m state --state NEW -m tcp --dport 22 -j ACCEPT
-A INPUT -j REJECT --reject-with icmp-host-prohibited
-A FORWARD -j REJECT --reject-with icmp-host-prohibited
COMMIT
# Completed on Sat Dec 5 10:09:24 2015
接下来,您还需要编辑/etc/sysconfig/iptables-config文件,以指示防火墙规则应在系统关机和重启时保持持久性。请注意,这些行已经存在于文件中,需要进行更改。为了谨慎起见,您可能希望在进行更改之前备份现有文件:
cp /etc/sysconfig/iptables-config /etc/sysconfig/iptables-config.orig
现在,使用你喜欢的文本编辑器打开/etc/sysconfig/iptables-config,并确保指定的行如下所示:
IPTABLES_SAVE_ON_STOP="yes"
IPTABLES_SAVE_ON_RESTART="yes"
如往常一样,别忘了重启iptables(systemctl restart iptables)以应用更改。
CentOS 7,和以往的版本一样,内置了SELinux(Security Enhanced Linux)支持。这为操作系统提供了基于内核本身的本地、灵活的访问控制功能。你可能会想知道在此阶段应该如何处理 SELinux 策略。当前的设置,可以通过sestatus和getenforce命令显示,如下图所示,暂时可以满足需求:

简单来说,为了安全起见,我们将默认模式保持为enforcing。这应该不会引起任何问题,但如果出现问题,可以使用以下命令将模式设置为permissive:
setenforce 0
前述命令将启用警告并记录错误,以帮助你在服务器仍在运行时进行故障排除。如果你需要排查问题,并且怀疑 SELinux 可能是原因,你应该查看/var/log/audit/audit.log。SELinux 的日志信息会通过auditd(Linux 审计系统,默认启动)写入该文件,其中带有 AVC 关键字。否则,这些信息会写入/var/log/messages。
现在,在处理下一个标题之前,别忘了在另一个节点上重复相同的操作并保存更改!
了解 PCS
我们正在接近实际设置集群的步骤。在开始这个任务之前,我们需要了解 PCS——我们集群的核心组件——可以说它将用于控制和配置 pacemaker 与 corosync。为了开始这项工作,我们可以仅仅运行 PCS 而不加参数,如下所示:
pcs
这将返回以下截图中显示的输出,其中提供了每个选项和命令的简要说明:

我们对Commands部分感兴趣,其中列出了可以通过此工具管理的集群实际类别,并简要描述了它们的使用方法。每个类别都支持多个功能,可以通过在pcs [category]后附加help来显示。例如,让我们看看cluster命令所提供的功能(顺便说一下,我们很快会使用到它):
pcs cluster help
Usage: pcs cluster [commands]...
Configure cluster for use with pacemaker
Commands:
auth [node] [...] [-u username] [-p password] [--force] [--local]
Authenticate pcs to pcsd on nodes specified, or on all nodes
configured in corosync.conf if no nodes are specified (authorization
tokens are stored in ~/.pcs/tokens or /var/lib/pcsd/tokens for root).
By default all nodes are also authenticated to each other, using
--local only authenticates the local node (and does not authenticate
the remote nodes with each other). Using --force forces
re-authentication to occur.
setup [--start] [--local] [--enable] --name <cluster name> <node1[,node1-altaddr]>
[node2[,node2-altaddr]] [..] [--transport <udpu|udp>] [--rrpmode active|passive]
[--addr0 <addr/net> [[[--mcast0 <address>] [--mcastport0 <port>]
[--ttl0 <ttl>]] | [--broadcast0]]
[--addr1 <addr/net> [[[--mcast1 <address>] [--mcastport1 <port>]
[--ttl1 <ttl>]] | [--broadcast1]]]]
[--wait_for_all=<0|1>] [--auto_tie_breaker=<0|1>]
[--last_man_standing=<0|1> [--last_man_standing_window=<time in ms>]]
[--ipv6] [--token <timeout>] [--join <timeout>]
[--consensus <timeout>] [--miss_count_const <count>]
[--fail_recv_const <failures>]
Configure corosync and sync configuration out to listed nodes
--local will only perform changes on the local node
--start will also start the cluster on the specified nodes
--enable will enable corosync and pacemaker on node startup
--transport allows specification of corosync transport (default: udpu)
The --wait_for_all, --auto_tie_breaker, --last_man_standing,
--last_man_standing_window options are all documented in corosync's'
votequorum(5) man page.
--ipv6 will configure corosync to use ipv6 (instead of ipv4)
--token <timeout> sets time in milliseconds until a token loss is
declared after not receiving a token (default 1000 ms)
--join <timeout> sets time in milliseconds to wait for join mesages
(default 50 ms)
--consensus <timeout> sets time in milliseconds to wait for consensus
to be achieved before starting a new round of membership configuration
(default 1200 ms)
--miss_count_const <count> sets the maximum number of times on
receipt of a token a message is checked for retransmission before
a retransmission occurs (default 5 messages)
--fail_recv_const <failures> specifies how many rotations of the token
without receiving any messages when messages should be received
may occur before a new configuration is formed (default 2500 failures)
注意
请注意,输出已被截断以简化显示。
你将经常查阅文档,因此你应该认真考虑熟悉帮助功能。
管理身份验证并创建集群
现在我们已经准备好将 PCS 认证到命令行中指定节点上的pcsd服务。默认情况下,所有节点之间会进行相互认证,因此 PCS 可以从一个集群成员与其他成员进行通信。
这正是hacluster用户派上用场的时候(我们之前已经更改了它的密码),因为这是用于此目的的账户。PCS 在具有N个节点的集群中执行此步骤的通用语法如下:
pcs cluster auth member1 member 2 … memberN
在我们当前的两节点设置中,设置认证意味着:
pcs cluster auth node01 node02
我们将被提示输入用户名和密码,以进行认证,正如前面讨论的那样,幸运的是,这个过程不需要重复进行,因为我们现在可以从任何节点控制集群。这个过程在下面的截图中进行了示范(我们从node01设置pcs的认证),然后当我们从node02发出命令创建集群时,/etc/corosync/corosync.conf文件会同步到另一个节点:

要使用指定节点创建集群,请在(仅在一个节点上,在如前所示成功尝试密码之后)键入以下命令:
pcs cluster setup --name MyCluster node01 node02
在这里,MyCluster是我们为集群选择的名称(你可以根据自己的喜好进行更改)。接下来,按下Enter键并验证输出。请注意,正是这个命令在两个节点的/etc/corosync/corosync.conf路径中创建了集群配置文件。
如果你按照本章前面的说明使用示例配置文件创建了corosync.conf文件(以启动 pacemaker 和 corosync),你将需要使用--force选项,以当前新创建的集群设置覆盖该文件:
[root@node01 ~]# pcs cluster setup --name MyCluster node01 node02
Error: /etc/corosync/corosync.conf already exists, use --force to overwrite
[root@node01 ~]# pcs cluster setup --name MyCluster node01 node02 --force
Shutting down pacemaker/corosync services...
Redirecting to /bin/systemctl stop pacemaker.service
Redirecting to /bin/systemctl stop corosync.service
Killing any remaining services...
Removing all cluster configuration files...
node01: Succeeded
node02: Succeeded
[root@node01 ~]#
注意
如果在尝试设置pcs认证时收到以下错误信息,请确保pcsd在nodeXX节点上正在运行(并且已启用),然后重试:
Error: Unable to communicate with nodeXX
注意
(此处,XX是节点编号)
此时,node02中的/etc/corosync/corosync.conf文件应与node01中的文件完全相同,从任一节点运行diff命令时,输出为空表示corosync配置文件已正确同步到另一个节点:
diff /etc/corosync/corosync.conf <(ssh node02 'cat /etc/corosync/corosync.conf')
下一步是通过发出命令来实际启动集群(同样,仅在一个节点上执行):
pcs cluster start --all
注意
用于启动集群的命令(pcs cluster start)值得进一步解释:
start [--all] [node] [...]
Start corosync & pacemaker on specified node(s), if a node is not
specified then corosync & pacemaker are started on the local node.
If --all is specified then corosync & pacemaker are started on all
nodes.
注意
有时你可能希望在特定节点上启动集群。在这种情况下,你将指定该节点,而不是使用--all标志。
前一个命令的输出应如下所示:
pcs cluster start --all
[root@node01 ~]# pcs cluster start --all
node01: Starting Cluster...
node02: Starting Cluster...
[root@node01 ~]#
一旦集群启动,你可以从任何节点检查其状态(记住,PCS 让你可以从任何节点管理集群):
[root@node01 log]# pcs status cluster
Cluster Status:
Last updated: Sat Dec 5 11:59:14 2015 Last change: Sat Dec 5 11:53:01 2015 by root via cibadmin on node01
Stack: corosync
Current DC: node02 (version 1.1.13-a14efad) - partition with quorum
2 nodes and 0 resources configured
Online: [ node01 node02 ]
[root@node01 log]#or just pcs status:
[root@node01 log]# pcs status
Cluster name: MyCluster
WARNING: no stonith devices and stonith-enabled is not false
Last updated: Sat Dec 5 11:55:43 2015 Last change: Sat Dec 5 11:53:01 2015 by root via cibadmin on node01
Stack: corosync
Current DC: node02 (version 1.1.13-a14efad) - partition with quorum
2 nodes and 0 resources configured
Online: [ node01 node02 ]
Full list of resources:
PCSD Status:
node01: Online
node02: Online
Daemon Status:
corosync: active/disabled
pacemaker: active/disabled
pcsd: active/enabled
注意
pcs status 命令提供了更详细的信息,包括服务和资源的状态。可能会注意到其中一个节点显示为 OFFLINE,如下所示:
Online: [ node01 ]
OFFLINE: [ node02 ]
注意
在这种情况下,请确保 pacemaker 和 corosync 在标记为 OFFLINE 的节点上都已启用(如在 Daemon status: 行后指示的),然后再次执行 pcs status 命令。
您可能会遇到的另一个问题是,一个或多个节点处于不干净的状态。虽然这不常见,但通过在两个节点上停止和重新启动集群来重新同步节点将解决此问题:
pcs cluster stop
pcs cluster start
标记为 DC 的节点,即 Designated Controller,是最初启动集群并从该节点典型地发出集群相关命令的节点。如果当前的 DC 由于某种原因失败,将自动从剩余节点中选择新的指定控制器。您可以使用以下命令查看当前 DC 的节点:
pcs status | grep -i dc
要查看集群中的当前 DC,请执行:
[root@node01 ~]# pcs status | grep -i dc
Current DC: node02 (version 1.1.13-a14efad) - partition with quorum
[root@node01 ~]#
您还需要分别检查每个节点:
pcs status nodes 命令允许您查看有关集群及其配置资源的所有信息:
[root@node01 ~]# pcs status nodes
Pacemaker Nodes:
Online: node01 node02
Standby:
Offline:
[root@node01 ~]#
corosync-cmapctl 命令是访问集群对象数据库的另一个工具,您可以在其中查看每个节点的属性和配置。由于 corosync-cmapctl 命令的输出相当长,您可能希望按选定的关键字进行过滤,例如 members 或 cluster_name:
[root@node01 ~]# corosync-cmapctl | grep -Ei 'cluster'_name|members'
runtime.totem.pg.mrp.srp.members.1.config_version (u64) = 0
runtime.totem.pg.mrp.srp.members.1.ip (str) = r(0) ip(192.168.0.2)
runtime.totem.pg.mrp.srp.members.1.join_count (u32) = 1
runtime.totem.pg.mrp.srp.members.1.status (str) = joined
runtime.totem.pg.mrp.srp.members.2.config_version (u64) = 0
runtime.totem.pg.mrp.srp.members.2.ip (str) = r(0) ip(192.168.0.3)
runtime.totem.pg.mrp.srp.members.2.join_count (u32) = 1
runtime.totem.pg.mrp.srp.members.2.status (str) = joined
totem.cluster_name (str) = MyCluster
[root@node01 ~]#
正如您可以看到的前面的输出,您可以查看集群的名称、IP 地址以及每个成员的状态。
为集群设置虚拟 IP
正如在 第一章 中提到的,Cluster Basics and Installation on CentOS 7,由于集群定义为一组计算机(我们一直称之为节点或成员),它们共同工作,使得外部从端看起来像是单一系统,我们需要确保最终用户和客户也这样看待。
因此,本章的最后一件事情是配置虚拟 IP,这是外部客户端连接到我们集群的地址。请注意,在普通的非集群环境中,您可以使用诸如 ifconfig 的工具来为系统配置虚拟 IP。
但在我们的情况下,我们将只使用 PCS 并同时执行两个操作:
-
创建 IPv4 地址
-
将其分配给整个集群
将虚拟 IP 添加为集群资源
由于虚拟 IP 是所谓的 集群资源,我们将使用 pcs resource help 查找有关如何创建它的信息。您需要事先选择一个在您的局域网中未被使用的 IP 地址分配给虚拟 IP 资源。初始化虚拟 IP 后,您可以像通常一样对其进行 ping 测试以确认其可用性。
要创建名为virtual_ip、地址为192.168.0.4/24、每 30 秒监控一次enp0s3的虚拟 IP,在任一节点上运行以下命令:
pcs resource create virtual_ip ocf:heartbeat:IPaddr2 ip=192.168.0.4 cidr_netmask=24 nic=enp0s3 op monitor interval=30s
到目前为止,在pcs cluster status或pcs status的输出中,虚拟 IP 资源将显示为已停止,直到后续阶段我们禁用 STONITH(STONITH 是一个集群功能,将在下一节中解释)。
查看虚拟 IP 的状态
要查看集群资源的当前状态,请使用以下命令:
pcs status resources
如果新创建的虚拟 IP 没有自动启动,你需要进行更彻底的检查,包括通过crm_verify提供的正在运行的集群配置的详细输出,crm_verify是 pacemaker 集群资源管理器的一部分:
[root@node01 ~]# crm_verify -L -V
error: unpack_resources: Resource start-up disabled since no STONITH resources have been defined
error: unpack_resources: Either configure some or disable STONITH with the stonith-enabled option
error: unpack_resources: NOTE: Clusters with shared data need STONITH to ensure data integrity
Errors found during check: config not valid
[root@node01 ~]#
注意
STONITH,即Shoot The Other Node In The Head的缩写,代表一个集群功能,防止高可用集群中的节点同时变为活跃状态,从而避免同时提供相同的内容。
正如前面的错误信息所示,共享数据的集群需要 STONITH 来确保数据完整性。然而,我们将把对这个功能的适当讨论推迟到下一章,并且暂时禁用它,以便能够展示虚拟 IP 如何启动并变得可访问。另一方面,当crm_verify –L –V没有返回任何输出时,表示配置有效且没有错误。
请禁用 STONITH,但请记住,我们将在下一章中重新讨论此问题:
pcs property set stonith-enabled=false
接下来,再次检查集群状态。
当你查询集群状态时,资源现在应该显示为已启动。你可以通过 ping 来检查资源的可用性:
ping -c 4 192.168.0.4
如果 ping 操作返回一个警告,说明一些数据包未能送达目标,请查看/var/log/pacemaker.log或/var/log/cluster/corosync.log,获取有关可能失败的原因的信息。
总结
在本章中,你学习了如何设置和配置基本的网络基础设施,以及我们在第一章,CentOS 7 上的集群基础与安装中安装的集群组件。通过回顾与安全、防火墙和互联网协议相关的概念,我们能够添加防火墙规则,允许每个节点之间的通信,并确保每台机器上的集群服务正常运行。
我们将在本书接下来的内容中继续使用本文讨论的工具,不仅用于检查集群或单个节点的状态,还作为故障排除技巧,以防事物未按预期进行。
第三章:高可用性的更深入探讨
本章将比在第一章中更详细地讲解高可用性集群的组件;你可能希望复习那一章,以便在继续深入学习之前刷新记忆。
本章将涵盖以下主题:
-
故障切换——高可用性和性能的概述
-
围栏——隔离故障节点
-
脑裂——准备避免不一致
-
多数决策——在集群内评分
-
通过 PCS 图形界面配置我们的集群
本章将通过提问几个关于如何实现高可用性的问题来开始,我们将在过程中尝试寻找答案。在下一章中,我们将设置实际的实际示例:
-
如何确保自动故障切换而不需要人工干预?
-
为了确保在多种故障场景下的高可用性,集群中需要多少个节点?
-
如何在离线节点重新上线时始终确保数据完整性和高可用性?
总体而言,集群可以分为两大类。为了简化,我们将使用一个由两个节点组成的集群来进行以下定义,但这个概念可以轻松扩展到包含更多节点的集群:
-
主动/主动(A/A):在这种类型的集群中,所有节点都同时处于活动状态。因此,它们能够同时并平等地处理请求,每个节点都有独立的工作负载。当需要故障切换时,剩余的节点将承担额外的处理负载,从而对集群的整体性能产生负面影响。
-
主动/被动(A/P):在这种类型的集群中,有一个活动节点和一个被动节点。正常情况下,活动节点处理所有流量,而被动节点则处于空闲状态,等待在发生故障切换时登场,实际通过自己的资源接管情况,直到另一个节点重新上线。
正如你从最后两段中可以推测的那样,A/P 集群相比 A/A 集群有一个明显的优势,即在发生故障切换时,相同比例的硬件和软件资源会被分配给最终用户。这使得性能保持稳定且透明,这在数据库服务器中尤其重要,因为性能是一个关键要求。另一方面,A/A 集群通常提供更高的可用性,因为至少有两个服务器在积极运行应用程序并向最终用户提供服务。在下一章中,你会注意到,我们将首先详细设置一个 A/P 集群,并提供总体说明,以便你在后续阶段如果希望将其转换为 A/A 集群时能够做到。
故障转移 – 高可用性和性能简介
故障转移过程大致可以描述为,在发生电力或网络故障时,切换到一个可用资源,以尽可能减少停机时间,零停机时间是高可用性集群的主要目标。
在第二章,安装集群服务并配置网络组件,我们配置了一个简单但对我们目的至关重要的资源:虚拟 IP 地址。你还会记得,为了开始了解 PCS——用于管理集群配置的前端工具——我们介绍了它的基本语法和使用方法。
提示
与 Linux 生态系统中的其他情况一样,程序/协议/包的名称写成大写,而工具和实用程序的名称写成小写。因此,PCS 用于表示包名称,而它是用于管理 PCS 的命令行工具。
使用pcs status命令,我们将能够查看集群的当前状态以及几条重要信息,如下图所示:

以下内容展示了当前可用的MyCluster集群资源:
Full list of resources:
virtual_ip (ocf::heartbeat:IPaddr2): Started node01
如图所示,虚拟 IP 地址(在第二章中方便地命名为virtual_ip,安装集群服务并配置网络组件)已在node01上启动。由于虚拟 IP 是集群资源,因此可以预期,如果该节点发生故障,此资源会自动故障转移到node02。我们将通过停止该集群成员上的corosync和pacemaker来模拟节点因真实问题而下线。
对于我们当前的目的,这次模拟不涉及关闭(关机)节点,因为我们想在停止该节点上的corosync和pacemaker之后,展示pcs status的输出中一些有趣的内容。
提示
您还可以通过在 VirtualBox 中暂停其中一台虚拟机来模拟故障转移(选择VM选项,在Oracle VM VirtualBox Manager中按Ctrl + P,或者从机器菜单中选择暂停),也可以通过在该节点上使用systemctl disable network命令禁用网络来模拟。
让我们在node01上停止pacemaker和corosync:
pcs cluster stop node01
然后在另一台节点,即node02上再次运行,使用以下命令:
pcs status
要查看集群、节点和资源的当前状态,如下图所示,您需要在当前运行集群的节点上运行pcs status命令:

有一些前面截图中的行值得讨论。
OFFLINE: [ node01 ]这一行表示node01处于离线状态——就整个集群而言——这是我们在停止集群资源管理器和该成员的消息服务后所预期的。但是,接下来的代码表明,pcsd守护进程(远程配置接口)仍在node01上运行,这使得仍然可以本地或通过其他节点远程控制pacemaker和corosync:
PCSD Status:
node01: Online
最后,virtual_ip (ocf::heartbeat:IPaddr2): Started node02命令让我们看到虚拟 IP 地址从node01故障转移到node02是自动完成的且没有错误。如果在执行虚拟 IP 地址故障转移时遇到错误,你需要检查相关日志,以了解可能出了什么问题。
例如,让我们来看一个集群资源没有其他节点可以故障转移的案例。假设node02处于离线状态(可能是因为你暂停了虚拟机,或者真的将其关闭了),然后突然node01也宕机了(记住,我们这里讨论的是集群服务不可用,而非实际的电力或网络中断)。当然,这一切都发生在幕后——你现在唯一知道的是,有用户投诉无法访问你的集群提供的任何应用、资源或服务。
你可能最先想尝试的是查看虚拟 IP 地址是否可以在你的网络内 ping 通(在配置资源时根据你的选择更改 IP 地址,参考第二章,安装集群服务和配置网络组件):
ping -c 4 192.168.0.4
你会注意到四个数据包中没有一个能够到达其预定目的地:
PING 192.168.0.4 (192.168.0.4) 56(84) bytes of data.
From 192.168.0.2 icmp_seq=1 Destination Host Unreachable
From 192.168.0.2 icmp_seq=2 Destination Host Unreachable
From 192.168.0.2 icmp_seq=3 Destination Host Unreachable
From 192.168.0.2 icmp_seq=4 Destination Host Unreachable
--- 192.168.0.4 ping statistics ---
4 packets transmitted, 0 received, +4 errors, 100% packet loss, time 3000ms
因此,前往node01,你首先启动资源的地方,检查节点状态:
Error: cluster is not currently running on this node
然后你会看到集群在node01上宕机。但故障转移不是应该自动发生吗?此时,你有两个选择:
-
转到
node02检查集群是否在该节点上运行。 -
检查
node01上的日志。注意,这假设你已经关闭了node02,然后是node01。无论如何,你需要查看你最后关闭的节点上的日志。
在/var/log/pacemaker.log中简要搜索关键字virtual_ip(或在第二章的最后阶段你为资源设置的名称)会告诉你问题所在。以下是grep virtual_ip /var/log/pacemaker.log文件的简短摘录:
Mar 21 07:52:45 [3839] node01 pengine: info: native_print: virtual_ip (ocf::heartbeat:IPaddr2): Stopped
Mar 21 07:52:45 [3839] node01 pengine: info: native_color: Resource virtual_ip cannot run anywhere
Mar 21 07:52:45 [3839] node01 pengine: info: LogActions: Leave virtual_ip (Stopped)
第一条消息表示virtual_ip在node01上被停止,第二条消息则指出它无法在任何地方进行故障转移。结果是,资源保持为Stopped状态(如第三条消息所述),直到从集群中的任何节点手动重新启用它。然而,请记住,在此之前需要先启动该节点上的集群:
pcs cluster start node01
然后,在node01上运行以下命令:
pcs resource enable virtual_ip
进一步检查pcs status可能会表明资源仍然处于停止状态(此时最好也 ping 一下虚拟 IP 地址)。如果virtual_ip拒绝启动,我们可以使用以下命令获取有关该资源未正确启动的详细信息,然后重置集群资源以重新加载其正确配置:
pcs resource debug-start virtual_ip --full
请记住,pcs命令接受一个选项(不是必需的)和一个命令作为参数,这些参数后面可能会跟随特定的选项。在这方面,pcs cluster stop中,cluster是命令,stop表示该命令的特定操作,可以用来关闭corosync和pacemaker,无论是在本地节点、所有节点,还是特定节点上。在以下man pcs摘录中,你可以查看pcs cluster stop的语法:
stop [--all] [node] [...]
Stop corosync and pacemaker on specified node(s), if a node is not specified then corosync and pacemaker are stopped on the local node. If --all is specified then corosync and pacemaker are stopped on all nodes.
注意
请记住,当corosync和pacemaker在两个节点上运行时,你可以从任一节点运行任何 PCS 命令来配置集群。如果发生严重故障,pcsd在两个节点上都不可用时,你将不得不使用 SSH 从一个节点连接到另一个节点来排查和修复问题。
正如在其他情况下发生的一样,日志文件是系统管理员最好的朋友,在发生问题时,它们可以发挥关键作用,帮助你找出问题的根本原因。有三个日志是你可能需要不时查看的,甚至在执行故障转移时也需要查看:
-
/var/log/pacemaker.log -
/var/log/cluster/corosync.log -
/var/log/pcsd/pcsd.log
注意
此外,你还可以使用journalctl -xn在 systemd 日志中进行搜索,并使用grep来过滤特定的单词或短语。
提示
你可以使用pcs resource disable <resource_name>和pcs resource enable <resource_name>命令重置集群资源的状态。
隔离——隔离故障节点
随着集群中节点数量的增加,其可用性也增加,但其中一个节点在某个时刻失败的可能性也随之增加。无论事件严重与否,这种失败事件都意味着我们必须找到一种方法来将故障节点与集群隔离,以便完全释放其处理任务给集群的其他部分。想象一下在共享存储集群中一个不稳定的节点可能引发的问题——数据损坏将不可避免地发生。在这里,“故障”一词的含义不仅仅是在英语中通常的意思(指不能正常工作的东西),还包括一个节点及其上启动的资源,无论出于何种原因,集群都无法确定其状态。
这就是“隔离”这个术语的用处所在。根据定义,集群隔离是将一个节点与其不应访问的资源或启动服务分离或隔离出来,并与其他节点隔离开来的过程。因此,计算机集群的 ABC 法则之一可以表述为,不要让一个故障节点运行任何集群资源——在所有情况下都要进行隔离。根据上述声明,一个无响应的节点在另一个节点接管之前必须被下线。
使用一种称为 STONITH 的机制执行隔离操作,我们在上一章节中简要介绍过(简单来说,STONITH 是一种用于隔离故障节点以防止其在集群中引发问题的隔离方法)。你会记得我们在那时禁用了这个功能,并提到我们会在这里重新讨论这个话题。对集群配置的快速检查,如下面截图所示,将确认 STONITH 当前处于禁用状态:

小贴士
如果你运行pcs config代码,你将能够详细查看集群的当前配置,如前面的截图所示。
最后,stonith-enabled: false一行清楚地提醒我们 STONITH 在我们的集群中是禁用状态的。
在继续进行集群配置时,你会想把pcs config添加到必须牢记的基本命令列表中。它将允许你快速查看通过集群提供的设置和资源。
因此,让我们开始重新启用 STONITH:
pcs property set stonith-enabled=true
接下来,再次检查配置,可以使用pcs config或pcs property list命令。为了简洁起见,在下面截图所示的情况下,我们使用了pcs property list命令,以介绍另一个有用的 PCS 命令。注意在重新启用 STONITH 之前和之后如何检查此属性:

一旦我们在集群中启用了 STONITH,现在是时候通过配置 STONITH 资源(也称为 STONITH 设备)来最终设置集群中的隔离操作了。
安装和配置 STONITH 设备
值得注意的是,STONITH 设备是一个集群资源,用于关闭故障或无响应的节点。在两个节点上安装以下软件包将使多个 STONITH 设备在我们的集群中可用。如果你正在按照第一章中早期的建议,使用两台虚拟机设置 2 节点集群,集群基础与 CentOS 7 上的安装,请在两个节点上安装以下软件包:
yum update && yum install fence-agents-all fence-virt
安装完成后,你可以使用pcs stonith list命令列出所有可用的代理,如下图所示。
在下图中列出的每个设备都由多个可用参数描述,这些参数可以通过pcs stonith describe agent命令显示,在这里你需要将agent替换为相应的资源名称。请注意,在稍后的步骤中,我们在实际配置 STONITH 设备时会使用这些参数。所需的参数在描述的开头标有(required)字样,使用pcs stonith describe fence_ilo命令将返回以下输出:
Stonith options for: fence_ilo
ipaddr (required): IP Address or Hostname
login (required): Login Name
passwd: Login password or passphrase
ssl: SSL connection
notls: Disable TLS negotiation
ribcl: Force ribcl version to use
ipport: TCP/UDP port to use for connection with device
inet4_only: Forces agent to use IPv4 addresses only
inet6_only: Forces agent to use IPv6 addresses only
passwd_script: Script to retrieve password
ssl_secure: SSL connection with verifying fence device's' certificate
ssl_insecure: SSL connection without verifying fence device's' certificate
action (required): Fencing Action
verbose: Verbose mode
debug: Write debug information to given file
version: Display version information and exit
help: Display help and exit
power_timeout: Test X seconds for status change after ON/OFF
shell_timeout: Wait X seconds for cmd prompt after issuing command
login_timeout: Wait X seconds for cmd prompt after login
power_wait: Wait X seconds after issuing ON/OFF
delay: Wait X seconds before fencing is started
retry_on: Count of attempts to retry power on
stonith-timeout: How long to wait for the STONITH action to complete per a stonith device.
priority: The priority of the stonith resource. Devices are tried in order of highest priority to lowest.
pcmk_host_map: A mapping of host names to ports numbers for devices that do not support host names.
pcmk_host_list: A list of machines controlled by this device (Optional unless pcmk_host_check=static-list).
pcmk_host_check: How to determine which machines are controlled by the device.

在这些参数中,你可以看到有一个操作(action),它将在发生围栏事件时执行,还有一个将由该设备控制的主机列表(pcmk_host_list)和一个等待时间(timeout或stonith-timeout),即等待围栏操作完成所需的时间。这些都是在创建设备并设置基础设施时,指定 STONITH 选项时需要考虑的关键信息。
下一步,创建设备本身,将主要依赖于你所拥有的硬件设备。例如,如果你想用内置 iLO 接口为惠普节点(如 Proliant 服务器)设置围栏,你将使用fence_ilo代理,或者如果你的节点是在 VMWare 虚拟化环境上,你可能需要选择fence_vmware_soap。另一个常见的选项是戴尔的戴尔远程访问控制器(DRAC),你将使用fence_drac5。遗憾的是,截止目前,VirtualBox 并没有现成的围栏设备。
提示
iLO(集成灯光关闭)卡是一个独立的接口,具有独立的网络连接和 IP 地址,允许系统管理员通过 HTTPS 远程执行某些操作,适用于 HP 服务器。类似的功能在戴尔服务器上也可通过内置的 DRAC 实现。
现在,让我们创建一个名为Stonith_1的 STONITH fence_ilo设备,用来围栏node01(尽管我们在这个例子中使用的是node01,但请注意这必须逐个节点进行设置):
pcs stonith create Stonith_1 fence_ilo pcmk_host_list="""node01" action=reboot --force
创建围栏设备的基本语法如下:
pcs stonith create stonith_device_name stonith_device_type stonith_device_options
你可以通过man stonithd查看已解释的stonith_device_options列表。
要更新设备,请使用以下命令:
pcs stonith update stonith_device_name stonith_device_options
要删除设备,请使用以下命令:
pcs stonith delete stonith_device_name
最后,pcs stonith show [stonith_device_name] --full命令将显示所有用于[stonith_device_name]的选项,或者如果未指定[stonith_device_name],则显示所有围栏设备。
然后,你可以通过使用以下命令杀死pacemaker和corosync进程来模拟围栏情况(请注意,在实际事件中,这一过程是自动进行的):
pcs cluster stop node01 # Clean stop of the cluster on node_name
pcs stonith fence node01 --off
同时,使用pcs stonith confirm node01命令确认node_name实际上已脱机。
分脑现象 – 为避免不一致性进行准备
到此为止,我们已经考虑了一些集群中的基本概念,接下来是一个不完全虚构的场景——如果一个集群由位于不同网络中的节点组成,并且它们之间的通信链路中断会发生什么?当节点处于同一网络中,链路中断时也是如此。也就是说,实际上没有任何节点脱机,但每个节点都认为对方不可用。默认行为是,每个节点假设另一个节点已经宕机,并继续提供集群之前运行的资源或应用程序。
到目前为止,一切正常!现在,假设网络连接恢复在线,但两个节点仍然认为它们是主集群成员。这时就会发生数据损坏(最坏的情况)或不一致(最好情况)。这是由于任何一方对数据所做的更改未能复制到另一端所造成的。
这就是为什么配置围栏如此重要,同时也要确保集群成员之间的冗余通信链路,以便不会因为单点故障(SPOF)导致我们集群中的分脑现象。
就围栏而言,只有标记为指定控制器(DC)并且具有法定人数的节点才能围栏其他节点,并在我们的 A/P 集群中作为主节点或活动节点运行应用程序和资源。通过这样做,我们确保不会允许另一个节点接管可能导致前面提到的数据不一致性的资源。
法定人数 – 在集群内部评分
简单来说,法定人数的概念指的是为了使整个集群可用,必须保持活动状态的最小节点数量。具体来说,当活动节点的数量大于总节点数量的一半时,集群被认为具有法定人数。另一种表达方式是,法定人数通过至少简单多数(总节点数的 50% + 1)来实现。
尽管仲裁概念不能防止分裂大脑的情况发生,但它将决定哪个节点(或节点组)是主导的,并允许运行集群,以便在发生分裂大脑情况时,只有一个节点(或节点组)能够运行集群服务。
默认情况下,当集群没有仲裁时,pacemaker将完全停止所有资源,以防止它们在比期望的更多节点上启动。然而,集群成员仍将监听其他节点在网络上重新出现的情况,但在再次具备仲裁之前,它们将无法作为集群工作。
您可以通过停止node01和node02上的集群,然后再次启动来轻松确认此行为。您将注意到virtual_ip仍然停止:
Full list of resources:
virtual_ip (ocf::heartbeat:IPaddr2): Stopped
直到您手动启用它,可以使用以下命令:
pcs resource enable virtual_ip
对于我们的情况是 2 节点集群,当我们在第二章中使用pcs cluster设置时,为我们在/etc/corosync/corosync.conf中添加了以下部分:
quorum {
provider: corosync_votequorum
two_node: 1
}
two_node: 1行告诉corosync在 2 节点集群中,一个成员足以维持仲裁。因此,即使一些人会争辩说 2 节点集群是没有意义的,我们的集群在至少一个节点在线时仍将继续工作。也许您之前在一个节点上停止和启动集群时已经注意到了,但是值得指出的是,在尝试停止我们 2 节点集群中的一个成员时,您将被要求使用--force选项:
pcs cluster stop node01 --force
要显示集群中当前节点列表及其对集群仲裁的个别贡献(如在Votes列下的图中所示),请运行corosync-quorumtool -l命令:

在前述潜在的分裂大脑情况下,并假设集群被划分为两个分区,得票数占多数的分区仍然可用,而其他分区将由 DC 自动进行隔离,如果已经放置并正确配置了 STONITH。例如,在 4 节点集群中,仲裁在至少三个集群节点正常运行时建立。否则,集群将不再具备仲裁,pacemaker将停止集群运行的服务。
使用 PCS GUI 配置我们的集群
如果您按照第二章中概述的步骤来为 Hacluster 帐户启用集群管理,我们还可以使用 PCS GUI,一个集群管理 Web 界面,来管理集群。这包括能够添加、删除和编辑现有的集群。
要访问 PCS Web 界面,请前往 https://<ip_of_one_node>:2224(注意是 https 而不是 http),接受安全例外,然后使用之前为 Hacluster 设置的凭据登录,如下图所示:

你接下来看到的屏幕(如下图所示)将展示移除现有集群、添加现有集群或创建新集群的菜单。当你点击添加现有按钮时,系统会提示你输入一个当前属于现有集群的节点的主机名或 IP 地址,以便使用 Web UI 进行管理:

然后,点击集群名称,并可以随意浏览下图顶部的菜单,这也有助于我们添加、删除或编辑我们迄今为止讨论过的资源:

摘要
在本章中,我们探讨了节点故障和故障集群成员的基本技术,以及一些更深入的集群概念。除此之外,我们还学习了如何添加集群资源,以便进一步将我们新创建的集群配置为实际使用案例,这将在下一章中详细讲解。
还值得再次强调的是,我们并没有详细讨论某些硬件组件,比如围栏设备,你应该注意围栏代理和设备(根据 pcs stonith list),并查看它们是否适用于你所在案例中的可用硬件。
最后但同样重要的是,你需要记住,为了避免分脑现象,除了彻底应用本章中概述的概念外,还需要确保节点所在网络之间有冗余通信链路。这将帮助你防止单点故障(SPOF)可能导致此类不希望发生的事件。
第四章:集群的实际应用
在本章中,您将学习如何通过部署 Web 服务器和数据库服务器在实际场景中使用集群。在此之前,我们需要回顾一些与这些关键组件相关的基本概念,配置复制存储,以便文件在节点之间保持同步,然后最后用示例数据填充数据库,之后我们将使用一个简单的 PHP 应用程序对其进行查询。
由于本书不涉及编程方面的内容,您可以根据自己的选择使用其他编程语言。如果您希望使用 PHP,我选择它是因为简便。请记住,本书的重点不是教您如何构建用于 CentOS 7 集群的 Web 应用程序,而是如何使用它为这些应用程序提供高可用性。
在本章中,您将注意到我们将依赖前几章介绍的概念和配置的服务,随着深入探讨如何利用我们已经搭建好的集群架构。
设置存储
当我们开始讨论集群的基本概念时,我们提到高可用性集群的目标,简单来说,就是通过提供故障切换功能,尽量减少服务的停机时间。在我们开始在集群中安装 Web 服务器和数据库服务器的过程中,我们不禁要想,如何在节点之间同步这些服务应提供给我们的内容。我们需要找到一种方法,让节点共享一个共同的存储空间,数据将保存在其中。如果一个节点无法提供访问,另一个节点将接管客户端请求。
在 Linux 中,处理这个问题的一种常见且免费的方法是一个开源技术,称为分布式复制块设备(DRBD),它使得能够通过网络连接将单个存储设备(如硬盘或分区)从一个节点镜像或复制到另一个节点。用一个相对高层次的解释,您可以把 DRBD 提供的功能看作是一个基于网络的 RAID-1。其基本结构和数据流如图所示:

提示
所有复制的数据集,例如共享存储设备,都称为 DRBD 中的资源,不应与前面章节中讨论的 PCS 资源混淆。
为了安装 DRBD,您需要在两个节点上启用 ELRepo 仓库,因为该软件包未通过标准的 CentOS 仓库分发。以下是 ELRepo 仓库的目的和内容的简要说明:
-
第一步是导入用于签署
rpm包的 GPG 密钥,该包代表着仓库的基础。如果在导入密钥之前尝试使用 rpm 安装该软件包,安装将因为安全措施而失败。 -
在两个节点上运行以下命令:
rpm --import https://www.elrepo.org/RPM-GPG-KEY-elrepo.org rpm -Uvh http://www.elrepo.org/elrepo-release-7.0-2.el7.elrepo.noarch.rpm -
你可以通过以下命令验证 ELRepo 是否已被添加到你配置的仓库中:
yum repolist | grep elrepo输出应该与以下屏幕截图所示相似:
![设置存储]()
提示
另外,你可以在安装添加它到系统中的
rpm包后显式禁用 ELRepo,并仅在安装必要的包时启用它(为防万一,请确保先备份原始仓库配置文件):cp /etc/yum.repos.d/elrepo.repo /etc/yum.repos.d/elrepo.repo.ORG sed -i "s/enabled=1/enabled=0/g" /etc/yum.repos.d/elrepo.repo yum --enablerepo elrepo update yum --enablerepo elrepo install -y drbd84-utils kmod-drbd84 -
然后,使用以下命令:
yum update && yum install drbd84-utils kmod-drbd84它将安装必要的管理工具,以及相应的 DRBD 内核模块。此过程完成后,你需要使用以下命令检查模块是否已加载:
lsmod | grep -i drbd如果模块没有自动加载,你可以按如下方式在两个节点上手动加载该模块:
modprobe drbd
注意
请注意,modprobe 命令将在当前会话中负责加载内核模块。然而,为了让它在启动时加载,你必须通过创建一个文件到 /etc/modules-load.d/ 中来使用 systemd-modules-load 服务,以确保每次系统启动时 DRBD 模块都能正确加载:
echo drbd >/etc/modules-load.d/drbd.conf
ELRepo 仓库与 DRBD 可用性
ELRepo 是一个为兼容 Red Hat 企业版 Linux 的 Linux 发行版提供的软件仓库,CentOS 和 Scientific Linux 是其衍生版。ELRepo 主要关注与硬件相关的软件包(尤其是驱动程序),以增强或提供当前内核中没有的功能。因此,通过安装相应的软件包,你可以免去仅为添加某个功能而重新编译内核,或者等待它在上游仓库中得到支持,或等待该功能被包含在以后版本的内核发布中。ELRepo 仓库由相关发行版(RHEL、CentOS 和 Scientific Linux)的活跃成员维护。
由 ELRepo 提供的 DBRD 主要用于评估和体验 RHEL 基础平台上的 DRBD,但它并未得到 Red Hat 和 DRBD 的创建者 LINBIT 官方支持。然而,按照本章及本书其余部分所述的程序,你可以确保在集群中提供所有必要的功能。
一旦我们安装了前面提到的包,我们需要分配用于存储复制内容的物理空间。考虑到可扩展性,我们将使用 逻辑卷管理器(LVM)技术来创建动态硬盘分区,这样以后如果需要,可以轻松调整其大小。
首先,我们将为每个节点添加一块 2GB 的硬盘。该硬盘的用途是作为 Apache Web 服务器访问的 PHP 应用程序的底层文件系统。
我选择这个大小是因为它足以存储所有需要复制的文件,并且因为 Virtualbox 允许你为存储磁盘选择任意大小。如果你在跟随本书操作时使用的是实际硬件,你可能需要根据实际情况选择不同的大小。
要向 Virtualbox 中的现有虚拟机添加虚拟硬盘,请按照以下步骤操作:
-
关闭 虚拟机
-
在 Virtualbox 的初始界面中右击它
-
在上下文菜单中选择 设置,然后选择 存储
-
选择 控制器:SATA,然后点击 添加硬盘,接着点击 创建新磁盘
-
选择 虚拟磁盘映像(VDI) 和 动态分配,然后继续到下一步
-
最后,为设备指定一个名称并选择 2 GB 作为大小
启动并启动每个节点后,我们应该执行以下命令来识别新添加的磁盘(在我们的例子中,新磁盘是尚未分区的那个):
ls -l /dev | grep -Ei sd[a-z]
我们将通过以下命令来识别新添加的磁盘:
dmesg | grep sdb
这里,/dev/sdb 是新磁盘的 ID,正如之前列出 /dev 目录内容时返回的那样:
[root@node02 ~]# dmesg | grep sdb
[ 2.484257] sd 3:0:0:0: [sdb] 4194304 512-byte logical blocks: (2.14 GB/2.00 GiB)
[ 2.484258] sd 3:0:0:0: [sdb] Write Protect is off
[ 2.484258] sd 3:0:0:0: [sdb] Mode Sense: 00 3a 00 00
[ 2.484258] sd 3:0:0:0: [sdb] Write cache: enabled, read cache: enabled, doesn't support DPO or FUA
[ 2.487361] sdb: unknown partition table
[ 2.498564] sd 3:0:0:0: [sdb] Attached SCSI disk
[root@node02 ~]#
现在,让我们在磁盘上创建一个分区,对应的物理卷,一个卷组(drbd_vg),以及最终的逻辑卷(drbd_vol)。确保在每个节点上重复这些步骤,根据需要更改设备(dev/sdX):
parted /dev/sdb mklabel msdos
parted /dev/sdb mkpart p 0% 100%
pvcreate /dev/sdb1
vgcreate drbd_vg /dev/sdb1
lvcreate -n drbd_vol -l 100%FREE drbd_vg
注意
你可以通过命令 lvdisplay /dev/drbd_vg/drbd_vol 来检查新创建的逻辑卷的状态。
配置 DRBD
在每个节点上成功创建并分区我们的 DRBD 磁盘后,DRBD 的主配置文件位于 /etc/drbd.conf,该文件仅包含以下两行:
include "drbd.d/global_common.conf";
include "drbd.d/*.res";
这两行包括相对路径,从 /etc/ 开始,指向实际的配置文件。在 global_common.conf 文件中,你将找到你的 DRBD 安装的全局设置,以及 DRBD 配置中的公共部分(定义那些应该被每个资源继承的设置)。另一方面,在 .res 文件中,你会找到每个 DRBD 资源的特定配置。
我们将通过以下命令将现有的 global_common.conf 文件重命名为 global_common.conf.orig(作为原始设置的备份副本):
mv /etc/drbd.d/global_common.conf /etc/drbd.d/global_common.conf.orig
然后,我们将通过打开文件并使用你喜欢的文本编辑器创建一个新的 global_common.conf 文件,内容如下:
global {
usage-count no;
}
common {
net {
protocol C;
}
}
一旦你在一个节点(例如,node01)上创建了前面的文件,你可以轻松地将其复制到另一个节点,方法如下:
ssh node02 mv /etc/drbd.d/global_common.conf /etc/drbd.d/global_common.conf.orig
scp /etc/drbd.d/global_common.conf node02:/etc/drbd.d/
注意
你应该养成备份原始配置文件的习惯,这样当出现问题时,你可以恢复到之前的设置。
usage-count no 行在全局部分会跳过每次安装新版本软件时向 DRBD 团队发送通知。如果你希望提交来自系统的信息,可以将其更改为 yes。或者,如果你希望每次升级时都提示你做出决定,可以将其更改为 ask。无论哪种方式,你都应该知道他们仅将这些信息用于统计分析,而且他们的报告总是公开的,位于 usage.drbd.org/cgi-bin/show_usage.pl。
protocol C 行告诉 DRBD 资源使用完全同步的复制,这意味着,作为主节点的本地写操作只有在本地和远程磁盘的写入都得到确认后,才视为完成。因此,如果单个节点出现故障,在正常情况下不会导致任何数据丢失,除非两个节点(或其存储子系统)同时不可恢复地损坏。
接下来,我们需要为我们的资源创建一个特定的新配置文件(称为 /etc/drbd.d/drbd0.res),我们将其命名为 drbd0,文件内容如下(其中 192.168.0.2 和 192.168.0.3 是我们两个节点的 IP 地址,7789 是用于通信的端口):
resource drbd0 {
disk /dev/drbd_vg/drbd_vol;
device /dev/drbd0;
meta-disk internal;
on node01 {
address 192.168.0.2:7789;
}
on node02 {
address 192.168.0.3:7789;
}
}
注意
你可以在 Linbit 网站上的资源配置文件中查找每个指令的含义(以及其他指令),地址为 drbd.linbit.com/users-guide-8.4/。
TCP 端口 7789 是大多数 DRBD 安装中使用的典型端口号。然而,官方文档指出,DRBD(按照惯例)使用从 7788 开始的 TCP 端口,每个资源都监听一个单独的端口。在本章中,由于我们只处理一个资源,我们将仅使用端口 7789——无论是在唯一的资源配置文件中,还是在两个节点的防火墙设置中。请务必记住在防火墙中打开此端口,否则,资源将无法进行后续的同步。
要在防火墙配置中打开 7789 TCP 端口,在两个节点上执行以下命令:
iptables -I INPUT -p tcp -m state --state NEW -m tcp --dport 7789 -j ACCEPT
service iptables save
另外,你可以按如下方式将此文件复制到另一个节点:
scp /etc/drbd.d/drbd0.res node02:/etc/drbd.d/
当我们之前安装 DRBD 时,一个名为 drbdadm 的工具也被安装了,从它的名字可以猜到,它是用于管理 DRBD 资源的工具,类似于我们新配置的卷。启动并使 DRBD 资源上线的第一步是初始化其元数据(如果你在配置文件中设置了不同的名称,可能需要更改资源名称)。请注意,事先需要 /var/lib/drbd 目录。如果在安装 DRBD 时没有创建该目录,请在继续之前手动创建它,使用以下代码:
mkdir /var/lib/drbd
drbdadm create-md drbd0
这些行应返回以下输出,并显示相应的确认消息,表示设备的元数据已成功创建:

注意
“元数据”一词被定义为关于数据的数据。在 DRBD 资源的上下文中,资源的元数据包含有关设备及其所存储数据的多条信息。如果出现问题,drbdadm create-md [drbd resource]命令将返回有用的调试信息。
下一步是启用drbd0,以完成磁盘和网络资源的分配:
drbdadm up drbd0
你可以通过查看/proc虚拟文件系统来验证资源的状态,它允许你查看内核视角下的系统资源,正如以下截图所示。但是,请确保你已按照之前的指示在两个节点上执行:
cat /proc/drbd
请查看以下截图:

请注意,由于我们尚未指明哪个 DRBD 设备(每个节点一个)将作为主设备,哪个将作为从设备,因此设备的状态显示为未知和不一致。在这种情况下,考虑到我们从零开始设置了两个 DRBD 设备,选择哪个作为主设备并不重要。然而,如果我们使用了一个已有数据的设备,那么选择那个设备作为主资源就非常重要。否则,你有丢失数据的严重风险。
运行以下命令,将其中一个设备标记为主设备并执行初步同步。你只需要在具有主资源的节点(在我们的示例中,是node01)执行此操作:
drbdadm primary --force drbd0
如同之前一样,你可以在同步进行时检查当前的同步状态。cat /proc/drbd命令显示资源的创建和同步进度,如下所示:

现在,通过drbd-overview命令,如其名称所示,你可以查看当前配置的 DRBD 资源概览。在这种情况下,你应该会看到node01作为主设备,node02作为从设备,通过在两个节点上运行命令可以验证这一点(如下截图所示):
在node01上,drbd-overview命令应该返回:
0:drbd0/0 Connected Primary/Secondary UpToDate/UpToDate
而在node02上,你应该看到:
0:drbd0/0 Connected Secondary/Primary UpToDate/UpToDate

最后,我们需要在node01上的/dev/drbd0上创建一个文件系统。你可以选择任何适合你需求或要求的文件系统,如果有的话。如果你还没有决定使用哪个,Ext4是一个不错的选择。XFS 是 CentOS 7 系统默认的文件系统。然而,如果我们以后需要调整它的大小(例如,遇到更复杂的底层存储需求来支持网页和数据库服务器的运行),则无法调整 XFS 的大小。
在主节点上运行以下命令,为/dev/drbd0创建ext4文件系统,并等待其完成,如下面的屏幕截图所示:
mkfs.ext4 /dev/drbd0

现在,您的 DRBD 资源已准备好如常使用。您现在可以挂载它并开始保存文件。但是,在我们将其用作高可用和故障转移组件之前,我们仍然需要将其添加为集群资源。这就是我们将在下一节中执行的操作。
非常重要的是,您需要从node01,即我们的主节点上为资源创建文件系统。否则,在试图从非主集群成员节点添加文件系统时,将遇到挂载问题。
将 DRBD 添加为 PCS 集群资源
您会回想起在第二章中,我们如何为集群添加虚拟 IP 地址。现在,是时候为我们刚刚创建和配置的 DRBD 资源执行相同的操作了。
然而,在执行此操作之前,我们必须指出 PCS 命令行工具的一个最显著特性之一,即它能够将当前集群配置保存到文件中,然后可以使用命令行工具添加进一步的设置。然后,您可以使用生成的文件更新运行中的集群配置。
要从集群信息库(CIB)中检索集群配置并将其保存到名为drbd0_conf的文件中,当前工作目录,请确保首先启动集群,并使用以下命令:
pcs cluster start --all
然后将集群配置保存到之前提到的文件中(drbd0_conf将自动创建):
pcs cluster cib drbd0_conf
接下来,我们将 DRBD 设备作为 PCS 集群资源添加。请注意-f开关,指示以下命令的更改应追加到drbd0_conf文件。以下命令必须从与前一条命令相同的目录执行(即包含drbd0_conf文件的目录):
pcs -f drbd0_conf resource create web_drbd ocf:linbit:drbd drbd_resource=drbd0 op monitor interval=60s
最后,我们需要确保该资源同时在两个节点上运行,通过添加克隆资源(一种应在多个主机上同时活动的特殊资源)来实现此目的:
pcs -f drbd0_conf resource master web_drbd_clone web_drbd master-max=1 master-node-max=1 clone-max=2 clone-node-max=1 notify=true
此时,我们可以使用drbd0_conf文件更新集群配置。但是,在更新全局配置之前和之后运行pcs status命令快速检查集群状态及其资源,能更好地可视化变更:
pcs status
pcs cluster cib-push drbd0_conf
如果更新成功,最后的命令应该会显示以下消息:
CIB updated
现在,让我们再次检查当前的集群配置:
pcs status
如果最后的 PCS 状态显示有某个故障事件(很可能与 SELinux 策略有关,而不太可能与常规文件权限有关),你应该检查/var/log/audit/audit.log文件来开始排查问题。以 AVC 开头的行会指明你需要首先查看的地方。以下是一个示例:
type=AVC msg=audit(1429116572.153:295): avc: denied { read write } for pid=24192 comm="drbdsetup-84" name="drbd-147-0" dev="tmpfs" ino=20373 scontext=system_u:system_r:drbd_t:s0 tcontext=unconfined_u:object_r:var_lock_t:s0 tclass=file
前面的错误信息似乎表明 SELinux 正在拒绝drbdsetup-84可执行文件对临时tmpfs文件系统的读/写访问。其相应的被拒绝的系统调用支持这一理论:
type=SYSCALL msg=audit(1429116572.153:295): arch=c000003e syscall=2 success=no exit=-13 a0=125e080 a1=42 a2=180 a3=7fff42b39f80 items=0 ppid=24191 pid=24192 auid=4294967295 uid=0 gid=0 euid=0 suid=0 fsuid=0 egid=0 sgid=0 fsgid=0 tty=(none) ses=4294967295 comm="drbdsetup-84" exe="/usr/lib/drbd/drbdsetup-84" subj=system_u:system_r:drbd_t:s0 key=(null)
注意
NSA 增强安全 Linux(SELinux)是 Linux 中一个灵活的强制访问控制架构的实现。如果你在最初遇到一些问题,你可以禁用 SELinux 来执行以下步骤(但强烈建议不要这么做)。如果你选择通过编辑/etc/sysconfig/selinux禁用 SELinux,别忘了使用pcs resource cleanup [resource_id]清理资源错误计数,其中resource_id是pcs resource show返回的资源名称。
为了清除所有疑虑,安装policycoreutils-python包(其中包含用于管理 SELinux 环境的管理工具):
yum update && yum install policycoreutils-python
使用其中包含的audit2allow工具,以人类可读的形式查看访问被拒绝的原因,然后根据被拒绝操作的日志生成 SELinux 的允许规则。以下命令将输出audit.log文件中最后一行包含 AVC 的内容,然后将其传递给audit2allow,生成可读格式的结果:
cat /var/log/audit/audit.log | grep AVC | tail -1 | audit2allow -w -a
如下图所示,我们可以确认由于缺少类型强制规则,访问被拒绝:

现在我们知道是什么原因导致了问题,让我们创建一个策略包,将必要的类型强制规则应用到命令行中指定的模块:
cat /var/log/audit/audit.log | grep AVC | tail -1 | audit2allow -a -M drbd0_access_0
如果你在当前工作目录中执行ls -l,你会发现前面的命令创建了一个类型强制文件(drbd_access_0.te)并将其编译成一个策略包(drbd_access_0.pp),你需要使用以下命令激活它:
semodule -i drbd0_access_0.pp
前面的命令可能需要约一分钟才能完成,所以如果你遇到这种情况也不用担心,正如下面的截图所示,没有输出意味着操作成功:

现在,我们需要将模块复制到node02并在那里安装。这也是我们在第一章中设置节点间基于密钥的认证的原因之一,集群基础与 CentOS 7 上的安装:
scp drbd0_access_0.pp node02:~
然后,在node02上运行以下命令:
semodule -i drbd0_access_0.pp
另外,你也可以在 node01 上执行以下命令:
ssh node02 semodule -i drbd0_access_0.pp
此外,SELinux 的 daemons_enable_cluster_mode 策略应在两个节点上设置为 true:
setsebool -P daemons_enable_cluster_mode 1
然后,如果 pcs status 的输出显示进一步的错误,你可能需要多次重复这个过程。如果你发现需要多次重复,可能需要考虑将 SELinux 设置为 permissive,这样它就会发出警告而不是阻止集群资源。然后,你可以继续进行设置,稍后再进行调试。
我们可以看到两个节点都在线,集群资源已正确启动,如下所示:

现在,让我们暂时休息一下 DRBD,集中安装 Web 和数据库服务器。请注意,我们将在第五章 集群健康监控中重新讨论这个话题,我们将在那里模拟并排除问题。需要注意的是,如果你重新启动了一个节点或两个节点,它们可能会在此时检测到分脑情况,我们将在下一章手动修复这一问题(因为这是 LINBIT 推荐的方法),当时我们会排除集群操作中可能出现的最常见问题。
安装 Web 和数据库服务器
在写这本书时,Apache HTTP 服务器(简称 Apache)仍然是全球使用最广泛的 Web 服务器,通常用于所谓的 LAMP 堆栈中。在这个堆栈中,Linux 发行版作为操作系统,Apache 作为 Web 服务器,MySQL/MariaDB 作为数据库服务器,PHP 作为应用程序的服务器端编程语言。每个组件都是免费的,这些技术被广泛使用,因此学习和获取帮助也非常容易。
要安装 Apache 和 MariaDB(MySQL 的免费开源分支)服务器,请在每个节点上运行以下命令。请注意,这也会安装 PHP:
yum update && yum install httpd mariadb mariadb-server php
安装成功后,我们将继续之前的操作。首先,让我们在两个节点上启用并启动 Web 服务器:
systemctl enable httpd
systemctl start httpd
别忘了确保 Apache 正在运行:
systemctl status httpd
在防火墙中允许通过 TCP 端口 80 的流量:
iptables -I INPUT -p tcp -m state --state NEW -m tcp --dport 80 -j ACCEPT
service iptables save
此时,你可以启动一个 Web 浏览器,并指向节点的独立 IP 地址(记住,我们还没有将 Apache 添加为集群资源,因此不能通过两个节点的虚拟 IP 访问 Web 服务器)。你应该能看到 Apache 的欢迎页面,如下图所示,我们可以看到 Web 服务器在 node02(根据我们的初始设置为 192.168.0.3)上运行正常:

现在,是时候稍微退后一步了。我们将禁用并停止两个节点上的 Apache,这样 PCS 在继续时会管理它:
systemctl disable httpd
systemctl stop httpd
为了让 Apache 在虚拟 IP(我们已将 192.168.0.4 分配为该 IP 地址)和回环地址上监听(稍后我们会解释原因),我们需要修改主配置文件 (/etc/httpd/conf/httpd.conf),如下所示(你可能需要先备份此文件):
# Listen: Allows you to bind Apache to specific IP addresses and/or
# ports, instead of the default. See also the <VirtualHost>
# directive.
#
# Change this to Listen on specific IP addresses as shown below to
# prevent Apache from glomming onto all bound IP addresses.
#
#Listen 12.34.56.78:80
Listen 192.168.0.4:80
Listen 127.0.0.1
然后,重新启动 Apache:
systemctl restart httpd
请注意,当在第二个节点上重启 Web 服务器时,预计会出现错误,因为该套接字上已经有一个服务在运行。然而,这是正常现象,现在,你应该能够通过将浏览器指向虚拟 IP 来访问 Apache 欢迎页面。
有趣的部分是找出虚拟 IP 启动的节点,如下图所示。如果这里出现错误,确保 virtual_ip 首先由 PCS 启动:
pcs status | grep virtual_ip

现在,让我们使用以下命令停止该节点上的集群:
pcs resource show virtual_ip
然后,在另一个节点上,它仍应指示该资源处于活动状态。
然而,即使虚拟 IP 被故障转移到 node02,也无法通过该资源访问 Web 服务器,因为它最初并没有在该节点启动。因此,我们仍然需要将 Apache 配置为集群资源,以便它能作为资源进行管理。
将 Web 服务器配置为集群资源
你会记得在我们在第二章 安装集群服务和配置网络组件中配置虚拟 IP 时,以及在本章早些时候添加复制存储时,我们必须指明一种方式,供 PCS 定期检查资源是否可用。
在这种情况下,我们将使用服务器状态页面(http://node0[1-2]/server-status),这是首选的 Apache 网页,因为它提供了有关服务器性能的信息,PCS 每分钟会查询一次该页面。通过在两个节点的/etc/httpd/conf.d目录下创建一个名为status.conf的文件,可以实现这一功能:
<Location /server-status>
SetHandler server-status
Order deny,allow
Deny from all
Allow from 127.0.0.1
</Location>
然后,使用以下命令,我们将 Apache 添加为集群资源。资源的状态将由 PCS 每分钟检查一次:
pcs resource create webserver ocf:heartbeat:apache configfile=/etc/httpd/conf/httpd.conf statusurl="http://localhost/server-status" op monitor interval=1min
默认情况下,pacemaker 会尝试平衡集群中的资源使用。然而,在某些情况下,我们的设置要求两个相关资源(如 Web 服务器和虚拟 IP)必须在同一主机上运行。
Web 服务器应始终在虚拟 IP 活动的主机上运行。这也意味着,如果虚拟 IP 资源在任何节点上都没有激活,则 Web 服务器根本不应运行。此外,由于我们需要 Web 服务器在虚拟 IP 地址上以及每个主机的回环设备上监听,显然
我们必须确保虚拟 IP 资源在 Web 服务器资源之前启动。
我们可以通过以下约束来实现这两个要求:
pcs constraint colocation add webserver with virtual_ip INFINITY
pcs constraint order virtual_ip then webserver
运行第二个命令后,您应该会在屏幕上看到以下消息。请注意,必须先启动虚拟 IP 资源,然后才能启动 Web 服务器,这是强制性的要求:
Adding virtual_ip webserver (kind: Mandatory) (Options: first-action=start then-action=start)
现在,让我们检查集群的状态,并关注其分配的资源,如下图所示:

现在,您可以通过强制 node01 下线来模拟故障转移。为此,您可以运行以下命令:
pcs cluster stop
资源应该会在 node02 上自动启动,如下图所示:

最后的步骤是将 DRBD 资源挂载到 /var/html/www 目录 上,并在其中添加一个简单的 PHP 页面以显示集群的 PHP 配置。然后,您可以在这个简单示例的基础上构建更复杂的应用程序。
在尝试使用 /dev/drbd0 之前,我们应该通过 drbd-overview 检查它在两个节点上的状态。如果输出显示 StandAlone 或 WFConnection,我们就遇到了脑裂(split-brain)情况,可以通过以下命令的输出确认这一点:
dmesg | grep -i brain
这将导致出现 Split-Brain detected, dropping connection! 错误信息。
Linbit 建议通过选择一个修改将被丢弃的节点来手动解决此类情况,然后在该节点上执行以下命令:
drbdadm secondary [resource name]
drbdadm connect --discard-my-data [resource name]
然后连接另一个节点上的 DRBD 资源:
drbdadm connect [resource name]
您还可以在 node01 上使用以下命令启动或停止 DRBD 并查看概况:
drbdadm up drbd0
drbdadm down drbd0
drbd-overview
ssh node02 drbdadm up drbd0
ssh node02 drbdadm down drbd0
ssh node02 drbd-overview
注意
在选择脑裂情况的恢复方法之前,请仔细审查 DRBD 文档。由于没有适用于所有情况的单一解决方案,因此我选择在本书中介绍推荐的方法。
挂载 DRBD 资源并与 Apache 一起使用
在使用 DRBD 资源之前,必须在其上定义一个文件系统并将其挂载到本地目录。我们将使用 Apache 的文档根目录(/var/www/html),但根据情况,您也可以使用虚拟主机目录。如前所述,我们将逐步在配置文件中添加这些更改,并稍后将其推送到运行中的 CIB(node01 或其他数据中心)。
首先,创建一个名为 fs_dbrd0_cfg 的新配置文件(如果需要,可以更改文件名):
pcs cluster cib fs_drbd0_cfg
接下来,我们将创建文件系统资源本身(如果需要,修改变量值)。这是另一个开箱即用的特殊类型资源:
pcs -f fs_drbd0_cfg resource create web_fs Filesystem device="/dev/drbd0" directory="/var/www/html" fstype="ext4"
这表示文件系统应该始终在主 DRBD 资源上可用:
pcs -f fs_drbd0_cfg constraint colocation add web_fs with web_drbd_clone INFINITY with-rsc-role=Master
请注意,为了确保文件系统能够正确启动,必须首先启动 /dev/drbd0,因此我们需要为此目的添加一个约束条件:
pcs -f fs_drbd0_cfg constraint order promote web_drbd_clone then start web_fs
最后,确保 Apache 需要与文件系统资源在同一节点上运行,且该资源也需要在 Web 服务器资源启动之前上线:
pcs -f fs_drbd0_cfg constraint colocation add webserver with web_fs INFINITY
pcs -f fs_drbd0_cfg constraint order web_fs then webserver
你可以使用以下命令查看配置:
pcs -f fs_drbd0_cfg constraint
输出如下所示的截图:

如果一切正确,使用以下命令将其推送到运行中的 CIB:
pcs cluster cib-push fs_drbd0_cfg
上述命令应在成功完成后显示 CIB 已更新。
如果现在运行pcs status,你应该会看到新添加的资源,正如下面截图所示:

现在,你无需手动挂载/dev/drbd0到/var/www/html,因为集群会自动处理。你可以使用以下命令验证 DRBD 设备是否已经挂载到/var/www/html:
mount | grep drbd0
注意
请记住,在/dev/drbd0挂载时,/var/html/www中任何原有的内容将不可用。
测试 DRBD 资源与 Apache 一起使用
作为一个简单的测试,我们将显示 PHP 安装信息。在node01的/var/www/html中创建一个名为info.php的文件,内容如下:
<?php
phpinfo();
?>
现在,将浏览器指向192.168.0.4/info.php,并验证输出是否与此处显示的类似:

然后,停止node01上的集群(pcs cluster stop)或将其置于待机模式(pcs cluster standby node01),并刷新浏览器。输出中唯一应该变化的是系统名称,如下图所示,因为phinfo() PHP 函数返回的是本地主机名以及 PHP 安装的信息:

此外,如果你列出node02上/var/www/html的内容,你会看到原本在node01上创建的info.php文件现在也出现在node02上,如下图所示:

在继续之前,请记得将node01恢复到正常模式:
pcs cluster unstandby node01
设置具有复制存储的高可用数据库
本章的最后部分重点介绍设置具有复制存储的高可用 MariaDB 数据库。首先,我们需要像之前一样设置另一个 DRBD 资源。为了清晰起见,我们将在此回顾必要的步骤:
-
为每个虚拟机添加另一个虚拟磁盘(2 GB 磁盘即可)。
-
在新添加的磁盘上创建一个分区,然后按照流程在
/dev/``sdc1上创建物理卷(PV)、卷组(VG,命名为drbd_db_vg),最后创建逻辑卷(LV,drbd_db_vol):parted /dev/sdc mklabel msdos parted /dev/sdc mkpart p 0% 100% pvcreate /dev/sdc1 vgcreate drbd_db_vg /dev/sdc1 lvcreate -n drbd_db_vol -l 100%FREE drbd_db_vg -
为新的 DRBD 资源(
drbd1)创建一个配置文件(/etc/drbd.d/drbd1.res),并基于第一个复制存储资源的配置文件,按需编辑设置并使用不同的端口:resource drbd1 { disk /dev/drbd_db_vg/drbd_db_vol; device /dev/drbd1; meta-disk internal; on node01 { address 192.168.0.2:7790; } on node02 { address 192.168.0.3:7790; } }然后,添加一条防火墙规则以允许流量:
iptables -I INPUT -p tcp -m state --state NEW -m tcp --dport 7790 -j ACCEPT service iptables save -
在第二个节点上重复之前的步骤。为新 DRBD 资源初始化元数据:
drbdadm create-md dbrd1 -
启用复制存储资源,以便为其操作分配磁盘和网络资源:
drbdadm up drbd1 -
将 DC 节点上的 DRBD 设备标记为主设备:
drbdadm primary --force drbd1 -
将新的 DRBD 设备添加为集群资源:
mkdir -p /var/lib/mariadb_drbd1/data pcs cluster cib drbd1_conf pcs -f drbd1_conf resource create db_drbd ocf:linbit:drbd drbd_resource=drbd1 op monitor interval=60s pcs -f drbd1_conf resource master db_drbd_clone db_drbd master-max=1 master-node-max=1 clone-max=2 clone-node-max=1 notify=true pcs -f fs_drbd1_cfg resource create db_fs Filesystem device="/dev/drbd1" directory="/var/lib/mariadb_drbd1" fstype="ext4" pcs cluster cib-push drbd1_conf
当此过程完成时,所有已配置的 DRBD 资源概述应如下所示:
[root@node01 ~]# cat /proc/drbd
version: 8.4.6 (api:1/proto:86-101)
GIT-hash: 833d830e0152d1e457fa7856e71e11248ccf3f70 build by phil@Build64R7, 2015-04-10 05:13:52
0: cs:Connected ro:Primary/Secondary ds:UpToDate/UpToDate C r-----
ns:98324 nr:0 dw:32888 dr:66457 al:11 bm:0 lo:0 pe:0 ua:0 ap:0 ep:1 wo:f oos:0
1: cs:Connected ro:Primary/Secondary ds:UpToDate/UpToDate C r-----
ns:2092956 nr:0 dw:33996 dr:2094412 al:0 bm:0 lo:0 pe:0 ua:0 ap:0 ep:1 wo:f oos:0
[root@node01 ~]# drbd-overview
0:drbd0/0 Connected Primary/Secondary UpToDate/UpToDate /var/www/html ext4 2.0G 6.1M 1.9G 1%
1:drbd1/0 Connected Primary/Secondary UpToDate/UpToDate
[root@node01 ~]#
此外,集群现在应包含新的 DRBD 资源及其克隆(分别为db_drbd和db_drbd_clone)以及文件系统资源,正如您在此截图中所看到的:

我们现在可以将 MariaDB 文件分成两个独立的部分:
-
二进制文件、套接字和
.pid文件将放置在常规分区的一个目录中,每个节点独立(默认在/var/lib/mysql)。这些文件不需要具备高可用性或故障安全性。 -
数据库和配置文件(
my.cnf)将存储在一个 DRBD 资源中,该资源将挂载在/var/lib/mariadb_drbd1下的名为 data 的目录中。
接下来,我们需要将数据库服务器作为集群资源添加:
pcs resource create dbserver ocf:heartbeat:mysql config="/var/lib/mariadb_drbd1/my.cnf" datadir="/var/lib/mariadb_drbd1/data" op monitor interval="30s" op start interval="0" timeout="60s" op stop interval="0" timeout="60s"
我们将添加与 Apache 相同的约束:
pcs constraint colocation add dbserver with virtual_ip INFINITY
pcs constraint order virtual_ip then dbserver
pcs constraint colocation add db_drbd_clone with virtual_ip INFINITY
pcs constraint order virtual_ip then db_drbd_clone
接下来,我们将添加防火墙规则以允许流量:
iptables -I INPUT -p tcp -m state --state NEW -m tcp --dport 3306 -j ACCEPT
service iptables save
我们将首先在drbd1上创建一个ext4文件系统,并将其挂载到之前创建的目录中。此步骤仅在数据中心(DC)上执行:
mkfs.ext4 /dev/drbd1
mount /dev/drbd1 /var/lib/mariadb_drbd1
接下来,我们需要将数据库服务器配置文件移动到drbd1的挂载点(在两个节点上执行以下所有步骤):
mv /etc/my.cnf /var/lib/mariadb_drbd1/my.cnf
编辑该文件,确保datadir变量指向 DRBD 资源挂载点内正确的目录,同时指定数据库服务器应监听虚拟 IP 资源的 IP 地址上的 TCP 连接:
datadir=/var/lib/mariadb_drbd1/data
bind-address=192.168.0.4
接下来,我们需要初始化数据库数据目录:
mysql_install_db --no-defaults --datadir=/var/lib/mariadb_drbd1/data
最后,登录到数据库服务器:
mysql –h 192.168.0.4 –u root –p
然后,授予通过定义的密码识别的 root 用户所有权限:
GRANT ALL ON *.* TO 'root'@'%' IDENTIFIED BY 'MyDBpassword';
FLUSH PRIVILEGES;
注意
此权限设置仅用于测试,在将集群迁移到生产环境之前,应根据需要修改以满足安全要求。
或者,我们可以创建一个空数据库:
CREATE DATABASE cluster_db;
最后,确保mysql用户可以访问/var/lib/mariadb_drbd1目录:
chown -R mysql:mysql /var/lib/mariadb_drbd1/
如果我们现在从活动节点切换到被动节点,datadir中的实际数据库文件将通过 DRBD 复制到另一个节点的相同目录中。
故障排除
如前所述,pcs status命令的Failed actions部分将显示集群资源是否存在问题,并提供解决方案的信息。
这是一个示例:
-
exit-reason='Config /var/lib/mariadb_drbd1/my.cnf doesn't exist':确保 MariaDB 的配置文件存在,并且在两个节点上的内容完全一致。 -
exit-reason='Couldn't find device [/dev/drbd1]. Expected /dev/??? to exist':DRBD 设备未正确创建。请检查指示并尝试重新创建该设备。
如您所见,退出原因将为您提供有价值的信息,以帮助排除故障并修复可能遇到的问题。如果在验证了错误信息中列出的条件后,您仍然在处理特定资源时遇到问题,那么清理资源的操作历史并重新检测其当前状态是非常有用的:
pcs resource cleanup [resource name]
来自 Kamran 的真实问题场景,发生在读者按照本章的指示操作时(或者在跟随过程中迷失方向):
[root@node01 ~]# pcs status
Cluster name: MyCluster
Last updated: Tue May 12 17:07:04 2015
Last change: Tue May 12 16:54:03 2015
Stack: corosync
Current DC: node01 (1) - partition with quorum
Version: 1.1.12-a14efad
2 nodes configured
9 resources configured
Online: [ node01 node02 ]
Full list of resources:
virtual_ip (ocf::heartbeat:IPaddr2): Started node02
Master/Slave Set: web_drbd_clone [web_drbd]
Masters: [ node01 ]
Slaves: [ node02 ]
webserver (ocf::heartbeat:apache): Stopped
web_fs (ocf::heartbeat:Filesystem): Started node01
dbserver (ocf::heartbeat:mysql): Stopped
Master/Slave Set: db_drbd_clone [db_drbd]
Masters: [ node02 ]
Stopped: [ node01 ]
db_fs (ocf::heartbeat:Filesystem): Stopped
Failed actions:
dbserver_start_0 on node01 'not installed' (5): call=36, status=complete, exit-reason='Config /var/lib/mariadb_drbd1/my.cnf doesn't exist', last-rc-change='Tue May 12 17:01:09 2015', queued=0ms, exec=66ms
db_fs_start_0 on node01 'not installed' (5): call=41, status=complete, exit-reason='Couldn't find device [/dev/drbd1]. Expected /dev/??? to exist', last-rc-change='Tue May 12 17:01:09 2015', queued=0ms, exec=38ms
dbserver_start_0 on node02 'not installed' (5): call=41, status=complete, exit-reason='Config /var/lib/mariadb_drbd1/my.cnf doesn't exist', last-rc-change='Tue May 12 17:01:09 2015', queued=0ms, exec=91ms
db_fs_start_0 on node02 'not installed' (5): call=32, status=complete, exit-reason='Couldn't find device [/dev/drbd1]. Expected /dev/??? to exist', last-rc-change='Tue May 12 17:01:08 2015', queued=0ms, exec=39ms
PCSD Status:
node01: Online
node02: Online
Daemon Status:
corosync: active/enabled
pacemaker: active/enabled
pcsd: active/enabled
[root@node01 ~]#
总结
本章中,我们解释了如何设置集群的实际应用:一个数据库服务器和一个 Web 服务器。这两个应用都基于一个复制的存储设备,通过提供故障转移存储来增加可用性,用于存储常规文件和数据库文件。
在接下来的两章中,我们将基于这里介绍的概念和资源进行扩展,排查基于集群的 Web 和数据库服务器中的常见问题,并防止常见瓶颈,以确保应用程序的高可用性。
第五章. 监控集群健康状态
在第二章,安装集群服务并配置网络组件中,我们提到,熟悉 PCS 及其众多选项将有助于我们朝着安装一个完全可操作的高可用性集群的目标迈进。尽管在前面的章节中我们已经确认了这一说法的准确性,但在这里,我们将进一步利用 PCS 来监控集群的性能和可用性,以便识别并防止可能的瓶颈,并解决可能出现的任何问题。
集群服务和性能
尽管每个系统管理员必须熟悉广泛使用的 Linux 命令,如top和ps,以便快速报告每个节点中运行的守护进程和其他进程的快照,但您还必须学会依赖 CentOS 7 提供的新工具,来启动我们的节点监控,这些工具我们在之前的章节中已经介绍过。但更重要的是,我们还将使用基于 PCS 的命令来深入了解我们的集群及其资源。
监控节点状态
正如您所猜测的那样,也许您首先需要检查的就是每个节点的状态——它们是在线还是离线。否则,继续进行进一步的可用性和性能分析就没有意义了。
如果您有一个网络管理系统(例如Zabbix或Nagios)服务器,您可以轻松监控集群成员的状态,并在它们无法访问时收到警报。如果没有,您必须想出一个补充解决方案(可能没有那么有效或没有那么防错),用来检测节点何时离线。
一种解决方案是一个简单的 bash 脚本(我们将其命名为pingreport.sh,并将其保存在/root/scripts中,通过chmod +x /root/scripts/pingreport.sh使其可执行),它将定期从另一台主机 ping 您的节点,并通过电子邮件向系统管理员报告,如果其中一个节点处于离线状态,以便您采取适当的措施。以下 shell 脚本正是这样做的,它针对 IP 地址为192.168.0.2和192.168.0.3的节点(您可以在NODES变量中添加更多节点,这些节点将用于以下的 for 循环,但记得用空格分隔它们)。如果两个节点都能 ping 通,则报告将为空,且不会发送任何电子邮件。
为了利用以下脚本,您需要准备好电子邮件解决方案,以便发送警报。在这种情况下,我们使用名为 mailx 的邮件工具,该工具在安装包(yum install mailx)后可用:
#!/bin/bash
# Directory where the ping script is located
DIR=/root/scripts
# Hostname or IP of remote host (to send alerts to)
REMOTEHOST="192.168.0.5"
# Name of report file
PING_REPORT="ping_report.txt"
# Make sure the current file is empty
cat /dev/null > $DIR/$PING_REPORT
#Current date to be used in the ping script
CURRENT_DATE=$(date +'%Y-%m-%d %H:%M')
# Node list
NODES="node01 node02"
# Loop through the list of nodes
for node in $NODES
do
LOST_PACKETS=$(ping -c 4 $node | grep -i unreachable | wc -l)
if [ $LOST_PACKETS -ne "0" ]
then
echo "$"LOST_PACKETS packets were missed while pinging $node at $CURRENT_DATE" >> $DIR/$PING_REPORT
fi
done
# Mail the report unless it's' empty
if [ -s "$"DIR/$PING_REPORT" ]
then
mail root@$REMOTEHOST -s "Ping report" -a $DIR/$PING_REPORT
fi
尽管前面的脚本足以判断一个节点是否可以 ping 通,你可以根据需要调整该脚本,然后将其添加到 cron 中,以便按期望的频率自动运行。例如,以下的 cron 作业将每五分钟执行一次该脚本,无论是哪个日子:
*/5 * * * * /root/scripts/pingreport.sh
如果你想手动运行脚本,可以按以下方式进行:
/root/scripts/pingreport.sh
以下示例表明,在上次运行脚本时,192.168.0.2 和 192.168.0.3 都无法 ping 通。请注意,为了简便起见,脚本从 node01(集群成员)执行;然而,在正常情况下,你会希望使用一个独立的主机来执行该操作:

我们将在本章稍后继续使用该脚本,并扩展其功能。
现在,是时候深入查看 corosync/pacemaker 中配置节点的状态了,使用以下命令:
pcs status nodes pacemaker | corosync | both
在前面的命令中,使用竖线来表示互斥的参数。
在以下截图中,你可以看到pcs status nodes both如何返回两个节点上pacemaker和corosync的状态:

注意
虽然你可以使用pcs status检查集群的整体状态,但正如我们之前提到的,pcs status nodes both会提供更加精细的节点状态信息。你可以停止其中一个(或两个)节点上的服务,然后运行相同的命令来验证。这相当于在每个节点上使用systemctl is-active pacemaker | corosync。
监控资源
正如我们在前面的章节中所解释的,集群资源是通过至少一个节点提供的高可用服务。在我们到目前为止配置的资源中,可以提到虚拟 IP、复制存储设备、Web 服务器和数据库服务器。你可以参考第四章,集群的实际应用,我们在其中添加了约束,指示了集群资源应该如何(按什么顺序)以及在哪个节点上启动。
无论是pcs status还是pcs resource show,都将列出当前所有配置资源的名称和状态。
注意
如果你通过其 ID 指定一个资源(即pcs resource show virtual_ip),你将看到该资源的配置选项。另一方面,如果指定了--full(pcs resource show --full),则会显示所有配置的资源选项。
如果资源在错误的节点上启动(例如,如果它依赖于当前在另一个节点上活动的服务),在尝试使用它时,你会收到一条信息性消息。例如,以下截图显示dbserver在node02上启动,而其相关的底层存储设备(db_fs)已在node01上启动。你会从之前的章节中回忆到,这是pcs status输出的一部分:

因此,如果你尝试使用虚拟 IP 地址登录到数据库服务器(这是集群资源的公共链接),你将得到以下截图中所示的错误消息,告诉你无法连接到 MariaDB 实例:

让我们看看当我们将dbserver资源移动到node01并手动启用它,以便它立即启动时会发生什么(如下一个截图所示)。以下约束旨在使dbserver优先选择node01,这样每当有可用节点时,它始终在node01上运行:
pcs constraint location dbserver prefers node01=INFINITY
pcs resource restart dbserver

提示
如果需要删除约束,可以使用pcs constraint --full查找其 ID,并定位相关资源。然后,使用pcs constraint remove constraint_id删除它,其中constraint_id是第一个命令返回的标识符。你也可以使用pcs resource move <resource_id> <node_name>手动将资源从一个节点移到另一个节点,但请注意,当前的约束可能会允许或不允许你成功完成此操作。
现在我们可以按预期访问数据库服务器资源,如下所示:

偶尔,在故障转移过程或启动过程中,你可能会遇到一些错误——你可以自己判断。这些消息会出现在pcs status的输出中,如下文摘所示:

在我们继续之前,也许你会问自己:如果我想保存关于集群问题的所有可用信息,以便进行离线分析和故障排除该怎么办?如果你期待 PCS 提供一个工具来帮助你,你是对的。在--from和--to选项后输入日期和时间,并将dest替换为文件名(在以下命令中也提供了具体示例):
pcs cluster report [--from "YYYY-M-D H:M:S" [--to "YYYY-M-D" H:M:S"]]" dest
这将创建一个包含报告集群问题所需的所有信息的 tar 包。如果没有使用--from和--to选项,则报告将包括过去 24 小时的数据。
在接下来的截图中,我们省略了--from和--to标志以简洁起见,我们还可以看到设置通过ssh进行基于密钥的认证在第一章中并非仅仅是一个建议——您必须报告来自两个节点的集群信息。
在我们的例子中,我们将执行以下命令,在当前工作目录中获取一个名为YYYY-MM-DD-report.tar.gz的 tar 包。请注意,文件名中的日期部分仅用于标识:
pcs cluster report $(date +%Y-%m-%d)-report

一旦包含报告文件的 tar 包创建完成,您可以解压并检查它。您会注意到它包含了以下图像中看到的文件和目录。在进一步操作之前,您可能希望查看其中的一些文件,如下所示:
tar xzf $(date +%Y-%m-%d)-report.tar.gz
cd $(date +%Y-%m-%d)-report

当然,您现在可能想清除过去已解决的失败操作记录。为此,PCS 允许您指示集群忘记资源(或所有资源)的操作历史,重置故障计数,并重新检测当前状态:
pcs resource cleanup <resource_id>
请注意,如果未指定resource_id,则所有资源/STONITH 设备将被清理。
最后,在我们还在讨论监控集群资源时,不妨问自己:是否有一种方法可以备份当前的集群配置文件,并在需要时恢复它们,是否可以轻松回到之前的配置?这两个问题的答案是肯定的——让我们看看怎么做。
为了备份集群配置文件,您将使用以下命令:
pcs config backup <filename>
在这里,<filename>是您选择的文件标识,PCS 会在创建 tar 包后为其追加tar.bz2扩展名。
请考虑以下示例:
pcs config backup cluster_config_$(date +%Y-%m-%d)
这将导致创建一个 tar 包备份,内容如以下截图所示。为了方便起见,我们将在当前工作目录中创建一个名为cluster_config的子目录。我们将使用这个新创建的子目录来解压报告 tar 包的内容:
mkdir cluster_config
tar xzf cluster_config_$(date +%Y-%m-%d).tar.bz2 -C cluster_config
ls -R cluster_config

注意
如果您按照本书中概述的步骤逐步进行安装,bzip2 可能未安装。您需要使用yum update && yum install bzip2来安装它,以便解压集群配置 tar 包。
恢复配置同样简单(您需要停止节点并在恢复过程完成后重新启动它),请使用以下命令:
pcs config restore [--local] <filename>
此命令将使用备份文件作为源,在所有节点上恢复集群配置文件。如果只需要恢复当前节点的文件,请使用--local flag。请注意,文件名必须是.tar.bz2文件(而不是解压后的文件)。
你还可以通过 pcs config checkpoint 及其相关选项,回到集群配置的某个时间点。如果不加任何选项,pcs config checkpoint 会列出所有可用的配置检查点,如下所示:

pcs config checkpoint view <checkpoint_number> 命令将指定的配置检查点详细信息显示到标准输出中,如下图所示。请参考以下示例:
pcs config checkpoint view 1

pcs config checkpoint restore <checkpoint_number> 命令将集群配置恢复到指定的检查点,这也是在恢复之前检查所需检查点详细信息的一个好主意。
当资源拒绝启动
在正常情况下,集群资源将自动管理,系统管理员不需要太多干预。然而,有时可能会出现某些问题,导致资源无法正常启动,这时就需要采取即时的行动。
如 PCS 手册页所述,
在集群上启动资源几乎总是由 pacemaker 完成,而不是直接由 PCS 执行。如果你的资源没有启动,通常是由于资源配置错误(你可以通过系统日志进行调试)、约束条件阻止资源启动或资源被禁用。你可以使用
pcs resource debug-start测试资源配置,但通常不应使用它来启动集群中的资源。
话虽如此,当 pacemaker 因某些原因无法正常启动资源时,可以执行以下命令:
pcs resource debug-start <resource id> [--full]
这将强制在当前节点上启动指定的资源,忽略集群的推荐配置。结果将显示在屏幕上(使用 --full 参数可以获取更详细的输出),并提供有助于排除资源和集群操作故障的相关信息。
在以下截图中,pcs resource debug-start virtual_ip --full 的输出已被截断,以简化显示:

从这个示例中,你可以开始领略到这个命令的实用性,因为它会逐步为你提供关于资源操作的非常详细的信息。例如,如果 dbserver 资源即使在反复清理后仍然无法启动并返回错误,可以运行以下命令:
pcs resource debug-start dbserver --full | less
通过此命令,你将能够非常详细地查看集群通常在尝试启动此类资源时执行的步骤。如果该过程在某个环节失败,你将获得关于出错原因和时间的描述,帮助你更好地修复问题。
检查核心组件的可用性
在结束之前,让我们回到第一个示例(检查每个节点的在线状态),并对其进行扩展,以便我们还能够监控集群框架的核心组件,即pacemaker、corosync和pcsd,这些内容在第二章,安装集群服务和配置网络组件中已有概述。
提示
为确保通过ssh从一个节点成功连接到自身,您需要将其密钥复制到authorized_keys中。因此,要为用户 root 启用无密码登录,请在两个节点上运行以下命令:
cp /root/.ssh/id_rsa.pub /root/.ssh/authorized_keys
在最佳情况下,在优雅的故障转移期间,您希望在其中一个(或多个)服务停止时收到通知。通过在脚本中添加几行代码,还可以检查相应守护进程的状态,并在它们停止时发出警报:
#!/bin/bash
# Directory where the ping script is located
DIR=/root/scripts
# Hostname or IP of remote host (to send alerts to)
REMOTEHOST="192.168.0.5"
# Name of report file
PING_REPORT="ping_report.txt"
# Make sure the current file is empty
cat /dev/null > $DIR/$PING_REPORT
#Current date to be used in the ping script
CURRENT_DATE=$(date +'%Y-%m-%d %H:%M')
# Node list
NODES="node01 node02"
# Outer loop: check each node
for node in $NODES
do
LOST_PACKETS=$(ping -c 4 $node | grep -i unreachable | wc -l)
if [ $LOST_PACKETS -ne "0" ]
then
echo "$"LOST_PACKETS packets were missed while pinging $node at $CURRENT_DATE" >> $DIR/$PING_REPORT
fi
# Inner loop: check all cluster core components in each node
for service in corosync pacemaker pcsd
do
IS_ACTIVE=$(ssh -qn $node systemctl is-active $service)
if [ $IS_ACTIVE != "active" ]
then
echo "$"service is NOT active on $node. Please check ASAP." >> $DIR/$PING_REPORT
fi
done
done
# Mail the report unless it's' empty
if [ -s "$"DIR/$PING_REPORT" ]
then
mail -s "Ping report" root@localhost < $DIR/$PING_REPORT
fi
作为一个简单的测试,请在node02(192.168.0.3)上停止集群(pcs cluster stop),从监控主机或任何节点运行脚本,并检查您的邮件收件箱,以验证它是否正常工作。在以下截图中,您可以看到其应该呈现的样子:

总结
本章中,我们已经解释了如何监控、故障排除和修复常见的集群问题和需求。并非所有问题都会像突然的系统崩溃那样是不期而至或不希望出现的。有时,您需要关闭集群及其运行的资源,以便进行计划维护,或者在断电时,确保不间断电源(UPS)还没有耗尽。
由于预防是此类情况下最好的盟友,请确保定期监控集群的健康状况。按照本章中概述的程序进行操作,以确保在真实的紧急情况出现时不会遇到任何意外。具体来说,无论是在真实还是模拟的情况下,都必须备份集群配置,分别停止两个节点上的集群,然后才能停用节点。
第六章。衡量与提升性能
到目前为止,我们已经创建了一个主动/被动集群,向其添加了几个资源并测试了其故障转移功能。我们还讨论了如何排查常见问题。我们旅程的最后一步是衡量和提高集群的性能,直到目前为止它的安装情况——就其上运行的服务而言。
此外,我们还将提供将 A/P 集群转换为 A/A 集群的整体指南。
设置示例数据库
为了正确测试我们的 MariaDB 数据库服务器,我们需要一个填充了示例数据的数据库。因此,我们将使用 Employees 数据库,由 Patrick Crews 和 Giuseppe Maxia 开发,并由 Oracle 公司根据创意共享署名-相同方式共享 3.0 国际许可协议提供。它提供了一个非常大的数据集(约 160 MB 和约 400 万条记录),分布在六个表中,非常适合我们的性能测试。
注意
创意共享署名-相同方式共享 3.0 国际许可协议,详情请见creativecommons.org/licenses/by-sa/3.0/,它赋予我们以下自由,关于 Employees 数据库:
分享:这使我们能够在任何介质或格式中复制和再分发该素材
改编:这使我们能够混合、转化并基于该素材进行创作
用于任何目的,包括商业用途。
只要你遵循许可证条款,许可方不能撤销这些自由。
下载并安装 Employees 数据库
让我们继续通过以下步骤下载并安装数据库:
-
要下载 Employees 表,请访问
launchpad.net/test-db/并获取最新稳定版本的 tarball 链接(在写这本书时,版本是 v1.0.6),如下图所示:![下载并安装 Employees 数据库]()
-
然后,将其下载到运行数据库服务器的节点(在我们的案例中,是
node01)。为此,首先需要使用以下命令安装名为wget和bzip2的两个软件包:yum –y install wget bzip2 && wget https://launchpad.net/test-db/employees-db-1/1.0.6/+download/employees_db-full-1.0.6.tar.bz2然后,在当前工作目录中提取/解压其内容:
tar xjf employees_db-full-1.0.6.tar.bz2 -
这将创建一个名为
employees_db的子目录,其中包含主安装脚本(employees.sql),如以下两个命令的输出所示:cd employees_db ls -
接下来,使用以下命令连接到我们在第四章中设置和配置的集群数据库服务器,集群的实际应用(注意,你将被提示输入 root MariaDB 用户的密码):
mysql -h 192.168.0.4 -u root -p -t < employees.sql -
这还将安装 employees 数据库并将相应的信息加载到其表中:
-
departments -
employees -
dept_emp -
dept_manager -
titles -
salaries
注意
在设置好示例数据库后,随时进行强制故障转移,验证资源和数据库(以及它们的表和记录)是否能在当前被动节点中变得可用。如果需要,回顾第四章以回顾相关指令。
由于大量数据正在加载到数据库中,预计安装过程可能需要一两分钟的时间才能完成。我们在此期间会看到导入过程的进展:数据库结构和存储引擎被实例化,然后创建表,最后填充数据,如下所示:
![下载并安装员工数据库]()
-
-
我们可以通过登录到数据库服务器并执行这些命令来验证,首先列出所有数据库。然后,切换到最近安装的员工数据库,并用它进行后续查询:
SHOW DATABASES; USE employees; SHOW TABLES; -
输出应该类似于前面截图所示的内容。
![下载并安装员工数据库]()
-
在我们继续进行实际性能测试(在故障转移事件前后测量整体性能)之前,可以使用
DESCRIBE语句来调查那些表(以及它们包含的字段)。然后,使用SELECT语句浏览记录,如下所示:DESCRIBE salaries; SELECT * FROM salaries LIMIT 5; -
结果可以在以下截图中看到:
![下载并安装员工数据库]()
一旦你花时间熟悉了数据库的结构,我们就准备好继续进行测试了。
引入初始集群测试
此外,对于实际的性能测试,你应该注意,MariaDB 附带了几个与数据库相关的工具,这些工具可以帮助你完成各种管理任务。其中之一是mysqlshow,它可以通过一个快速命令返回关于数据库和表的完整信息。
它的通用语法如下:
mysqlshow [options] [db_name [tbl_name [col_name]]]
所以,我们可以使用以下命令来显示employees数据库中titles表的描述:
mysqlshow employees titles -h 192.168.0.4 -u root -p
注意
你可以使用ls /bin | grep mysql命令列出包含在 MariaDB 安装中的完整工具集。每个工具都有相应的手册页面,可以像平常一样从命令行调用。
我们将使用 MariaDB 附带的另一个工具,看看在显著负载下我们的数据库服务器表现如何。该工具是mysqlslap,这是一个诊断程序,旨在模拟 MariaDB/MySQL 服务器的客户端负载,并报告每个阶段的时间。它的工作方式就像多个客户端同时访问服务器一样。
在执行我们将在后续测试中使用的实际命令之前,我们将介绍mysqlslap的几个可用标志:
-
--create-schema:此命令指定我们将在其中运行测试的数据库 -
--query:这是一个字符串(或者说是一个文件),其中包含用于检索数据的SELECT语句 -
--delimiter:此命令允许你指定一个分隔符,用来分隔--query中同一字符串中的多个查询 -
--concurrency:此命令表示模拟的并发连接数 -
--iterations:这是运行测试的次数 -
--number-of-queries:此命令限制每个客户端(参见--concurrency)的查询数量
此外,mysqlslap手册页中列出了其他你可以使用的开关,如果你愿意的话。
也就是说,我们将在集群中的数据库服务器上运行以下测试。
测试 1 – 检索所有记录的所有字段
在第一个测试中,我们将执行一个相当简单的查询,内容是从员工表中检索所有记录的所有字段。我们将模拟10个并发连接,总共进行50次查询。这将导致每个客户端运行5次查询(50/10 = 5):
mysqlslap --create-schema=employees --query="SELECT * FROM employees" --concurrency=10 --iterations=2 --number-of-queries=50 -h 192.168.0.4 -u root -p
几分钟后,你将能够看到类似以下截图中的输出。虽然这里列出了一个独立测试的结果,但你可能希望自己多次执行此操作并记录结果以供后续对比。然而,如果你选择这样做,请确保查询结果没有被缓存,在每次运行后,运行以下命令清除 MariaDB 服务器会话中的缓存:
RESET QUERY CACHE;

测试 2 – 执行 JOIN 操作
在这个第二个测试中,我们将执行一个JOIN操作,将员工表和薪资表进行连接(一个更现实的例子),并稍微调整连接数、查询数和迭代次数:
mysqlslap --create-schema=employees --query="SELECT A.first_name, A.last_name, B.salary FROM employees A JOIN salaries B on A.emp_no = B.emp_no" --concurrency=3 --number-of-queries=12 --iterations=2 -h 192.168.0.4 -u root -p
在以下截图中,我们可以看到这次运行查询所花费的时间有所增加,这是预期中的结果:

在继续之前,可以随意调整连接数、迭代次数和查询,或者修改查询本身。根据这些值,你可能会使数据库服务器崩溃。这在某些时候是可以预期的,因为我们构建基础设施和示例时使用的是基于虚拟机的集群。因此,你可能希望在每个节点的 VirtualBox 配置中增加处理资源,尽可能利用可用容量,或者考虑购买真实硬件来搭建集群。
注意
数据库管理和优化是本书范围之外的话题。强烈建议在将集群迁移到生产环境之前,您也要考虑这些主题。由于数据库和 Web 服务器的性能可以通过各自的设置单独优化,在本书中,我们将重点分析并改进这些资源(分别命名为dbserver和webserver)的可用性,使用它们各自的配置文件和内部设置。
执行故障切换
我们现在通过停止当前所有资源运行所在节点(node01)上的集群功能来强制进行故障切换,这样资源将转移到node02。在这里,我们将执行测试 1 和测试 2,预计会看到与之前相似的行为。需要牢记的是,在故障切换期间,数据不会自动加密。如果您担心敏感数据在不安全的连接上传输,您应采取必要的预防措施,使用加密措施,无论是在文件系统级别还是在逻辑卷级别。然而,在我们进行此操作之前,必须牢记,频繁将敏感资源(例如数据库服务器)在集群中移动可能会对该资源的可用性产生负面影响。因此,我们希望它保持在当前活动的节点上,除非发生实际的节点停机。资源粘性正是实现这一目标:它允许我们指示所有集群资源,在节点恢复可用后,要么恢复到其原始节点,要么保持在当前活动的节点上。以下语法用于指定所有资源的默认值:
pcs resource defaults resource-stickiness=value
值越高,资源越倾向于保持当前所在的位置。默认情况下,Pacemaker 使用0作为值,这意味着在发生故障切换时,集群希望(并且认为最优)将资源迁移到其他位置。要为特定资源指定粘性,请使用以下语法设置该资源的粘性:
pcs resource meta <resource_id> stickiness=value
假设您在前面的命令中使用INFINITY作为值:
pcs resource defaults resource-stickiness=INFINITY
pcs resource meta <resource_id> stickiness=INFINITY
(其中,resource_id需要替换为实际的资源标识符)
然后,所有资源的默认粘性和由resource_id标识的资源的粘性将设置为INFINITY。话虽如此,现在我们开始执行故障切换。请使用以下命令记录当前节点和资源状态:
pcs status
然后,通过以下命令停止集群:
pcs cluster stop
然后,验证所有资源是否在另一个节点上正确启动。如果没有,使用第五章中解释的工具进行故障排除,监控集群健康。最后,继续在node02上运行测试 1 和测试 2。
当前情况下的结果在此解释。
对于测试 1,请参考以下截图:

总结测试 1 在两个节点上的结果
为了方便比较,我们将两个结果汇总如下:
| 测试 1 [秒] | Node01 | Node02 |
|---|---|---|
| 平均值,所有查询 | 20.770 | 20.179 |
| 最小值,所有查询 | 20.242 | 19.930 |
| 最大值,所有查询 | 21.298 | 20.428 |
另一方面,对于测试 2,以下截图和下一张表格展示了详细信息:

总结测试 2 在两个节点上的结果
| 测试 2 [秒] | Node01 | Node02 |
|---|---|---|
| 平均值,所有查询 | 40.008 | 39.084 |
| 最小值,所有查询 | 38.713 | 38.779 |
| 最大值,所有查询 | 41.304 | 39.389 |
正如您所看到的,两种情况下的结果非常相似,这证明了故障转移并未影响我们集群上运行的数据库服务器的性能。虽然故障转移确实没有提高性能,但我们可以看到,资源在故障转移期间的可用性已经得到确认,并且对集群的功能有一定的负面影响。
测量和提高性能
您可能还记得,在之前的章节中,按照定义,资源是由集群使其高度可用的服务。每个资源都会被分配一个叫做 资源代理 的外部 Shell 脚本,负责独立于系统管理的方式(如 systemd)管理集群中的实际资源。因此,资源的实际操作对集群来说是透明的,因为它是由资源代理来管理的。
资源代理位于 /usr/lib/ocf/resource.d 目录下,您可以随意查看它们,以便更好地了解它们的结构。在大多数情况下,您无需修改它们,而是需要修改特定资源的配置文件,正如我们接下来将看到的那样。您可能还记得,在之前的章节中,添加集群资源涉及使用 standard:provider:resource_agent 形式的参数(例如 ocf:heartbeat:mysql)。您还可以通过分别使用 pcs resource standards 和 pcs resource providers 查看完整的资源标准和提供者列表。此外,您可以通过 pcs resource agents standard:provider 查看每个 standard:provider 配对的可用代理。
Apache 的配置和设置
当 Apache web 服务器首次安装时,默认情况下,它会附带几个模块,形式为 动态共享对象 (DSO),用于扩展其功能。缺点是,如果这些模块持续加载,而您的应用程序并没有使用它们,它们可能会不必要地消耗资源。正如您可能猜到的,这可能会随着时间的推移导致性能损失。
在 CentOS 7 中,您可以通过 httpd -M 查看当前加载和共享的模块列表。以下输出由于简洁起见已被截断,但在您的情况下应该非常相似:
Loaded Modules:
core_module (static)
so_module (static)
http_module (static)
access_compat_module (shared)
actions_module (shared)
alias_module (shared)
allowmethods_module (shared)
auth_basic_module (shared)
auth_digest_module (shared)
authn_anon_module (shared)
authn_core_module (shared)
仔细检查模块列表,并充分了解您的应用程序实际需要哪些模块,这将帮助您定义哪些模块不需要,因此可以暂时卸载它们。
查看 /etc/httpd/conf/httpd.conf 中的以下行:
IncludeOptional conf.modules.d/*.conf
这一行表示 Apache 将在 conf.modules.d 目录中查找加载 .conf 文件内模块的指令。例如,在标准安装中,00-base.conf 包含约 70 个 LoadModule 指令,指向 /etc/httpd/modules 内的 DSO。在这些 .conf 文件中,您可以启用或禁用 Apache 模块(通过在每个 LoadModule 指令前添加 # 符号,从而注释掉该行)。请注意,这必须在两个节点上执行。
加载和禁用模块
在下图中,已加载 userdir_module 模块、version_module 和 vhost_alias_module,而 buffer_module、watchdog_module 和 heartbeat_module 通过 00-base.conf 被禁用:

例如,要禁用 userdir 模块,请在两个节点的 /etc/httpd/conf.modules.d/00-base.conf 中注释掉对应的 LoadModule 指令:
#LoadModule userdir_module modules/mod_userdir.so
在当前节点上重启集群资源:
pcs resource restart webserver
限制 Apache 进程和子进程的数量
为了使 Apache 能够处理所需的并发请求数量,同时防止其占用超过您为应用程序所能承受的 RAM,您需要将 MaxRequestWorkers(在 2.3.13 版本之前称为 MaxClients)指令设置为一个适当的值,主要依据您的特定环境中可分配的物理内存。请注意,如果此值设置得过高,可能会导致 Web 服务器(以及资源本身)崩溃。
另一方面,设置一个适当的值,该值是基于每个 Apache 进程的内存使用情况与分配的 RAM 相比计算出来的,将使 Web 服务器能够同时响应如此多的请求。如果请求数量超过服务器的处理能力,多余的请求将在先前的请求处理完毕后才会被处理,从而避免所有连接的资源挂起。
有关更多详情,请参阅 Apache MPM 常用指令文档:httpd.apache.org/docs/2.4/mod/mpm_common.html。请记住,Apache 的精细调优超出了本书的范围,文中提到的操作通常不足以用于生产环境。
数据库资源
由于你很少会使用没有附带数据库服务器的 Web 服务器,因此你也需要关注那一侧的性能优化。以下是一些你可能需要关注的基本事项。
创建索引
一个包含数十万或百万条记录的数据库,在执行典型的 SELECT-FROM-WHERE 语句以检索特定记录时,可能迅速成为性能瓶颈。为了实现这一点,必须逐行检查表中的每一行,这在硬盘级别上执行时被认为是非常低效的。
使用索引时,操作会在内存中执行而不是在磁盘上,且记录可以自动排序,这样查找我们想要的记录会更快,因为索引仅包含实际排序的数据和指向原始数据记录的链接。此外,我们可以为每个需要排序的列创建索引,因此使用索引成为提高性能的便捷工具。
首先,退出 MariaDB 会话并运行测试 3,以衡量没有索引时的性能:
mysqlslap --create-schema=employees --query="SELECT * FROM employees WHERE emp_no=1007" --concurrency=15 --number-of-queries=150 --iterations=10 -h 192.168.0.4 -u root -p
现在,让我们在 employees 和 salaries 表的 emp_no 字段上创建索引,因为我们将在 WHERE 子句中使用它们,然后再次执行测试 3。执行以下步骤:
-
首先,使用以下命令登录到数据库服务器:
mysql -h 192.168.0.4 -u root -p -
然后,从 MariaDB shell 中执行以下命令:
USE employees; RESET QUERY CACHE; CREATE INDEX employees_emp_no ON employees(emp_no); CREATE INDEX salaries_emp_no ON salaries(emp_no); -
之后,退出 MariaDB shell 并再次运行测试以比较性能。结果显示在以下截图中,并在下一个表格中与之前的示例(没有索引)进行了汇总:
![创建索引]()
现在,让我们来看一下相同测试的结果,不过这次使用了索引:

总结 node01 上有索引和没有索引的测试 2 结果
| 测试 3(秒) | Node01(没有索引) | Node01(有索引) |
|---|---|---|
| 平均值,所有查询 | 0.043 | 0.038 |
| 最小值,所有查询 | 0.035 | 0.037 |
| 最大值,所有查询 | 0.055 | 0.046 |
上面的截图演示了在可搜索字段上创建索引将提高性能,因为它可以防止服务器在返回结果之前必须遍历所有行。
使用查询缓存
在 MariaDB 数据库服务器中,SELECT 查询的结果存储在查询缓存中,这样当相同的操作再次执行时,结果可以更快地返回。现代大多数网站正是如此,重复进行相似的查询(高读低写环境)。
那么,这在服务器级别是如何发生的呢?如果一个传入的查询在缓存中找不到,它将按正常方式处理,然后将其结果集存储在查询缓存中。否则,结果将从缓存中提取,这使得操作比正常处理时完成得要快得多。
在 MariaDB 中,默认启用查询缓存(SHOW VARIABLES LIKE 'query'_cache_type';),但其大小设置为零(SHOW VARIABLES LIKE 'query'_cache_size';),如以下截图所示:

出于这个原因,我们需要根据应用程序的使用情况设置查询缓存大小变量为一个合适的值。在下面的截图中,这个变量设置为 100 KB(SET GLOBAL query_cache_size = 102400;),我们可以看到查询缓存大小已经相应更新:

请注意,查询缓存大小的正确值在很大程度上(如果不是完全)取决于您具体案例的需求。将其设置得过高会导致性能下降,因为系统必须分配额外的资源来管理一个较大的缓存。另一方面,设置得过低会导致至少一些重复查询正常处理而不被缓存。在前面的示例中,我们将 100 KB 的数据分配为缓存,以存储查询及其对应的结果。
如需更多详细信息,请参考 MariaDB 文档(mariadb.com),特别是管理 MariaDB/优化与调优部分。
注意
MariaDB 文档包含非常有用的信息,帮助从头开始调优数据库服务器(从操作系统级别到查询优化)。其他可以提高性能和稳定性的工具包括 MySQL 调优器(mysqltuner.com/)、MySQL 调优指南(launchpad.net/mysql-tuning-primer)以及 phpMyAdmin 顾问(www.phpmyadmin.net/)。最后一个工具可以在标准 phpMyAdmin 安装的状态标签页中找到。
转向 A/A 集群
正如您从第三章的介绍中记得的那样,深入了解高可用性,A/A 集群倾向于提供更高的可用性,因为多个节点同时运行应用程序(顺便说一下,这要求所有集群成员上同时可用这些应用程序所需的数据)。其缺点是,如果一个或多个节点下线,剩余的节点将被分配额外的处理负载,从而对集群的整体性能产生负面影响。
话虽如此,让我们简要地看一下将当前的 A/P 集群转换为 A/A 集群所需的步骤。确保已定义 STONITH 资源(有关更多详细信息,请参考第三章)。
-
使用以下命令启用 STONITH 资源:
pcs property set stonith-enabled=trueInstall -
安装将需要的额外软件:
yum update && yum install gfs2-utils dlm与传统的日志文件系统如
ext4(我们在本书中到目前为止使用的文件系统)不同,你将需要一种方式来确保所有节点能够同时访问相同的块存储。全局文件系统 2(也称为GFS2)通过其命令行工具提供了这一功能,这些工具包含在gfs2-utils包中。 -
此外,
dlm包将安装分布式锁管理器(也称为DLM),这是集群文件系统中同步访问共享资源的要求。将(并克隆)分布式锁管理器作为ocf类的集群资源,pacemaker 提供程序和controld类:pcs cluster cib dlm_cfg pcs -f dlm_cfg resource create dlm ocf:pacemaker:controld op monitor interval=60s pcs -f dlm_cfg resource clone dlm clone-max=2 clone-node-max=1 -
现在,将新创建的资源推送到 CIB:
pcs cluster cib-push dlm_cfg -
选择一个复制存储资源,并在其关联的设备节点上创建
gfs2文件系统。例如,我们可以使用在第四章,集群的实际实现中创建的
/dev/drbd0设备。在我们能够在该设备上创建gfs2文件系统之前,需要先将其从具有 DRBD 主角色的节点(最可能是node01)卸载:umount /dev/drbd0 mkfs.gfs2 -p lock_dlm -j 2 -t MyCluster:Web /dev/drbd0如下图所示,
MyCluster是我们集群的原始名称,Web是一个随机名称,-j标志表示文件系统将使用两个日志(在这种情况下,每个节点一个——如果你的集群包含更多节点,您将需要更改此数字)。最后,-p选项告诉我们,我们将使用由内核提供的 DLM:![移动到 A/A 集群]()
你还需要将
web_fs资源的fstype选项从ext4(我们在第四章,集群的实际实现中首次创建时使用的原始文件系统)更改为gfs2,并在 PCS 资源配置中进行相应更改:pcs resource update web_fs fstype=gfs2需要注意的是,如果集群在
dlm-clone之前尝试启动web_fs,我们将遇到问题(如果没有dlm功能,就无法挂载gfs2文件系统)。因此,我们需要添加同居和排序约束,以确保web_fs总是在dlm-clone启动的节点上启动:pcs constraint colocation add web_fs with dlm-clone INFINITYanddlm-clone将在web_fs之前启动。 -
pcs constraint顺序dlm-clone然后web_fsClone虚拟 IP 地址资源。克隆 IP 地址将使我们能够有效地在两个节点上使用资源,但与此同时,任何给定的数据包将只会发送到一个节点(从而在集群中实现基本的负载均衡方法):
为此,我们将把集群配置保存到一个名为
load_balancing_cfg的文件中,并使用以下命令更新该文件:pcs cluster cib load_balancing_cfg从 pcs resource 帮助中你会注意到,克隆操作允许你指定某些选项。在接下来的几行中,
clone-max指定了承载virtual_ip资源的节点数量(在本例中为 2),而clone-node-max指定了每个节点允许运行的资源实例数量。接下来,globally-unique指示资源代理每个节点与其他节点不同,因此也处理不同的流量。最后,clusterip_hash=sourceip告诉我们,将使用数据包的源 IP 地址来决定哪个节点处理哪个请求:pcs -f load_balancing_cfg resource clone virtual_ip clone-max=2 clone-node-max=2 globally-unique=true pcs -f load_balancing_cfg resource update virtual_ip clusterip_hash=sourceip下一步是克隆文件系统和 Apache 和/或 MariaDB 资源。请注意,为了允许 DRBD 设备中的两个主节点同时提供内容,你需要在资源配置文件的网络部分中将
allow-two-primaries指令设置为 yes(例如,allow-two-primaries yes;),配置文件路径为/etc/drbd.d/drbd0.res:resource drbd0 net { protocol C; allow-two-primaries yes; } ... } -
再次保存当前的 CIB 到本地文件,并添加克隆资源信息。在下一个示例中,我们将使用
web_fs、web_drbd_clone和webserver:pcs cluster cib current_cfg pcs -f current_cfg resource clone web_fs pcs -f current_cfg resource clone webserver -
现在,
web_drbd应该被允许作为主节点或主节点提供两个实例:pcs -f current_cfg resource update web_drbd_clone master-max=2 -
然后,激活新的配置:
pcs cluster cib-push current_cfg -
最后但同样重要的是,你需要记住,你需要将资源粘性值设置为
0,以便在故障转移后将实例返回其原始节点。为此,请参考本章的 执行故障转移 部分。
现在,你可以像往常一样强制进行故障转移并测试资源的可用性。不幸的是,正如我之前所解释的那样,在 Virtualbox 环境中这是不可能的。然而,如果你能够使用真实硬件和实际的 STONITH 设备构建集群,那么完全是可行的。
总结
在本章的最后,我们为需要在集群中实现高可用性的示例服务设置了一些性能测试工具,并提供了一些建议来分别优化它们的性能。请注意,这些建议并不旨在代表一份详尽的调优方法清单,而只是一个起点。我们还提供了整体的指导,以便你可以将一个 A/P 集群转变为 A/A 集群。
最后,请记住,本书是使用虚拟机而非专用硬件编写的。因此,我们遇到了一些相关的限制,例如缺少真实的 STONITH 设备,否则我们本可以实际演示 A/A 集群的功能。然而,本书中概述的原则无疑将成为你自己搭建集群的指南,无论你是使用虚拟机进行实验还是使用真实硬件。
祝你在努力中取得成功!














浙公网安备 33010602011771号