【原创,转载请说明】
我们在开发过程中,对于数据的要求格外严格,往往要做到数据库的备份。本文基于现实案例,实现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环境下还原备份库。