ITPub博客

首页 > 数据库 > 数据库开发技术 > Halo数据库之--主从库故障切换

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

原创 数据库开发技术 作者:Jet_Zhang 时间:2022-05-19 17:30:00 0 删除 编辑

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

一、手工切换

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

当主库故障后,从库系统日志中会出现错误:

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

从库提示无法连接到主库。


这时我们可以手动执行pg_ctl promote命令来提升从库,当pg_ctl promote被运行,pg_promote()被调用,或一个触发器文件被找到(promote_trigger_file),从库模式会退出并且服务器会切换到普通操作。

[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:22022-05-18 09:58:22.228 CST [1504] 日志:  归档恢复完毕2022-05-18 09:58:22.243 CST [1503] 日志:  数据库系统准备接受连接 完成服务器加载完毕

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


我们可以用psql连接到数据库中,看到数据库已经变成主库状态:

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

如果原主库故障解决之后,通常我们会把原主库转换成新主库的Standby从库。正常一般是需要重新搭建从库,因为原主库的一些数据还没有同步过去就把从库激活了,从库相当于丢失了一些数据。再重新搭建从库的话,如果数据库很大,基础备份执行时间会很长,解决这个问题的方法可以使用pg_rewind命令。不需要复制太多的数据就可以把原主库转换成新主库的从库。


使用pg_rewind命令要求原主库必须把wal_log_hints参数设置成on,或者在数据库初始化时使用“-k”参数开启 checksums 功能,这样配置的主库在出现故障时才能使用pg_rewind命令。

如果没有把参数wal_log_hints设置成on,运行pg_rewind时会报错:

[halo@localhost ~]$ pg_rewind -D $PGDATA --source-server='host=192.168.56.109 user=pgrewind password=123456 dbname=halo0root' -Ppg_rewind: 已连接服务器pg_rewind: 致命的: 目标服务器需要使用数据校验和或者让"wal_log_hints = on"

将原主库wal_log_hints参数为“on”之后,把数据库重启再正常关闭,然后再执行pg_rewind:

[halo@localhost ~]$ pg_rewind -D $PGDATA --source-server='host=node2 user=pgrewind password=123456 dbname=halo0root' -Ppg_rewind: 已连接服务器pg_rewind: 服务器在时间线1上的WAL位置0/302D640处发生了分歧pg_rewind: 从时间线1上0/302D590处的最后一个普通检查点倒带pg_rewind: 读取源文件列表pg_rewind: 读取目标文件列表pg_rewind: 读取目标中的WALpg_rewind: 需要复制 51 MB(整个源目录的大小是 73 MB)已复制52893/52893 kB (100%)pg_rewind: 正在创建备份标签并且更新控制文件pg_rewind: 正在同步目标数据目录pg_rewind: 完成!

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


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

touch $PGDATA/standby.signal

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

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的从库:

[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-bit2022-05-18 10:57:15.957 CST [6220] 日志:  正在监听IPv4地址"0.0.0.0",端口 19212022-05-18 10:57:15.957 CST [6220] 日志:  正在监听IPv6地址"::",端口 19212022-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,但得到的是 02022-05-18 10:57:16.578 CST [6220] 日志:  数据库系统准备接受只读请求的连接2022-05-18 10:57:16.584 CST [6226] 日志:  在时间点: 0/3000000 (时间安排2)启动日志的流操作 完成服务器进程已经启动

注意:一定要先建好standby.signal文件,再启动数据库。


二、自动切换

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

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

yum install -y keepalived

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

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

keepalived.conf文件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脚本#!/bin/bash
PGHOME=$1PGDATA=$2VIPADDR=$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.logecho "Status A: $A" >> /tmp/health_check.logecho "Status VIP: $B" >> /tmp/health_check.logecho "Status C: $C" >> /tmp/health_check.logecho "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 keepalivedelse 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 fifi
# 启动 keepalivedsystemctl start keepalived

先启动主库再启动从库。


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

原文作者:Halo Tech;如有侵权,请联系管理员删除。

请登录后发表评论 登录
全部评论
中国南方Oracle用户组(SOUG)联合创始人,Oracle ACE,曾服务于国外某大型银行,曾担任国内某中型保险公司的技术经理,现为易景科技合伙人、首席架构师、CTO。主要研究方向数据库内核。

注册时间:2024-06-26

  • 博文量
    124
  • 访问量
    542487