前沿技术:Pacemaker 高可用性堆栈
高可用性堆栈服务于一个目的:通过两个或多个节点的冗余设置,确保服务可用性,并在出现问题时自动恢复服务。Florian Haas 探讨了 Pacemaker,Linux 上最先进的高可用性堆栈。
硬件和软件都容易出错。最终,硬件问题或软件错误会影响任何应用程序。然而,我们越来越期望服务——运行在我们的基础设施之上的应用程序——默认情况下 24/7 全天候运行。即使我们没有这样期望,我们的老板和客户也会这样期望。使这一切成为可能的是高可用性堆栈:它在面对软件和硬件问题时自动恢复应用程序和服务,并确保服务可用性和正常运行时间。Linux 平台上权威的开源高可用性堆栈构建于 Pacemaker 集群资源管理器之上。为了确保最大的服务可用性,该堆栈由四个层组成:存储、集群通信、资源管理和应用程序。
集群存储存储层是我们保存数据的地方。各个集群节点以联合和协调的方式访问这些数据。集群存储有两种基本类型
-
单实例存储可能是更传统的集群存储形式。集群将其所有数据存储在一个中心化的实例中,通常是 SAN 上的一个卷。对这些数据的访问可以来自一次一个节点(主动/被动),也可以来自多个节点同时访问(主动/主动)。后一种选项通常需要使用共享集群文件系统,例如 GFS2 或 OCFS2。为了防止对数据进行不协调的访问——这肯定会破坏数据——所有单实例存储集群架构都需要使用隔离(fencing)。单实例存储非常容易设置,特别是如果您已经拥有 SAN,但它有一个非常明显的缺点:如果由于任何原因,数据变得不可访问甚至被破坏,那么您的高可用性架构中的所有服务器冗余都将化为乌有。没有数据可服务,服务器就变成了一块几乎无用的铁。
-
复制存储解决了这个问题。在这种架构中,集群数据集有两个或多个副本,每个集群节点都可以访问其自己的数据副本。然后,底层复制工具保证副本在块层上完全相同。这有效地使复制存储成为单实例存储的直接替代品,尽管在数据级别增加了冗余。现在您可以丢失整个节点(包括其数据),并且仍然有更多节点可以故障转移。为此目的存在几种专有的(基于硬件的)解决方案,但在 Linux 上实现复制块存储的规范方法是分布式复制块设备 (DRBD)。存储复制也可能发生在文件系统级别,GlusterFS 和 Ceph 是目前最突出的实现。
集群通信层服务于三个主要目的:它提供集群节点之间可靠的消息传递,建立集群成员资格并确定仲裁。Linux HA 堆栈中的默认集群通信层是 Corosync,它从早期的、现在几乎已经失效的 OpenAIS 项目演变而来。
Corosync 实现了 Totem 单环排序和成员协议,这是一种经过充分研究的消息传递算法,拥有近 20 年的研究资历。它提供了一种安全可靠的消息传递方式,保证消息按顺序传递到集群节点。Corosync 通常通过 UDP 多播在以太网链路上发送集群消息,但它也可以使用单播或广播消息传递,甚至可以通过 InfiniBand 链路直接 RDMA。它还支持冗余环,这意味着集群可以使用两条物理上独立的路径进行通信,并从一个环透明地故障转移到另一个环。
Corosync 还通过相互验证节点来建立集群成员资格,可以选择使用简单的预共享密钥身份验证和加密方案。最后,Corosync 建立仲裁——它检测是否有足够多的节点加入了集群以进行操作。
集群资源管理在高可用性中,资源可以像在集群节点之间“浮动”的 IP 地址一样简单,也可以像具有非常复杂配置的数据库实例一样复杂。简而言之,资源是集群启动、停止、监视、恢复或移动的任何东西。集群资源管理为我们执行这些任务——以自动化、透明、高度可配置的方式。高可用性 Linux 中的规范集群资源管理器是 Pacemaker。
Pacemaker 是 Heartbeat 的衍生产品,Heartbeat 是以前主要由 Novell(当时拥有 SUSE)和 IBM 驱动的高可用性堆栈。它在 2008 年重新发明了自己,成为一个独立且更以社区驱动的项目,来自 Red Hat、SUSE 和 NTT 的开发人员现在是最活跃的贡献者。
Pacemaker 提供了一个分布式集群信息库 (CIB),其中记录了所有集群资源的配置和状态。CIB 从指定协调器 (DC) 自动复制到所有集群节点——指定协调器是 Pacemaker 从所有可用集群节点中自动选举出来的一个节点。
CIB 使用基于 XML 的配置格式,在 Pacemaker 1.0 之前的版本中,这是配置集群的唯一方法——这理所当然地让潜在用户尖叫着逃跑。然而,从这些不起眼的开端开始,Pacemaker 已经发展成为一个非常有用的、分层的、自文档化的基于文本的 shell,有点类似于许多读者从 libvirt 熟悉的“virsh”子 shell。这个 shell——其开发者不加想象力地称之为“crm”——向用户隐藏了所有那些令人讨厌的 XML,并使集群的配置更加简单和容易。
在 Pacemaker 中,shell 允许我们配置集群资源——这不足为奇——和操作(集群对资源执行的操作)。此外,我们可以设置每个节点和集群范围的属性,将节点发送到备用模式,使其暂时不符合运行资源的条件,操纵集群中的资源放置,并执行大量其他操作来管理我们的集群。
最后,Pacemaker 的策略引擎 (PE) 周期性地检查集群配置与集群状态,并根据需要启动操作。例如,PE 会启动对资源的周期性监视操作(例如,“检查此数据库是否仍然存活”);评估其状态(“嘿,它没有!”);考虑集群配置中的其他项(“如果此特定资源在 24 小时内故障超过三次,则不要尝试就地恢复它”);并启动后续操作(“将此数据库移动到不同的节点”)。所有这些步骤都是完全自动的,不需要人工干预,从而确保快速的资源恢复和最长的正常运行时间。
在集群资源管理级别,Pacemaker 使用一个抽象模型,其中所有资源都支持预定义的通用操作(例如启动、停止或检查状态)并生成标准化的返回代码。为了将这些抽象操作转换为对应用程序真正有意义的东西,我们需要资源代理。
资源代理资源代理是少量代码,允许 Pacemaker 与应用程序交互并将其作为集群资源进行管理。资源代理可以用任何语言编写,绝大多数是简单的 shell 脚本。在撰写本文时,超过 70 个单独的资源代理与高可用性堆栈本身一起发布。但是,用户可以轻松地添加自定义资源代理——Pacemaker 堆栈中的一个关键设计原则是使第三方可以轻松访问资源管理。
资源代理将 Pacemaker 的通用操作转换为对特定资源类型有意义的操作。对于像虚拟“浮动”IP 地址这样简单的东西,启动资源相当于将该地址分配给网络接口。更复杂的资源类型,例如管理数据库实例的资源类型,带有更复杂的启动操作。同样适用于资源关闭、监视和迁移的不同实现:所有这些操作的范围都可以从简单到复杂,具体取决于资源类型。
高可用性 KVM:一个简单的 Pacemaker 集群此参考配置由一个三节点集群和单实例 iSCSI 存储组成。这样的配置可以轻松支持超过 20 个高可用性虚拟机实例,尽管为了简单起见,此处显示的配置仅包含三个。您可以在任何最新的 Linux 发行版上完成此配置——Corosync/Pacemaker 堆栈在 CentOS 6,[1] Fedora、OpenSUSE 和 SLES、Debian、Ubuntu 和其他平台上普遍可用。它在 RHEL 6 中也可用,尽管目前是作为不受支持的技术预览版。在所有目标平台上,安装 pacemaker
、corosync
、libvirt
、qemu-kvm
和 open-iscsi
软件包应该就足够了——您首选的软件包管理器会很乐意拉入所有软件包依赖项。
此示例假设所有三个集群节点——alice、bob 和 charlie——都具有对 192.168.122.100:3260 门户的 iSCSI 访问权限,并且被允许连接到 IQN 为 iqn.2011-09.com.hastexo:virtcluster
的 iSCSI 目标。此外,已经预安装了三个 libvirt/KVM 虚拟机——xray、yankee 和 zulu——并且每个虚拟机都使用 iSCSI 目标上的卷(LUN)之一作为其虚拟块设备。在所有三个物理节点上的默认配置目录 /etc/libvirt/qemu 中都存在域配置文件的相同副本。
Corosync 的配置文件位于 /etc/corosync 中,中心配置文件位于 /etc/corosync/corosync.conf 中。以下是此文件内容的示例
totem {
# Enable node authentication & encryption
secauth: on
# Redundant ring protocol: none, active, passive.
rrp_mode: active
# Redundant communications interfaces
interface {
ringnumber: 0
bindnetaddr: 192.168.0.0
mcastaddr: 239.255.29.144
mcastport: 5405
}
interface {
ringnumber: 1
bindnetaddr: 192.168.42.0
mcastaddr: 239.255.42.0
mcastport: 5405
}
}
amf {
mode: disabled
}
service {
# Load Pacemaker
ver: 1
name: pacemaker
}
logging {
fileline: off
to_stderr: yes
to_logfile: no
to_syslog: yes
syslog_facility: daemon
debug: off
timestamp: on
}
这里重要的部分是两个接口声明,它们启用了冗余集群通信和相应的 rrp_mode
声明。相互节点身份验证和加密 (secauth on
) 是良好的安全实践。最后,service
节加载 Pacemaker 集群管理器作为 Corosync 插件。
启用 secauth 后,Corosync 还要求使用共享密钥进行相互节点身份验证。Corosync 使用一个简单的 128 字节密钥,将其存储为 /etc/corosync/authkey,您可以使用 corosync-keygen
实用程序轻松生成该密钥。
一旦 corosync.conf 和 authkey 准备就绪,将它们复制到您预期集群中的所有节点。然后,启动 Corosync 集群通信——一个简单的 service corosync start
就可以做到。
一旦服务在所有节点上运行,命令 corosync-cfgtool -s
将显示两个环都处于健康状态,并且集群已准备好进行通信
Printing ring status.
Local node ID 303938909
RING ID 0
id = 192.168.0.1
status = ring 0 active with no faults
RING ID 1
id = 192.168.42.1
status = ring 1 active with no faults
Pacemaker
一旦 Corosync 运行,我们就可以使用 service pacemaker start
命令启动 Pacemaker。几秒钟后,Pacemaker 在三个可用节点中选举出一个指定协调器 (DC) 节点,并开始全面集群操作。然后,在任何集群节点上可执行的 crm_mon
实用程序都会生成类似于以下的输出
============
Last updated: Fri Feb 3 18:40:15 2012
Stack: openais
Current DC: bob - partition with quorum
Version: 1.1.6-4.el6-89678d4947c5bd466e2f31acd58ea4e1edb854d5
3 Nodes configured, 3 expected votes
0 Resources configured.
============
crm_mon
生成的输出是存储在分布式 XML 数据库(集群信息库 (CIB))中的内部集群配置和状态的更友好的用户表示。那些有兴趣且足够勇敢地关心内部表示的人欢迎使用 cibadmin -Q
命令。但请注意,在您执行此操作之前,您可能需要指示您旁边的初级系统管理员去泡咖啡——cibadmin
生成的 XML 乱码可能会让新手感到害怕。
Pacemaker 的标准配置工具 crm shell 不那么令人生畏。这个自文档化的、分层的、可脚本化的子 shell 是操作 Pacemaker 集群的最简单和最通用的方法。在其 configure 子菜单中,shell 允许我们加载和导入配置片段——甚至完整的配置,如下所示
primitive p_iscsi ocf:heartbeat:iscsi \
params portal="192.168.122.100:3260" \
target="iqn.2011-09.com.hastexo:virtcluster" \
op monitor interval="10"
primitive p_xray ocf:heartbeat:VirtualDomain \
params config="/etc/libvirt/qemu/xray.xml" \
op monitor interval="30" timeout="30" \
op start interval="0" timeout="120" \
op stop interval="0" timeout="120"
primitive p_yankee ocf:heartbeat:VirtualDomain \
params config="/etc/libvirt/qemu/yankee.xml" \
op monitor interval="30" timeout="30" \
op start interval="0" timeout="120" \
op stop interval="0" timeout="120"
primitive p_zulu ocf:heartbeat:VirtualDomain \
params config="/etc/libvirt/qemu/zulu.xml" \
op monitor interval="30" timeout="30" \
op start interval="0" timeout="120" \
op stop interval="0" timeout="120"
clone cl_iscsi p_iscsi
colocation c_xray_on_iscsi inf: p_xray cl_iscsi
colocation c_yankee_on_iscsi inf: p_yankee cl_iscsi
colocation c_zulu_on_iscsi inf: p_zulu cl_iscsi
order o_iscsi_before_xray inf: cl_iscsi p_xray
order o_iscsi_before_yankee inf: cl_iscsi p_yankee
order o_iscsi_before_zulu inf: cl_iscsi p_zulu
除了将我们的三个虚拟域定义为完全集群管理和监视下的资源(p_xray
、p_yankee
和 p_zulu
)之外,此配置还确保所有域都可以找到其存储(cl_iscsi
克隆),并且它们会等待直到 iSCSI 存储可用(order
和 colocation
约束)。
由于这是一个单实例存储集群,因此我们还必须采取措施来防止破坏我们的数据。这通常被称为节点隔离(fencing),但 Pacemaker 使用更亲切的术语 STONITH(Shoot The Other Node In The Head,射杀另一个节点)来表示相同的概念。一种普遍的节点隔离方法是通过其 IPMI 基板管理控制器控制节点,Pacemaker 原生支持此方法
primitive p_ipmi_alice stonith:external/ipmi \
params hostname="alice" ipaddr="192.168.15.1" \
userid="admin" passwd="foobar" \
op start interval="0" timeout="60" \
op monitor interval="120" timeout="60"
primitive p_ipmi_bob stonith:external/ipmi \
params hostname="bob" ipaddr="192.168.15.2" \
userid="admin" passwd="foobar" \
op start interval="0" timeout="60" \
op monitor interval="120" timeout="60"
primitive p_ipmi_charlie stonith:external/ipmi \
params hostname="charlie" ipaddr="192.168.15.3" \
userid="admin" passwd="foobar" \
op start interval="0" timeout="60" \
op monitor interval="120" timeout="60"
location l_ipmi_alice p_ipmi_alice -inf: alice
location l_ipmi_bob p_ipmi_bob -inf: bob
location l_ipmi_charlie p_ipmi_charlie -inf: charlie
property stonith-enabled="true"
这里的三个位置约束确保没有节点必须射杀自己。
一旦该配置处于活动状态,Pacemaker 将根据集群配置启动资源。同样,我们可以使用 crm_mon
命令查询集群状态,现在生成的输出比以前更有趣
============
Last updated: Fri Feb 3 19:46:29 2012
Stack: openais
Current DC: bob - partition with quorum
Version: 1.1.6-4.el6-89678d4947c5bd466e2f31acd58ea4e1edb854d5
3 Nodes configured, 3 expected votes
9 Resources configured.
============
Online: [ alice bob charlie ]
Clone Set: cl_iscsi [p_iscsi]
Started: [ alice bob charlie ]
p_ipmi_alice (stonith:external/ipmi): Started bob
p_ipmi_bob (stonith:external/ipmi): Started charlie
p_ipmi_charlie (stonith:external/ipmi): Started alice
p_xray (ocf::heartbeat:VirtualDomain): Started alice
p_yankee (ocf::heartbeat:VirtualDomain): Started bob
p_zulu (ocf::heartbeat:VirtualDomain): Started charlie
请注意,默认情况下,Pacemaker 集群是对称的。资源管理器以轮询方式在集群节点之间平衡资源。
此配置可防止资源和节点故障。如果其中一个虚拟域崩溃,Pacemaker 会就地恢复 KVM 实例。如果整个节点宕机,Pacemaker 会重新洗牌资源,以便其余节点接管故障节点托管的服务。在下面的屏幕截图中,charlie 节点已故障,bob 节点已适当地接管了 charlie 节点托管的虚拟机
============
Last updated: Sat Feb 4 16:18:00 2012
Stack: openais
Current DC: bob - partition with quorum
Version: 1.1.6-4.el6-89678d4947c5bd466e2f31acd58ea4e1edb854d5
3 Nodes configured, 2 expected votes
9 Resources configured.
============
Online: [ alice bob ]
OFFLINE: [ charlie ]
Full list of resources:
Clone Set: cl_iscsi [p_iscsi]
Started: [ alice bob ]
Stopped: [ p_iscsi:2 ]
p_ipmi_alice (stonith:external/ipmi): Started bob
p_ipmi_bob (stonith:external/ipmi): Started alice
p_ipmi_charlie (stonith:external/ipmi): Started alice
p_xray (ocf::heartbeat:VirtualDomain): Started bob
p_yankee (ocf::heartbeat:VirtualDomain): Started bob
p_zulu (ocf::heartbeat:VirtualDomain): Started alice

图 1. 正常运行;虚拟域分布在所有三个集群节点上。

图 2. charlie 节点已故障;alice 节点已自动接管虚拟域 zulu。
一旦主机 charlie 恢复,资源可以选择自动移回恢复的主机,或者它们可以保持原位,直到管理员在她选择的时间重新分配它们。
在本文中,我仅仅触及了 Linux 高可用性堆栈功能的表面。Pacemaker 支持各种恢复策略、资源放置策略和集群约束,这使得堆栈非常强大。
词汇表节点:在集群术语中,指参与集群通信并可能托管集群资源的任何系统(通常是服务器)。
隔离(Fencing):在通信故障时协调对共享资源访问的一种手段。一旦节点意外停止响应集群消息(而不是正常注销),其他节点会将其关闭,以确保它不再有权访问任何共享资源。通常通过与故障节点建立带外连接并拨动虚拟电源开关来实现,IPMI-over-LAN 是最广泛使用的实现。
资源:集群通常管理的任何东西。资源可能非常多样化,从简单的 IP 地址到复杂的数据库实例或守护进程。
环(Ring):在 Totem 协议术语中,指集群消息通信所经过的(通常是冗余的)链路之一。
资源“The Totem Single-Ring Ordering and Membership Protocol”(解释 Totem 协议的研究论文):http://www.cs.jhu.edu/~yairamir/tocs.ps
“Clusters From Scratch”(Pacemaker 新手的实践文档):http://www.clusterlabs.org/doc/en-US/Pacemaker/1.1/html/Clusters_from_Scratch
“Pacemaker Configuration Explained”(Pacemaker 配置内部结构的参考文档,不适合胆小者):http://www.clusterlabs.org/doc/en-US/Pacemaker/1.1/html/Pacemaker_Explained