With all the databases I run, I need a daily sanity check. I download a copy of each database and do a test load on my system at home. Today I timed that process:
$ time ~/bin/backup-supernews.sh ... real 77m57.323s user 12m52.610s sys 0m56.136s
There are 11 such databases. The dump files range in size from 5K (globals.sql) to 2.8G (freshports.sql).
The script that does this is pretty simple, but has evolved over the years.
#!/bin/sh # # This file does a backup of each database on the nyi server. # It relies upon a file on nyi to do the actual backup, # then uses rsync to copy the files from nyi to here. # BACKUPDIR=${HOME}/backups/supernews/database-backup IDENTITY_FILE=${HOME}/.ssh/id_dsa_no_passphrase SERVER_TO_BACKUP=supernews.example.org cd ${BACKUPDIR}/postgresql YYYYMMDD=`eval date "+%Y.%m.%d"` echo will tar things up into ${YYYYMMDD} format FILES=`echo *.sql` echo will be processing ${FILES} # maybe there are no such files if [ "x${FILES}" != 'x\*.sql' ] then for i in $FILES do # mv ${i} archive tar -cvzf archive/`basename ${i} .sql`.${YYYYMMDD}.sql.tgz ${i} done else echo no files found for processing fi cd ${BACKUPDIR}/mysql FILES=`echo *.sql` # maybe there are no such files if [ "x${FILES}" != 'x\*.sql' ] then for i in $FILES do # mv ${i} archive tar -cvzf archive/`basename ${i} .sql`.${YYYYMMDD}.sql.tgz ${i} done fi cd ${BACKUPDIR} # # dump the databases on the remote server # logger "dumping the databases on ${SERVER_TO_BACKUP} from `hostname`" ssh -i ${IDENTITY_FILE} dan@${SERVER_TO_BACKUP} ~dan/bin/backup.sh # # use rsync to get local copies # /usr/local/bin/rsync -e "ssh -i ${IDENTITY_FILE}" --recursive -avz --stats --progress \ --exclude 'archive' dan@${SERVER_TO_BACKUP}:~/database-backup/ ${BACKUPDIR} # # now do a test of the backups to ensure they actually restore ~/bin/test-backups.sh ${BACKUPDIR}
That is the job that archives the old files and downloads the new ones.
The following script loads up that database and is referred to in the last line of the above script:
#!/bin/sh # # test the files we've recovered # BACKUPDIR=$1 GLOBALS="globals" PSQL=/usr/local/bin/psql CREATEDB=/usr/local/bin/createdb DROPDB=/usr/local/bin/dropdb cd ${BACKUPDIR}/postgresql echo dropping test databases FILES=`echo *.sql` for i in $FILES do DBNAME=`basename $i .sql` if [ ${DBNAME} != ${GLOBALS} ] then ${DROPDB} ${DBNAME}_test fi done echo loading GLOBALS if [ -r "${GLOBALS}.sql" ] then ${PSQL} postgres < ${GLOBALS}.sql fi echo creating the databases for i in $FILES do DBNAME=`basename $i .sql` if [ ${DBNAME} != ${GLOBALS} ] then ${CREATEDB} ${DBNAME}_test -E SQL_ASCII ${PSQL} --quiet ${DBNAME}_test < ${DBNAME}.sql fi done
The final part of the puzzle is the script run on the production server which dumps all the databases required:
#!/bin/sh PGDUMP=/usr/local/bin/pg_dump MYSQLDUMP=/usr/local/bin/mysqldump BACKUPROOT=${HOME}/database-backup cd ${BACKUPROOT}/postgresql DATABASES="bsdcert fpphorum freshports.org fsphorum openx nagios \ pentabarf pentabarf_bsdcan pentabarf_pgcon postgres" for database in ${DATABASES} do echo dumping $database if [ -f ${database}.sql ] then mv ${database}.sql archive fi ${PGDUMP} ${database} > ${database}.sql if [ $? -ne 0 ] then echo backup of ${database} failed fi done # # Now dump the globals # if [ -f globals.sql ] then mv globals.sql archive fi /usr/local/bin/pg_dumpall -g > globals.sql if [ $? -ne 0 ] then echo backup of globals failed fi DATABASES="cacti mysql" cd ${BACKUPROOT}/mysql for database in ${DATABASES} do echo dumping $database if [ -f ${database}.sql ] then mv ${database}.sql archive fi ${MYSQLDUMP} -u root ${database} > ${database}.sql if [ $? -ne 0 ] then echo backup of ${database} failed fi done
Any questions? :)