介绍
前段时间,我接到了开发故障转移集群的任务
这一决定提出了一个合理的问题:故障转移集群的容错能力如何? 为了研究这个问题,我开发了一个测试平台,模拟集群节点上的各种故障,等待服务恢复,恢复故障节点,并继续循环测试。 这个项目最初被称为 hapgsql,但随着时间的推移,我厌倦了这个只有一个元音的名字。 因此,我开始调用容错数据库(以及指向它们的浮动IP) 克罗根 (计算机游戏中的角色,其中所有重要器官都被复制),并且节点、集群和项目本身是 图昌卡 (克洛根人居住的星球)。
现在管理层已经允许
集群部署在虚拟机上
精准授时服务 ntpd
(孤儿模式)。 共享服务器 见证 充当中央 NTP 服务器,将其时间分配给所有集群,从而使所有服务器相互同步。 如果 见证 发生故障或变得孤立,然后集群服务器之一(集群内)将开始分配其时间。 辅助缓存 HTTP代理 也提升至 见证,在它的帮助下,其他虚拟机可以访问 Yum 存储库。 实际上,准确时间和代理等服务很可能托管在专用服务器上,但在展位中它们托管在 见证 只是为了节省虚拟机数量和空间。
版本
v0。 适用于 VirtualBox 7 上的 CentOS 11 和 PostgreSQL 6.1。
簇结构
所有集群均设计为位于多个数据中心,组合成一个扁平网络,并且必须能够承受单个数据中心的故障或网络隔离。 这就是为什么 不可能 用于防护 脑裂 标准起搏器技术称为 斯托尼斯 (射击另一个节点的头部)或 击剑。 其本质是:如果集群中的节点开始怀疑某个节点出现问题,没有响应或行为不正确,那么它们会通过“外部”设备(例如 IPMI 或 UPS 控制卡)强制将其关闭。 但这仅适用于在发生单一故障时 IPMI 或 UPS 服务器继续工作的情况。 在这里,我们计划在整个数据中心发生故障(例如断电)时防止发生更灾难性的故障。 有了这样的拒绝,一切 斯托尼斯- 设备(IPMI、UPS 等)也将无法工作。
相反,该系统是基于法定人数的思想。 所有节点都有发言权,只有能看到半数以上节点的节点才能工作。 这个“一半+1”的数量称为 法定人数。 如果未达到法定人数,则节点决定其处于网络隔离状态,并且必须关闭其资源,即就是这样 裂脑保护。 如果负责此行为的软件无法工作,则必须使用看门狗(例如基于 IPMI 的看门狗)来工作。
如果节点数量为偶数(一个集群在两个数据中心),那么可能会出现所谓的不确定性 50%/ 50% (五十五)当网络隔离将集群正好分成两半时。 因此,对于偶数个节点,我们添加 法定设备 是一个要求不高的守护进程,可以在第三个数据中心的最便宜的虚拟机上启动。 他将票投给其中一个片段(他看到的),从而解决了 50%/50% 的不确定性。 我命名了将启动仲裁设备的服务器 见证 (repmgr 的术语,我喜欢它)。
资源可以从一个地方移动到另一个地方,例如,从有故障的服务器到健康的服务器,或者根据系统管理员的命令。 以便客户知道他们需要的资源位于哪里(连接到哪里?), 浮动IP (浮动IP)。 这些是 Pacemaker 可以在节点之间移动的 IP(一切都在平面网络上)。 它们中的每一个都象征着一种资源(服务),并将位于您需要连接才能访问该服务的位置(在我们的例子中是数据库)。
Tuchanka1(压缩电路)
产品管理
我们的想法是,我们有很多低负载的小型数据库,为此维护一个热备模式的专用从服务器用于只读事务是无利可图的(没有必要如此浪费资源)。
每个数据中心有一台服务器。 每台服务器都有两个 PostgreSQL 实例(在 PostgreSQL 术语中,它们被称为集群,但为了避免混淆,我将它们称为实例(与其他数据库类比),而我只会将 Pacemaker 集群称为集群)。 一个实例运行在master模式,只有它提供服务(只有浮动IP通向它)。 第二个实例作为第二个数据中心的从属实例,仅在其主实例发生故障时才提供服务。 由于大多数时候只有两个实例(主实例)中的一个会提供服务(执行请求),因此所有服务器资源都会针对主实例进行优化(内存分配给shared_buffers缓存等),但这样第二个实例在其中一个数据中心发生故障的情况下,还拥有足够的资源(尽管通过文件系统缓存进行次优操作)。 在集群正常运行期间,Slave不提供服务(不执行只读请求),这样就不会与同一台机器上的Master争夺资源。
在两个节点的情况下,容错只能通过异步复制实现,因为通过同步复制,从站的故障将导致主站的停止。
未能见证
未能见证(法定设备)我只会考虑 Tuchanka1 集群,对于所有其他集群来说,情况都是一样的。 如果见证失败,集群结构不会发生任何变化,一切都将继续以原来的方式工作。 但法定人数将变为 2 中的 3,因此任何后续故障对于集群来说都将是致命的。 它仍然需要紧急修复。
图昌卡1 拒绝
Tuchanka1 的一个数据中心发生故障。 在这种情况下 见证 将其投票给第二个数据中心的第二个节点。 在那里,以前的从站变成了主站,因此,两个主站都在同一台服务器上工作,并且它们的两个浮动IP都指向它们。
图昌卡2(古典)
产品管理
两个节点的经典方案。 主人在其中之一工作,奴隶在第二个上工作。 两者都可以执行请求(从机是只读的),因此两者都由浮动 IP 指向:krogan2 是主机,krogan2s1 是从机。 主从机都会有容错能力。
在两个节点的情况下,容错只能通过异步复制实现,因为同步复制时,slave的故障会导致master的停止。
图昌卡2 拒绝
如果其中一个数据中心发生故障 见证 投票给第二个。 在唯一工作的数据中心上,主站将被提升,并且两个浮动IP将指向它:主站和从站。 当然,实例必须配置为具有足够的资源(连接限制等)以同时接受来自主从浮动IP的所有连接和请求。 也就是说,在正常操作期间,它应该有足够的限制供应。
Tuchanka4(许多奴隶)
产品管理
已经是另一个极端了。 有些数据库会收到大量只读请求(高负载站点的典型情况)。 Tuchanka4 是一种可能有三个或更多从站来处理此类请求的情况,但仍然不会太多。 由于从站数量非常多,因此有必要发明分层复制系统。 在最小情况下(如图所示),两个数据中心各有两台服务器,每台服务器都有一个 PostgreSQL 实例。
该方案的另一个特点是已经可以组织一次同步复制。 如果可能,它被配置为复制到另一个数据中心,而不是复制到与主数据中心相同的数据中心的副本。 主站和每个从站都由一个浮动IP指向。 幸运的是,在从属之间有必要以某种方式平衡请求 SQL代理,例如,在客户端。 不同类型的客户可能需要不同的类型 SQL代理,并且只有客户端开发人员知道谁需要哪个。 该功能可以通过外部守护程序或客户端库(连接池)等来实现。 所有这些都超出了故障转移数据库集群(故障转移 SQL代理 可以独立实现,与客户端容错一起实现)。
图昌卡4 拒绝
如果一个数据中心(即两台服务器)发生故障,见证人将投票支持第二个数据中心。 这样一来,第二个数据中心就有两台服务器在运行:一台运行master,master浮动IP指向它(用于接收读写请求);另一台运行master,master浮动IP指向它(用于接收读写请求); 在第二台服务器上有一个运行同步复制的从属服务器,并且其中一个从属浮动 IP 指向它(用于只读请求)。
首先要注意的是,并非所有从属浮动 IP 都会成为工作人员,而只有一个。 为了正确地使用它,有必要 SQL代理 将所有请求重定向到仅存的浮动IP; 而如果 SQL代理 否,那么您可以在连接 URL 中列出所有以逗号分隔的浮动 IP 从站。 在这种情况下,与 库 连接将连接到第一个工作 IP,这是在自动测试系统中完成的。 也许在其他库中,例如 JDBC,这将不起作用并且是必要的 SQL代理。 这样做是因为禁止在一台服务器上同时提高从属服务器的浮动 IP,以便在有多个从属服务器运行时,它们会均匀地分布在从属服务器之间。
第二:即使在数据中心发生故障的情况下,也会保持同步复制。 并且即使发生二次故障,即剩余数据中心的两台服务器之一发生故障,集群虽然会停止提供服务,但仍会保留所有已提交确认的已提交事务的信息(二次故障不会有丢失信息)。
Tuchanka3(3 个数据中心)
产品管理
这是一个集群,适用于具有三个功能齐全的数据中心的情况,每个数据中心都有一个功能齐全的数据库服务器。 在这种情况下 法定设备 不需要。 一个数据中心由主站负责,另外两个数据中心由从站负责。 复制是同步的,类型ANY(slave1,slave2),即当任何一个slave第一个响应他已接受提交时,客户端都会收到提交确认。 资源由主设备的 4 个浮动 IP 和从设备的 XNUMX 个浮动 IP 表示。 与 TuchankaXNUMX 不同,所有三个浮动 IP 都是容错的。 要平衡只读 SQL 查询,您可以使用 SQL代理 (具有单独的容错功能),或者将一个从浮动 IP 分配给一半客户端,将另一半分配给第二个客户端。
图昌卡3 拒绝
如果其中一个数据中心发生故障,则剩下两个。 在第一种情况下,主设备和来自主设备的浮动 IP 被提升,在第二种情况下,从设备和两个从设备浮动 IP 都被提升(实例必须具有双重资源保留,以便接受来自两个从设备浮动 IP 的所有连接)。 主从之间的同步复制。 此外,当两个数据中心被破坏时(如果它们不是同时被破坏),集群将保存已提交和确认的事务信息(不会丢失信息)。
我决定不包含文件结构和部署的详细描述。 任何想要尝试的人都可以阅读 README 中的全部内容。 我只是提供自动化测试的描述。
自动测试系统
为了通过模拟各种故障来测试集群的容错能力,创建了自动测试系统。 通过脚本启动 test/failure
。 该脚本可以将要测试的集群数量作为参数。 例如这个命令:
test/failure 2 3
将仅测试第二个和第三个集群。 如果未指定参数,则将测试所有集群。 所有集群都会并行测试,结果显示在 tmux 面板中。 Tmux 使用专用的 tmux 服务器,因此可以从默认 tmux 下运行脚本,从而产生嵌套的 tmux。 我建议在大窗口中使用小字体的终端。 在测试开始之前,所有虚拟机都会回滚到脚本完成时的快照 setup
.
终端根据正在测试的集群数量分为几列;默认情况下(在屏幕截图中)有四个。 我将使用 Tuchanka2 的示例来描述各列的内容。 屏幕截图中的面板已编号:
- 此处显示测试统计数据。 列:
- 失败 — 模拟故障的测试(脚本中的函数)的名称。
- 反应 — 集群恢复其功能的算术平均时间(以秒为单位)。 它是从模拟故障的脚本开始到集群恢复其功能并能够继续提供服务的那一刻进行测量的。 如果时间很短,例如六秒(这种情况发生在有多个从站(Tuchanka3和Tuchanka4)的集群中),这意味着故障在异步从站上,并且不会以任何方式影响性能;没有集群状态切换。
- 偏差 — 显示值的分布(准确性) 反应 使用标准差法。
- 数 — 该测试进行了多少次。
- 简短的日志允许您评估集群当前正在执行的操作。 显示迭代(测试)编号、时间戳和操作名称。 运行时间太长(> 5 分钟)表明存在问题。
- 心 (心)- 当前时间。 用于视觉评估性能 主 使用浮动 IP 主站将当前时间不断写入其表中。 如果成功,结果将显示在此面板中。
- 打 (pulse) - “当前时间”,之前由脚本记录 心 掌握,现在阅读 奴隶 通过其浮动IP。 允许您直观地评估从属和复制的性能。 Tuchanka1中没有浮动IP的从站(没有提供服务的从站),但是有两个实例(DB),所以这里不会显示 打和 心 第二审。
- 使用该实用程序监控集群运行状况
pcs mon
。 显示节点间的结构、资源分布以及其他有用信息。 - 此处显示集群中每个虚拟机的系统监控。 根据集群拥有的虚拟机数量,可能会有更多这样的面板。 两张图 CPU负载 (虚拟机有两个处理器)、虚拟机名称、 系统负载 (之所以称为“平均负载”,是因为它是 5 分钟、10 分钟和 15 分钟的平均值)、进程数据和内存分配。
- 执行测试的脚本的跟踪。 如果发生故障 - 操作突然中断或无休止的等待周期 - 您可以在此处查看此行为的原因。
测试分两个阶段进行。 首先,该脚本会进行所有类型的测试,随机选择要应用此测试的虚拟机。 然后进行无限循环的测试,每次都是随机选择虚拟机和故障。 测试脚本突然终止(底部面板)或等待某件事的无限循环(一项操作的执行时间> 5 分钟,这可以在跟踪中看到)表明该集群上的某些测试已失败。
每个测试由以下操作组成:
- 启动模拟故障的功能。
- 准备好了? — 等待集群恢复(当所有服务都提供时)。
- 显示集群恢复超时(反应).
- 固定 — 集群正在“修复”。 之后,它应该返回到完全运行状态并为下一次故障做好准备。
以下是测试列表,并描述了它们的作用:
- 叉子炸弹:使用叉子炸弹制造“内存不足”。
- 太空之外: 硬盘已满。 但测试相当具有象征意义;由于测试过程中产生的负载微不足道,因此当硬盘驱动器已满时,PostgreSQL通常不会失败。
- Postgres-KILL: 使用命令杀死 PostgreSQL
killall -KILL postgres
. - Postgres-STOP: 挂起 PostgreSQL 命令
killall -STOP postgres
. - 关机:使用命令“断电”虚拟机
VBoxManage controlvm "виртуалка" poweroff
. - 重设:使用命令使虚拟机超载
VBoxManage controlvm "виртуалка" reset
. - SBD停止:使用命令暂停 SBD 恶魔
killall -STOP sbd
. - 关机:通过SSH向虚拟机发送命令
systemctl poweroff
,系统正常关闭。 - UNLINK:网络隔离、命令
VBoxManage controlvm "виртуалка" setlinkstate1 off
.
使用标准 tmux 命令“kill-window”完成测试 Ctrl-b &,或“分离客户端”命令 Ctrl-b d:至此测试结束,tmux关闭,虚拟机关闭。
测试过程中发现的问题
-
目前, 看门狗恶魔sbd 致力于停止观察到的守护进程,但不冻结它们。 因此,仅导致冻结的故障 科罗同步 и 起搏器,但不悬挂 SBD... 用于检查 科罗同步 已经有了
PR#83 (在 GitHub 上 SBD) , 接受到线程 主。 他们承诺(在 PR#83 中)Pacemaker 会有类似的东西,我希望通过 Redhat xnumx 会做。 但这种“故障”是推测性的,可以很容易地进行人工模拟,例如:killall -STOP corosync
,但在现实生活中从未见过面。 -
У 起搏器 在版本中 CentOS 7的 设置不正确 同步超时 у 法定设备, 因此
如果一个节点发生故障,第二个节点有可能也会重新启动 ,主人应该移动到那里。 扩大治愈 同步超时 у 法定设备 部署期间(在脚本中setup/setup1
)。 此修改未获开发商接受 起搏器相反,他们承诺以这样的方式(在某个未指定的未来)重新设计基础设施,以便自动计算超时。 -
如果数据库配置指定
LC_MESSAGES
(文本消息)可以使用 Unicode,例如ru_RU.UTF-8
,然后在启动时 Postgres的 在语言环境不是 UTF-8 的环境中,例如在空环境中(此处 起搏器+数据库管理系统(paf) 运行 Postgres的) 然后日志将包含问号而不是 UTF-8 字母 。 PostgreSQL 开发人员尚未就这种情况下该怎么做达成一致。 需要付费,需要安装LC_MESSAGES=en_US.UTF-8
配置(创建)数据库实例时。 -
如果设置了wal_receiver_timeout(默认为60s),则在tuchanka3和tuchanka4集群中的master上进行PostgreSQL-STOP测试期间
复制不会重新连接到新的主服务器 。 那里的复制是同步的,所以不仅slave停止了,新的master也停止了。 通过在配置 PostgreSQL 时设置 wal_receiver_timeout=0 来解决此问题。 -
有时,我在 ForkBomb 测试中观察到 PostgreSQL 中的复制冻结(内存溢出)。
ForkBomb 之后,有时从站可能无法重新连接到新的主站 。 我只在tuchanka3和tuchanka4集群中遇到过这种情况,其中master由于同步复制而冻结。 很长一段时间(大约两个小时)后问题自行消失。 需要更多的研究来纠正这个问题。 这些症状与之前的错误类似,虽然是由不同的原因引起的,但具有相同的后果。
克洛根图片取自
来源: habr.com