HAS配置文件参数说明
vastbase.yml
关键参数说明
Global/Universal相关配置
scope:集群名称。
name:主机名,两个节点不能相同。
HAS相关配置
ttl:主库存活时间,超出此时间主库未更新状态即执行failover。至少为loop_wait 的3倍,低于则无法启动。
loop_wait:HAS两次循环间隔时间,至少为5,低于5 时HAS无法启动。
arbitration_file_path:仲裁存储路径。
arbitration_file_type:仲裁存储类型,目前实现方案为raw,即裸设备仲裁。
node_index:该节点写入仲裁设备的分区,只能为1或2,且该值两个节点不能相同。
gateway:本节点HAS用以网络自检的地址。若HAS ping 该地址失败则执行failover。一般设置为网关地址。
postgresql相关配置
callbacks:均为回调脚本has_callback.sh路径。
connect_address:当前节点ip及数据库端口。
data_dir:数据库实例路径,备节点则为预备的挂载点中的数据实例目录。
config_dir:数据库实例配置文件路径。
bin_dir:数据库可执行文件路径。
vastbase_lib_dir:数据库共享库路径。
vastbase_home:数据库安装路径。
pre_promote:mount.sh脚本路径。
pre_demote:umount.sh脚本路径。
pre_switchover:switchover前置检查脚本,用于检查是否有除本实例数据库进程之外的数据库在使用挂载点目录。
superuser
username:数据库超级用户名称。
password:数据库超级用户密码。
其他相关配置
op_arbitration_timeout
读写仲裁盘的时间超过此值就会在执行读写完毕后进行日志记录,用于诊断。
取值范围为 > 0,默认值为 1 秒。将此值配置的过小可以看到日志,如0.001。
日志级别:若读/写仲裁盘超时,log为warning级别;若参数配置 ≤ 0时,log为error级别,并退出has。
get_mount_info_timeout
has的心跳进程向仲裁盘中写自己的心跳和挂载信息(用于给对端检测)时,先要获取本节点的挂载信息,用时超过此参数值后,会在获取挂载信息完毕后记录日志,用于诊断。
取值范围为 > 0,默认值为 1 秒。将此值配置的过小可以看到日志,如0.001。
日志级别:获取挂载信息超时,log为warning级别;若参数配置 ≤ 0时,log为error级别,并退出has。
failover_delay_time
参数值 > 0 ,代表开启该功能(默认值2min),failover延迟failover_delay_time秒;参数值 ≤ 0,代表关闭该功能。
考虑到网络和仲裁盘都失效或者宕机的场景可能较少,建议打开该参数且设置failover延迟时间为2~3分钟。
此参数功能即延迟failover功能,会在failover备机升主机前,延迟此参数值设定的时间,具体行为参见如下:
(1)如果获取到对端仍然在挂载(检测方式详见后文),则不会进行failover,直接进入下次loop。
(2)如果获取到对端不再挂载,则允许立刻failover。
(3)如果没有办法与对端通信,则认为对端不存活,会持续进行检测对端状态,直到failover_delay_time超时就发生failover;若期间检测到(1)或(2)描述的状态,则分别按照(1)或(2)进行处理。
检测方式如下:
优先通过仲裁盘进行检查,认为对端不存活后(对端心跳未更新),则再调用check_before_failover脚本通过ssh进行检查;注意需要数据库用户的互信连接,可直接在节点上使用数据库用户执行此脚本验证行为。
日志级别(check_before_failover):对应文件不存在,log级别为 error,并退出has;该文件在执行失败的时候报异常,执行脚本前后有info级别日志提示。
watchdog(通过watchdog让节点释放数据盘的挂载):
开启此功能需在主机提前安装好如下内核模块,安装后会新增/dev/watchdogXXX设备,对应日志可用
dmesg -w
查看:modprobe softdog
mode
默认值为off,表示关闭此功能。
若配置为required,则watchdog能被成功启动时节点才能变成主库。
日志级别(mode):非法值,log级别是error,并退出has;watchdog不能正常开启同时配置为required,则log级别为error,并退出has。
device
watchdog设备接口。
以CentOS系统为例,默认为/dev/watchdog。
需要确保运行HAS的用户对此文件具有读写权限。
safety_margin
watchdog触发和leader key超时之间的安全余量,用于系统重置。
取值范围为 -1 或 >0,默认值为-1,表示ttl//2时间。该值需要大于loop_wait时间(未开启延迟failover功能时需大于failover_delay_time)。
safety_margin是预留的重置系统时间,watchdog的保活时机在写leader key后会进行一次。
日志级别(safety_margin):非法值,log级别为error,并退出has。
系统重启或者
modproobe -r softdog
后watchdog失效。重启系统可能会导致仲裁盘盘符(设备文件名,如/dev/sdj 变成 /dev/sdk)变化,因此每次启动HAS前需要人工保证配置文件中仲裁盘设备名和实际的冲裁设备名一致。
当watchdog不能让旧主及时释放仲裁盘,且延迟failover功能无法检测旧主挂载状态,这种情况下备升主有双挂数据盘造成数据盘损坏的风险。
vastbase.yml文件模板
scope: vastbase # 集群实例名称
namespace: /vastbase/ # 集群实例所在的命名空间,默认是/service
name: 'vastbase_node2' # 节点在集群内的名称,每个节点都必须不一样,通过hasctl list命令查看高可用集群状态时,在Member显示该名称
has:
ttl: 30 # 持有单个DCS key的最长时间,单位秒,例如主节点持有leader key,如果不能再该时间内更新leader key,那么可以认为发生failover
loop_wait: 10 # patroni两次执行工作之间的时间间隔,单位秒
retry_timeout: 10 # 重试次数
arbitration_file_path: /dev/sdc
arbitration_file_type: raw
node_index: 1
gateway: 172.xx.103.254
op_arbitration_tieout:1
#读或写仲裁盘超时时间,取值要大于0,默认值1秒,超时会进行日志记录
get_mount_info_timeout:1
#获取本机mount_point_path挂载点的信息(用于填入仲裁盘),取值要大于0,默认值1秒,超时会进行日志记录
get_peer_mount_info_timeout:0.3
#备库failover前获取对端写入仲裁盘的挂载信息(对端存活时挂载信息才有效),共读取两次,取值为两次读取的时间间隔,取值要大于0,默认值0.3秒
failover_delay_time:120
#备库failover前同构仲裁盘和check_before_failover脚本都无法获取对端的挂载信息,则延迟failover时间,取回要大于0,默认值2分钟
mount_point_path:/data
#数据盘挂载点,同mount.sh和unmount.sh脚本中的mount_point
watchdog:
mode: off
#配置为required ,watchdog能被成功启动节点才能变成主库,off为关闭
device:/devwatchdog
#watchdog设备接口
safety_margin:-1
#watchdog触发和leader key超时之间的安全余量,用于系统重置,-1为ttl//2
postgresql:
callbacks:
on_start: /home/vastbase/has/bin/has_callback.sh # 回调脚本路径,一般用于管理VIP
on_stop: /home/vastbase/has/bin/has_callback.sh
on_role_change: /home/vastbase/has/bin/has_callback.sh
on_master_check: /home/vastbase/has/bin/has_callback.sh
listen: 0.0.0.0:5432 # 设置数据库的监听地址,此处的配置会覆盖postgresql.conf的listen_addresses和port参数,如果此处没有配置端口号,默认监听5432端口。此处无论是否配置端口号,postgresql.conf配置的port参数都会被覆盖
connect_address: 172.xx.102.74:5432
use_unix_socket: true
pg_ctl_timeout: 600 # 数据库启动超时时间,根据实际情况设置
data_dir: /data/vastbase # 数据库实例路径
config_dir: /data/vastbase # 数据库实例配置文件路径
bin_dir: /home/vastbase/local/vastbase/bin # 数据库可执行文件路径
vastbase_lib_dir: /home/vastbase/local/vastbase/lib:/home/vastbase/local/vastbase/jre/lib/aarch64:/home/vastbase/local/vastbase/jre/lib/aarch64/server # 数据库共享库路径,根据实际路径配置
vastbase_home: /home/vastbase/local/vastbase # 数据库安装路径
pre_promote: /home/vastbase/has/bin/mount.sh
pre_demote: /home/vastbase/has/bin/umount.sh
pre_switchover: /home/vastbase/has/bin/check_switchover.sh
authentication:
superuser:
username: vbadmin
password: Vbase@admin
has_callback.sh
关键配置项含义
- After:指定HAS服务在‘network’启动成功后启动。
- Type:一般设置为simple即可,如操作系统支持exec,则配置为exec。
- User:HAS运行过程中可能会初始化或者启动数据库,这些操作不能以‘root’用户执行,故指定该服务的用户跟数据库用户一致为‘vastbase’。
- ExecStopPost:指定HAS进程终止后执行的命令,需要使用绝对路径指定命令路径,在HAS服务中,用于释放VIP与取消数据存储挂载。
- ExecStartPre:指定HAS进程执行前执行的命令,需要使用绝对路径指定命令路径,在HAS服务中,用于检测与添加仲裁设备的读写权限。
- TimeoutStopSec:设置等待关闭的超时时间。
文件模板
#!/bin/bash
# -------------------------------------------------------------------------------
# Filename: has_callback.sh
# Revision: 1.0
# Date: 2019/10/09
# Description:
# Notes:
# callback 仅实现vip 的 添加和移除
#
# -------------------------------------------------------------------------------
#
# -------------------------------------------------------------------------------
readonly cb_name=$1
readonly role=$2
readonly scope=$3
VIP=172.xx.102.5 # vip 地址
#VIP=2001::e1:172:16:102:5
VIPBRD=172.xx.103.255 # 广播地址
VIPNETMASKBIT=22 # 掩码
VIPDEV=ens33 # 网络接口名称,vip会绑定到该接口
VIPLABEL=1 # 接口标签,默认为1
PING_TIMEOUT=2 # 设置为不高于vastbase.yml配置文件里loop_wait的40%,如果loop_wait设置为10,PING_TIMEOUT建议设置为3,如果loop_wait设置为5,建议设置为2
function usage() {
echo "Usage: $0 <on_start|on_stop|on_role_change> <role> <scope>";
exit 1;
}
function addvip(){
echo "`date +%Y-%m-%d\ %H:%M:%S,%3N` INFO: /sbin/ip addr add ${VIP}/${VIPNETMASKBIT} brd ${VIPBRD} dev ${VIPDEV} label ${VIPDEV}:${VIPLABEL}"
sudo /sbin/ip addr add ${VIP}/${VIPNETMASKBIT} brd ${VIPBRD} dev ${VIPDEV} label ${VIPDEV}:${VIPLABEL}
sudo /usr/sbin/arping -q -A -c 1 -I ${VIPDEV} ${VIP}
#sudo /sbin/iptables -F
}
function delvip(){
echo "`date +%Y-%m-%d\ %H:%M:%S,%3N` INFO: sudo /sbin/ip addr del ${VIP}/${VIPNETMASKBIT} dev ${VIPDEV} label ${VIPDEV}:${VIPLABEL}"
sudo /sbin/ip addr del ${VIP}/${VIPNETMASKBIT} dev ${VIPDEV} label ${VIPDEV}:${VIPLABEL}
sudo /usr/sbin/arping -q -A -c 1 -I ${VIPDEV} ${VIP}
#sudo /sbin/iptables -F
}
if [[ $cb_name != 'on_master_check' ]]; then
echo "`date +%Y-%m-%d\ %H:%M:%S,%3N` WARNING: has callback $cb_name $role $scope"
fi
case $cb_name in
on_stop)
delvip
;;
on_start)
if [[ $role == 'master' ]]; then
addvip
fi
;;
on_role_change)
if [[ $role == 'master' ]]; then
addvip
elif [[ $role == 'slave' ]]||[[ $role == 'replica' ]]||[[ $role == 'logical' ]]; then
delvip
fi
;;
on_master_check)
if [[ $role == 'master' ]]; then
vip_status=`ip addr|grep ${VIP}`
if [[ ${vip_status} == '' ]]; then
echo "`date +%Y-%m-%d\ %H:%M:%S,%3N` WARNING: has callback $cb_name $role $scope"
echo "`date +%Y-%m-%d\ %H:%M:%S,%3N` WARNING: The vip was lost,bind vip because i am leader"
/usr/bin/ping -I ${VIPDEV} -q -c 3 -W ${PING_TIMEOUT} ${VIP}
is_vip_used=$?
if [[ $is_vip_used -eq 0 ]]; then
echo "`date +%Y-%m-%d\ %H:%M:%S,%3N` WARNING: The vip bind failed, ${VIP} is in use"
else
addvip
fi
fi
fi
;;
*)
usage
;;
esac
check_peer_mount_info.sh脚本
#!/bin/bash
#-----------------------------------
# 调用于 failover 发生前,
# 检查仲裁盘中的挂载信息失败后,会调用此脚本返回对端挂载信息。
#
# 允许的返回值:
# 返回 0 代表对端没有挂载数据盘
# 返回 1 代表对端正在挂载数据盘
# 返回 2 代表登录对端后,没有办法获取到对端的数据盘挂载信息(此时认为数据盘被挂载)
# 返回 3 代表没有办法登录对端
# 返回其他值,非法值
#-----------------------------------
CONNECT_TIMEOUT=10
PEER_USER=vastbase
PEER_IP=XXX.XXX.XXX.XXX
PEER_MOUNT_POINT=/data
PEER_VASTBASE_DIR=/data/vastbase
# 需要确保有权限读写
SSH_RESULT_FILE=/home/vastbase/has/bin/ssh_result_file.log
# 执行 mountpoint 获取数据盘挂载信息
# 默认 CONNECT_TIMEOUT 秒没有返回,则视为链接超时
ssh -o ConnectTimeout=${CONNECT_TIMEOUT} ${PEER_USER}@${PEER_IP} "sudo mountpoint ${PEER_MOUNT_POINT}" > ${SSH_RESULT_FILE} 2>&1
grep "is a mountpoint" ${SSH_RESULT_FILE} > /dev/null 2>&1
mountstatus=$?
if [ ${mountstatus} -eq 0 ]; then
# 数据盘被挂载
exit 1
fi
grep "is not a mountpoint" ${SSH_RESULT_FILE} > /dev/null 2>&1
mountstatus=$?
if [ ${mountstatus} -eq 0 ]; then
# 数据盘没有被挂载
exit 0
fi
# 主机不可达
grep "No route to host" ${SSH_RESULT_FILE} > /dev/null 2>&1
mountstatus=$?
if [ ${mountstatus} -eq 0 ]; then
exit 3
fi
# 上面检测失败,再次检查数据盘挂载目录下的文件以确定是否被挂载
ssh -o ConnectTimeout=${CONNECT_TIMEOUT} ${PEER_USER}@${PEER_IP} "ls ${PEER_VASTBASE_DIR} | grep -E 'base|global' | wc -l" > ${SSH_RESULT_FILE} 2>&1
# 此时超时就认为对端不存活
grep "Connection timed out" ${SSH_RESULT_FILE} > /dev/null 2>&1
mountstatus=$?
if [ ${mountstatus} -eq 0 ]; then
exit 3
fi
grep "No route to host" ${SSH_RESULT_FILE} > /dev/null 2>&1
mountstatus=$?
if [ ${mountstatus} -eq 0 ]; then
exit 3
fi
grep "2|1" ${SSH_RESULT_FILE} > /dev/null 2>&1
mountstatus=$?
if [ ${mountstatus} -eq 0 ]; then
exit 1
fi
# base 和 global 文件同时不存在情况下认为数据盘没有被挂载
grep "0" ${SSH_RESULT_FILE} > /dev/null 2>&1
mountstatus=$?
if [ ${mountstatus} -eq 0 ]; then
exit 0
fi
# 其余情况直接认为主机不可达(不存活)
exit 3
mount.sh脚本
文件模板
#!/bin/bash
#-------------------------
# 在启动数据库前挂载共享数据存储
#-------------------------
#uuid,通过blkid查看
uuid=55d511bd-4a14-4779-b22f-8c6d2ee09c48
mount_point=/data
#物理卷名
vg_name=vg1
sudo mountpoint -q ${mount_point}
mountstatus=$?
if [ ${mountstatus} -ne 0 ]; then
sudo vgchange -ay ${vg_name}
sudo mount -U ${uuid} ${mount_point}
fi
exit 0
umount.sh脚本
文件模板
#!/bin/bash
#-----------------------------------
# 在切换或停库后进行umount操作
#-----------------------------------
# 脚本执行模式,分为once 和 loop
readonly mode=$1
#挂载点路径
mount_point=/data
#物理卷名
vg_name=vg1
#sd_hasctl路径
ctl_path=/home/vastbase/has/bin/sd_hasctl
#配置文件路径
config_path=/home/vastbase/has/etc/vastbase.yml
#先打印正在使用挂载点的进程
sudo lsof ${mount_point}
# 先删掉正在使用挂载点的进程
mount_count=`sudo lsof ${mount_point}|wc -l`
if [ ${mount_count} -gt 1 ]; then
echo "start to kill process using mount point ${mount_point}"
sudo lsof ${mount_point}|awk 'NR==1 {next} {print $2}'| xargs sudo kill -9
fi
sudo umount ${mount_point}
sudo mountpoint -q ${mount_point}
umountstatus=$?
if [ ${mode} == "once" ]; then
if [ ${umountstatus} -ne 0 ]; then
sudo vgchange -an ${vg_name}
exit 0
else
exit 1
fi
#循环尝试umount,通过umountstatus查看挂载点状态
elif [ ${mode} == "loop" ]; then
while [ ${umountstatus} -eq 0 ]; do
sleep 2
sudo umount ${mount_point}
sudo mountpoint -q ${mount_point}
umountstatus=$?
done
sudo vgchange -an ${vg_name}
else
echo "Error: mode must be once or loop."
exit 1
fi
check_arbitrator.sh
文件模板
#!/bin/bash
#验证仲裁设备权限,如无权限则添加
arbitrator='/dev/sdc'
#检查读权限
if [ ! -r ${arbitrator} ]
then
sudo chmod o+r ${arbitrator}
fi
#检查写权限
if [ ! -w ${arbitrator} ]
then
sudo chmod o+w ${arbitrator}
fi
exit 0
check_switchover.sh
文件模板
#!/bin/bash
#-----------------------------------
# switchover时检查是否能够进行umount
#-----------------------------------
readonly db_pid=$1
#挂载点路径
mount_point=/data
mount_count=0
if [ ${db_pid} == '0' ]; then
mount_count=`sudo lsof ${mount_point}|awk 'NR==1 {next} {print $2}'|wc -l`
else
mount_count=`sudo lsof ${mount_point}|awk 'NR==1 {next} {print $2}'|grep -v ${db_pid}|wc -l`
fi
if [ ${mount_count} -gt 0 ]; then
exit 1
fi
has.service
文件模板
[Unit]
Description=Vastbase HAS server daemon
[Install]
WantedBy=multi-user.target
[Service]
Type=simple
User=vastbase
EnvironmentFile=-/etc/sysconfig/vastbase-has
ExecStartPre=/usr/bin/bash /home/vastbase/has/bin/check_arbitrator.sh
ExecStart=/home/vastbase/has/bin/sd_has $CONFIG_FILE
ExecStopPost=/usr/bin/bash /home/vastbase/has/bin/umount.sh loop
ExecStopPost=/bin/sudo /usr/sbin/ip addr del ${VIP}/${VIPNETMASKBIT} dev ${VIPDEV} label ${VIPDEV}:${VIPLABEL}
Restart=no
LimitMEMLOCK=infinity
LimitNOFILE=1024000
TimeoutStopSec=1024000
vastbase-has
文件模板
CONFIG_FILE=/home/vastbase/has/etc/vastbase.yml
VIP=172.xx.102.5
VIPBRD=172.xx.103.255
VIPNETMASKBIT=22
VIPDEV=ens33
VIPLABEL=1