第十章:网络磁盘故障转移

通过网络运行磁盘和文件系统提供了有趣的可能性。最明显的是,即使支持数据存储的主机发生故障,也能保持数据存储的运行。FreeBSD包括一些工具,可以让备份主机在主主机发生故障时接管,使用每个数据中心中的标准硬件。

首次尝试网络磁盘故障切换时,请使用测试环境。准备重新启动。

任何类型的故障转移自动化都要求你熟悉基本的shell脚本。

集群风险

任何商品硬件上的双节点集群解决方案都有可能出现某种形式的分裂大脑。

HAST可能会发出字面上的”split brain“错误,但当多个主机挂载相同的UFS文件系统或导入相同的ZFS池时,iSCSI支持的高可用性可能会出现同样的问题。

一个不稳定的网络交换机不仅会中断客户端连接,还会让每个服务器相信它的对等端已经崩溃,它自己应该成为主服务器。仅仅拔掉网线就会引发此错误。操作双节点集群的某些阶段确实需要高度智能的管理。

高级集群系统通常至少有三台主机参与集群,因此它们可以使用法定人数(quorum)方法来确定主机。在法定人数制度中,大多数参与的主机必须就哪个主机担任主主机(master)达成一致。一个孤立的主机不能宣告自己为独裁者。这些系统本身就是一本书,对硬件的要求也更高。

仔细看看你的硬件,并研究FreeBSD对它的支持。有些硬件有解决这些问题的方法。例如,如果你拥有共享SCSI机框,你可以在故障转移脚本中通过camcontrol使用SPC-3 SCSI持久保留。如果你的iSCSI设备后面又多路径SCSI,请按照ctl中的讨论,通过非对称逻辑单元访问(Asymmetric Logical Unit Access——ALUA)研究FreeBSD的高可用性支持。

本书提出的任何具体硬件建议都可能是过时的,建议对你自己的硬件研究。

考虑到软件的局限性和商品硬件,这里描述的系统尽可能安全。如果你决定构建一个双主机集群,请做好在最坏的情况下发生时进行恢复的准备。

许多人成功地将CARP用于文件系统故障转移。他们长期以来一直在努力思考如何从问题中恢复过来。

故障转移体系结构

故障转移自动化建立在CARP和devd这两项关键技术之上。它们的使用方式取决于所使用的存储后端。

CARP

通用地址冗余协议(Common Address Redundancy Protocol——CARP)是OpenBSD为在机器之间共享IP地址而创建的。

它允许网络地址根据需要在机器之间浮动。CARP类似于思科的虚拟路由器冗余协议(Virtusl Router Redundancy Protocol——VRRP),但也包括安全性和完整性检查。此外,CARP没有专利的负担,因此你可以出于任何目的自由使用、分发和重新实施它。

CARP集群中的每个主机都有一个附加到一个或多个接口的CARP属性。每个具有CARP的接口都会不断地向网络上的其他主机宣布其存在。主机协商确定确定哪一个将成为主主机。虽然运行CARP的每个接口都有一个专门为该机器分配的IP地址,但CARP主机会应答所有对浮动CARP IP地址的请求。当主主机停止响应时,集群中的另一台主机将接管并声明CARP IP。

客户端只知道CARP IP,而不知道单个机器的管理地址。当地址浮动到另一台机器时,客户端请求会跟随它。诀窍是让文件系统和服务器进程跟随它。

Devd

当CARP接口上升或下降,接管或放弃IP地址时,它会向devd发送一个事件。正如第二章所讨论的,devd事件可以触发命令。你可以让FreeBSD在CARP接口打开时激活存储,在接口关闭时停用存储。

存储后端

FreeBSD有两个主机可以共享的块存储系统:iSCSI(第八章)和HAST(第九章)。你应该使用哪种取决于你的环境。

在大型环境中,iSCSI是网络存储设备的最佳选择。有两个单独的服务器提供iSCSI目标,另外两个面向客户端的服务器。面向客户端的服务器可以使用每个iSCSI服务器中的一个驱动器创建镜像,也可以使用每个服务器中的多个驱动器创建条带镜像。该环境可以承受一个iSCSI服务器和一个面向客户端的服务器的故障。只要每种类型的服务器都有一台处于活动状态并正常工作,服务就会保持正常。你可以轻松扩展此环境并根据需要更换硬件。你可能需要一个独立的存储区域网络(Storage Area Network——SAN),将你的存储流量与客户端和管理流量分开。为了获得更高的可用性,请研究多路径SCSI。

使用RAID-Z实现高可用性是可能的,但需要在独立的服务器上实现更多的iSCSI目标。八磁盘RAID-3可以承受三个磁盘的损失。如果你有两台独立的iSCSI服务器,丢失一台服务器意味着丢失四个磁盘和池。你可以在每台iSCSI服务器上创建一个单独的RAID-Z设备,然后镜像池。

如果你只有两台主机,HAST是你故障转移文件系统的唯一真正选择。可以在两台主机之间使用iSCSI,每台主机为另一台主机提供一个驱动器,但这达到了令人惊讶的新水平。理想情况下,HAST主机之间将有一个专用网络连接,例如交叉网线。

以下逐一研究这个架构。

配置 CARP

在FreeBSD10及更高版本,CARP是附加到现有接口的属性。旧版本的FreeBSD为CARP创建了一个虚拟接口,但新模型简化了对具有许多接口的主机的管理。CARP非常灵活,所以我们只介绍它的基本配置。更多细节可参阅carp(4)。

首先,在引导时使用loader.conf条目加载carp内核模块:

CARP的基本单元时virtual host。虚拟主机和连接到该虚拟主机的IP地址可以在机器之间浮动。每个虚拟主机都需要一个ID号,称作VHID。大多数人从1开始对VHID进行编号。

每个VHID还需要一个密码。该密码可防止同一网络上的流氓主机欺骗CARP公告。与iSCSI密码一样,CARP密码以纯文本形式存储在每台机器上,因为配置主机网络的任何人都需要访问它。

在/etc/rc.conf中将CARP配置为以太网接口别名。这里接口em0有自己的地址,但它也有一个CARP VHID:

两台主机都需要完全相同的CARP别名配置。当然,它们需要唯一的主IP地址。

你可以为两者添加额外的CARP配置,例如将一台主机硬编码为CARP主机,但这会带来额外的风险。请参阅本章后面的”Cluster Startup“。

重新启动第一台主机,你应该在ifconfig中看到CARP信息:

此主机有自己的IP地址203.0.113.214,它还具有IP地址203.0.113.219,作为vhid1的一部分。

最后一行显示此接口是CARP主接口,这意味着它当前正在该VHID的请求提供服务。

重启第二台主机。其ifconfig输出应显示该主机处于备份状态。如果主服务器发生故障,备份将承担服务。

使用ifconfig强制主机更改角色。给出接口名称、VHID和新状态:

我们通常在主主机上运行这样的命令,告诉它们将自己降级到备份状态,但它们在备份上同样有效。

如果这是你第一次体验CARP,请在继续之前做充分测试。启动VHIP IP的持续ping。重新启动主CARP。根据你的网络交换机和服务器硬件,当CARP IP地址从一个主机移动到另一个主机时,你的客户端可能会发出ping。当主机完成重新启动时,它将看到另一台主机已经声明主状态,从而将自己设置为备份角色。

一旦你了解了VHID如何在机器之间浮动,我们将配置devd。

CARP 和 devd(8)

在FreeBSD上,CARP接口在更改角色时向devd发送事件。

在旧版本中,当CARP作为虚拟接口运行时,这些事件时向上和向下的通知。

既然CARP是应用于现有接口的属性,那么当接口承担主或备份角色时,这些事件会专门通知devd。如果不清楚这些如何工作,请查看第二章。

处理这些事件需要自定义规则来触发shell脚本。我建议将这些规则放在/usr/local/etc/devd/carp.conf中。由于我们还没有文件系统故障转移脚本,下面我们使用这些事件来触发日志条目:

让你的主机在主角色和备份角色之间切换几次。在单独的终端窗口中运行tail -f /var/log/messages,这样你就可以看到日志出现。一旦明确devd按预期运行命令,就可以实际实现文件系统故障转移了。

故障转移脚本

无论你将哪种存储后端用于高可用性网络磁盘,都需要三个基本的脚本。

在系统启动时,你必须将存储置于可用状态。此启动脚本无法使新启动的主机成为集群主机,这可能会导致HAST大脑分裂或ZFS池损坏。但在启动时,你可以安全地连接iSCSI目标,或将HAST设备置于次要角色。

当主机成为CARP主机时,你需要激活存储。HAST主机必须切换到主要角色,并导入或挂载任何文件系统。iSCSI主机必须导入或挂载任何文件系统。最后,此脚本需要启动使用文件系统的任何进程。

当一台主机成为CARP备份机时,快速停止使用文件系统的任何进程。这些进程不再为客户端请求提供服务——客户端用于服务的IP地址不再连接到此计算机。终止进程后,卸载或导出文件系统。如果你使用的是HAST设备,主机会将HAST设备切换到次要角色。

在部署故障转移脚本中,请对其进行测试。使用该脚本将主服务器降级为备份。然后在备用主机上运行提升脚本。

记住,你不能同时拥有两个主主机——这会导致大脑分裂问题或文件系统损坏。

一旦你确信脚本适用于你的环境,请编辑/usr/lcoal/etc/devd/carp.conf文件,是carp状态更改自动执行故障转移过程。然后通过更改CARP状态触发故障转移。

重启每台主机,看另一台是否被接管。

最后,执行”unceremonius shutdown“(随意关机)测试。拔下一台主机上的电源,确保另一台主机会接管。

尽可能彻底测试主机。部署前执行的每个测试都以降低生产中丢失数据的风险。

以下是每个存储后端的一些示例脚本。这些脚本使用ZFS,但也可以轻松改为使用UFS。

HAST 故障转移脚本

当hastd启动时,它将所有HAST设备置于init模式。它们会根据你的指示工作。这是出于安全原因,如果两个主机都决定它们是同一个HAST设备的主节点,那么你和你的服务器会出现分裂大脑错误。

当你设计HAST支持的故障转移系统时,请记住HAST是串行同步设备,而不是并行同步设备。主机在切换角色之前必须同步每个HAST设备。如果一台主机有八个HAST设备,故障转移过程中最慢的部分将比只有一个设备的情况长八倍。

但是,你可以安全地自动将HAST设备置于次要角色。如果另一个节点一直在运行并担任主节点角色,则一切正常。如果两个节点同时启动,则它们都将处于辅助模式。服务不会启动,但你不会丢失数据。但是你必须在hastd启动后运行hastctl。这是一个非常精简的rc.d脚本,可以实现这一点。

我跳过了rcorder的大部分函数,因为将HAST设备置于可用状态并不是真正的服务。

为每个HAST设备输入一个条目。或者添加循环,以增加想象力。

但是,如果你有很多HAST设备需要循环,请重新考虑你的应用程序架构。最好将任何ZFS冗余置于HAST设备之下。

记住,通过HAST发送ZFS元数据会使冗余磁盘变慢。将此脚本复制到/usr/local/etc/rc.d/hastctl并为其分配可执行权限。

这些故障转移脚本假定你的ZFS池与HAST资源同名。每个池下面应该只有一个设备——记住,任何冗余都属于HAST设备下面。

如果你将UFS与HAST结合使用,请以HAST资源命名UFS挂载点。将zpool命令替换为对umount的调用。

对于master-to-backup脚本,你必须将资源设置为HAST资源的名称。还必须确定要停止的进程。在这个例子中,我使用了httpd,并使用service停止了它。如果所有其他方法都失败了,你的脚本可以使用kill -9来终止带有偏见的进程。运行此脚本时,CARP VHID已在另一台主机上。这台机器不再提供服务。

将此脚本复制到/usr/local/scripts/hast-carp-demote.sh并赋予可执行权限。

下面的backup-to-master脚本要求你将资源设置为HAST资源的名称。此脚本实际上不会挂载任何文件系统。如第九章所示,使用HAST事件脚本来挂载文件系统。在HAST事件脚本中或此脚本末尾启动任何进程。

保持此脚本为/usr/local/secripts/hast-carp-promote.sh。

按照本节开头所述测试脚本。一旦你确定它们有效,就可以编辑/usr/local/etc/devd/carp.conf来自动触发这些脚本:

你现在拥有HAST支持的故障转移。

iSCSI 故障转移

iSCSI故障转移比基于HAST的故障转移更简单、更复杂。

iSCSI支持的系统比HAST灵活得多,允许更大的扩展。另一方面,HAST是专门设计为故障转移协议的。其设计使您可以在装载存储之前验证其是否未被使用。

任何数量的主机都可以同时连接到iSCSI目标。多个主机同时挂载UFS分区或在这些目标上使用ZFS池会损坏文件系统。

不是可能,而是会。这些访问甚至可能使主机恐慌,损坏缓冲区缓存,将问题传播到其他文件系统,并引发一场青蛙雨。毫无疑问,这将导致会议,而你处于尴尬的境地。

执行基于iSCSI的故障切换需要一个专门为故障切换设计的协议。在尝试导入磁盘之前,您需要确切地知道另一台主机没有使用该磁盘。

幸运的是,我们有一个。我们将使用HAST。我们不会在HAST设备上使用任何数据,而是依赖于HAST协议。

您可以找到其他选项,包括为此特定目的编写的故障转移守护进程,但它们没有我们需要的任何功能,HAST包含在基本系统中。

首先创建一个非常小的HAST设备。我使用10MB的zvol作为后备存储:

有了这样的HAST设备,我们不需要太多的数据完整性。HAST设备的存在允许挂载文件系统,而不是存储在HAST设备上的任何数据。这是一个简单但完全足够的hast.conf文件。

与任何HAST环境一样,您必须在主机之间建立稳固可靠的网络。正如许多其他故障转移解决方案所要求的那样,交叉电缆当然不会有问题。但是数据负载很小,因此您可以通过主网络接口运行此标志。不过,如果您的组织在大型iSCSI阵列上投入了大量资金,如果前端的糟糕网络导致ZFS损坏,您会感到非常尴尬,因为您想节省网卡。

您需要一个启动脚本,以便在系统启动时将HAST设备置于备份状态。(有关启动时系统状态的更多讨论,请参阅本章后面的“群集启动”。)您还需要登录到iSCSI目标。集群启动脚本/usr/local/etc/rc.d/cluster看起来像这样。

充当HAST主服务器的主机现在有一个设备节点/dev/hast/failover。我们将使用此设备节点的存在作为触发器来装载或导入iSCSI支持的文件系统。

backup-tomaster iSCSI脚本必须首先检查主机是否仍然认为它是HAST备份节点。一旦它不再充当HAST备份,主机就可以将自己升级为主服务器,导入池并启动服务。您需要编辑此脚本,以便在开始时命名池,并在结束时启动服务。

将以上脚本保存为/usr/local/scriptes/iscsi-carp-promote.sh并赋予可执行权限。

master-to-backup脚本简单一些,只需要设置ZFS池的名称并配置命令来终止使用这些池的进程。请记住,当主机切换到备份模式时,客户端不再访问此主机。如有必要,你可以不正当地终止大多数软件。

将以上脚本保存为/usr/local/scripts/iscsi-carp-demote.sh,并赋予可执行权限。

如本节开头所述,手动测试故障转移。一旦你确定它们有效,就把它们集成到devd(8)中,如下所示:

现在,您可以对iSCSI支持的系统进行实时故障切换。

集群启动

这些脚本在启动时将主机置于备份模式。如果你一次重启一台主机,一切都会正确地进行故障转移。然而,两个节点的冷启动更成问题。当系统判断整个集群是否已冷启动。

FreeBSD在启动过程的早期就启动了它的网络。当然,该网络包括CARP。它在HAST或iSCSI上线之前启动CARP。你希望重新启动的服务器自动从功能齐全的对等端声明主角色吗?可能不会——它不会准备好存储、应用程序,甚至SSH。调试有问题的服务器意味着要多次重启它。

当两个节点同时启动时,我建议让第三方决定哪个节点作为主节点。这个第三方就是你。它可能是另一台机器上的一个软件。在所选主节点上运行升级脚本应使其完全启动并启动故障转移。