Backup MYSQL

Прежде чем бекапить MYSQL, нужно выполнить экспорт данных в текстовые файлы. Для этого используется программа mysqldump.

Ниже приведен универсальный скрипт экспорта баз mysql в текстовые файлы для дальнейшей передачи на сервер бекапов.

Скрипт реализован на универсальном для UNIX языке bash и должен работать почти на любом хосте.

Возможности скрипта:

  • умеет принимать логин с паролем в параметрах запуска
  • умеет принимать в параметрах запуска (третий и далее параметры) список баз для полного копирования
  • умеет импортировать список нужных баз из cvs файла, если файл существует и заданы логин с паролем
  • умеет импортировать список таблиц из этого же файла
  • умеет дампить все таблицы базы данных при отсутствии cvs файла
  • умеет писать достаточно информативные логи в файл
  • умеет передавать логи на стандартный вывод при включенном режиме отладки
  • умеет производить ротацию собственных логов
  • умеет удалять устаревшие бекапы. Период, за который бекапы считаются устаревшими настраивается.

Файл backupmysql.sh

#!/usr/bin/env bash
#Oleg Yamshikov 2014 v1.0
#Скрипт обертка к mysqldump. Может запускаться в процедурах DumpPreUserCmd в различных системах автобекапа.
#Краткая инструкция. 
# ./backupmysql.sh root password #Запуск с пользователем и паролем: экспорт всех баз данных, видимых для пользователя.
# Такой же запуск при наличии файла backuptables.dat (синтаксис файла: 
# Имя_базы_данных:+: таблица1 таблица2
# Имя_базы_данных2:-: таблица1 таблица2
# - частичный экспорт указанных баз данных с включением(+)/исключением(-) указанных таблиц
# ./backupmysql.sh root password db1 db2 ... dbn # Полный дамп всех баз данных, перечисленных после логина с паролем.
#Далее перечислены некоторые настройки с комментариями
 
 
LOG="${HOME}/mysql_backup.log" #Расположение файла логов
DIR="${HOME}/backups" #Расположение каталога с бекапами (автоматически создается при лостаточном наличии прав)
DUMP_OPTIONS="--skip-lock-tables" #Сюда все необходимые опции mysqldump. 
SAVE_DUMP_PERIOD=5 #Сколько дней хранить файлы дампов на сервере
LOG_TO_STDOUT='no' #yes, если нужно выводить сообщения логов так же в stdout на экран
 
#Универсальная процедура логирования. Может принимать параметры, либо поток stdin
LOGGER(){
	echo -n `date '+%F %T'`" " >> $LOG
	if [[ $# > 0 ]]; then 
		echo $@ >> $LOG
	else
		err=$(cat -)	
		if [[ ${#err} = 0 ]]; then
			err="Выполнено без ошибок"
		fi
		echo $err>> $LOG
	fi
	if [[ ! -z $LOG_TO_STDOUT && $LOG_TO_STDOUT != 'no' ]]; then tail -n 1 $LOG; fi
}
#Для отделения друг от друга логов запуска скрипта в разное время.
LOGGER "";
 
#Урезаем лог до 500 строк, на всякий случай..
if [[ -f $LOG ]]; then
    tail --lines=500 --silent $LOG > "$LOG.cut"
    mv "$LOG.cut" $LOG
fi
 
if [[ ! -d $DIR ]]; then
	mkdir -p $DIR
	LOGGER "создан каталог бекапов $DIR"
fi
 
#Получаем логин с паролем к базе данных. Не храним авторизацию в скрипте, храним ее на сервере бекапов в строке вызова скрипта
if [[  -z $1 ||  -z $2 ]]; then
	echo "usage $0   [<список бд для бекапа через пробел, заключенный в кавычки>]"
	LOGGER "Запуск без параметров, выход"
	LOGGER "";
	exit 0
else
	user=$1
	LOGGER "Начало резервного копирования. Используем имя пользователя $1"
	password=$2
fi
 
data_from_file(){
	#Чтобы не использовать pipe
	egrep -v '^#|^$' backuptables.dat > "${HOME}/backuptables.dat1"	
	oldIFS=$IFS; IFS=':'
	while read db oper tables
	do	
		DATADASES[${#DATADASES[*]}]=$db
		opers[${#opers[*]}]=$( echo "${oper}"| sed -e 's/^ *//' -e 's/ *$//' ); #нужна чистая строка без пробелов
		tabless[${#tabless[*]}]=$tables
	done < "${HOME}/backuptables.dat1" 
	IFS=$oldIFS
	rm 	"${HOME}/backuptables.dat1"
	if [[ ${#DATADASES[@]} == 0 ]]; then
	LOGGER "Список данных для резевного копирования загружен из файла backuptables.dat"
	fi
}
 
 
dump_database(){
for (( i=0; i<${#DATADASES[@]}; i++ )); do
	if [[ ${DATADASES[$i]} != '' ]]; then
	TIMEDUMP=`date '+%F_%H_%M_%S'`
		if [[ ${opers[$i]} = '+' ]]; then
			LOGGER "$i. Бекап таблиц ${tabless[$i]} базы данных ${DATADASES[$i]}"
			LOGGER "Бекап схемы базы данных ${DATADASES[$i]} [$DIR/$TIMEDUMP-${DATADASES[$i]}-dbschema.sql.gz]"
			{ mysqldump -u$user  -p"$password" -B "${DATADASES[$i]}" $DUMP_OPTIONS --no-data 2>&1 1>&666 | LOGGER; } 666>&1 |  gzip -c > "$DIR/$TIMEDUMP-${DATADASES[$i]}-dbschema.sql.gz"
			if [[ ${#tabless[$i]} > 0 ]]; then
				LOGGER "Бекап данных ${DATADASES[$i]} [$DIR/$TIMEDUMP-${DATADASES[$i]}-dbdata.sql.gz]"
				{ mysqldump -u$user  -p$password ${DATADASES[$i]} $ignoretables $DUMP_OPTIONS ${tabless[$i]} 2>&1 1>&666 | LOGGER; } 666>&1 |  gzip -c > "$DIR/$TIMEDUMP-${DATADASES[$i]}-dbdata.sql.gz" 		
			else 
				LOGGER "Нет таблиц для дампа информации для базы данных ${DATADASES[$i]}"
			fi
		elif [[ ${opers[$i]} = '-' ]]; then
			LOGGER "$i. Бекап всей базы данных ${DATADASES[$i]} кроме таблиц ${tabless[$i]}"
			LOGGER "Бекап схемы базы данных ${DATADASES[$i]} [$DIR/$TIMEDUMP-${DATADASES[$i]}-dbschema.sql.gz]"
			{ mysqldump -u$user  -p"$password" -B "${DATADASES[$i]}" $DUMP_OPTIONS --no-data 2>&1 1>&666 | LOGGER; } 666>&1 |  gzip -c > "$DIR/$TIMEDUMP-${DATADASES[$i]}-dbschema.sql.gz" 
			if [[ ${#tabless[$i]} > 0 ]]; then
				for table in ${tabless[$i]}; do
					ignoretables="$ignoretables  --ignore-table=${DATADASES[$i]}.$table"
				done;
				LOGGER "Бекап данных ${DATADASES[$i]} [$DIR/$TIMEDUMP-${DATADASES[$i]}-dbdata.sql.gz]"
				{ mysqldump -u$user  -p$password -B "${DATADASES[$i]}" $ignoretables $DUMP_OPTIONS 2>&1 1>&666 | LOGGER; } 666>&1 |  gzip -c > "$DIR/$TIMEDUMP-${DATADASES[$i]}-dbdata.sql.gz" 		
			else 
				LOGGER "Нет таблиц для дампа информации для базы данных ${DATADASES[$i]}"
			fi
		else
			LOGGER "$i. Полный бекап базы данных ${DATADASES[$i]} [$DIR/$TIMEDUMP-${DATADASES[$i]}-db.sql.gz]"
		    { mysqldump -u$user  -p"$password" -B "${DATADASES[$i]}" $DUMP_OPTIONS 2>&1 1>&666 | LOGGER; } 666>&1 |  gzip -c > "$DIR/$TIMEDUMP-${DATADASES[$i]}-db.sql.gz" 
		fi
	fi
done;
}
 
 
if [[ -z $3 ]]; then
	if [ -f backuptables.dat ]; then
		data_from_file
	fi
	if [[ ${#DATADASES[@]} == 0 ]]; then
		DATADASES=($(mysql -u $user -p$password -Bse "show databases"))
	fi
else
	#Извлекаем срез переданных аргументов. Все что больше первых двух - имена баз данных для бекапа
	#(первое - логин, второе - пароль)
	DATADASES=(${@:3})
fi
 
 
LOGGER "Список баз для резервного копирования: ${DATADASES[@]}"
dump_database
 
#Очистка резервных копий
find $DIR -mtime +7 -exec rm -fR {} \;
 
LOGGER "Резервное копирование завершено"
cp $LOG $DIR

В том случае, если нужно бекапить только определенные таблицы баз данных, или бекапить базы данных без определенных таблиц (например, если эти таблицы слишком большие) в этой не большой системе предусмотрен специальный файл, описывающий наши потребности.

Этот файл формата csv - файл с разделителями, где в качестве разделителя принимается ":" (двоеточие) Вот пример файла с комментариями по использованию

Файл backuptables.dat

#Oleg Yamshikov 2014
#Файл содержит список баз данных и таблицы для бекапа
#Для корректной работы, имя файла должно быть backuptables.dat
#Формат файла и пример:
#  Имя базы данных&nbsp;: + или -&nbsp;: таблица1 таблица2
#  zabbix:-:events history_uint proxy_history
#
# + -- бекап только указанных таблиц
# - -- Бекап всех таблиц базы, за исключением указанных
#список таблиц баз данных нужно писать через пробел, если таблицы не указаны, то дампится только структура базы, независимо от режима + или - 
redmine_allo:+&nbsp;:roles users
todo_allo:-:attachments
phpmyadmin:+:
rex:        

Общая логика работы скрипта такая:

  • Проверяем переданные параметры, если нет пользователя или пароля, то выходим.
  • Если есть пользователь пароль и еще как минимум один параметр - полностью бекапим все базы данных, перечисленные после имени пользователя с паролем.
  • Если есть логин пароль и файл backuptables.dat то парсим файл и бекапим только определенные таблицы по вышеописанным правилам
  • Если нет файла backuptables.dat, то определяем, какие базы данных доступны пользователю и дампим их все.

При первом запуске скрипт создает каталог, куда будут складываться резервные копии (по умолчанию он находится в домашнем каталоге пользователя, от которого запускается скрипт), так же создается файл лога, в который записывается достаточно подробная информация.

Пример лога:

2014-03-18 12:35:55 
2014-03-18 12:35:55 Начало резервного копирования. Используем имя пользователя root
2014-03-18 12:35:55 Список данных для резевного копирования загружен из файла backuptables.dat
2014-03-18 12:35:55 Список баз для резервного копирования: redmine_allo todo_allo phpmyadmin rex
2014-03-18 12:35:55 0. Бекап таблиц roles users базы данных redmine_allo
2014-03-18 12:35:55 Бекап схемы базы данных redmine_allo [/home/oyamshikov/backups/2014-03-18_12_35_55-redmine_allo-dbschema.sql.gz]
2014-03-18 12:35:55 Выполнено без ошибок
2014-03-18 12:35:55 Бекап данных redmine_allo [/home/oyamshikov/backups/2014-03-18_12_35_55-redmine_allo-dbdata.sql.gz]
2014-03-18 12:35:55 Выполнено без ошибок
2014-03-18 12:35:55 1. Бекап всей базы данных todo_allo кроме таблиц attachments
2014-03-18 12:35:55 Бекап схемы базы данных todo_allo [/home/oyamshikov/backups/2014-03-18_12_35_55-todo_allo-dbschema.sql.gz]
2014-03-18 12:35:55 Выполнено без ошибок
2014-03-18 12:35:55 Бекап данных todo_allo [/home/oyamshikov/backups/2014-03-18_12_35_55-todo_allo-dbdata.sql.gz]
2014-03-18 12:35:55 Выполнено без ошибок
2014-03-18 12:36:02 2. Бекап таблиц базы данных phpmyadmin
2014-03-18 12:36:02 Бекап схемы базы данных phpmyadmin [/home/oyamshikov/backups/2014-03-18_12_36_02-phpmyadmin-dbschema.sql.gz]
2014-03-18 12:36:02 Выполнено без ошибок
2014-03-18 12:36:02 Нет таблиц для дампа информации для базы данных phpmyadmin
2014-03-18 12:36:03 3. Полный бекап базы данных rex [/home/oyamshikov/backups/2014-03-18_12_36_03-rex-db.sql.gz]
2014-03-18 12:36:03 Выполнено без ошибок
2014-03-18 12:36:03 Резервное копирование завершено

Если нужно включить режим отладки, чтобы логи выводились в стандартный вывод на консоль, достаточно установить переменную LOG_TO_STDOUT='yes'

Категории:

Комментарии

 Надо как нибудь рецепт приготовления bacula закинуть.