- PVSM.RU - https://www.pvsm.ru -
В Ситимобил мы используем базу данных MySQL в качестве основного хранилища постоянных данных. У нас есть несколько кластеров баз данных под различные сервисы и цели.
Постоянная доступность мастера является критическим показателем работоспособности всей системы и ее отдельных частей. Автоматическое восстановление кластера в случае отказа мастера сильно снижает время реагирования на инцидент и время простоя системы. В этой статье я рассмотрю схему обеспечения высокой доступности (HA) кластера MySQL на основе MySQL Orchestrator [1] и виртуальных IP адресов (VIP).
Сначала кратко расскажу о том, что из себя представляет наша система хранения данных.
Мы используем классическую схему репликации с одним мастером, доступным на запись, и множеством реплик, которые используются только на чтение. Кластер может содержать промежуточный мастер — узел, который одновременно является и репликой, и мастером для других. Клиенты обращаются к репликам через HAProxy, что позволяет равномерно распределять нагрузку и легко масштабироваться. Использование HAProxy обусловлено историческими причинами, и сейчас мы в процессе миграции на ProxySQL.
Репликация выполняется в полусинхронном режиме на основе GTID
. Это значит, что как минимум одна реплика должна записать транзакцию в журнал, прежде чем та будет признана успешной. Такой режим репликации обеспечивает оптимальный баланс между производительностью и сохранностью данных в случае выхода из строя главного узла. В основном все изменения передаются от мастера к репликам с помощью Row Based Replication (RBR)
, но часть узлов может иметь mixed binlog format
.
Оркестратор периодически обновляет состояние топологии кластера, анализирует полученную информацию и в случае возникновения проблем может запустить процедуру автоматического восстановления. За саму процедуру отвечает разработчик, поскольку её можно реализовать разными способами: на основе VIP, DNS, с использованием служб обнаружения сервисов (service discovery) или самописных механизмов.
Одним из простых способов восстановления мастера в случае его отказа является использование плавающих VIP-адресов.
Что нужно знать об этом решении, прежде чем двигаться дальше:
keepalived
.
Рассмотрим возможные проблемы с нашим мастером и представим, как должен отработать механизм автоматического восстановления.
split brain
при возврате старого мастера.
Алгоритм аналогичен предыдущему случаю: обновление топологии и запуск процесса восстановления. Так как сервер доступен, мы успешно освобождаем VIP на старом мастере, переносим его на новый и отправляем несколько ARP-запросов. Возможный возврат старого мастера не должен повлиять на перестроенный кластер и работу приложения.
Отказ реплик или промежуточных мастеров не приводит к автоматическим действиям и требует ручного вмешательства.
Виртуальный сетевой интерфейс всегда добавляется временно, то есть после перезагрузки сервера VIP автоматически не назначается. Каждый экземпляр БД по умолчанию запускается в режиме только для чтения, оркестратор автоматически переключает новый мастер на запись и пробует установить read only
на старом мастере. Эти действия направлены на уменьшение вероятности split brain
.
В процессе восстановления могут возникнуть проблемы, о которых стоит также уведомлять через UI оркестратора помимо стандартных средств мониторинга. Мы расширили REST API, добавив такую возможность (PR [2] сейчас находится на рассмотрении).
Общая схема HA-решения представлена ниже.
Оркестратор достаточно умён и старается выбрать наиболее подходящую реплику [3] в качестве нового мастера по следующим критериям:
errant GTID
— транзакции, которые были выполнены на реплике и отсутствуют на мастере;
Не каждая реплика является идеальным кандидатом на роль мастера. Например, реплика может использоваться для резервного копирования данных, либо сервер имеет более слабую конфигурацию «железа». Оркестратор поддерживает [4] ручные правила, с помощью которых можно настроить свои предпочтения по выбору кандидата от наиболее предпочтительных до игнорируемых.
В случае инцидента важно минимизировать время простоя системы, поэтому рассмотрим параметры MySQL, влияющие на построение и обновление топологии кластера оркестратором:
slave_net_timeout
[5] — количество секунд, в течение которых реплика ожидает поступления новых данных или heartbeat-сигнала от мастера, прежде чем соединение признается потерянным и выполняется переподключение. Чем меньше значение, тем быстрее реплика сможет определить, что связь с мастером нарушена. Мы устанавливаем это значение равным 5 секундам.
MASTER_CONNECT_RETRY
[6] — количество секунд между попытками переподключения. В случае сетевых проблем низкое значение этого параметра позволит быстро переподключиться и предотвратить запуск процесса восстановления кластера. Рекомендуемое значение — 1 секунда.
MASTER_RETRY_COUNT
— максимальное количество попыток переподключения.
MASTER_HEARTBEAT_PERIOD
— интервал в секундах, после которого мастер отправляет heartbeat-сигнал. По умолчанию равен половине значения slave_net_timeout
.
Параметры оркестратора:
DelayMasterPromotionIfSQLThreadNotUpToDate
— если равен true
, то роль мастера не будет применена на реплике-кандидате до тех пор, пока SQL-поток реплики не выполнит все непримененные транзакции из Relay Log. Мы используем эту опцию, чтобы не терять транзакции в условиях отставания всех реплик-кандидатов.
InstancePollSeconds
— частота построения и обновления топологии.
RecoveryPollSeconds
— частота анализа топологии. В случае обнаружения проблемы запускается восстановление топологии. Это константа [7], равная 1 секунде.
Каждый узел кластера опрашивается оркестратором один раз в InstancePollSeconds
секунд. При обнаружении проблемы состояние кластера принудительно обновляется [8], а затем принимается окончательное решение о выполнении восстановления. Экспериментируя с различными параметрами БД и оркестратора, нам удалось снизить длительность реагирования и восстановления до 30 секунд.
Тестирование HA-схемы мы начали с разработки локального тестового стенда [9] и дальнейшего внедрения в тестовое и боевое окружения. Локальный стенд полностью автоматизирован на основе Docker и позволяет экспериментировать с конфигурацией оркестратора и сети, масштабировать кластер от 2-3 серверов до нескольких десятков и проводить учения в безопасной среде.
Во время учений мы выбираем один из методов эмуляции проблемы: мгновенно отстрелить мастер с помощью kill -9
, мягко завершить процесс и остановить сервер (docker-compose stop
), имитировать проблемы с сетью с помощью iptables -j REJECT
или iptables -j DROP
. Мы ожидаем такие результаты:
Как вы знаете, система может вести себя по-разному в тестовом и production-окружениях из-за разной конфигурации «железа» и сети, различий в синтетической и реальной нагрузке и т.д. Поэтому периодически мы проводим учения в реальных условиях, проверяя, как ведет себя система при потере сетевой связности или деградации ее отдельных частей. В будущем хотим построить полностью идентичную инфраструктуру для обеих сред и автоматизировать ее тестирование.
Работоспособность главного узла системы хранения данных является одной из основных задач команды SRE и эксплуатации. Внедрение оркестратора и HA-решения на основе VIP позволило добиться следующих результатов:
Однако решение имеет свои ограничения и недостатки:
split brain
.
Чтобы избежать split brain
, можно использовать метод STONITH [10] («Shoot The Other Node In The Head»), который полностью изолирует или отключает проблемный узел. Существуют и другие способы реализации высокой доступности кластера: комбинация VIP и DNS, обнаружение служб и прокси-сервисы, синхронная репликация и прочие способы, которые имеют свои недостатки и преимущества.
Я рассказал о нашем подходе к созданию отказоустойчивого кластера MySQL. Он прост в реализации и обеспечивает приемлемый уровень надежности в текущих условиях. По мере развития всей системы в целом и инфраструктуры в частности этот подход, несомненно, будет эволюционировать.
Автор: parshinpn
Источник [11]
Сайт-источник PVSM.RU: https://www.pvsm.ru
Путь до страницы источника: https://www.pvsm.ru/mysql/348584
Ссылки в тексте:
[1] MySQL Orchestrator: https://github.com/github/orchestrator
[2] PR: https://github.com/openark/orchestrator/pull/1088
[3] наиболее подходящую реплику: https://github.com/openark/orchestrator/blob/5126b849ae4f655e1cbe0fbddfa0d7299674f712/go/inst/instance_utils.go#L112
[4] поддерживает: https://github.com/openark/orchestrator/blob/master/docs/topology-recovery.md#adding-promotion-rules
[5] slave_net_timeout
: https://dev.mysql.com/doc/refman/5.7/en/replication-options-slave.html#sysvar_slave_net_timeout
[6] MASTER_CONNECT_RETRY
: https://dev.mysql.com/doc/refman/5.7/en/change-master-to.html
[7] константа: https://github.com/github/orchestrator/blob/548265494b3107ca2581d6ccee059e062a759b77/go/config/config.go#L45
[8] обновляется: https://github.com/github/orchestrator/blob/548265494b3107ca2581d6ccee059e062a759b77/go/logic/topology_recovery.go#L1409
[9] тестового стенда: https://github.com/ParshinPavel/mysql-ha-sandbox
[10] STONITH: https://en.wikipedia.org/wiki/STONITH
[11] Источник: https://habr.com/ru/post/491044/?utm_campaign=491044&utm_source=habrahabr&utm_medium=rss
Нажмите здесь для печати.