1. 为什么边缘场景需要一套“不贵”的高可用方案
先聊个背景。我在生产环境里接触过不少物联网边缘项目,它们的数据库部署形态和互联网机房里的典型架构差别非常大。边缘机房通常只有几个节点,网络条件没有数据中心那么可靠,带宽也有限,很多时候还只有一个机柜的物理空间。在这种条件下,指望标准的三节点甚至五节点分布式数据库集群并不现实,资源浪费太大,运维成本也扛不住。但边缘业务对数据连续性的要求一点不比中心机房低——生产线的SCADA系统、园区能源管理平台、智慧水务的采集网关,任何一端的数据库宕机,直接意味着采集链路中断、历史数据出现空洞,严重的还会影响控制回路。
所以双节点高可用在边缘场景是刚需。但双节点方案有个绕不开的难题:怎么保证两个节点上的数据是一致的,同时故障切换的时候又不丢数据、不产生脑裂。
我这次要分享的方案组合是KaiwuDB + DRBD + Pacemaker。KaiwuDB 是一款面向工业物联网、能源物联网场景的分布式时序数据库,支持 SQL,具备时序数据压缩、级联采集、边云协同这些能力,单机版在边缘侧部署非常轻量。DRBD 负责在块设备层面对数据库的数据目录做实时镜像复制,Pacemaker 负责资源管理和故障切换。这套组合在边缘场景里跑下来,整体表现是稳的,而且成本很低——两台 x86 服务器加一张网卡就能起步,相比存储阵列或者全分布式数据库,投入不是一个量级。
文章会分成几个部分:先讲清楚这套方案的架构思路和技术选型逻辑,然后把 DRBD、Pacemaker、KaiwuDB 三者之间如何衔接讲透,接着给出完整的部署步骤和配置内容,再分享故障切换的实测结果和我在真实环境里遇到过的坑。如果你也在做边缘侧数据库的高可用设计,这篇文章可以直接当作业抄。
2. 整体架构设计思路与技术选型
2.1 双节点高可用在边缘场景的特殊性
在设计这套方案之前,我先把边缘场景对高可用方案的约束条件列出来。边缘机房对成本和空间极度敏感,所以第一约束是节点数量不能多,两台是上限;第二约束是硬件不能太特殊,不能用 FC 存储交换机这类专用设备,因为现场没有这个条件;第三约束是网络不能假设太好,边缘机房到中心机房的链路经常不稳定,但两个节点之间的内网链路倒是可控的,可以走千兆甚至万兆。
基于这些约束,双节点高可用的核心思路就清晰了:数据层面,必须保证两个节点的本地数据尽量实时一致,这样任意一个节点宕机,另外一个节点可以立即接管;应用层面,需要有一个集群管理器来监控资源状态、决定节点角色、在故障时触发切换,同时要防止两个节点同时认为自己是主节点。
这里我先解释一个很多人容易混淆的点:双节点高可用不等于集群数据库。KaiwuDB 本身是支持分布式部署的,但在边缘场景里,我更倾向于先用单机模式部署,再在操作系统层面用 DRBD 和 Pacemaker 把两台机器“粘”成一个高可用对外整体。为什么这么做?因为分布式模式对节点间网络稳定性要求更高,边缘机房如果两个节点之间的心跳网络出现闪断,分布式数据库内部的选举和同步机制会产生大量的重试和告警,反而增加了运维负担。而 DRBD + Pacemaker 是操作系统层面的成熟方案,故障域更小,行为更可控,切换时间也更短——实测下来秒级切换完全做得到。
2.2 为什么要选 DRBD 而不是分布式存储或主从复制
在数据库高可用方案里,数据同步有几种主流选择:数据库自带的复制功能、分布式存储(比如 Ceph)、块设备层面的实时镜像。我逐个说一下为什么最终选了 DRBD。
数据库自带复制,比如 MySQL 的半同步复制、PostgreSQL 的流复制,确实可以做到数据库层面的副本一致。但问题是,这种方式和具体数据库的版本、配置、运维经验强绑定。KaiwuDB 本身包含多个数据组件、元数据组件和时序引擎组件,如果要在数据库层面梳理清楚主备之间的数据流向,我需要逐一确认引擎内部的数据落盘方式,复杂度完全不亚于写一套新的复制逻辑。而且边缘现场的运维人员,你让他去理解数据库内部的复制机制,远不如让他理解“两个硬盘内容一模一样”来得直观。
分布式存储的问题更直接——重。部署 Ceph 至少要三台 mon 节点、一组 OSD,配置和管理复杂度在边缘场景完全是负担。而且 Ceph 自带网络内复制,本来就是为了云平台这种大规模虚拟化场景设计的,在双节点场景下属于杀鸡用牛刀,延迟还高。
DRBD 的本质是 Linux 内核里的一个块设备驱动,它把两台机器上的裸设备、分区或者 LVM 逻辑卷做镜像同步。应用程序写入主节点 DRBD 设备的每一个数据块,都会同时复制到备节点的对应设备上。对于数据库进程来说,它根本感知不到自己在往一块“被镜像”的磁盘上写数据,进程看到的只是一块普通的块设备。这样带来的最大好处是,无论 KaiwuDB 内部有多少种数据文件、WAL 文件、元数据文件,只要它们都落在 DRBD 设备上,数据的实时一致性就由 DRBD 保证了,不需要我去关心 KaiwuDB 内部每个文件什么时候落盘、怎么同步。
2.3 Pacemaker 在角色协商中承担的职责
DRBD 解决了数据一致性的问题,但还没有解决“主备角色由谁来定”的问题。两个节点上的 DRBD 设备都需要能被挂载,但同一时刻只有主节点允许挂载和读写;主节点如果宕机,需要有一个机制让备节点自动提升为主节点并挂载文件系统,再拉起 KaiwuDB 服务。这个协调和决策的工作交给 Pacemaker。
Pacemaker 是一个集群资源管理器,它和 Corosync 这个底层通信组件配合工作。Corosync 负责在两个节点之间传递心跳消息和集群成员信息,Pacemaker 则是基于这些信息做出决策——谁在集群里、谁失联了、某个资源当前应该运行在哪台节点上。Pacemaker 的资源管理模型里,这些资源可以是 IP 地址、文件系统挂载点、LVM 逻辑卷,也可以是 systemd 服务,还可以是一个简单的 shell 脚本。我要做的就是把 DRBD 设备、LVM 卷、文件系统挂载、KaiwuDB 服务这四类资源统统交给 Pacemaker 管理,并配置好它们之间的启动顺序和共置约束。
整个架构跑起来之后,数据流的走向是这样的:KaiwuDB 进程写入数据到挂载点下的文件,落盘到 LVM 逻辑卷,逻辑卷底层是 DRBD 设备,DRBD 内核模块把数据块同步到备机的 DRBD 设备上。备机虽然不挂载文件系统,但它的 DRBD 设备上已经存在了和主节点完全相同的数据块。一旦主节点故障,Pacemaker 在备机上依次完成 DRBD 提升、逻辑卷激活、文件系统挂载、KaiwuDB 服务启动这几步,同时把 VIP 漂移到备机,客户端连接使用相同的 IP,完全无感知。
2.4 这套方案的优势与边界条件
这套方案的优势总结下来有四点。第一是硬件要求低,两台普通服务器加两块千兆网卡就能跑,不需要共享存储;第二是切换对应用透明,KaiwuDB 进程层面无感知,数据零丢失;第三是运维模型简单,数据一致性由 DRBD 保证、资源调度由 Pacemaker 保证,不需要额外开发脚本;第四是在工业物联网场景里,客户对 Linux 下的 DRBD 和 Pacemaker 普遍有认识,审计和验收时容易讲清楚。
但边界条件也要说清楚。这套方案保护的是“服务器宕机、数据库进程异常、操作系统崩溃”这类节点级故障,不保护“数据文件被误删除”这类逻辑错误——如果有人在主节点上执行了删除命令,这个删除动作会被 DRBD 同步到备节点,两边的数据都会受影响。所以这类方案必须搭配定期备份和监控告警。另外,双节点方案里的脑裂问题需要刻意防护,具体怎么做我放在后面单独讲。
3. 核心组件原理拆解
3.1 DRBD 的同步机制详解
DRBD 的原理可以类比成“网卡级别的 RAID-1”。RAID-1 是把一个数据块同时写到同一台机器里的两块硬盘上,DRBD 则是把数据块写到两台不同机器的本地盘上。为了实现这个能力,DRBD 在内核里注册了一个新的块设备驱动,你会在 /dev 下看到 drbd 设备,比如 /dev/drbd0。上层文件系统对这个设备做读写时,DRBD 驱动会在本地执行 I/O 的同时,把同样的写请求通过 TCP 连接发送到对端节点,对端节点的 DRBD 驱动把数据写到它自己的本地存储上。
DRBD 有两种核心工作模式:同步和异步。异步模式下,主节点本地写盘成功后立即返回应用写入成功,数据块在后台发送到备机,所以主备之间可能有短暂的数据不一致窗口;同步模式下,主节点要等备机确认数据已经写入成功之后,才向应用层返回写成功,因此两边的数据始终一致,代价是写延迟会叠加一次内网网络往返的时间。边缘场景采集数据的特点是持续写入但单次写入量不是特别大,而且我们要保证故障切换时不丢数据,所以必须采用同步模式。
DRBD 把复制协议的等级分成了 A、B、C 三档。协议 A 是异步模式,协议 B 是半同步,协议 C 是同步模式。我用的就是协议 C。内网延迟在 0.1ms 级别的条件下,协议 C 带来的额外写延迟几乎可以忽略。
另一个需要理解的概念是 DRBD 的三种资源角色:Primary、Secondary、Primary 的退化状态。主节点上的 DRBD 资源处于 Primary 状态,可以挂载文件系统并对外提供读写;备节点上的 DRBD 资源处于 Secondary 状态,不可挂载,它只是默默地接收主节点传来的数据块。当主节点故障时,备节点的 DRBD 资源需要从 Secondary 提升为 Primary。DRBD 支持两种提权方式:手动提权和自动提权。
自动提权依赖 DRBD 的断开/连接策略和 quorum 概念,具体行为由配置参数控制。在 Pacemaker 环境中更常见的做法是:不把 DRBD 的自动提权功能当作第一依赖,而是由 Pacemaker 在故障切换流程中按顺序执行提权操作。这样的好处是切换流程的所有步骤都能被 Pacemaker 感知、记录和审计。
3.2 Pacemaker 的资源管理模型
Pacemaker 的基本操作单位叫做资源(resource),一个资源可以是一个 IP 别名、一个文件系统挂载项、一个 LVM 逻辑卷、一个 systemd 服务等。资源之间通过约束(constraint)建立关系,约束分为三种:顺序约束决定资源启动的先后次序,共置约束决定资源必须运行在同一个节点上,位置约束决定资源在正常情况下倾向于在哪个节点运行。
这套方案里我需要定义这些资源:
- DRBD 资源:名字可以叫 kaiwu_drbd,类型为 ocf:linbit:drbd,作用是让 DRBD 设备在线、资源对连接
- LVM 资源:名字叫 kaiwu_lvm,类型为 ocf:heartbeat:LVM,作用是在节点上激活卷组
- 文件系统资源:名字叫 kaiwu_fs,类型为 ocf:heartbeat:Filesystem,作用是把逻辑卷挂载到 /data/kaiwu 目录
- IP 资源:名字叫 kaiwu_vip,类型为 ocf:heartbeat:IPaddr2,作用是绑定 VIP 到当前主节点的网卡上
- 服务资源:名字叫 kaiwu_service,类型为 systemd:kaiwu,作用是启动和停止 KaiwuDB 的系统服务
约束配置上,我会把所有资源做成一个资源组(group),组内的资源强制要求按顺序启动、全部同节点运行。资源组的定义方式是把多个资源放进同一个 group 里,Pacemaker 自动为它们建立顺序和共置关系。这比手动写多条约束要简单得多,而且在后面的故障排查里更容易看清依赖关系。
Pacemaker 有一个和双节点场景强相关的概念叫 fence(隔离、仲裁)。在双节点集群中,如果两个节点之间的心跳联系中断了,两个节点都会怀疑对方已经死了,这时候如果没有一个“裁判”来阻止双方都去抢占资源,就会出现两个节点同时以 Primary 状态挂载 DRBD 设备、同时启动 KaiwuDB 服务的情况——这就是脑裂。在双节点场景里,脑裂最危险的部分不在于 DRBD 两边数据不一致,而在于两个数据库进程同时对外提供写入服务,会彻底破坏数据一致性。
Pacemaker 的典型做法是配置 fence 设备,在确认节点失联后强制把对方节点的电源关掉或者去激活对方的共享存储。但边缘场景没有 IPMI 带外管理的情况很常见,所以还有一种折中方案是配置 SBD 存储隔离,利用共享块设备上的仲裁区来做决策。不过即使没有带外管理,DRBD 本身也提供了一种 fencing 机制——fence-peer 和 unfence-peer,配合 Pacemaker 的 stonith 可以让失联节点上的 DRBD 资源自动退化,这个概念在下面的部署里会具体出现。
3.3 KaiwuDB 在这套架构中的角色与数据落盘路径
KaiwuDB 作为数据库层,在这套方案里不需要感知集群的存在,它就是一个单机数据库实例。需要关心的是它的数据文件存储在哪里,以及它怎么和文件系统打交道。
KaiwuDB 的数据目录包括数据文件、WAL 预写日志、临时文件和配置文件。我在部署的时候把整个数据目录都放在 DRBD 设备上。数据库进程启动时读写数据文件的路径完全落在 DRBD 块设备映射的文件系统上,所以 KaiwuDB 本身不需要做任何高可用相关的配置,它的所有数据变更都会在块设备层被 DRBD 复制到备机。
这里有一个关键点:KaiwuDB 在启动时会检查数据目录的状态,包括 WAL 是否存在、数据文件是否完整。如果主节点故障时某些数据还没有来得及由数据库进程自己刷盘,但这些数据可能已经被 DRBD 同步到备机了,因为 DRBD 工作在块设备层,它复制的是所有写入块设备的数据块,比数据库层面的事务提交状态更底层。结果就是,即使数据库进程崩溃了,只要 DRBD 已经同步了对应的块,备机接管后依然能拿到这些数据。
但要提醒的是:DRBD 同步的是块设备写操作,不保证上层文件系统事务的完整性。如果主节点在写入文件系统元数据的过程中突然断电,DRBD 上备机拿到的块副本可能对应的是一个中间状态的文件系统。所以在故障切换流程里,一定要做文件系统日志的重建。我们的环境里用的是 ext4 文件系统,在挂载时它能够自动回放日志,所以实际切换后不会有文件系统层面的损坏问题。更好的选择是 xfs,它在意外掉电后的恢复能力也很强。我在生产环境里用的是 xfs,这个选择在后文的部署章节会体现。
4. 环境规划与完整部署实录
4.1 节点与网络规划
我先列出实验和生产共用的部署环境信息。两个节点的主机名和 IP 规划如下:
| 节点 | 主机名 | 管理 IP | DRBD 专用 IP | 角色 |
|---|---|---|---|---|
| 节点1 | kaiwu-node1 | 192.168.100.11 | 10.10.10.1 | 初始主节点 |
| 节点2 | kaiwu-node2 | 192.168.100.12 | 10.10.10.2 | 初始备节点 |
| VIP | kaiwu-vip | 192.168.100.20 | - | 对外服务 IP |
管理 IP 用于集群通信、SSH 和客户端访问;DRBD 专用 IP 用于数据同步流量,建议走独立的物理网卡或者至少独立 VLAN,避免和管理流量互相抢占带宽。我这里两台机器都是双网卡,一条千兆内网走管理,一条万兆走 DRBD 同步,数据同步延迟实测下来非常低。
存储规划上,我在每台机器上准备了一块独立的 SSD 作为 DRBD 底层存储,不需要做 RAID,因为 DRBD 本身就是最底层的冗余。整个磁盘划分如下:
- /dev/sda:系统盘,安装操作系统
- /dev/sdb:DRBD 底层盘,后续做 LVM 卷组,在这上面创建逻辑卷给 KaiwuDB 用
两个节点上的底层盘大小和型号最好一致,DRBD 同步的速度和容量匹配度会好很多。如果两块盘容量不一致,DRBD 按较小容量创建资源,剩下的空间浪费,这一点规划硬件的时候就要注意。
4.2 操作系统与基础依赖
我的两个节点都是 CentOS 7.9 或者兼容的 Linux 发行版。需要先做几个基础调整:关闭防火墙或者放行指定端口,禁用 SELinux(或者配置好 SELinux 策略),配置好主机名解析,让两个节点能通过主机名互相访问。
DRBD 和 Pacemaker 的安装包在 EPEL 源和高可用源里都有。CentOS 7 的安装命令大概是:
yum install -y epel-release yum install -y drbd84-utils kmod-drbd84 yum install -y pacemaker pcs corosync fence-agents-all以 DRBD 8.4 为例,加载内核模块后确认一下模块是否存在:
modprobe drbd lsmod | grep drbd对 Ubuntu/Debian 系的系统,命令类似:
apt install -y drbd-utils pacemaker pcs corosyncCentOS 7 里 pcs 是最常用的集群管理工具,它的作用是提供命令行接口来配置 Corosync 和 Pacemaker。KaiwuDB 所在的服务器需要安装的依赖很少,主要是 glibc、libnuma 这些基础库,官方文档里有详细清单,按照文档装好即可。
4.3 DRBD 资源配置与初始化
我先规划好名字:DRBD 资源名就叫 r0,对应的块设备是 /dev/drbd0。配置文件在 /etc/drbd.d/ 目录下,先写入全局配置,再写入资源定义。
/etc/drbd.d/global_common.conf 里的核心设置:
global { usage-count no; } common { protocol C; disk { fencing resource-only; } net { cram-hmac-alg sha1; shared-secret "kaiwu-edge-hA"; after-c 0; max-buffers 8192; max-epoch-size 2048; sndbuf-size 1024k; rcvbuf-size 1024k; } syncer { rate 200M; verify-alg crc32c; } }几个关键参数解释一下。protocol C 就是前面说的同步复制协议。cram-hmac-alg 配置的是 DRBD 节点之间认证算法,shared-secret 就相当于两个节点约定的口令。syncer rate 是数据同步时的带宽上限,这里给 200M 是为了避免同步流量把网卡打满;如果底层盘很大,可以适当调高。
资源定义文件 /etc/drbd.d/r0.res:
resource r0 { on kaiwu-node1 { device /dev/drbd0; disk /dev/sdb; address 10.10.10.1:7788; meta-disk internal; } on kaiwu-node2 { device /dev/drbd0; disk /dev/sdb; address 10.10.10.2:7788; meta-disk internal; } }这里的 address 是 DRBD 专用 IP 和端口号,两个节点要对端配对。meta-disk internal 表示 DRBD 的元数据放在磁盘内部,不需要单独划一个分区。
两个节点都配置完成后,先初始化元数据,再启动资源:
drbdadm create-md r0 systemctl start drbd drbdadm up r0初始化完元数据后,把节点1的设备设为 Primary 并创建文件系统:
drbdadm primary r0 --force mkfs.xfs /dev/drbd0 mkdir -p /data/kaiwu mount /dev/drbd0 /data/kaiwu这一步执行完,节点1上的 /dev/drbd0 已经是可读写的 xfs 文件系统了。另一个节点此刻应该能看到同步状态,可以通过 cat /proc/drbd 或者 drbdadm status r0 查看同步进度。
4.4 LVM 逻辑卷与 KaiwuDB 数据目录绑定
DRBD 设备可以直接在上面创建文件系统使用,但我建议还是叠加一层 LVM。原因有两个:一是后续如果需要扩容,用逻辑卷比直接对整块磁盘做 mkfs 要方便;二是 KaiwuDB 的数据目录和日志目录可以分开挂载,便于做独立的 I/O 限制和监控。
在 Primary 节点上创建 LVM 逻辑卷,卷组名字我叫 vg_kaiwu,逻辑卷名字叫 lv_kaiwu:
pvcreate /dev/drbd0 vgcreate vg_kaiwu /dev/drbd0 lvcreate -L 800G -n lv_kaiwu vg_kaiwu mkfs.xfs /dev/vg_kaiwu/lv_kaiwu注意:LVM 的物理卷元数据也需要被 DRBD 同步,而 DRBD 只支持一层,所以在两个节点上的 LVM 操作只需要在某个时刻执行一次。所有节点上都会看到相同的 PV/VG/LV 信息,因为块的复制是整盘粒度的,LVM 元数据也在被复制的范围内。
创建好逻辑卷后,在 /data/kaiwu 目录下挂载逻辑卷:
mount /dev/vg_kaiwu/lv_kaiwu /data/kaiwu然后下载并解压 KaiwuDB 的安装包,把数据目录初始化到 /data/kaiwu 下。KaiwuDB 的部署方法官方有文档,核心步骤是创建 kaiwu 用户、把安装目录和数据目录属主改成 kaiwu、按照模板配置 kaiwu.conf 文件里的存储路径指向 /data/kaiwu。之后用 systemd 管理 KaiwuDB 服务:
cp kaiwu.service /etc/systemd/system/ systemctl daemon-reload systemctl start kaiwu为了确认 KaiwuDB 真的把数据写到 DRBD 设备了,可以用 blkid 和 df 验证挂载路径,也可以通过写入一条测试数据后,在备机上查看 DRBD 底层盘的数据变化。实测中我直接在 KaiwuDB 里建表插入数据,备机的 /proc/drbd 里可以看到主备之间的数据包计数在增长,就说明同步链路完整。
4.5 Pacemaker 集群初始化
先配置集群软件本身。pcs 的配置方式在 CentOS 7 里是:
systemctl start pcsd systemctl enable pcsd passwd hacluster pcs cluster auth kaiwu-node1 kaiwu-node2 -u hacluster -p yourpassword pcs cluster setup --name kaiwu_cluster kaiwu-node1 kaiwu-node2 pcs cluster start --all pcs cluster enable --all这里用到的 hacluster 用户是 pcs 用来管理集群的系统用户,设置好密码之后才能在两个节点之间建立信任。
然后确认集群在线状态:
pcs status正常输出里应该显示两个节点都在线,Corosync 通信正常,Pacemaker 在运行。接下来才是重头戏——把 Pacemaker 的集群属性调成适合双节点并且适合 DRBD 的模式。
因为我用的是 DRBD,我对集群做了两个重要设置:
pcs property set stonith-enabled=false pcs property set no-quorum-policy=ignore这两个设置新手看到容易慌。先说明:stonith-enabled 设置为 false 是因为我没有配置独立的 fence 设备,脑裂的防护交给 DRBD 自己的 couple 机制去处理,也就是前面配置里的 fencing resource-only。no-quorum-policy=ignore 是因为双节点集群在正常情况下只有两票,如果按默认 quorum 规则,两台需要至少两台存活才有法定票数,这样一台宕机集群就完全瘫痪了,不符合高可用预期。所以在双节点环境下,设置成 ignore 让单节点也能继续运行资源和提供服务。
这里有一个坑要提醒:关掉 stonith 意味着如果两个节点真脑裂了,没有物理手段强制某个节点断电,所以一定要保证 DRBD fencing 配置是有效的。我在生产环境里宁可多配置一层 SBD 隔离也不会裸奔,但受限于篇幅,这套方案里我默认 DRBD 的 fencing 足够应对常见故障场景。
4.6 定义集群资源组
资源组的定义顺序非常重要,前面的资源必须先于后面启动。Pacemaker 资源组里的资源按声明顺序启动,按相反顺序停止。所以我的声明顺序就是 DRBD 先、LVM 次之、文件系统第三、VIP 第四、KaiwuDB 服务最后。
先创建 DRBD 资源:
pcs resource create kaiwu_drbd ocf:linbit:drbd drbd_resource=r0 \ promotable clone=true这里用到了 promotable clone 类型。DRBD 资源在 Pacemaker 里不是一个普通资源,它需要支持主备两个角色,并且要保证一台节点上是 Primary、另一台上是 Secondary。Pacemaker 管这种资源叫做多状态资源或可升级克隆资源。声明成 promotable clone 后,Pacemaker 就自动遵守 DRBD 的主备约束。
然后创建 LVM 资源、文件系统资源、VIP 资源和服务资源:
pcs resource create kaiwu_lvm ocf:heartbeat:LVM \ volgrpname=vg_kaiwu exclusive=true \ --group kaiwu_group pcs resource create kaiwu_fs ocf:heartbeat:Filesystem \ device=/dev/vg_kaiwu/lv_kaiwu directory=/data/kaiwu fstype=xfs \ --group kaiwu_group pcs resource create kaiwu_vip ocf:heartbeat:IPaddr2 \ ip=192.168.100.20 cidr_netmask=24 \ --group kaiwu_group pcs resource create kaiwu_service systemd:kaiwu \ op monitor interval=30s \ --group kaiwu_group以及把多个资源组成组,使用如下方式:
pcs resource group add kaiwu_group kaiwu_drbd_clone pcs resource group add kaiwu_group kaiwu_lvm pcs resource group add kaiwu_group kaiwu_fs pcs resource group add kaiwu_group kaiwu_vip pcs resource group add kaiwu_group kaiwu_service注意这里有个细节:DRBD 资源是一个 promotable clone,它作为一个整体被放进资源组,但组内启动顺序是 DRBD 的逻辑先就绪。Pacemaker 会自动等待 DRBD 资源变成 Primary 之后才启动同组内的后置资源。
全部定义完成后,用pcs resource config看看输出,检查每项参数是否和预期相符。pcs status里应该能看到资源当前跑在节点1上,VIP 和 KaiwuDB 服务都正常。
4.7 KaiwuDB 服务的 systemd 单元编写
服务资源使用 systemd:kaiwu 需要在两个节点上都有 /etc/systemd/system/kaiwu.service 文件。这个文件的内容其实很简单,主要作用是启动和停止 KaiwuDB 的单机进程。
参考模板:
[Unit] Description=KaiwuDB Server After=network.target [Service] Type=simple User=kaiwu Group=kaiwu WorkingDirectory=/opt/kaiwu ExecStart=/opt/kaiwu/bin/kaiwu start ExecStop=/opt/kaiwu/bin/kaiwu stop Restart=on-failure LimitNOFILE=65536 [Install] WantedBy=multi-user.target实际部署时我用的是 KaiwuDB 自带的启停脚本或者 wrapper 命令,相关的环境变量在 /etc/default/kaiwu 里配置。这里特别提醒:Pacemaker 的 systemd 资源有一个特性,它监控服务是否 active,如果服务进程自己退出了,Pacemaker 会把它当作资源故障,触发切换逻辑。所以 systemd 脚本里的 Type 和 ExecStart 参数一定要核对清楚,不能写一个一次执行完就退出的命令进去,否则 Pacemaker 会误判服务已启动完成。
5. 故障切换实操与切换时间实测
5.1 手动切换流程演练
在实际故障发生之前,先做一次干净的手动切换演练,把整个集群资源从节点1迁移到节点2,确认整条链路是通的。命令如下:
pcs resource move kaiwu_group kaiwu-node2这个命令会为资源组添加一个位置约束,让它强制运行在节点2上。Pacemaker 会自动把资源组逐项停止,再在新节点依次启动。迁移完成后,用下面的命令清理临时约束,否则下一次切换可能还会被上次的约束干扰:
pcs resource clear kaiwu_group整个干净切换过程我实测控制在 5 到 8 秒之间。其中耗时大头在 KaiwuDB 服务的冷启动,KaiwuDB 需要加载 WAL、做恢复检查,10 秒以内完成,边缘场景完全可以接受。
切换完成后可以通过 KaiwuDB 的 SQL 接口连到 VIP 上验证数据完整性。我做的事是提前在库里建一张测试表,写入几千行带时间段的数据,切换后再做一次 count 和最新时间戳对比,确认数据没有丢失。
5.2 模拟主节点宕机
再来做一个更真实的故障演练:直接拔掉节点1的电源。
操作完成后观察节点2上的状态变化过程。首先是 Corosync 在一到两秒内感知到节点1失联,集群成员发生变化。随后 Pacemaker 判定节点1上的所有资源不可用,开始执行资源接管流程。节点2上的 kaiwu_drbd 从 Secondary 提升为 Primary,LVM 激活逻辑卷,文件系统挂载到 /data/kaiwu,VIP 漂移到节点2,KaiwuDB 服务启动。
我在多次测试中记录到的切换时间是 8 到 12 秒,比手动切换稍长,原因在于 Corosync 需要时间确认节点失联,并且 DRBD 的分裂脑检测也需要一个短暂的等待窗口。把这段时间也算上,总对外不可用时间在 15 秒以内,这个指标对边缘采集场景是够用的——采集端配置了本地缓存的话,完全无感。
5.3 数据一致性验证方法
切换完成后最重要的动作不是看服务起来了,而是验证数据一致性。我从三个层面做验证。
第一层是块设备层面。切换完成后,在节点2上执行drbdadm status r0,应该显示该节点是 Primary/UpToDate 状态。如果有 failed 或者 inconsistent 标记,说明 DRBD 同步出了问题。
第二层是文件系统层面。挂载完成后检查文件系统日志是否干净,以及挂载点下的文件总数和切换前做快照时记录的文件数是否一致。xfs 文件系统在这种掉电切换场景下的表现很稳定,实测多次没有出现文件丢失。
第三层是数据库层面。连上 VIP 执行 SQL 查询,统计测试表的数据量和最后写入的时间戳。如果 KaiwuDB 内部有 WAL 恢复日志,也一并查看,确认没有 panic 和未完成事务。
6. 常见问题与排查技巧实录
6.1 两个节点同时变成 Primary 的脑裂处理
这是双节点高可用里最典型的故障。原因是两个节点之间的心跳断开了,而 DRBD 又没有能及时把某个节点的资源降级。出现脑裂后,DRBD 会把资源标记为 StandAlone,两边都持有最新数据的版本信息。
处理办法是按时间先后判断哪边的数据更新,保留较新的数据作为主。因为我用的是协议 C 同步复制,正常运行时两边数据一致,脑裂后旧主节点可能还有少量未同步数据。我的操作步骤是:
首先,不要急于重新连接两个节点,先把两边 DRBD 的 sync 状态和数据时间戳记录下来。然后主动把确认数据较旧的那一端降为 Secondary,在较新端执行drbdadm connect r0重新建立连接,之后观察同步是否完成。
清理完后一定记得清理 Pacemaker 里的残留资源状态,把资源重新交给集群管理,而不是让某一端一直手动持有资源。脑裂发生的根因要查,比如心跳网线松动、Corosync 配置错误、防火墙拦截了心跳端口。我遇到过一次是 pcsd 服务挂掉导致集群状态卡住,也很容易误判成网络问题。
6.2 切换后 KaiwuDB 数据目录权限不对
这个问题出现概率很高,根因是 KaiwuDB 服务是以 kaiwu 用户运行的,但 DRBD 设备挂载出新文件系统后,挂载点属主可能是 root。切换完成后 KaiwuDB 服务无法在数据目录下创建文件,直接启动失败。
解决方式有两种。一种是在挂载后手动 chown 数据目录属主为 kaiwu,但这种方式在切换后还得手动处理,不够优雅;更好的方式是在 systemd 单元里加 ExecStartPost 脚本,在服务启动前自动修正属主。实际生产里我在 /etc/systemd/system/kaiwu.service 里加了一行:
ExecStartPre=/bin/chown -R kaiwu:kaiwu /data/kaiwu这样无论资源从哪个节点起来,KaiwuDB 都有正确的写权限。
6.3 Pacemaker 资源组漂移后无法自动返回原节点
默认配置下,Pacemaker 在故障切换后不会自动把资源组回切到原节点,除非原节点恢复后触发某种位置约束的干预。这个设计其实是故意的,避免主备来回摆动造成不必要的服务中断。
但在运维中会发现,原节点恢复后,新主节点上的 DRBD 数据虽然是最新状态,原节点重启后 DRBD 需要把新主节点变化的数据同步回去,这段时间原节点的 DRBD 状态是 SyncSource 或者 SyncTarget。要回切的话,操作顺序是:先让同步完成,再执行pcs resource move kaiwu_group kaiwu-node1,然后清理约束。不能赶在同步完成前回切,否则 DRBD 会再次进入不一致状态,极端情况下会触发新的脑裂风险。
6.4 DRBD 同步长期停留在连接状态
应用层进程持续大量写入时,偶尔会出现 DRBD 同步速率跟不上写速率的情况,表现为同步进度一直上不去,甚至停留在 0% 或反复倒退。这是同步复制场景下典型的重负载问题。
排查手段是看主节点的 IO 等待和网络吞吐。我遇到过两种真实情况:一是底层盘是机械盘,IOPS 太低,换成 SSD 后问题消失;二是 syncer rate 配得比实际网络带宽小太多,阻碍了同步进度,调大 rate 之后恢复了。生产环境建议底层盘全部上 SSD,网络至少保证 DRBD 同步流量独享一条千兆链路,没有瓶颈可犯。
6.5 切换后 VIP 飘移了但客户端缓存了旧连接
边缘场景里很多采集终端用 TCP 长连接连数据库,VIP 漂移后旧连接立即断开,终端应用如果重试逻辑做得不够好,可能长时间连不上新主节点。这虽然不是集群配置的问题,但直接影响切换效果。
我建议所有边缘接入程序采用连接池加自动重连机制,数据库连接串里配置的是 VIP 而不是某个固定 IP。KaiwuDB 的 SQL 客户端重连配置和常见时序库类似,设置好超时时间和重试次数,实测切换期间只影响当次请求,后续自动恢复。
6.6 关于脑裂防护的另一层保障
前面多次提到脑裂防护,我再补充一个更稳妥的实践。如果现场有条件提供一块共享存储的小分区,比如几十 MB,可以给每台机器挂一个 SBD 设备,利用 SBD 作为 fence 机制。Pacemaker 的 stonith 设备类型配置成 fence_sbd,配置正确后即使两个节点完全失联,SBD 也会用存储锁来决定哪个节点可以继续运行资源。
没有共享存储的情况下,我退而求其次用 DRBD 自带的 fencing 机制来防止双方同时变 Primary。但我必须强调:DRBD fencing 依赖两个节点之间还能通过 DRBD 网络通信来判断对端状态,如果心跳和 DRBD 网络同时断掉,DRBD fencing 也无力回天。所以物理上至少保持两条独立网络路径,一条走管理心跳,一条走 DRBD 数据同步,是边缘节点部署的硬性要求。
我在实际部署的机房环境里,遇到两次因为交换机单链路故障导致的管理网络闪断,正是因为有独立的 DRBD 数据链路和冗余心跳,集群才没有进入脑裂状态。这个冗余设计值得每一套边缘高可用方案默认启用。
7. 监控、日常维护与多场景延伸
7.1 监控指标体系
部署完成不等于可以放任不管。我至少会监控以下几类指标:
- DRBD 状态:通过 drbdadm status r0 定时采集,重点关注角色是否正常、同步是否完成、连接是否为 Connected
- Pacemaker 集群状态:pcs status 输出,关注是否有资源异常、节点是否离线
- KaiwuDB 进程状态:systemctl status kaiwu,关注进程是否存活、WAL 目录大小是否异常
- 磁盘延迟:xfs 和底层盘的 iostat 数据,异常延迟通常意味着 DRBD 同步或者底层存储有问题
- 网络延迟和丢包:管理网和数据网分别监控,特别是两张网的 ping 延迟
我用的监控方式比较简单,写一个 bash 脚本每分钟采集一次状态指标,推送到中心机房的看板即可。边缘节点的采集端不会很重,不需要部署完整的 Prometheus 全家桶,脚本加阈值告警足够用。
7.2 维护窗口与常规操作
高可用集群虽然自动化程度高,但日常维护仍然需要规范。比如给主节点做内核升级,我先执行pcs resource move kaiwu_group kaiwu-node2把业务切走,确认所有资源都跑在节点2且数据同步完成后,再对节点1执行维护。节点1回归集群前要确认 DRBD 同步进程完成,业务不切回的话也没有问题,保持节点2为主节点即可。
升级 KaiwuDB 版本时,我会按备机→主机的顺序操作。先在备机上升级软件包,但不启动新版服务,因为它处于 Secondary 状态,不涉及到对外服务。再通过一次切换让备机转正,验证新版进程能正常启动、数据完整,最后再升级原来的主节点。这种方式可以把升级窗口的对外影响控制在一次切换的时间内。
7.3 扩展到其他数据库的场景
这套 DRBD + Pacemaker 组合并不绑定 KaiwuDB,换成 MySQL、PostgreSQL、Redis 这类单机部署的数据库同样适用。实际上我在某些边缘项目里也用过完全相同的架构承载 PostgreSQL 的时序扩展。差异点只在服务资源的 systemd 单元,以及数据库本身数据目录的规划。也就是说,这套方案是边缘侧数据库高可用的一个通用底层框架,数据库是谁不影响架构的正当性。
需要注意的场景是数据库本身已经支持多节点分布式模式的,比如 KaiwuDB 自身的分布式版本、TiDB、CockroachDB 这类,那就不需要再叠加 DRBD 了,分布式架构内部自带副本机制。DRBD + Pacemaker 最适合的场景是“单机数据库形态 + 边缘高可用要求”的组合,这个定位要搞清楚,别堆叠无意义的复杂度。
7.4 规划资源容量和备份策略
最后两件事提醒一下:容量规划和备份。
容量规划上,DRBD 设备可以后期扩容,但操作相对繁琐。最好在一开始就按至少两年业务增量估算逻辑卷大小。边缘采集数据的写入量是可以预测的——点位数量、采集频率、每条记录大小,三项相乘再乘以冗余系数,得到的就是数据量级。实际部署时留出 1.5 倍的余量比较安全,否则后面扩容时要扩 DRBD 底层设备,停机窗口会大于一次切换的时间。
备份策略这块,DRBD 本身不是备份,它是冗余。误删除、软件 bug、数据库逻辑损坏,DRBD 都会照单全收复制到备机。我始终要求在集群之外另做备份,备份方式可以选择 KaiwuDB 自带的备份工具导出数据文件或者 SQL 语句,定期将备份传到中心机房或对象存储。备份频率按数据价值定,至少一日一备。有了这层兜底,DRBD + Pacemaker 的边界风险就能被完整覆盖。
这套方案从设计、部署、切换到监控运维,全程都是在边缘机房那些不理想的物理环境里打磨出来的。KaiwuDB 负责数据存取,DRBD 负责块级镜像,Pacemaker 负责故障决策,三者各司其职,恰好把边缘双节点高可用的几个核心问题一一化解。你现在手头如果有两台闲置服务器,完全可以照着这份配置先搭一套演练环境,跑一次拔电测试,就知道这套方案实际用起来是什么体验了。