in Профессиональное

Скрипт для бэкапа mysql баз

Написал для себя простенький скрипт (linux bash) для бэкапа всех баз на одном сервере. Его отличительные особенности:

  • Наличие списка исключений (т.е. бэкапим все кроме…)
  • Получение списка всех БД из MySQL (не надо добавлять вновь созданные базы к бекапу)
  • Создание директории под бэкап вида “…/YYYY/mm/dd/HH-MM/”
  • Бэкап каждой базы в отдельный файл вида “YYYY-mm-dd.HH-MM.databasename.backup.sql” (mysqldump бэкапит все в один файл)
  • Архивирование бэкапа в тарбол
  • Зачистка .sql

Собственно к написанию скрипта меня сподвигло именно то что mysqldump бэкапит все что ему сказано в один файл (если требуется восстановить одну базу, то попробуй ее выцарапай из общего дампа…), а создавать отдельную строку для бэкапа всякой новой БД геморно (об этом как минимум надо вспомнить!).

В общем если интересно – прошу под кат:


Собственно сам скрипт

#!/bin/bash
 
##
# MySQL backup utility
# @author dmitry.bykadorov@gmail.com
##
 
# current date
DATE=`date +%Y-%M-%d`
 
# y/m/d/h/m separately
YEAR=`date +%Y`
MONTH=`date +%m`
DAY=`date +%d`
HOURS=`date +%H`
MINUTES=`date +%M`
 
# database credentials
DBUSER=""
DBPASS=""
DBHOST=""
 
# create list of databases
mysql -h $DBHOST -u $DBUSER -p$DBPASS -e "show databases;" > /tmp/databases.list
 
# create backup dir (e.g. ../2011/01/01/04-00)
BACKUP_DIR=/home/backups/mysql/$YEAR/$MONTH/$DAY/$HOURS-$MINUTES
mkdir --parents --verbose $BACKUP_DIR
 
# excludes list (Database is a part of SHOW DATABASES output)
EXCLUDES=( 'Database' 'information_schema' )
NUM_EXCLUDES=${#EXCLUDES[@]}
 
for database in `cat /tmp/databases.list`
do
  skip=0
 
  let count=0
  while [ $count -lt $NUM_EXCLUDES ] ; do
    # check if this name in excludes list
    if [ "$database" = ${EXCLUDES[$count]} ] ; then
      let skip=1
    fi
    let count=$count+1
  done
 
  if [ $skip -eq 0 ] ; then
    echo "++ $database"
    # now we can backup current database
    cd $BACKUP_DIR
    backup_name="$YEAR-$MONTH-$DAY.$HOURS-$MINUTES.$database.backup.sql"
    backup_tarball_name="$backup_name.tar.gz"
    `/usr/bin/mysqldump -h "$DBHOST" --databases "$database" -u "$DBUSER" --password="$DBPASS" > "$backup_name"`
    echo "   backup $backup_name"
    `/bin/tar -zcf "$backup_tarball_name" "$backup_name"`
    echo "   compress $backup_tarball_name"
    `/bin/rm "$backup_name"`
    echo "   cleanup $backup_name"
  fi
done
 
`/bin/rm /tmp/databases.list`
 
echo "done!"

Можете его свободно:

  • использовать (никаких гарантий я вам конечно же не даю – на свой страх и риск )))
  • модифицировать (например добавить выгрузку бэкапа на другой сервер или на Amazon S3 )))
  • критиковать ))

P.S. Если таки будете использовать – не забудьте подставить ваши mysql credentials ))

Write a Comment

Comment

*

12 Comments

  1. Несколько мыслей вслух:
    – такой скрипт можно использовать только если к базе не идут интенсивные запросы на изменения (иначе mysqldump не всегда делает консистентный дамп)
    – скрипт можно использовать только если реквизиты доступа для всех баз одни
    – для реквизитов можно использовать переменные окружения и/или передаваемые параметры
    – сжимать можно на лету (это быстрее): | gzip > dump.gz

    • Привет, Сережа! ) Спасибо что заглянул!

      – касательно нагрузки – тут ты безусловно прав. У меня сейчас этот процесс происходит ночью, когда нагрузки практически нет. Но, понятное дело, не всем этот рецепт подойдет. С другой стороны при объемах/нагрузках когда mysqldump может давать неконсистентный дамп, наверное и сам дамп уже настолько объёмен что снимать его невыгодно. Во всяком случае часто и под нагрузкой. Тут уже нужна совсем другая архитектура )

      – права доступа на базы, ценное замечание, но я, редиска, пользуюсь суперюзером )

      – передача логина/пароля через параметры скрипта мне была не нужна (все-равно пришлось бы в crontab указывать например), а вот переменные окружения стоит попробовать. Хотя чтобы после ребута их не перенабирать – видимо все-равно придется прописать куда-нибудь в init скрипт.

      С другой стороны для бекапов можно сделать backup%localhost без пароля с правами на все. Хотя наверное тоже не айс.

      А вот насчет “сжимать на лету” – может подскажешь, я как-то все tar да tar, он через перенаправление у меня не фурычит ) Наверное не так готовлю…

  2. А tar в данном случае и не требуется, потому как он архиватор, т. е. собирает кучу файлов один, тут лучше подойдет компрессор, коим gzip и является. А скрипт будет выглядеть примерно так:

    if [ $skip -eq 0 ] ; then
      echo "++ $database"
      # now we can backup current database
      cd $BACKUP_DIR
      backup_name="$YEAR-$MONTH-$DAY.$HOURS-$MINUTES.$database.backup.sql.gz"
      /usr/bin/mysqldump -h "$DBHOST" --databases "$database" -u "$DBUSER" --password="$DBPASS" | gzip > $backup_name
    fi
    • В принципе да, можно и на gzip переделать, это реально быстрее, Сережа ‘FatCat’ выше тоже это отметил. Tar я использовал потому как думал что его тоже можно через пайп запустить )

  3. чето не отрабатывает ваш скриптец на дебиане(

    root@serever:/home/blind# sh sql.sh
    : not found
    : not found
    : not found
    : not found
    : not found
    ‘@’localhost’ (using password: YES)or user ‘root
    : not found
    mkdir: создан каталог «/home/backups/mysql/2011\r/10\r/30\r/23\r-59\r\r\r»
    : not found
    sql.sh: 31: Syntax error: “(” unexpected

    • Ну почему же так категорично ) У меня в bash трудится во всю с момента написания этого поста. @blind: кокой шелл?

      mkdir: создан каталог «/home/backups/mysql/2011\r/10\r/30\r/23\r-59\r\r\r»

      Вот тут \r какие-то подозрительные больно. Можешь сам скрипт намылить?

  4. Могу предложить свой вариант.
    Основой стал Ваш пример, а я допилил хранение ограниченое кол-во число архивов, и включил в архивацию не олько SQL базы а и каталоги сайтов…

    #!/bin/sh
    to="/var/www/hosting-user/data/backup"
    patch="/var/www/hosting-user/data/www"
    
    # current date
    DATE=`date +%Y-%M-%d`
     
    # y/m/d/h/m separately
    YEAR=`date +%Y`
    MONTH=`date +%m`
    DAY=`date +%d`
    HOURS=`date +%H`
    MINUTES=`date +%M`
     
    # database credentials
    DBUSER="user-name"
    DBPASS="user-password"
    DBHOST=""
     
    #muve old backups on +1 day
    # i=0
    for i in {5..0}
    do
      mv $to/backup+$i $to/backup+$[$i+1]
    done
    mkdir --parents --verbose $to/backup+0
    
    # create list of databases
    mysql -u $DBUSER -p$DBPASS -e "show databases;" > $to/databases.list
     
    # excludes list (Database is a part of SHOW DATABASES output)
    EXCLUDES=( 'Database' 'information_schema' 'mysql')
    NUM_EXCLUDES=${#EXCLUDES[@]}
     
    for database in `cat $to/databases.list`
    do
      skip=0
     
      let count=0
      while [ $count -lt $NUM_EXCLUDES ] ; do
        # check if this name in excludes list
        if [ "$database" = ${EXCLUDES[$count]} ] ; then
          let skip=1
        fi
        let count=$count+1
      done
     
      if [ $skip -eq 0 ] ; then
        echo "++ $database"
        # now we can backup current database
        cd $to/backup+0
        backup_name="$YEAR-$MONTH-$DAY.$database.backup.sql"
        backup_tarball_name="$backup_name.tar.gz"
        `/usr/bin/mysqldump --databases "$database" -u "$DBUSER" --password="$DBPASS" > "$backup_name"`
        echo "   backup $backup_name"
        `/bin/tar -zcf "$backup_tarball_name" "$backup_name"`
        echo "   compress $backup_tarball_name"
        `/bin/rm "$backup_name"`
        echo "   cleanup $backup_name"
      fi
    done
    `/bin/rm $to/databases.list`
    echo "MySQL backup is done!"
    
    
    #########################
    # backuping is www dir
    #########################
    
    ls $patch | grep -v 'www.simbl.linc.ua' > $to/dir.list
    for dir in `cat $to/dir.list`
    do
    	tar -zcvpf $to/backup+0/"$YEAR-$MONTH-$DAY.$dir.backup.www.tar.gz" --exclude=$patch/$dir/backup.txt --exclude=$patch/$dir/awstats --exclude=$patch/$dir/bitrix/backup --exclude=$patch/$dir/upload/update --exclude=$patch/$dir/upload/support/not_image --exclude=$patch/$dir/modlogan --exclude=*.exe --exclude=*.rar $patch/$dir/
    done
    rm $to/dir.list
    echo "Dir backup is Done!"
    
    • Вообще скрипт под bash писался, на фряхе сейчас какой шелл по умолчанию? Если доберусь до консоли freebsd на днях, проверю.

Webmentions

  • http://wiki.toplistforum.com/ 2017/03/06

    http://wiki.toplistforum.com/

    Скрипт для бэкапа mysql баз