【原创,转载请说明】
        我们在开发过程中,对于数据的要求格外严格,往往要做到数据库的备份。本文基于现实案例,实现Postgresql数据库备份,实现每日定时备份的功能。
        项目需求:实现项目中每天凌晨数据库自动备份。其中数据库为开源数据库Postgresql。

        我们采用shell脚本+pg_dump方式实现每日0点数据库自动备份,方案即为,设置定时任务,服务器每天0点会自动执行shell脚本,shell中会出发数据库备份。

 首先,设置linux下的定时任务,即我们可以在项目初始化时候,在当前环境中设置系统定时任务,定时任务去触发所要执行的脚本内容,如下所示,即将定时任务脚本重定向到/etc/crontab中。

echo "0 0 0 * * *  root /usr/local/bin/dbbk_pgsql.sh" >> /etc/crontab

重启crontab:

/bin/systemctl restart crond.service

以上中的dbbk_pgsql.sh即为定时任务定时执行的脚本命令,用此命令进行数据库备份。

在设置完定时任务后,每到凌晨即会易root用户执行dbbk_pgsql.sh,那么接下来就要在此shell中实现数据库的备份。

在备份数据库前,必要的操作是获取当前所需备份的PostgreSql的数据库密码。如下所示:

/home/postgres/pgsql/bin/psql postgres postgres
Password for user postgres: 

但我们在shell执行中肯定不能这么搞,需要提前知晓PostgreSql的数据库密码。

其中PostgreSql默认当前进程中的环境变量PGPASSWORD为数据库密码!

即可在当前shell中指定环境变量PGPASSWORD,此时的PGPASSWORD需要提前记录到相关文件中,否则是获取不到密码的,例如,我们可以将密码设置到/mnt/syncdata/pg.cfg文件中。记录形式为:

DBPassword=password

故获取密码方式为:

cat /mnt/syncdata/pg.cfg | grep DBPassword | awk -F "=" '{ print $2}'

获取库名称:

/home/postgres/pgsql/bin/psql -d postgres -U postgres -h 127.0.0.1 -c "select datname from pg_database where datname not in('template0','template1','postgres') order by datname;"  >/tmp/temp.txt

## -c "select datname from ...",此部分为执行后sql,由于pg自带三个库(postgres、template0、##template1)我们需要将其排除掉。
## >/tmp/temp.txt 将上述的sql,即筛选出来的库输出重定向到一个临时文件中,用于后续在备份数据库时
## 从改临时文件中读取库名,进行数据库的备份。

接下来开始写dbbk_pgsql.sh。

大体流程图如下所示:

 其实pg备份就是用到的pg自带的pg_dump工具,其命令为:

/home/postgres/pgsql/bin/pg_dump -Fc --username=postgres -h 127.0.0.1   --if-exists postgres >> /psqldata.dump
## --username为用户名
##127.0.0.1为本机ip
## >> /home/pgsqldata.sql 将备份的文件输出重定向到/psqldata.dump中

注意!如配合pg_restore进行还原则使用-Fc,表示以一个适合pg_restore使用的自定义格式输出并归档。这是最灵活的输出格式,在该格式中允许手动查询并且可以在pg_restore恢复时重排归档项顺序。

如不带-Fc,我们可以采用如下写法,但此备份出的文件不能用pg_restore进行恢复,必须用psql进行恢复!

/home/postgres/pgsql/bin/pg_dump --username=postgres -h 127.0.0.1 --create --disable-triggers -c --if-exists postgres >> /pgsqldata.sql
## --username为用户名
##127.0.0.1为本机ip
##--disable-triggers 备份数据库时将触发器停掉
## >> /home/pgsqldata.sql 将备份的文件输出重定向到/home/pgsqldata.sql中

我们采用第一种方式即pg_dump和pg_restore共同使用的情况。

此时再对psqldata.dump进行压缩,得到压缩包:

完整dbbk_pgsql.sh如下,其中忽略了判断磁盘容量和内存大小的判断,跟据实际需要可自行添加判断。

#!/bin/bash
##日志
DBDUMP_LOGDIR=/var/log/pglog
##备份文件路径
DBBKUP_DIR=/var/backup/
DBDUMP_LOGFILE="$DBDUMP_LOGDIR"/dbbr.log

DBDUMP_OUTFILE=/psqldata.dump
MY_PGSQL=/home/postgres/pgsql/bin/psql
DBNAMEFILE=/tmp/temp.txt
DBUSER=postgres
DBDUMP_METHODB=/home/postgres/pgsql/bin/pg_dump

bkdb(){
    outdir=$1
    filename=$2
    MY_PGADDR=$3
    if [ ! -d "$outdir" ]
    then
       mkdir $outdir
    fi
    cd $outdir
    echo "=====================================================================" >> $DBDUMP_LOGFILE
    echo "`date +"%Y-%m-%d %H:%M:%S"`   BEGIN : timing backup db:file:$filename" >> $DBDUMP_LOGFILE
    postgresbk $filename  $outdir ${MY_PGADDR}

    echo "`date +"%Y-%m-%d %H:%M:%S"`  END   : timing backup db:file:$filename" >> $DBDUMP_LOGFILE
    echo "=====================================================================" >> $DBDUMP_LOGFILE
cd --
}

postgresbk(){
##压缩包的名称
  outfile=$1
##备份路径
    my_datadir=$2
##本机ip
    MY_PGIP=$3
export PGPASSWORD=`cat /mnt/syncdata/pg.cfg | grep DBPassword | awk -F "=" '{ print $2}'`
##删除可能已存在的原有备份文件
    if [ -f $DBDUMP_OUTFILE ]; then
        rm -rf $DBDUMP_OUTFILE
    fi   
##读取所需库名称 ,利用临时文件输入重定向读库名称...
    while read  -r line
    do
        DBNAME=${line}
        if [ ! -z "$DBNAME" ]
        then
            $DBDUMP_METHODB -Fc --username=$DBUSER -h ${MY_PGIP}  $DBNAME >>$DBDUMP_OUTFILE
        fi
  done < ${DBNAMEFILE}  
    cd ${my_datadir}
    unset PGUSER
    unset PGPASSWORD
        if [ -f $DBDUMP_OUTFILE ]
    then
        echo "database backup success!" >> $DBDUMP_LOGFILE
        ##  将备份的数据库脚本进行压缩!
		tar cvfzP $outfile $DBDUMP_OUTFILE  >> $DBDUMP_LOGFILE
        if [ $? != 0 ]
        then
            echo "tar cvfz $outfile $DBDUMP_OUTFILE failed!" >> $DBDUMP_LOGFILE
            exit 1
        fi
echo "tar success!" >> $DBDUMP_LOGFILE
    else
        echo "database backup fail!" >> $DBDUMP_LOGFILE
        exit 1
    fi
    if [ -f $DBDUMP_OUTFILE ]; then
        rm -rf $DBDUMP_OUTFILE
    fi
    
    unset PGUSER
    unset PGPASSWORD
}
if [ ! -d  ${DBDUMP_LOGDIR} ]
then
    mkdir -p   ${DBDUMP_LOGDIR}
fi

if [ ! -d  ${DBBKUP_DIR} ]
then
    mkdir -p   ${DBBKUP_DIR}
fi
if [ ! -f  ${DBDUMP_LOGFILE} ]
then
    touch  ${DBDUMP_LOGFILE}
fi
if [ -f ${DBDUMP_OUTFILE} ]
then
    rm -rf ${DBDUMP_OUTFILE}
fi
rm -rf ${DBNAMEFILE}
touch ${DBNAMEFILE}
chmod 775 ${DBNAMEFILE}
HOST_IP=127.0.0.1
export PGPASSWORD=`cat /mnt/syncdata/pg.cfg | grep DBPassword | awk -F "=" '{ print $2}'`
##由于pgsql自带三种库,我们在备份时应将此三种库排除。
${MY_PGSQL} -d postgres -U postgres -h ${HOST_IP} -c "select datname from pg_database where datname not in('template0','template1','postgres') order by datname;"  >${DBNAMEFILE}
##在上一步中筛选出库的形式(假如就一个库,名称为test)为:
##
##  datname
##-----------
## test
##(1 row)
##
##故,我们只需保留test,所以将其他的数据都删除掉。

sed -i '$d' ${DBNAMEFILE}
sed -i '$d' ${DBNAMEFILE}
sed -i '1d' ${DBNAMEFILE}
sed -i '1d' ${DBNAMEFILE}

##设置压缩文件的文件格式名,每天备份,则采用日期来区别
time=`date "+20%y-%m-%d_%H%M"`
##调用方法进行备份,传参分别为:备份文件所在路径、文件名称、和本机ip
bkdb $DBBKUP_DIR pgsqldata-$time.tar.gz ${HOST_IP}

unset PGPASSWORD
exit 0 

以上操作完后,服务器会在每天0点进行备份数据库并在/var/backup/下生成对应的pgsqldata-*.tar.gz的压缩包文件。

备份已完成,下一篇,PosgreSql实战,分享如何在linux环境下还原备份库。

更多推荐