使用场景        

        因需求需要把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_LOG
    exec chmod 644 $DB_LOG

    puts "\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_LOG
        puts $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编辑器转换

  1. vim打开脚本:

    bash

    vim ./backup.sh
    
  2. 在 vim 命令模式下输入(按Esc进入命令模式):

    vim

    :set fileformat=unix
    
  3. 保存退出:

    vim

    :wq
Logo

腾讯云面向开发者汇聚海量精品云计算使用和开发经验,营造开放的云计算技术生态圈。

更多推荐