跳转到主要内容

【未完成】使用 Pacemaker 实现 MySQL 高可用

假设我们有一个 3 节点 MySQL 集群,显然我们需要有一个负载均衡/反向代理/自动故障转移服务,来将访问路由到可用的节点上。

传统上我们通常使用一个或一组负载均衡服务器来部署 HAProxy 或是 ProxySQL,访问该节点的 IP 就行了。

但要是部署 HAProxy 或是 ProxySQL 的负载均衡单个服务器挂了呢?
这就叫 SPOF,Single Point of Failure 单点故障。显然负载均衡也是需要高可用的。

那要是我们使用一组服务器部署负载均衡呢?
我想这样成本太高了。而且在流量不是太高和 Mysql 服务器性能不是太弱的情况下,完全可以和 Mysql 部署在同一台服务器上。

因此我觉得,我们可以在每一个 MySQL 节点上都部署一个  Pacemaker 来提供 VIP(Virural IP / 虚拟 IP) 来管理要路由到哪一个 MySQL 上,客户端始终访问 Virural IP 即可。
这样我们就可以保证只要有 MySQL 节点存活,就始终可以访问。
当然这就要求 MySQL 节点有多余的性能可以部署 Pacemaker。

如果你的应用场景需要网络层面的负载均衡,比如分散读取请求到多个节点,则你可能需要使用 Pacemaker 使 HAProxy 或  ProxySQL 高可用,然后再由它们转发到 MySQL 服务器,原理是一样的。

你也可以使用 Keepalived 来简单配置一个 Virural IP,只是功能上不如 Pacemaker 强大。

组件介绍与前言

Pacemaker 堆栈 PCS

pacemaker 是一个高可用的集群资源管理器,它的核心是一个能够协调一组机器上相互关联的服务的启动和恢复的分布式有限状态机(指 CRMd / Cluster Resource Management daemon)。
Pacemaker 支持多种资源代理标准(LSB 初始化脚本、OCF 资源代理、systemd 单元文件等)来管理任何服务,并且可以对它们之间的复杂关系(托管、排序等)进行建模。
Pacemaker 支持高级服务配置,例如依赖资源组、必须在多台机器上处于活动状态的克隆资源、可以在两个不同角色之间切换的资源以及容器化服务。

Pacemaker 堆栈包括以下组件:

名称

功能

libQB

 libqb 是一个库,其主要目的是为客户端/服务器应用程序提供高性能、可重用的功能,包括高性能日志记录、跟踪、IPC 和轮询

Corosync 消息层组件,管理成员关系、消息与仲裁,为高可用环境中提供通讯服务,位于高可用集群架构的底层,为各节点之间提供心跳信息
Resource agents  资源代理,在节点上接收 CRM 的调度,一般通过脚本对资源进行管理
Fencing agents 关闭不稳定或无答复的节点,以保障集群的其它资源,其主要功能是消除脑裂
Pacemaker 资源管理器,负责启停服务,位于集群架构中资源管理、资源代理层

这里有一点点迷惑,Pacemaker 堆栈是一组组件,其中包括 Pacemaker 本身。
在过去,Pacemaker 还支持 Corosync 1(有或没有 CMAN 的区别)以及 Heartbeat。
不同的发行版支持不同的集群层,需要不同的设置。我们将 Pacemaker 和集群层的每个组合称为“堆栈”。
真心希望 clusterlabs 能给它改个名字。 然而就是在 2.0 中全改成 pacemaker-xxxxx 的。

详情见:

说人话就是:

Pacemaker 是一个开源的集群资源管理器,用于监视和控制集群中的资源和服务。它可以管理各种资源,如虚拟 IP 地址、文件系统、数据库、应用程序等,以确保它们在集群节点之间实现高可用性。Pacemaker 提供了一个策略引擎,可以根据定义的资源约束和策略来自动调整资源的分配,以处理故障情况和负载均衡。

Corosync 是一个开源的通信框架,用于在集群节点之间提供高可用性集群通信。它提供了可靠的消息传递和集群成员检测机制,以确保节点之间的协调和同步。Corosync 负责维护集群成员的状态信息,以便 Pacemaker 可以基于此信息做出决策。它通常与Pacemaker 一起使用,作为 Pacemaker 的底层通信基础设施。

总之,Pacemaker 负责管理和监视集群资源,Corosync 则负责在集群节点之间提供通信和协同工作的能力,以确保高可用性和故障容忍性。它们共同构成了一个完整的高可用性解决方案,通常用于关键业务应用程序和服务的部署,以确保系统在面临硬件或软件故障时保持可用。

HAProxy

HAProxy 是一种开源、非常快速且可靠的反向代理,可为基于 TCP 和 HTTP 的应用程序提供高可用性、负载均衡和代理。

ProxySQL

ProxySQL 是一个开源的数据库代理服务器,主要用于数据库负载均衡、路由、缓存查询、读写分离、故障转移和监控等任务,可以自动故障转移,但没有 Virural IP 功能。

MySQL 集群选择

Percona XtraDB Cluster

在 MySQL 集群方面我选择了 Percona XtraDB Cluster (PXC),这是一种自由的使用 Galera Cluster 的多主集群,可以自动确保节点间数据一致性等(不支持 XA 事务)。

将普通 MySQL 服务器迁移至 PXC 很简单,只需卸载 Mysql 包(不会删除数据,但最好备份),然后安装 PXC 包,安装文档说明以引导方式启动第一个节点,添加其他节点后数据会自动同步,非常省心。
详见:https://docs.percona.com/percona-xtradb-cluster/8.0/install-index.html

注:当集群第一次启动或集群所有节点都离线的情况,需要以引导方式启动节点(systemctl start mysql@bootstrap.service),即该节点作为数据提供节点,以该节点的数据为基准同步到其他节点,同步完毕后(节点在线大于 2)可以 systemctl stop mysql@bootstrap.service 然后以普通方式启动数据库(systemctl start mysql.service)即引导节点重新从其他节点接受最新数据,然后作为普通成员加入。
如果所有节点都意外离线,则重新启动集群时所有节点都可能认为自己不是最后一个离开集群的节点而拒绝启动,此时需要查看 mysql 日志文件,里面大概会提到需要修改 /var/lib/mysql/grastate.dat 中的 safe_to_bootstrap1,修改后再次以引导方式启动节点即可。当然你需要自己找出哪个节点有最新数据,或者需要合并数据等情况。
崩溃恢复详见:https://docs.percona.com/percona-xtradb-cluster/8.0/crash-recovery.html

Galera Arbitrato (garb)

如果你不幸拥有偶数个节点且不想再添加一个相同性能的节点,那么可以添加一个轻量级 Galera Arbitrato(Galera 仲裁器),仲裁器作为集群普通成员参与投票(不储存数据,但集群同步数据时都会发它一份,所以你也需要考虑该节点的网络),此外 Galera Arbitrato 还可以充当节点之间的数据中继服务器,或是从此节点请求复制数据用来备份。
详见:https://docs.percona.com/percona-xtradb-cluster/8.0/garbd-howto.html

注:my.conf 中的 wsrep_cluster_address 无需填写 garb 节点地址,garb 配置文件中的 GALERA_NODES 无需填写本机地址。
garb 中的地址可以不与 wsrep_cluster_address 中的地址相同,garb 可以配置在不同网络中。
当 garb 正确加入节点后,你应该能看到 MySQL 中的 wsrep_cluster_size 数值增加。
(可通过 mysql> show status like 'wsrep%'; 查询)

例如:MySQL 服务器之间有专用链接,my.conf 填了 wsrep_cluster_address=gcomm://10.100.100.1,10.100.100.2 走专用链接,然后 garb 内填 GALERA_NODES="10.200.200.1:4567,10.200.200.2:4657" 走共享链接或者其他线路也是可以的,只要确实可达。

Corosync Qnetd

既然 Galera Cluster 有仲裁器,那么 Pacemaker 堆栈有没有呢?
Corosync Qnetd 就是 Corosync 的仲裁器,它提供投票给 Corosync-qdevice,以共同决定群集的法定人数(Quorum)状态。

  • corosync-qdevice:是一个在集群的每个节点上运行的守护进程。它通过依据第三方仲裁者的决定向集群的仲裁子系统提供投票,以帮助集群在节点故障时维持仲裁。

  • corosync-qnetd:是一个运行在集群外部的守护进程,它提供投票给 corosync-qdevice 的网络模型。Corosync-qnetd 设计用来支持多个集群,运行时几乎不需要配置和维护状态,新的集群可以动态处理,无需配置文件。它还可以作为非 root 用户运行。qnetd 主要作为第三方仲裁,配合 qdevice 来提供投票仲裁服务,不属于集群内节点,不承担任何集群节点功能。

即需要在每个 Corosync 节点上安装 Corosync-qdevice,然后使用一台单独的节点部署 Corosync-qnetd,一个 Corosync-qnetd 可以为多个集群提供服务。

架构图可参考:https://www.ibm.com/docs/en/db2/11.5?topic=option-install-configure-qdevice-quorum


搭建

本文以 RHEL 8.9 为例,其它系统除包不同和配置文件路径可能不同外基本一致。

使用 2 节点 PXC (Percona XtraDB Cluster) 兼 Pacemaker 堆栈+ 1 节点 corosync-qnetd 兼 garb。

PXC 与 garb 已预先搭建完成注意事项在上文中,本文将关注 Pacemaker 堆栈。

以下操作默认需要在每个 Pacemaker 节点上执行,需要在 qnetd 节点上部署的另外说明。

启用储存库

Pacemaker 堆栈相关包都在 Red Hat Enterprise Linux High Availability Add-On 里,它很可能已经在你的订阅里了,但需要先启用。

如果你是 RHEL

查看储存库列表:

subscription-manager repos --list

EL 8:

subscription-manager repos --enable=rhel-8-for-x86_64-highavailability-rpms

EL 9:

subscription-manager repos --enable=rhel-9-for-x86_64-highavailability-rpms

如果你是 AlmaLinux、Rocky Linux 等克隆版

查看储存库列表:

访问各发行版官网,例如

EL 8:

dnf config-manager --set-enabled ha

EL 9:

dnf config-manager --set-enabled highavailability
安装并启用包
yum install corosync pacemaker pcs

如果你打算使用 Corosync Qnetd

那么需要在每个集群成员节点上安装 corosync-qdevice

yum install corosync-qdevice

然后在单独的节点上安装 corosync-qnetd

yum install corosync-qnetd

检查版本

# crmadmin --version
Pacemaker 2.1.6-9.1.el8_9
Written by Andrew Beekhof and the Pacemaker project contributors
# corosync -v
Corosync Cluster Engine, version '3.1.7'
Copyright (c) 2006-2021 Red Hat, Inc.

Built-in features: dbus systemd xmlconf vqsim nozzle snmp pie relro bindnow
Available crypto models: nss openssl
Available compression models: zlib lz4 lz4hc lzo2 lzma bzip2

其他版本可能有略微差异。

启用包

systemctl enable --now pcsd.service

验证状态

systemctl status pcsd.service

配置主机名解析和防火墙

请根据你的防火墙实现配置。

协议 方向 端口 用途
TCP 入站 2224 用于 pcsd、Web UI 和节点到节点通信。所
有节点上都需要打开的 pcsd 端口。您可以使用 /etc/sysconfig/pcsd 文件中的 PCSD_PORT 参数来配置 pcsd 端口。
TCP 入站 3121 用于和远程 Pacemaker 节点通讯。
TCP 入站 5403 用于 corosync-qnetd 和 corosync-qnetd 通讯。
UDP 入站 5404 用于 corosync 通讯(如果配置为多播 UDP)。
UDP 入站 5405 用于 corosync 通讯。

/etc/hosts 中或你的 DNS 中配置主机名解析。

10.100.100.101   server1
10.100.100.102   server1
10.100.100.201   server2
10.100.100.102   server2
10.100.100.200   qnetd

hosts.conf 功能

注:在 /etc/hosts.conf 可以设置 2 个功能,根据文档:

  • multi 有效值为 onoff
     如果设置为 on,解析器库将返回 /etc/hosts 文件中出现的主机的所有有效地址,而不是仅返回第一个。 默认情况下此功能处于关闭状态,因为它可能会导致具有大型主机文件的站点出现严重的性能损失。(从 RHEL6 开始就默认是 on)

  • reorder 有效值为 onoff
    如果设置为 on,解析器库将尝试重新排序主机地址,以便在执行 gethostbyname(3) 时首先列出本地地址(即在同一子网上)。 对所有查找方法都进行了重新排序。 默认值是 off。


以下实验仅设置 multi on

我通过抓包和搜索都没发现 multi 是如何判断地址有效的,但在大部分情况下都能返回能 ping 通的地址,例如我配置以下 8 个地址,其中只有 10.1.1.200 是可以 ping 通的,那么当我 ping test ,它总会返回 10.1.1.200。抓包未发现发往其他地址的请求包。

10.1.1.13  test
10.1.1.140  test
10.1.1.220  test
10.1.1.200  test
10.1.1.130  test
10.1.1.100  test
10.1.1.110  test
10.1.1.210  test
10.1.1.150  test
10.1.1.16  test

如果是这种情况:

10.1.1.13  test
10.1.1.140 test
10.1.1.200 test
10.1.1.230 test
10.1.1.130 test
10.1.1.100 test
10.1.1.110 test
10.1.1.210 test
10.1.1.150 test
10.1.1.16 test

 那么我总会得到 10.1.1.230 但 10.1.1.230 是一个不可达的地址。

# ping test
PING test (10.1.1.230) 56(84) bytes of data.
^C
--- test ping statistics ---
2 packets transmitted, 0 received, 100% packet loss, time 1011ms

 

 

但如果能通的地址只有一个外网地址,那么 hosts 并不会返回该外网地址。

10.1.1.13  test
10.1.1.140  test
119.29.29.29 test
10.1.1.210  test
10.1.1.150  test
10.1.1.16  test

在上面这种情况中我得到了 10.1.1.210

# ping test
PING test (10.1.1.210) 56(84) bytes of data.
^C
--- test ping statistics ---
2 packets transmitted, 0 received, 100% packet loss, time 101

 

 

因此在一定程度上在 hosts 中配置多个 IP 可以实现某种冗余,但并不可靠。

配置用户

安装包时已自动添加 Linux 用户 hacluster ,现在你需要为其设置密码。红帽建议每个节点上 hacluster 用户的密码都相同。

passwd hacluster

创建集群

本章节命令在任意一个节点上执行即可。

为每个节点进行身份验证:

执行后会要求输入用户名密码,用户名为 hacluster,密码则为你刚刚设置的密码。

pcs cluster auth [节点主机名] [...] [-u 用户名] [-p 密码]

例如:

pcs host auth server1 server2

如果失败则使用此命令撤销:

pcs pscd clear-auth [节点主机名]

创建集群并将设置文件同步到配置的节点:

pcs cluster setup <集群名称> [--start] [--local] <节点1主机名> [节点2主机名] [...]

例如:

pcs cluster setup my_cluster --start server1 server2
  • 配置可以添加 --force 来强行覆盖。
  • 配置可以添加 --start 来自动启动集群。
如果你的服务器有多个接口,则应按照此说明配置冗余连接

如果你的服务器有多个接口,你可以添加多个 IP 地址组成冗余连接,IPv6 地址也可以:

pcs cluster --start setup <集群名> <节点1主机名> addr=<IP地址> addr=<IP地址> [...] <节点2主机名> addr=<IP地址> addr=<IP地址> [...]

当创建具有多个链接的集群时,你应该考虑以下内容。

  • addr=<IP地址> 参数的顺序非常重要。节点名称后指定的第一个地址为 link0,第二个 地址用于 link1,以此类推。
  • 默认情况下,如果没有为链接指定 link_priority,则链接的优先级等于链接号。根据指定的顺序,链接优先级为 link0、link1、link2、link3 等,以此类推,link0 是最高链接优先级。
  • 默认链路模式是 passive 的,这意味着使用具有最低链路优先级的激活链路。
  • 使用 link_mode 和 link_priority 的默认值,指定的第一个链接将用作最高优先级链接,如果该链接失败,则将使用指定的下一个链接。
  • 可以使用 knet 传输协议(即默认的传输协议)指定最多 8 个链接。
  • 所有节点必须具有相同数量的 addr=<IP地址> 参数。
  • 从 RHEL 8.1 开始,可以使用 pcs cluster link add、pcs cluster link remove、pcs cluster link delete 和 pcs cluster link update 命令在现有群集中添加、删除和更改链接。
  • 与单链路集群一样,请勿将 IPv4 和 IPv6 地址混合到一个链接中,虽然您可以有一个链接运行 IPv4,另一个运行 IPv6。
  • 与单链路集群一样,只要在一个单一的链接中没有混合使用 IPv4 和 IPv6,且名称可以被解析为 IPv4 或 IPv6 地址,就可以使用 IP 地址或名称来指定地址。

例如:

以下示例创建一个名为 my_twolink_cluster 的双节点群集,它有两个节点 rh80-node1 和 rh80-node2。rh80-node1 有两个接口,IP 地址 192.168.122.201 为 link0,192.168.123.201 为 link1。rh80-node2 有两个接口,IP 地址 192.168.122.202 为 link0,192.168.123.202 为 link1。

pcs cluster setup --start my_twolink_cluster rh80-node1 addr=192.168.122.201 addr=192.168.123.201 rh80-node2 addr=192.168.122.202 addr=192.168.123.202

 

执行此命令后,pcs 会在后台自动启用并启动(enable 并 start) corosync 和 pacemaker,并创建配置文件 /etc/corosync/corosync.conf

systemctl status corosync
systemctl status pacemaker

若配置失败,你可以使用 pcs cluster destroy 来销毁集群,或者重新配置时添加 --force 来强行覆盖。

启用所有节点:

pcs cluster enable --all

或者仅启用本节点: 

pcs cluster enable

启动所有节点:

pcs cluster start --all

或者仅启动本节点: 

pcs cluster start

如果你在 pcs cluster setup 命令时使用了 --start 那么集群会自动启动。

检查节点状态:

pcs status

检查集群状态:

pcs cluster status

你应该看到 PCSD 状态都为 Online:

# pcs cluster status
Cluster Status:
 Cluster Summary:
   * Stack: corosync (Pacemaker is running)
   * Current DC: server3 (version 2.1.6-9.1.el8_9-6fdc9deea29) - partition with quorum
   * Last updated: Thu Feb 22 14:55:03 2024 on server2
   * Last change:  Thu Feb 22 14:54:00 2024 by hacluster via crmd on server3
   * 2 nodes configured
   * 0 resource instances configured
 Node List:
   * Online: [ server2 server3 ]

PCSD Status:
  server2: Online
  server3: Online

添加 PCS 资源

在节点正常启动后,就可以添加 pcs 资源了,pcs 资源即由集群管理的服务,例如 Web 服务器、数据库实例或虚拟 IP 地址。

资源添加语法:

pcs resource create resource_id [standard:[provider:]]type [resource_options] [op operation_action operation_options [operation_action operation options]...] [meta meta_options...] [clone [clone_options] | master [master_options] [--wait[=n]]

这里我们添加虚拟 IP (Virural IP) 地址资源:

pcs resource create PXC_VirtualIP ocf:heartbeat:IPaddr2 ip=10.200.200.100 cidr_netmask=32 op monitor interval=5s

以上命令创建一个 standard 为 ocf 、名为 PXC_VirtualIP 的资源,provider 为 heartbeat,类型为 IPaddr2
这个资源的浮动地址是 10.10.2.100,CIDR 子网掩码为 32,系统会每 5 秒检查一次这个资源是否在运行。
建议使用 nic=<网卡名称> 来手动指定网卡。

如果配置错误可以使用此命令来删除资源:

pcs resource delete <资源名>

启用资源:

pcs resource enable PXC_VirtualIP

查看资源状态:

pcs status resources

可以看到 PXC_VirtualIP 还是处于 Stopped 状态。

# pcs status resources
  * PXC_VirtualIP       (ocf::heartbeat:IPaddr2):        Stopped

这时我们需要使用:

crm_verify --live-check -V
  • --live-check 活动检查。
  • -V 显示更多细节。
# crm_verify --live-check -V
(unpack_resources)      error: Resource start-up disabled since no STONITH resources have been defined
(unpack_resources)      error: Either configure some or disable STONITH with the stonith-enabled option
(unpack_resources)      error: NOTE: Clusters with shared data need STONITH to ensure data integrity
crm_verify: Errors found during check: config not valid

显示没有 STONITH 资源。

STONITH (Shoot The Other Node In The Head) 是 pacemaker 堆栈的 fencing 实现,提供节点级防护。
由于历史原因 stonith 和 fencing 术语经常互换使用,基本可以等同。

STONITH 控制物理设备,比如智能 PDU、IPMI、可禁用端口的交换机等,来在节点故障时将其物理隔离开来。
因为如果与集群中单个节点的通信失败,则集群中的其他节点必须能够限制或阻止对发生故障的节点访问集群资源。而这不能通过联系集群节点本身来完成,因为集群节点可能不响应。

STONITH 详见:

对于 PXC(Galera Cluster) 来说仲裁和隔离是由 PXC 集群完成的,所以我们不需要 STONITH。
PXC 使用 Quorum 算法来避免集群中出现多个主组件,如果故障导致集群分裂为两个大小相等的分区(除非您明确配置其他分区),则两个分区都不会成为主组件。
详见:https://galeracluster.com/library/documentation/weighted-quorum.html

因此我们直接禁用 STONITH 即可。

禁用 STONITH:

pcs property set stonith-enabled=false

由于仲裁也是由 PXC 完成的,所以我们不希望 Pacemaker 堆栈进行干扰。因此我们需要调整仲裁行为。

将集群调整为没有法定人数时也继续操作:

pcs property set no-quorum-policy=ignore
  • no-quorum-policy 调整当集群没有法定人数时该怎么做。可以为以下值:
    • ignore:继续所有资源管理
    • freeze:继续资源管理,但不从不在受影响分区中的节点恢复资源
    • stop:停止受影响集群分区中的所有资源
    • suicide:隔离受影响集群分区中的所有节点

 调整后 PXC_VirtualIP 应该正常启动,若还未正常启动,使用 pcs status 查看其状态,并查看日志 /var/log/pacemaker.log

待续

主要参考