Как определить мастера в MySQL Master-Slave


17

Я настраиваю репликацию MySQL Master-slave и пытаюсь выяснить, как справиться с ситуацией переключения при сбое, когда я продвигаю slave на master (в случае, если master выходит из строя).

Моему серверу приложений необходимо направить все записи на текущий мастер, но я не могу использовать HA уровня сервера между главным и подчиненным (heartbeat, keepalived), поскольку два сервера БД находятся в совершенно разных подсетях в разных физических местоположениях.

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

Есть ли в MySQL запрос, чтобы узнать, является ли текущий сервер ведущим в реплике «главный-подчиненный»?


Какую версию MySQL вы используете ???
RolandoMySQLDBA

Это вывод MySQLServer version: 5.5.23 MySQL Community Server (GPL)
Итан Хайон

Ответы:


13

@RolandoMySQLDBA ответил на вопрос точно ... но он также указал, что его решение было «быстрым и грязным».

И это очень верное утверждение. :)

Дело в том, что меня здесь интересует не тот ответ, а скорее то, что первоначальный вопрос, кажется, делает неверное предположение:

Я могу запросить два сервера и спросить, какой из них является главным, а затем выполнить все запросы к этому.

Проблема в том, что в репликации MySQL мастер никогда не осознает, что он мастер.

Понятие «продвижение к мастеру» на самом деле не является понятием в асинхронной репликации MySQL. «Продвижение» сервера MySQL на главную роль - это то, что происходит «внешне» по отношению к серверам MySQL, а не «внутренне» по отношению к серверам MySQL.

«Повышение до мастерства» не выполняется никаким видом серверной подготовки, потому что, технически говоря, каждый сервер MySQL, для которого включена двоичная регистрация, является мастером, даже если у него никогда не было ведомого устройства. SHOW MASTER STATUSработает точно так же и возвращает точно такой же результат, ведомые или нет, и мастер с 2 рабами не более или менее мастер, чем мастер с 1 рабом или 0 рабами. Точно так же мастер, все рабы которого находятся в автономном режиме, все еще является тем же мастером, потому что, когда рабы возвращаются в оперативный режим, они начинают репликацию там, где они остановились.

В некотором смысле, единственное «осознание» со стороны любого из серверов заключается не в том, является ли он ведущим, а в том, является ли он подчиненным (или «нет»).

Вот что говорит Роландо: «Ты раб?» Если ответ «нет», то предполагается, что это должен быть мастер ..., который он также указал как ошибочное предположение, если STOP SLAVE;оно выпущено. Но остановленный раб по-прежнему остается рабом, поэтому «не раб» (в любой момент времени) не означает «быть хозяином».

Подобный тест может быть выполнен на предполагаемом мастере:

SELECT COUNT(1) FROM information_schema.processlist
 WHERE user = 'the_username_used_by_the_slave';

или

SELECT COUNT(1) FROM information_schema.processlist
 WHERE command = 'binlog dump';

Если значение равно нулю, то поток ввода-вывода ведомого не подключен. Этот тест имеет аналогичный дефект в том, что если ведомое устройство отключено административно, изолировано или не выполнено, оно не будет подключено. Так что это тоже ничего не решает.

Что еще хуже (для любого из этих сценариев) «таблица» information_schema.processlist представляет собой виртуальную таблицу, которая материализуется каждый раз, когда ее выбирают, и это требует времени и затрат ресурсов. Чем занят ваш сервер, тем больше он стоит, потому что активность каждого потока должна быть одноранговой.

Более легкое решение будет:

SELECT @@global.read_only;

На ведомом устройстве вы можете / должны установить глобальную переменную read_onlyтак, чтобы пользователи без SUPERпривилегий не могли непреднамеренно писать в нее (а ваше приложение не должно иметь этого SUPER). Если вы вручную «продвигаете» подчиненное устройство к ведущей роли, вам SET GLOBAL read_only = OFFнужно включить запись. (Репликация всегда может писать на ведомое устройство, независимо от того, как это установлено).

Но это все же, я думаю, упускает важный момент:

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

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

Вот почему я говорю это: после того, как «кем бы то ни было» принято решение сделать главный сервер другим сервером, приложению по какой-либо причине не разрешается переключаться на первоначальный мастер, даже после того, как он возвращается в оперативный режим. без вмешательства.

Допустим, вы обнаружили ошибку и произошел программный сбой; mysqld_safeпокорно перезагружается mysqld, и восстановление после сбоя InnoDB выполняется безупречно. Но это занимает несколько минут.

Тем временем мастер не работает, поэтому ваше приложение переключилось на подчиненное устройство. Были созданы транзакции, размещены заказы, переведены средства, опубликованы комментарии, отредактированы блоги, что бы ни делала ваша система.

Теперь оригинальный мастер возвращается в онлайн.

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

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

Подождите, вы только что обнаружили проблему с этим сценарием, как я описал его? Мастер отказал, но ваше приложение не будет использовать ведомое устройство, потому что оно считает, что подчиненное устройство все еще является ведомым, а не ведущим ... information_schema.processlistзапрос на ведомом устройстве все равно будет возвращать ненулевое значение, даже если мастер-сервер выключен ,

Таким образом, нет ничего особенного в том, что приложение обнаруживает что-либо, так как вам придется вручную, STOP SLAVEчтобы этот тест был полезным.

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

Циркулярная репликация имеет свои собственные проблемы, но пока ваше приложение всегда всегда выполняет запись только на один сервер за один раз, большинство из этих проблем не возникает. Другими словами, обе машины всегда и одновременно являются и главными, и подчиненными, в смысле репликации, но ваше приложение через некоторый механизм всегда указывает только на одну машину за раз как «мастер», на который она может и должна записывать ,

Вы не можете развернуть инструменты HA на серверах MySQL из-за их разделения, но вы можете реализовать их с HAProxy, работающим на серверах приложений. Приложение подключается к «MySQL» на localhost, который вообще не является MySQL, но на самом деле является HAProxy ... и перенаправляет TCP-соединение на соответствующую машину MySQL.

HAProxy может тестировать соединения с серверами MySQL и предлагать трафик только к машине MySQL, которая принимает соединения и разрешает аутентификацию.

Комбинация HAProxy, работающего на сервере приложений (его потребность в ресурсах не будет существенной по сравнению со всем остальным, что должен делать сервер приложений - это просто объединение сокетов и игнорирование их полезной нагрузки) ... и циклическая репликация MySQL был бы подход, который я, вероятно, использовал бы в этом случае, основываясь на том, что известно из вопроса.

Или, для строго ручной настройки, используйте что-то намного более простое, чем «обнаружение», например запись в /etc/hostsфайле сервера приложений с именем хоста, которое приложение использует для подключения к MySQL, которое вы можете обновить вручную - при условии продвижения подчиненного к мастер предназначен для ручного процесса.

Или что-то более сложное, используя Percona XtraDB Cluster. Для этого, однако, вы хотите добавить третий сервер, потому что с 3 узлами в PXC, если 2 сервера могут видеть друг друга, но изолированы от 1 сервера (если все три еще работают), 2 сервера продолжают работать счастливо, но 1 сервер скручивается в маленький шарик и отказывается что-либо делать, поскольку понимает, что он должен быть нечетным. Это работает, потому что 2 понимают, что они все еще составляют большинство узлов, которые были в сети до разделения сети, а 1 понимает, что это не так. С PXC не имеет значения, к какому серверу подключается ваше приложение.

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


Прежде всего, спасибо за хорошо написанный ответ. Я думаю, что вы предложили хорошее решение. Я думал об использовании циклической репликации в прошлом, но прочитал плохие вещи относительно его надежности. Тем не менее, многие из этих проблем можно предотвратить, изменив auto_increment_increment, auto_increment_offset и т. Д. ... Использование HAProxy локально на серверах приложений (только для аварийного переключения) будет хорошо работать для нас, поскольку нам не придется изменять наше приложение, поэтому абстрагируясь от аварийного переключения логика от уровня приложений. Я посмотрю в настройке HAProxy, спасибо!
Итан Хайон

1
Рад помочь. Голосование будет приветствоваться, если вы еще этого не сделали. Циркулярная репликация столь же надежна, как и ведущий / ведомый (это та же технология, которая идет в обоих направлениях), если вы понимаете, как она работает, и разумно ее используете. Пока серверы синхронизируются должным образом и приложение пишет только на один сервер за раз, у меня никогда не было проблем с этим. Эти auto_increment_*переменные все еще хорошо использовать в этом случае, « на всякий случай» . Кроме того, не забывайте использовать binlog_format= rowили mixed- нет statement(даже если вы не делаете круговой).
Майкл - sqlbot

Я изменил принятый ответ исключительно потому, что это подробное объяснение помогло мне перестроить систему, чтобы она стала более надежной. Ответ @ RolandoMySQLDBA все еще правильный и решает проблему, которую я первоначально описал. Благодарность!
Итан Хайон

10

Если вы используете только Master / Slave, вот что-то быстрое и грязное:

SELECT COUNT(1) SlaveThreadCount
FROM information_schema.processlist
WHERE user='system user';

Что это говорит вам?

  • Если SlaveThreadCount= 0, у вас есть мастер
  • Если SlaveThreadCount> 0, у вас есть раб

ПРЕДУПРЕЖДЕНИЕ : это работает до тех пор, пока вы не запускаетеSTOP SLAVE;

Еще одна вещь, которую стоит попробовать: если вы отключите бинарное ведение журнала на ведомом устройстве и запустите SHOW MASTER STATUS;, мастер выдаст вам текущий двоичный журнал. Раб ничего не дает.


Круто, это именно то, что мне нужно. Как вы думаете, это грязное решение проблемы? Единственная проблема, которую я могу себе представить, - это повышение уровня владения обоими серверами, но это никогда не должно происходить.
Итан Айон

Если вам нужен этот ответ, отметьте принятый ответ, нажав на галочку на моем ответе.
RolandoMySQLDBA

Я не могу пометить его как принятый еще на 5 минут :)
Итан Хайон

Нет проблем. Я был рад, что смог помочь !!!
RolandoMySQLDBA

0

выполнить это утверждение из приглашения
mysql mysql> show slave status;

На ведомом устройстве отображается множество параметров и их значений / статус, а на главном - пустой набор.

Используя наш сайт, вы подтверждаете, что прочитали и поняли нашу Политику в отношении файлов cookie и Политику конфиденциальности.
Licensed under cc by-sa 3.0 with attribution required.