开发指南

Halo数据库--主从库故障切换

开发者社区
2023年11月01日

通常数据库故障切换称为“Failover”。当主从库是异步复制或同步复制时,如果主库出现了问题失效,我们有两个方案可以激活从库作为主库来提供服务。

一、手工切换

通过“pg_ctl promote”命令来激活从库。

bash
[halo@localhost ~]$ 2022-05-18 09:57:33.015 CST [1508] 致命错误:  无法从WAL流中获得数据: 服务器意外地关闭了联接
                这种现象通常意味着服务器在处理请求之前
        或者正在处理请求的时候意外中止
2022-05-18 09:57:33.016 CST [1504] 日志:  0/302D640 处的记录长度不合法:想要 24,但得到的是 0
2022-05-18 09:57:33.020 CST [2602] 致命错误:  无法连接到主用服务器:无法联接到服务器: 拒绝连接
                服务器是否在主机 "node1"(10.16.16.165) 上运行并且准备接受在端口
        1921 上的 TCP/IP 联接?

当主库故障后,从库系统日志中会出现错误,提示无法连接到主库。

bash
[halo@localhost ~]$ pg_ctl promote
等待服务器进程加载 ....2022-05-18 09:58:22.101 CST [1504] 日志:  接收到提或请求
2022-05-18 09:58:22.101 CST [1504] 日志:  redo 在 0/302D608 完成
2022-05-18 09:58:22.101 CST [1504] 日志:  上一次完成事务是在日志时间2022-05-18 09:37:14.742818+08完成的.
2022-05-18 09:58:22.143 CST [1504] 日志:  已选择的新时间线ID:2
2022-05-18 09:58:22.228 CST [1504] 日志:  归档恢复完毕
2022-05-18 09:58:22.243 CST [1503] 日志:  数据库系统准备接受连接
 完成
服务器加载完毕

一旦pg_ctl promote命令正确完成,此时从库即被提升为主库,可以正常对外提供服务。

sql
halo0root=# select pg_is_in_recovery();
 pg_is_in_recovery 
-------------------
 f
(1 行记录)

如果原主库故障解决之后,通常我们会把原主库转换成新主库的Standby从库。使用pg_rewind命令可以在不需要重新搭建从库的情况下实现这一目标。

bash
pg_rewind -D $PGDATA --source-server='host=node2 user=pgrewind password=123456 dbname=halo0root' -P

注意,上面的“-D”参数指向本地的目录,“node2”可以是IP地址,user需要是超级用户。

pg_rewind执行完成之后,需要手动创建文件“standby.signal”:

bash
touch $PGDATA/standby.signal

并将postgresql.auto.conf文件中的信息删掉。然后配置postgresql.conf中添加如下内容:

bash
primary_conninfo = 'user=replica password=123456 channel_binding=prefer host=node1 port=1921 sslmode=prefer sslcompression=0 ssl_min_protocol_version=TLSv1.2 gssencmode=disable krbsrvname=halo target_session_attrs=any'

这样原主库才能变成新主库的从库。现在启动node1数据库,就变成了node2的从库:

bash
[halo@localhost halo]$ pg_ctl start
等待服务器进程启动 ....2022-05-18 10:57:15.956 CST [6220] 日志:  终止日志输出到标准错误输出设备
2022-05-18 10:57:15.956 CST [6220] 提示:  后续的日志输出将进入到目标日志 "csvlog".
2022-05-18 10:57:15.956 CST [6220] 日志:  正在启动 Halo 13.6 on x86_64-pc-linux-gnu, compiled by gcc (GCC) 4.8.5 20150623 (Red Hat 4.8.5-44), 64-bit
2022-05-18 10:57:15.957 CST [6220] 日志:  正在监听IPv4地址"0.0.0.0",端口 1921
2022-05-18 10:57:15.957 CST [6220] 日志:  正在监听IPv6地址"::",端口 1921
2022-05-18 10:57:15.960 CST [6220] 日志:  在Unix套接字 "/var/run/halo/.s.PGSQL.1921"上侦听
2022-05-18 10:57:15.966 CST [6221] 日志:  当日志时间2022-05-17 10:38:22 CST进行恢复时,数据库系统被中断
2022-05-18 10:57:15.966 CST [6221] 提示:  如果这种现象多次发生,那么表示数据可能已经损坏,您可能需要选择更早一点的恢复目标
2022-05-18 10:57:16.569 CST [6221] 日志:  正在进入备用模式
2022-05-18 10:57:16.574 CST [6221] 日志:  redo 在 0/302D558 开始
2022-05-18 10:57:16.577 CST [6221] 日志:  在0/304DFA8上已到达一致性恢复状态
2022-05-18 10:57:16.577 CST [6221] 日志:  0/304DFA8 处的记录长度不合法:想要 24,但得到的是 0
2022-05-18 10:57:16.578 CST [6220] 日志:  数据库系统准备接受只读请求的连接
2022-05-18 10:57:16.584 CST [6226] 日志:  在时间点: 0/3000000 (时间安排2)启动日志的流操作
 完成
服务器进程已经启动

二、自动切换

我们基于keepalived实现2节点的主从自动切换。

在主从库上使用root用户安装keepalived

bash
yum install -y keepalived

安装之后修改/etc/keepalived路径下keepalived.conf原文件名

使用自己的keepalived.conf文件、health_check.sh文件,放到/etc/keepalived下

bash
global_defs {
   router_id halo_13 
   vrrp_skip_check_adv_addr
   vrrp_garp_interval 0
   vrrp_gna_interval 0
   script_user root
   enable_script_security
}
vrrp_script health_check {
  script "/etc/keepalived/health_check.sh /u01/app/halo/product/dbms/13 /data/halo 10.16.16.169"  
  interval 1  
  weight -5   
  fall 2
  rise 1
}
vrrp_instance VI_1 {
    state BACKUP   
    interface eth0  
    virtual_router_id 51  
    priority 100  
    advert_int 1   
    authentication {
      auth_type PASS
      auth_pass 12345
    }
    track_script {
      health_check
    }
    virtual_ipaddress {
       10.16.16.169   
    }
}

health_check.sh脚本

bash
#!/bin/bash
PGHOME=$1
PGDATA=$2
VIPADDR=$3
A=`ps -C postgres --no-header | wc -l`
B=`ip a | grep $VIPADDR | wc -l`
C=`ps -ef | grep postgres | grep 'startup recovering' | wc -l`
D=`ps -ef | grep postgres | grep 'walreceiver' | wc -l`
echo "===`date "+%Y-%m-%d--%H:%M:%S"`===" >> /tmp/health_check.log
echo "Status A: $A" >> /tmp/health_check.log
echo "Status VIP: $B" >> /tmp/health_check.log
echo "Status C: $C" >> /tmp/health_check.log
echo "Status D: $D " >> /tmp/health_check.log
if [ $A -eq 0 ]; then
    echo "`date "+%Y-%m-%d--%H:%M:%S"` failed" >> /tmp/health_check.log
    systemctl stop keepalived
else
    if [ $B -eq 1 -a $C -eq 1 -a $D -eq 0 ]; then
        su - halo -c "$PGHOME/bin/pg_ctl promote -D $PGDATA"
        echo "`date "+%Y-%m-%d--%H:%M:%S"` standby promote " >> /tmp/health_check.log
    fi
fi
# 启动 keepalived
systemctl start keepalived

先启动主库再启动从库。

当主库故障后,从库自动检测到主库出现故障,并提升自己为主库。VIP也一并从主库迁移至从库,应用无需修改配置即可继续正常运行(应用需支持重连)。


最新文章

安全公告
2025年04月11日

羲和(Halo)数据库关键补丁更新公告 - 2025年4月

安全公告
2024年06月20日

羲和(Halo)数据库关键补丁更新公告 - 2024年6月

安全公告
2023年12月18日

羲和(Halo)数据库关键补丁更新公告 - 2023年12月