Бесшовная миграция MySQL 5.0 -> Percona Server 5.5 с переразбивкой хранилища

в 5:19, , рубрики: mysql, Percona, Блог компании «Alawar Entertainment», миграция бд, метки: , ,

Здравствуйте.

Хочу поделиться опытом миграции боевой базы данных с MySQL 5.0 на Percona Server 5.5 под нагрузкой почти без отрыва от производства.

Опишу вкратце эволюцию нашей базы до текущего состояния

База у нас древняя, пережила несколько апгрейдов MySQL. Начинали с MySQL 3.x. С ростом нагрузки, уже на MySQL 5.0, настроили репликацию и подключили еще один сервер для чтения. Тогда мы это делали стандартными средствами MySQL, без привлечения xtrabackup — полностью блокировали сервер на время создания мастер-дампа и вывешивали на сайтах заглушки.

Затем встала следующая проблема — на томе с данными стало заканчиваться место. Плюс InnoDB-хранилище исторически располагалось в одном файле. Было рассмотрено много вариантов решения. Начиная от размещения базы на iSCSI-томе и заканчивая перетыканием в рейд более емких дисков, расширением на них volume group / logical volume с последующим расширением файловой системы.

В качестве временного варианта решили подключить iSCSI-том из виртуалки под VMWare vCloud (не реклама, честно!). vCloud стоит у нас под боком.

Начали с эксперимента на slave. Эксперимент прошел удачно, и какое-то время второй read-only MySQL держал хранилище на iSCSI-томе.

Стали всерьез задумываться о переезде базы полностью в облако

В качестве эксперимента подключили вторым слейвом на чтение сервер в vCloud. Перенесли на него всю нагрузку с первого слейва. По производительности виртуальный сервер выигрывал с хорошим отрывом. Сказывалось более мощное железо у хостов vCloud. Переключили нагрузку назад. Стали думать.

В этот момент случилось странное мистическое событие. Спустя нескольких часов после завершения эксперимента с нагрузкой на виртуальном сервере в датацентре произошла хитрая авария, в результате которой обесточилось несколько серверов, в том числе физический слейв. В relay log, находящийся на iSCSI-томе у физического слейва, попал мусор. Репликация остановилась.

Самым логичным действием в этой ситуации было переключение на облачный слейв, что мы и сделали.

Таким образом мы уже находились одной read-only ногой в vCloud. Надо было перетаскивать master.

Переехать решили на Percona 5.5, так же на два сервера, но с потабличным разбиением InnoDB-хранилища.

Основным ограничением при переезде была невозможность останавливать базу на сколько-нибудь продолжительное время.
Поскольку речь идет о разбиении InnoDB-хранилища на таблицы, простым копированием данных обойтись не получится. Надо вливать новую базу из дампа.

Чтобы получить мастер-дамп, надо залочить 125-гиговую базу на время более часа. Это неприемлемо на боевой базе. Мы решили бэкапить мастер при помощи xtrabackup, поднимать на получившемся слепке сервер, и снимать с него мастер-дамп.

Итак, ингредиенты

  • Два старых боевых MySQL-5.0-сервера под нагрузкой. Назовем их 5.0-master и 5.0-slave.
  • Два новых боевых Percona-5.5-сервера пока без нагрузки, данных и репликации. Назовем их 5.5-master и 5.5-slave.
  • Один промежуточный MySQL-5.0-сервер для снятия дампа. Назовем его 5.0-Kenny.

Для разбиения InnoDB-хранилища по таблицам на новых серверах надо выставить опцию "innodb_file_per_table=1".

Поскольку речь идет об облаке, мы играючи поднимаем три недостающих сервера за пять минут.

В рамках программы по сокращению времени простоя до минимума мы решили не перенастраивать приложения для работы с новым мастером, а просто поднять ip старого мастера на новом сервере. Для этого необходимо, чтобы ip старого сервера был виден на новом мастере для всех клиентов. В нашем случае все пять серверов находятся в одной подсети, так что проблем с этим нет.

А теперь — последовательность действий

  • С мастер-базы (5.0-master) снимаем дамп при помощи xtrabackup:
    innobackupex --user=root --password=Yoo0edae _каталог_назначения_
    

    Важно помнить, что чем больший объем данных вашей базы находится в MyISAM-таблицах, тем на большее время база будет заблокирована при финализации xtrabackup, так как MyISAM-таблицы копируются полностью во время финальной блокировки базы. В нашем случае MyISAM-данных практически нет, поэтому база находится в заблокированном состоянии всего несколько секунд.

  • В полученном каталоге с данными есть файл xtrabackup_binlog_info — запоминаем из него позицию в бинлоге.
  • Полученный слепок копируем на 5.0-Kenny (мы монтировали диск с Kenny по NFS на 5.0-Master, и указывали его в каталоге назначения при снятии данных xtrabackup-ом, так что данные на 5.0-Kenny появлялись в процессе работы xtrabackup). Там его подготавливаем:
    innobackupex --apply-log _каталог_с_бэкапом_
    

  • Останавливаем MySQL. вычищаем каталог с данными MySQL, в него копируем наш слепок:
    innobackupex --copy-back _каталог_с_бэкапом_
    

    Можно скопировать вручную. Тогда в MySQL-хранилище останется некоторый мусор от процесса резервирования. При необходимости выставляем правильного владельца на каталог с данными.

  • Запускаем MySQL. Убеждаемся, что ошибок нет.
  • С 5.0-Kenny снимаем дамп:
    mysqldump --all-databases > mysql.dump
    

  • Полученный дамп копируем на 5.5-master. Вливаем:
    mysql < mysql.dump
    

  • Рестартуем MySQL. Любуемся на гору ошибок в логе. Апгрейдим схему до версии 5.5:
    mysql_upgrade --force
    

  • Рестартуем MySQL. В логах должно быть чисто.
  • Включаем репликацию, подключаем 5.5-master к бинлогу 5.0-master. Для этого сначала добавляем на 5.0-master пользователя для репликации (про server-id все ведь помнят, да?):
    mysql> GRANT REPLICATION SLAVE ON *.* TO 'repl_master_55' IDENTIFIED BY 'slavepass';
    mysql> FLUSH PRIVILEGES;
    

    после чего на 5.5-master выполняем запрос:

    mysql> CHANGE MASTER TO MASTER_HOST='master_host_name', MASTER_USER='repl_master_55', 
    MASTER_PASSWORD='slavepass', MASTER_LOG_FILE='recorded_log_file_name', MASTER_LOG_POS=recorded_log_position;
    mysql> START SLAVE;

    Значения MASTER_LOG_FILE и MASTER_LOG_POS берем из файла "xtrabackup_binlog_info".

  • Убеждаемся, что репликация пошла:
    mysql> SHOW SLAVE STATUSG
    

    Наш 5.5-master какое-то время будет слейвом для 5.0-master. Для того чтобы запросы с 5.0-master попадали в бинлог на 5.5-master, на 5.5-master надо выставить опцию "log-slave-updates=1". По дефолту она равна нулю, то есть в бинлог попадают только локальные изменения.

  • Снимаем с 5.5-master дамп при помощи xtrabackup. Копируем дамп на 5.5-slave.
  • Поднимаем 5.5-slave, цепляем его к бинлогу 5.5-master.

Итого, у нас получается четыре сервера: два старых, но пока боевых MySQL 5.0, и два новых Percona 5.5 уже с актуальными данными.

  • Переключаем всю read-only-нагрузку со старого 5.0-slave на новый 5.5-slave. Поскольку 5.5-slave реплицируется с 5.5-master, который в свою очередь реплицируется с 5.0-master, никто ничего не замечает. Полдела сделано — часть нагрузки у нас уже на новой связке.

Начинается самое интересное. Здесь находится точка невозврата. Начиная с этого момента, засекаем время простоя мастер-базы.

  • Останавливаем MySQL на 5.0-master.
  • Убеждаемся, что все данные из бинлога попали на 5.5-master
  • Отлучаем 5.5-master от бинлога:
    mysql> RESET SLAVE ALL;
    

  • Останавливаем MySQL на 5.5-master
  • На 5.0-master кладем сетевой интерфейс, по которому происходило общение приложений с базой, поднимаем этот ip на сервере, на котором у нас находится 5.5-master.
  • Убеждаемся, что arp-таблица обновилась.
  • Поднимаем 5.5-master. Убеждаемся, что MySQL слушает на новом ip.
  • Перезапускаем приложения, использующие persistent-connect к базе.

Все

В нашем случае время простоя было около полутора минут. Бóльшую часть этого времени складывался 5.0-master. В принципе, можно было время простоя уменьшить еще сильнее, сбросив InnoDB-кэши перед остановкой баз.

vCloud показал себя с хорошей стороны. Производительность при переезде ощутимо выросла благодаря более мощному железу и значительно более шустрой дисковой подсистеме, так как виртуальный диск «размазан» по большому количеству физических носителей.

Автор: winduzoid

* - обязательные к заполнению поля


https://ajax.googleapis.com/ajax/libs/jquery/3.4.1/jquery.min.js