web-dev-qa-db-fra.com

Créer un déclencheur pour mettre à jour les données de table sur la base de données d'un autre serveur

Je crée un déclencheur dans MySQL et j'ai besoin d'un peu d'aide.

J'ai 2 sites Web, 2 bases de données (même nom) sur 2 serveurs Web différents, S1 et S2.

Ces bases de données ont les mêmes noms de tables.

Je souhaite que les données des utilisateurs sur les deux sites Web soient identiques.

Donc, si un utilisateur s'inscrit sur S1, ces informations d'enregistrement d'utilisateur doivent être transmises à S2.

Si les informations d'enregistrement d'un utilisateur sont mises à jour sur S1, les mêmes informations doivent être mises à jour sur S2.

Et il en va de même pour S2.

Comment puis-je créer un déclencheur pour que chaque fois qu'il y a une insertion/mise à jour/suppression dans la base de données sur S1, la table utilisateur sur S2 soit également automatiquement mise à jour.

Et chaque fois qu'il y a une insertion/mise à jour/suppression dans la base de données sur S2, la table utilisateur sur S1 est également mise à jour automatiquement.

Est-ce possible? Pourriez-vous donner quelques exemples?

8
mkb

Pour accomplir ce que vous voulez faire, il est possible d'utiliser FEDERATED moteur de stockage sur les deux serveurs, en conjonction avec des déclencheurs, pour permettre à chaque serveur de mettre à jour la base de données de l'autre serveur.

Ce n'est pas exactement une solution prête à l'emploi, car elle nécessite des précautions supplémentaires et vous oblige à décider si la cohérence ou la tolérance d'isolement est plus importante et à permettre aux requêtes d'échouer lorsque l'autre serveur n'est pas disponible (plus de cohérence ) ou utilisez un CONTINUE HANDLER pour supprimer les erreurs (tolérance d'isolement).

Mais voici un exemple extrêmement extrêmement simplifié.

Chaque serveur aurait la configuration identique.

La table des utilisateurs locaux:

CREATE TABLE user (
  username varchar(64) NOT NULL,
  password varbinary(48) NOT NULL, /* encrypted of course */
  PRIMARY KEY(username)
) ENGINE=InnoDB DEFAULT CHARSET=utf8;

Une table locale qui est fédérée à la table utilisateur sur l'autre serveur.

CREATE TABLE remote_user (
  username varchar(64) NOT NULL,
  password varbinary(48) NOT NULL, /* encrypted of course */
  PRIMARY KEY(username)
) ENGINE=FEDERATED DEFAULT CHARSET=utf8 CONNECTION='mysql://username:pass@the_other_Host:port/schema/user';

La sélection de remote_user sur un serveur récupérera les enregistrements de l'autre serveur, et insérer/mettre à jour/supprimer sur cette table modifiera les données sur l'autre serveur.

Ainsi, nous créons des déclencheurs qui accomplissent le but de mettre à jour le serveur à distance. Ils sont écrits en tant que déclencheurs BEFORE, l'idée étant que nous ne voulons pas nous faire quelque chose que nous ne pouvons pas faire à l'autre serveur - par exemple, si un nom d'utilisateur existe déjà sur l'autre serveur, mais pas ici, nous voulons que l'insertion sur l'autre serveur génère une erreur qui nous empêche de créer l'utilisateur ici ... au lieu de créer un utilisateur ici avec ce qui serait un nom d'utilisateur en conflit. C'est, bien sûr, l'une des décisions de compromis que vous devrez prendre.

DELIMITER $$

CREATE TRIGGER user_bi BEFORE INSERT ON user FOR EACH ROW
BEGIN
  INSERT INTO remote_user (username,password) VALUES (NEW.username,NEW.password);
END $$

CREATE TRIGGER user_bu BEFORE UPDATE ON user FOR EACH ROW
BEGIN
  UPDATE remote_user 
     SET username = NEW.username,
         password = NEW.password
   WHERE username = OLD.username;
END $$

CREATE TRIGGER user_bd BEFORE DELETE ON user FOR EACH ROW
BEGIN
  DELETE FROM remote_user
   WHERE username = OLD.username;
END $$

DELIMITER ;

Ce n'est pas une solution parfaite et n'est pas une solution à haute disponibilité, car elle repose sur une connectivité solide entre les deux systèmes et même si vous utilisez InnoDB et des transactions, les actions que vous prenez contre la table cible ne font pas partie de votre transaction locale et ne peut pas être annulé.

J'utilise pas mal le moteur FEDERATED; il est utile à plusieurs fins créatives dans mon environnement, y compris une situation où j'ai utilisé une requête fédérée lancée par un déclencheur pour imposer des contraintes de clé étrangère contre une source de données étrangère; cependant, je limite son utilisation aux processus principaux où des problèmes inattendus tels que des délais d'attente, des erreurs de codage ou des événements de réseau/panne/isolation de serveur à serveur ne peuvent pas entraîner de problème de type pour l'utilisateur final sur l'un de nos sites Web. . Votre capacité à tolérer une telle situation serait un facteur déterminant majeur pour savoir s'il s'agit d'une solution appropriée.

Une alternative serait de configurer vos deux serveurs en réplication maître/maître. Pour cela, vous devez utiliser différents noms de base de données sur chaque serveur, de sorte que pour la plupart des événements qui se répliquent, les deux serveurs ne peuvent pas entrer en conflit avec chacun autre. Dans le pire des cas, si vous perdez la connectivité ou rencontrez une erreur de réplication, les deux sites continueraient de fonctionner indépendamment et vous pourriez resynchroniser et récupérer. La configuration ressemblerait à ceci:

database_a database for site A
database_b database for site B
database_c database for only the shared table(s)

Ensuite, dans database_a et database_b:

CREATE ALGORITHM=MERGE SQL SECURITY INVOKER VIEW user AS SELECT * FROM c.user;

MySQL traitera database_a.user et database_b.user comme des alias pour la "vraie" table utilisateur, database_c.user, de sorte que vous n'auriez pas à changer votre application autrement que d'utiliser sa base de données désignée (c'est-à-dire que vous n'auriez pas à configurer pour comprendre que la table utilisateur était en fait dans un schéma différent, car la vue fonctionnera de manière assez transparente avec cette configuration). Si les schémas ont des clés étrangères par rapport à la table utilisateur, vous devez les déclarer par rapport à la vraie table de base database_c.user.

Configurez les deux serveurs pour tout répliquer, mais définissez auto_increment_increment et auto_increment_offset de manière appropriée afin que vous n'ayez pas de valeurs d'auto-incrémentation conflictuelles sur les tables partagées, si vos tables utilisent l'incrémentation automatique. (Remarque, la documentation indique que ces variables ne concernent que les tables NDB, mais ce n'est pas exact).

Un avantage supplémentaire de cette configuration est que vos deux serveurs auraient alors un double complet des données de l'autre site que vous pourriez potentiellement utiliser à votre avantage pour la récupération d'une défaillance matérielle dans l'un des serveurs.

11
Michael - sqlbot

Ce n'est qu'une table parmi plusieurs qui devraient être égales, n'est-ce pas?

Ainsi, les déclencheurs ne fonctionneront pas car ils ne peuvent être exécutés que dans le même schéma sur le même serveur.

Je suppose que vous avez 3 options:

  1. Synchronisez manuellement, par ex. en appelant un script qui exécute toutes les requêtes effectuées sur les données utilisateur sur S1 sur l'autre serveur. Un peu moche.

  2. Dirigez toutes les requêtes sur cette table vers un serveur, par exemple S1 contient l'utilisable et votre application, quelle qu'elle soit, sur le serveur 2 ne questionne pas l'utilisable local sur S2, mais à distance sur S1. Pas mieux.

  3. Utilisez le moteur FEDERATED. Stockez les données utilisateur sur S1, créez la même structure de table avec FEDERATED sur S2. Cela signifie que S2 ne contient pas les données utilisateur physiques, mais une connexion à la table sur S1. Toutes les actions prises sur S2 se font sur S1. Voir http://en.wikipedia.org/wiki/MySQL_Federated et http://dev.mysql.com/doc/refman/5.0/en/federated-storage-engine. html pour savoir si cela répond à vos besoins.

Dans les 3 scénarios, il est difficile de donner une déclaration sur les délais entre les synchronisations. L'option 3 est la seule où vous auriez besoin d'ajuster uniquement la base de données, pas l'application, mais je ne sais vraiment pas si c'est la grande chose.

1
32bitfloat

Tout d'abord une mise en garde rapide - je vais probablement suivre la voie des autres réponses et utiliser la fédération pour votre configuration spécifique. Cela dit, il vaut la peine de réfléchir en votre nom pour savoir si la division des données utilisateur en une troisième base de données serait une meilleure solution.

Cela supprimera la duplication des 2 bases de données, mais je prévois que cela nécessiterait également une bonne quantité de retouches pour que les 2 sites fonctionnent à partir d'une seule base de données d'authentification centrale.

0
James Sinclair