KingBase通过exp脚本实现数据库自动备份
使用场景
因需求需要把Kingbase做一个自动备份,又没有找到相关配置,因此就手搓一个脚本来实现,只备份了PRO/DEV开头的数据库,一个库一个dmp文件。
这里需要注意,该脚本是exp文件而不是sh。
使用 expect 自动应答密码
expect 是一个自动化交互工具,可以模拟手动输入密码的过程,彻底解决需要手动干预的问题。
步骤 1:安装 expect(如果未安装)
# CentOS/RHEL 系统
yum install -y expect# Debian/Ubuntu 系统
apt install -y expect
步骤 2:修改脚本为 expect 兼容格式
#!/usr/bin/expect -f# 全局配置 - 超时时间(单位:秒)
set TIMEOUT -1 # 全局配置 - 数据库密码
set PGPASSWORD "Kingbase@123456789" # 全局配置 - 备份目录
set BACKUP_DIR "/opt/KingbaseES/ES/V8/backData" # 全局配置 - 备份保留天数
set KEEP_DAYS 7 # 全局配置 - 数据库主机地址
set DB_HOST "localhost" # 全局配置 - 数据库端口号
set DB_PORT "54321" # 全局配置 - 数据库登录用户
set DB_USER "kingbase" # 全局配置 - 备份工具路径
set SYS_DUMP "/opt/KingbaseES/ES/V8/ClientTools/bin/sys_dump" # 全局配置 - 数据库客户端路径
set KSQL "/opt/KingbaseES/ES/V8/ClientTools/bin/ksql" # 全局配置 - 默认连接数据库
set DEFAULT_DB "template1" # 创建备份目录(若不存在)
if {[catch {exec mkdir -p $BACKUP_DIR} err]} {puts "错误:创建备份目录失败 - $err"exit 1
}# 检查备份目录写入权限
if {![file writable $BACKUP_DIR]} {puts "错误:备份目录$BACKUP_DIR无写入权限"exit 1
}# 获取符合条件的数据库列表
puts "获取符合条件的数据库列表..."# 创建临时文件存储查询结果
set temp_file [exec mktemp]# 执行ksql查询并将结果输出到临时文件
spawn sh -c "$KSQL -h $DB_HOST -p $DB_PORT -U $DB_USER -d $DEFAULT_DB -t -c \"SELECT datname FROM pg_database WHERE datistemplate = false AND (datname LIKE 'PRO%' OR datname LIKE 'DEV%');\" > $temp_file"# 处理ksql的密码交互
expect {-nocase "Password:" { send "$PGPASSWORD\r"; exp_continue }"Password for user $DB_USER:" { send "$PGPASSWORD\r"; exp_continue }timeout { puts "错误:获取数据库列表超时"; }eof { puts "数据库列表获取完成"; }
}# 从临时文件读取数据库列表
set DB_LIST [exec cat $temp_file]# 删除临时文件
exec rm -f $temp_file# 检查数据库列表是否为空
if {[string trim $DB_LIST] eq ""} {puts "未找到PRO/DEV开头的数据库,无需备份"exit 0
}# 开始备份数据库
puts "开始备份PRO/DEV开头的数据库..."# 生成时间戳
set DATE [exec date +%Y%m%d_%H%M%S]# 遍历数据库列表,逐个备份
foreach DB_NAME [split $DB_LIST "\n"] {set DB_NAME [string trim $DB_NAME]if {$DB_NAME eq ""} { continue }set BACKUP_FILE "$BACKUP_DIR/${DB_NAME}_${DATE}.dmp"set DB_LOG "$BACKUP_DIR/${DB_NAME}_${DATE}.log"# 提前创建日志文件并赋予权限(关键修复)exec touch $DB_LOGexec chmod 644 $DB_LOGputs "\n=== 开始备份 $DB_NAME(备份文件:$BACKUP_FILE) ==="puts "=== 备份日志:$DB_LOG ==="# 执行sys_dump备份命令(调整日志重定向方式)spawn sh -c "$SYS_DUMP -h $DB_HOST -p $DB_PORT -U $DB_USER -v -f $BACKUP_FILE -F c $DB_NAME > $DB_LOG 2>&1"# 记录备份开始时间set start_time [clock seconds]# 处理sys_dump的密码交互expect {-nocase "Password:" { send "$PGPASSWORD\r"; exp_continue }"Password for user $DB_USER:" { send "$PGPASSWORD\r"; exp_continue }timeout {# set elapsed [expr ([clock seconds] - $start_time) / 60]# puts "备份超时(已等待 $elapsed 分钟),终止备份"# catch {exec pkill -f "sys_dump.*$DB_NAME"}# break}eof {set elapsed [expr ([clock seconds] - $start_time) / 60]puts "备份进程结束(耗时 $elapsed 分钟)"}}# 检查备份结果set exit_status [wait]set exit_code [lindex $exit_status 3]# 即使失败也确保日志文件存在(关键修复)if {![file exists $DB_LOG]} {exec touch $DB_LOGputs $DB_LOG "备份失败:进程未生成日志(退出码:$exit_code)"}if {$exit_code == 0 && [file exists $BACKUP_FILE] && [file size $BACKUP_FILE] > 0} {puts "=== $DB_NAME 备份成功 ==="} else {puts "=== $DB_NAME 备份失败(退出码:$exit_code),查看日志:$DB_LOG ==="if {[file exists $BACKUP_FILE]} { exec rm -f $BACKUP_FILE }}
}# 清理旧备份
puts "\n开始清理超过 $KEEP_DAYS 天的旧备份..."
if {[catch {exec find $BACKUP_DIR -name "PRO*.dmp" -o -name "DEV*.dmp" -o -name "PRO*.log" -o -name "DEV*.log" -mtime +$KEEP_DAYS -exec rm -f {} \;} err]} {puts "清理警告:$err"
} else {puts "旧备份清理完成"
}puts "所有备份任务结束"
exit 0
步骤 3: 赋予给脚本权限
我这里使用root角色执行该脚本。
chown root:root backup.exp
chmod 755 backup.exp注意事项
复制到exp的文件可能会存在特殊字符问题(不同系统doc和unix风格不一致)问题;
用vim编辑器转换
- 用
vim打开脚本:bash
vim ./backup.sh - 在 vim 命令模式下输入(按
Esc进入命令模式):vim
:set fileformat=unix - 保存退出:
vim
:wq
