Comment déterminer le maître dans mysql master-slave

17

J'installe la réplication MySQL maître-esclave et j'essaie de comprendre comment gérer la situation de basculement où je promeut l'esclave à maître (dans le cas où le maître tombe en panne).

Mon serveur d'applications doit diriger toutes les écritures vers le maître actuel, mais je ne peux pas utiliser HA de niveau serveur entre le maître et l'esclave (battement de cœur, keepalived) car les deux serveurs db sont sur des sous-réseaux complètement différents dans des emplacements physiques différents.

Je pense que c'est quelque chose que je dois gérer au niveau de l'application. Je peux interroger les deux serveurs et demander lequel est un maître, puis effectuer toutes les requêtes sur celui-ci.

Existe-t-il une requête dans MySQL pour voir si le serveur actuel est un maître dans une réplique maître-esclave?

Ethan Hayon
la source
Quelle version de MySQL utilisez-vous ???
RolandoMySQLDBA
Ceci est la sortie mysqlServer version: 5.5.23 MySQL Community Server (GPL)
Ethan Hayon

Réponses:

13

@RolandoMySQLDBA a répondu à la question avec précision ... mais il a également souligné que sa solution était "rapide et sale".

Et c'est une déclaration très vraie. :)

La chose qui me préoccupe ici n'est pas avec cette réponse, mais plutôt que la question d'origine semble faire une hypothèse incorrecte:

Je peux interroger les deux serveurs et demander lequel est un maître, puis effectuer toutes les requêtes sur celui-ci.

Le problème est que dans la réplication MySQL, le maître n'est jamais vraiment conscient qu'il est le maître.

Le concept de "promotion à maîtriser" n'est pas vraiment un concept dans la réplication asynchrone MySQL. La «promotion» d'un serveur MySQL au rôle maître est quelque chose qui se produit «en dehors» des serveurs MySQL, par opposition à quelque chose qui se produit «en interne» aux serveurs MySQL.

La «promotion vers le maître» n'est effectuée par aucun type de provisionnement de serveur, car, techniquement parlant, chaque serveur MySQL sur lequel la journalisation binaire est activée est un maître, même s'il n'a jamais d'esclave. SHOW MASTER STATUSfonctionne exactement de la même manière et renvoie exactement le même résultat, esclaves ou non, et un maître avec 2 esclaves n'est ni plus ni moins maître qu'un maître avec 1 esclave ou 0 esclave. De même, un maître dont les esclaves sont tous hors ligne est toujours autant un maître, car lorsque les esclaves reviendront en ligne, ils reprendront la réplication là où ils se sont arrêtés.

Dans un sens, la seule "prise de conscience" de l'un ou l'autre serveur n'est pas de savoir s'il s'agit d'un maître, mais plutôt s'il s'agit d'un esclave (ou "non").

C'est ce que la solution de Rolando demande: "êtes-vous un esclave?" Si la réponse est non, alors l'hypothèse est que ce doit être le maître ... qu'il a également signalé comme hypothèse erronée s'il STOP SLAVE;est émis. Mais un esclave arrêté est toujours un esclave, donc «pas un esclave» (à tout moment) ne signifie pas «être un maître».

Un test similaire pourrait être effectué sur le maître présumé:

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

ou

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

Si la valeur est zéro, le thread IO de l'esclave n'est pas connecté. Ce test présente un défaut similaire, en ce sens que si l'esclave est déconnecté administrativement, isolé ou échoué, il ne sera pas connecté. Donc cela ne résout rien non plus.

Pire encore (pour l'un ou l'autre de ces scénarios), la "table" information_schema.processlist est une table virtuelle qui se matérialise à chaque fois qu'elle est sélectionnée, ce qui prend du temps et coûte des ressources. Plus votre serveur est occupé, plus il en coûte, car l'activité de chaque thread doit être examinée.

Une solution plus légère serait:

SELECT @@global.read_only;

Sur un esclave, vous pouvez / devez définir la variable globale read_onlyafin que les utilisateurs sans SUPERprivilège ne puissent pas y écrire involontairement (et que votre application ne devrait pas en avoir SUPER). Si vous "promouvez" manuellement l'esclave au rôle de maître, vous devez SET GLOBAL read_only = OFFactiver les écritures. (La réplication peut toujours écrire sur l'esclave, quel que soit le réglage).

Mais cela manque encore, je pense, un point important:

Je proposerais que l'application ne prenne pas cette décision de manière heuristique dans une configuration maître / esclave, et certainement pas sur une base connexion par connexion. L'application doit utiliser soit une option de configuration matérielle, soit l'application ne doit pas être au courant et la destination de connexion à la base de données doit être gérée par autre chose.

Ou, au minimum, l'application ne doit jamais basculer jusqu'à ce que le maître tombe en panne, puis elle ne doit jamais revenir en arrière d'elle-même.

Voici pourquoi je dis cela: une fois que la "décision" est prise - par qui ou quoi que ce soit - de faire d'un autre serveur le maître, l'application ne peut pas être autorisée pour une raison quelconque à revenir au maître d'origine, même après sa remise en ligne. , sans intervention.

Supposons que vous rencontriez un bogue et qu'il y ait un plantage forcé par logiciel; mysqld_saferedémarre consciencieusement mysqldet la récupération après incident d'InnoDB fonctionne parfaitement. Mais cela prend quelques minutes.

Pendant ce temps, le maître est en panne, votre application est donc passée à l'esclave. Les transactions ont été créées, les commandes passées, les fonds transférés, les commentaires publiés, les blogs modifiés, quoi que fasse votre système.

Maintenant, le maître d'origine revient en ligne.

Si votre application revient au maître d'origine, vous êtes dans un monde de souffrance absolu, car la prochaine chose qui risque de se produire est que la réplication s'arrête en raison d'une incohérence, car votre application a modifié les données sur l'esclave en moyenne temps. Vous avez maintenant deux serveurs de base de données avec des données incohérentes que vous devrez réconcilier manuellement. S'il y a des dollars ou des points ou des crédits impliqués, vous avez maintenant des soldes incompatibles.

Il est donc essentiel que l'application ne soit pas autorisée à revenir au maître d'origine sans votre intervention.

Attendez, vous venez de trouver le problème avec ce scénario tel que je l'ai décrit? Le maître a échoué mais votre application n'utilisera pas l'esclave, car il pense que l'esclave est toujours l'esclave et non le maître ... la information_schema.processlistrequête sur l'esclave renverra toujours non nul même si le serveur maître est hors tension .

Il n'y a donc pas grand intérêt à ce que l'application découvre quoi que ce soit, car vous devrez manuellement STOP SLAVEpour que ce test soit utile.

Peut-être une meilleure approche si vous voulez que l'application puisse basculer serait de configurer les serveurs avec une réplication circulaire.

La réplication circulaire a ses propres problèmes, mais tant que votre application n'écrit que toujours sur un serveur à la fois, la plupart de ces problèmes deviennent des problèmes non liés. En d'autres termes, les deux machines sont toujours et simultanément à la fois maître et esclave, dans un sens de réplication, mais votre application, via un mécanisme, ne pointe toujours que sur une machine à la fois comme le "maître" sur lequel elle peut et doit écrire. .

Vous ne pouvez pas déployer les outils HA sur les serveurs MySQL en raison de leur séparation, mais vous pouvez l'implémenter avec HAProxy exécuté sur le ou les serveurs d'applications. L'application se connecte à "MySQL" sur localhost, qui n'est pas du tout MySQL, mais est en fait HAProxy ... et il transfère la connexion TCP à la machine MySQL appropriée.

HAProxy peut tester les connexions aux serveurs MySQL et n'offrir du trafic qu'à une machine MySQL qui accepte les connexions et autorise l'authentification.

La combinaison de HAProxy fonctionnant sur le serveur d'applications (sa demande de ressources ne sera pas substantielle par rapport à tout ce que le serveur d'applications doit faire - c'est à peu près simplement relier les sockets ensemble et ignorer leur charge utile) ... et la réplication circulaire MySQL serait l'approche que je prendrais probablement dans ce cas, basée sur ce que l'on sait de la question.

Ou, pour une configuration strictement manuelle, optez pour quelque chose de beaucoup plus simple que «découverte», comme une entrée dans le /etc/hostsfichier du serveur d'application avec un nom d'hôte que l'application utilise pour se connecter à MySQL, que vous pouvez mettre à jour manuellement - en supposant la promotion de l'esclave vers master est censé être un processus manuel.

Ou quelque chose de plus complexe, en utilisant Percona XtraDB Cluster. Pour cela, cependant, vous voudriez ajouter un troisième serveur, car avec 3 nœuds dans PXC, si 2 serveurs peuvent se voir mais être isolés d'un seul serveur (si les trois fonctionnent toujours), les 2 serveurs continuent de fonctionner heureusement mais le serveur 1 se recroqueville en une petite boule et refuse de faire quoi que ce soit car il se rend compte qu'il doit être le plus étrange. Cela fonctionne parce que les 2 réalisent qu'ils constituent toujours la majorité des nœuds qui étaient en ligne avant la division du réseau et le 1 se rend compte que ce n'est pas le cas. Avec PXC, peu importe le serveur auquel votre application se connecte.

Je dis que tout cela revient à dire "ne demandez pas à l'application d'interroger les serveurs pour voir lequel est le maître", car cela vous mordra tôt ou tard et grignotera vos performances jusqu'au jour où il mordra.

Michael - sqlbot
la source
Tout d'abord, merci pour la réponse bien écrite. Je pense que vous avez proposé une bonne solution. J'ai pensé à utiliser la réplication circulaire dans le passé, mais j'ai lu de mauvaises choses concernant sa fiabilité. Cependant, la plupart de ces problèmes peuvent être évités en modifiant auto_increment_increment, auto_increment_offset, etc ... la logique loin de la couche application. J'examinerai la configuration de HAProxy, merci!
Ethan Hayon
1
Heureux de vous aider. Un vote positif serait apprécié si vous ne l'avez pas déjà fait. La réplication circulaire est tout aussi fiable que maître / esclave (c'est la même technologie, allant dans les deux sens) tant que vous comprenez comment cela fonctionne et que vous l'utilisez de manière sensée. Tant que les serveurs sont correctement synchronisés et que l'application n'écrit que sur un serveur à la fois, je n'ai jamais eu de problème avec. Les auto_increment_*variables sont toujours bonnes à utiliser dans ce scénario, "juste au cas où". N'oubliez pas non plus d'utiliser binlog_format= rowou mixed- pas statement(même si vous ne faites pas de circulaire).
Michael - sqlbot
J'ai changé la réponse acceptée uniquement parce que cette explication détaillée m'a aidé à ré-architecturer le système pour qu'il soit plus robuste. @ La réponse de RolandoMySQLDBA est toujours correcte et résout le problème que j'ai décrit initialement. Merci!
Ethan Hayon
10

Si vous utilisez uniquement Master / Slave, voici quelque chose de rapide et sale:

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

Qu'est-ce que cela vous dit?

  • Si SlaveThreadCount= 0, vous avez le maître
  • Si SlaveThreadCount> 0, vous avez l'esclave

CAVEAT : Cela fonctionne tant que vous n'exécutez pasSTOP SLAVE;

Une autre chose à essayer est la suivante: si vous désactivez la journalisation binaire sur l'esclave et que vous exécutez SHOW MASTER STATUS;, le maître vous donne le journal binaire actuel. L'esclave ne vous donne rien.

RolandoMySQLDBA
la source
Génial, c'est exactement ce dont j'ai besoin. Pensez-vous que c'est une solution compliquée au problème? Le seul problème que je peux envisager est que les deux serveurs soient promus en tant que maître, mais cela ne devrait jamais se produire.
Ethan Hayon
Si cette réponse est ce dont vous aviez besoin, veuillez cocher la réponse acceptée en cliquant sur la coche sur ma réponse.
RolandoMySQLDBA
Je ne peux pas le marquer comme accepté pendant encore 5 minutes :)
Ethan Hayon
Aucun problème. J'étais contente d'avoir pu aider !!!
RolandoMySQLDBA
0

exécutez cette instruction à partir de l'invite
mysql mysql> afficher le statut de l'esclave;

Sur l'esclave, il montre beaucoup de paramètres et leurs valeurs / état tandis que sur le maître, il montre l' ensemble vide

akrai48
la source