Les données de la base de données dans le projet récemment lancé abordent la saturation. Les données de table les plus importantes sont proches de 3000W et il y a plusieurs tables avec des millions de données. Le projet exige que le temps de lecture des données ne puisse pas dépasser 0,05 seconde, mais la situation réelle ne répond pas aux exigences. Expliquez l'indexation et l'utilisation de la technologie Redis et Ehcache Cache ne peut plus répondre aux exigences. Par conséquent, nous avons commencé à utiliser la technologie de séparation de lecture et d'écriture. Peut-être que lorsque le volume de données dépasse 100 millions ou plus à l'avenir, nous devons considérer le déploiement de bases de données distribuées. Cependant, à l'heure actuelle, la lecture et l'écriture de séparation + Cache + Index + Table Partition + SQL Optimization + Load Balancing peuvent répondre au travail de requête de 100 millions de volumes de données. Jetons un coup d'œil aux étapes pour utiliser le printemps pour réaliser la séparation de lecture et d'écriture:
1. Contexte
Notre application générale est de "lire plus et écrire moins" pour les bases de données, ce qui signifie que la pression sur la base de données pour lire les données est relativement élevée. Une idée consiste à utiliser une solution de cluster de base de données.
L'un d'eux est la bibliothèque principale, qui est responsable de la rédaction de données, que nous appelons: Rédaction de la bibliothèque;
Les autres proviennent tous de la bibliothèque, qui est responsable de la lecture des données, que nous appelons: la bibliothèque de lecture;
Ainsi, les exigences pour nous sont:
1. Les données de la bibliothèque Read et la bibliothèque d'écriture sont cohérentes; (Il s'agit d'un problème très important. Le traitement de la logique commerciale doit être traité dans la couche de service, et non au niveau DAO ou Mapper)
2. Lors de la rédaction de données, vous devez l'écrire dans la bibliothèque d'écriture;
3. Vous devez vous rendre à la bibliothèque de lecture pour lire les données;
2. Plan
Il existe deux solutions pour résoudre la séparation de la lecture et de l'écriture: la solution de couche d'application et la solution de middleware.
2.1. Solution de couche d'application:
avantage:
1. Plusieurs sources de données sont faciles à changer et sont automatiquement terminées par le programme;
2. Aucun middleware n'est requis;
3. En théorie, soutenez toute base de données;
défaut:
1. Complété par les programmeurs, et le fonctionnement et la maintenance ne sont pas impliqués;
2. Augmenter dynamiquement que les sources de données ne peuvent pas être obtenues;
2.2. Solution middleware
Pour et contre:
avantage:
1. Le programme source peut réaliser une séparation de lecture et d'écriture sans aucun changement;
2. L'ajout de sources de données dynamiquement ne nécessite pas de redémarrage du programme;
défaut:
1. Les programmes reposent sur le middleware, ce qui rend difficile le changement de bases de données;
2. Le middleware est utilisé comme agent de transit et les performances ont diminué;
3. Utilisez le ressort pour implémenter en fonction de la couche d'application
3.1. Principe
Avant d'entrer dans le service, utilisez AOP pour porter un jugement, que ce soit pour utiliser une bibliothèque d'écriture ou une bibliothèque de lecture, la base du jugement peut être jugée sur la base du nom de la méthode, comme celui qui commence par la requête, la recherche, l'obtention, etc., et d'autres bibliothèques d'écriture.
3.2. Dynamicdatasource
import org.springframework.jdbc.datasource.lookup.abstractroutingdatasource; / ** * définir les sources de données dynamiques et implémenter l'abstractroutingdatasource fourni par l'intégration Spring. Il vous suffit d'implémenter la méthode déterminante de l'Assuieiture * * Étant donné que DynamicDataSource est un singleton et un thread-insécurité, ThreadLocal est utilisé pour garantir la sécurité de thread, qui est complétée par DynamicDataSourceHolder. * * @author zhijun * * / classe publique DynamicDataSource étend AbstractroutingDataSource {@Override Protected Object DeterMectionCurrentLookupKey () {// Utilisez DynamicDataSourceHolder pour assurer la sécurité des threads, et obtenez la clé de source de données dans le thread actuel de retour dynamicdatasource.getdatasourcekekey dans (););); }} 3.3. Dynamicdatasourceholder
/ ** * * Utilisez la technologie ThreadLocal pour enregistrer la clé de la source de données dans le thread actuel * * @author zhijun * * / classe publique DynamicDataSourceHolder {// Écrivez la source de données correspondant à la bibliothèque finale privée finale maître = "Master"; // Lire la source de données correspondant à la bibliothèque finale statique privée slave = "esclave"; // Utilisez ThreadLocal pour enregistrer la source de données du thread actuel privé statique final ThreadLocal <string> Holder = new ThreadLocal <string> (); / ** * Définissez la clé de source de données * @param key * / public static void putDataSourceKey (string key) {Holder.set (key); } / ** * Obtenez la clé de source de données * @return * / public static String getDataSourceKey () {return holder.get (); } / ** * Bibliothèque d'écriture de balisage * / public static void markmaster () {putDataSourceKey (maître); } / ** * bibliothèque de lecture de balisage * / public static void markslave () {putDataSourceKey (esclave); }} 3.4. DataSourCeaspect
import org.apache.commons.lang3.stringutils; import org.aspectj.lang.joinpoint; / ** * définir la section AOP de la source de données, et juger s'il est temps de lire la bibliothèque ou d'écrire la bibliothèque via le nom de la méthode du service * @Author Zhijun * * / Public DataSourceCispect Office {/ ** * EXECUTER AVANT Avant la méthode de service * public void avant (point joinPoint) {// Obtenez la chaîne de méthode actuellement exécutée méthode MethodName = Point.getSignature (). getName (); if (issLave (méthodyName)) {// Mark comme Lire Library DynamicDataSourceHolder.Markslave (); } else {// Mark as Write Library DynamicDataSourceHolder.markmaster (); }} / ** * Déterminez s'il s'agit d'une bibliothèque de lecture * * @param methodname * @return * / private boolean isslave (String methodname) {// Le nom de la méthode commence par la question, find, get, return stringUtils.startswithany (méthodyname, "query", "find", "get"); }}3.5. Configurer 2 sources de données
3.5.1. jdbc.properties
jdbc.master.driver = com.mysql.jdbc.driverjdbc.master.url = jdbc: mysql: //127.0.0.1: 3306 / mybatis_1128? useucicode = true & ch araCterencoding = utf8 & autoreConnect = true & allowMultiqueries = truejdbc.master.userName = rootjdbc.master.password = 123456jd bc.slave01.driver = com.mysql.jdbc.driverjdbc.slave01.url = jdbc: mysql: //127.0.0.1: 3307 / mybatis_1128? useunicode = true & ch AracTeRencoding = UTF8 & AutoreConnect = true & allowMultiqueries = truejdbc.slave01.Username = rootjdbc.slave01.password = 123456
3.5.2. Définir le pool de connexion
<! - Configurer le pool de connexion -> <bean id = "masterdatasource" destrement-méthod = "close"> <! - Database Driver -> <propriété name = "driverclass" value = "$ {jdbc.master.driver}" /> <! - Le pilote correspondant jdbcurl -> <propriété name = "jdbcurl" value = "$ {jdbc.master.url} />" value = "$ {jdbc.master.url} <! - Le nom d'utilisateur de la base de données -> <propriété name = "username" value = "$ {jdbc.master.username}" /> <! - Le mot de passe de la base de données -> <propriété name = "mot de passe" value = "$ {jdbc.master.password}" /> <! - Vérifiez le temps d'intervention des connexions idle dans le pool de données de données. L'unité est une fraction. La valeur par défaut est 240. Si vous souhaitez annuler, réglé sur 0. -> <propriété name = "idleconnectiontestperiod" value = "60" /> <! - Le nombre maximum de connexions qui ne sont pas utilisées dans le pool de connexions. L'unité est une fraction. La valeur par défaut est 60. Si vous souhaitez survivre pour toujours, réglé sur 0. -> <propriété name = "idleMaxage" value = "30" /> <! - Le nombre maximum de connexions par partition -> <propriété name = "MaxConnectionsPartition" Value = "150" /> <! Nombre minimum de connexions par partition -> <propriété name = "MaxConnectionSperPartition" Value = "150" /> <! - Le nombre minimum de connexions par partition -> <propriété name = "MinConnectionsPerPartition" Value = "5" /> </Eban> <! - Configurer le pool de connexions -> <Bean Id = "Slave01datasource" Détrooth-Method = "Close"> <- Database - Slave01datasource "Detrère-Method =" Close "> name = "driverclass" value = "$ {jdbc.slave01.driver}" /> <! - Jdbcurl pour le pilote correspondant -> <propriété name = "jdbcurl" value = "$ {jdbc.slave01.url}" /> <! - Database username -> <propriété name = "userame" Value = "$ {jdbc.slave01.username}" /> <! - Le mot de passe de la base de données -> <propriété name = "mot de passe" value = "$ {jdbc.slave01.password}" /> <! - Vérifiez le temps d'intervalle de connexions inactif dans le pool de connexion de la base de données. L'unité est une fraction. La valeur par défaut est 240. Si vous souhaitez annuler, réglé sur 0. -> <propriété name = "idleconnectiontestperiod" value = "60" /> <! - Le temps de survie maximal des liens inutilisés dans le pool de connexion. L'unité est une fraction. La valeur par défaut est de 60. Si vous souhaitez survivre pour toujours, réglé sur 0. -> <propriété name = "idleMaxage" value = "30" /> <! - Le nombre maximum de connexions par partition -> <propriété name = "MaxConnectionsPartition" Value = "150" /> <! - Nombre minimum de connexions par partition -> <propriété name = "minconnectionperpartition" 3.5.3. Définir DataSource
<! - Définissez la source de données et utilisez la source de données que vous implémentez -> <bean id = "DataSource"> <! - Définissez plusieurs sources de données -> <propriété name = "TargetDatasources"> <Map Key-Type = "java.lang.string"> <! - Cette clé doit être cohérente avec la clé du programme -> <entrée clé = "Master" Value-ref = " key = "Slave" value-ref = "slave01datasource" /> </aph> </ propriété> <! - Définissez la source de données par défaut, ici la bibliothèque d'écriture par défaut -> <propriété name = "DefaultTargetDataSource" Ref = "MasterDataSource" /> </ bean>
3.6. Configurer la gestion des transactions et changer dynamiquement les surfaces de source de données
3.6.1. Définir le gestionnaire de transactions
<! - Définition Transaction Manager -> <bean id = "TransactionManager"> <propriété name = "dataSource" ref = "dataSource" /> </ank>
3.6.2. Définir les politiques de transaction
<! - Définir la politique de transaction -> <tx: conseil id = "txadvice" transaction-manager = "transactionManager"> <tx: attributs> <! - Définir les méthodes de requête sont en lecture-seule-> <tx: méthode name = "Query *" Read-only = "true" /> <tx: méthode name = "findly =" true "/> <tx: méthode =" get * " /> <! - La bibliothèque principale effectue des opérations, et le comportement de propagation des transactions est défini comme le comportement par défaut -> <tx: méthode name = "Save *" propagation = "requis" /> <tx: méthode name = "update *" propagation = "requis" /> <tx: méthode name = "delete *" propagation = "requis" /> <! </ tx: attributs> </ tx: conseils>
3.6.3. Définir la facette
<! - Définir le processeur de la section AOP -> <bean id = "DataSourCeaspect" /> <aop: config> <! - Définir des sections, toutes les méthodes de tous les services -> <aop: PointCut id = "txpointcut" Expression = "Exécution (* xx.xxx.xxxxx.service. conseils-ref = "txAdvice" Pointcut-ref = "txpointcut" /> <! - Appliquez la section à un processeur de section personnalisé, -9999 garantit que la section a la plus haute exécution prioritaire-> <aop: Aspect Ref = "DataSourceSpect" Order = "- 9999"> <aop: avant la méthode = "avant" Pointcut-ref = "txpoint" </aop: aspect> </ aop: config>
4. Améliorer la mise en œuvre de la section et utiliser la correspondance des règles de politique de transaction
Dans l'implémentation précédente, nous correspondrons au nom de la méthode au lieu d'utiliser la définition dans la stratégie de transaction, et nous utiliserons la correspondance des règles dans la politique de gestion des transactions.
4.1. Configuration améliorée
<! - Définir le processeur de la section AOP -> <bean id = "dataSourCeaspect"> <! - Spécifier la stratégie de transaction -> <propriété name = "txadvice" ref = "txadvice" /> <! - Spécifiez le préfixe de la méthode d'esclave (pas obligatoire) -> <propriété name = "SlaveMethodstart" value = "query, find, get" /> </ bean
4.2. Amélioration de la mise en œuvre
Importer java.lang.reflect.field; import java.util.arraylist; import java.util.list; import java.util.map; import org.apache.commons.lang3.stringutils; import org.aspectj.lang.joinpoint; import org.springframework.transaction.interceptor.namempoint; Importer org.springframework.transaction.interceptor.namempoint; Importer org.springframework.transaction.interceptor.namempoint; Importer org.springFramework.transaction.interceptor.namempoint; org.springframework.transaction.interceptor.transactionAttribute; import org.springframework.transaction.interceptor.transactionAttributesource; import org.springframework.transaction.interceptor.transactionInterceptor; import org.springframework.util.patternmatchUtils; import; org.springframework.util.reflectionutils; / ** * définit la section AOP de la source de données, qui contrôle s'il faut utiliser le maître ou l'esclave. * * Si une stratégie de transaction est configurée dans la gestion des transactions, la méthode de marquage en lecture dans la stratégie de transaction configurée est d'utiliser l'esclave et l'autre utilise Master. * * S'il n'y a pas de stratégie pour configurer la gestion des transactions, le principe de la correspondance du nom de la méthode est adopté et l'esclave est utilisé comme commençant par la requête, trouver et obtenir, et d'autres méthodes sont utilisées comme maître. * * @author zhijun * * / classe publique DataSourCeaSpect {private list <string> slavemethodpattern = new ArrayList <string> (); String final statique privé [] defaultSlaveMethodStart = new String [] {"Query", "Find", "get"}; chaîne privée [] SlaveMethodStart; / ** * Lire les politiques dans la gestion des transactions * * @param txadvice * @throws exception * / @SuppressWarnings ("Unchecked") public void SettxAdvice (TransactionInterceptor txAdvice) lève l'exception {if (txadvice == null) {// La stratégie de gestion des transactions n'est pas configurée de retour; } // Obtenir des informations de configuration de stratégie à partir de TxAdvice TransactionAttributesource TransactionAttributeSource = txAdvice.gettransactionAttributesource (); if (! (TransactionAtTributesource instanceof nameMatchTransactionAtTributesource)) {return; } // Utiliser la technologie de réflexion pour obtenir la valeur d'attribut NameMap dans l'objet NameMatchTransactionAttributeSource NameMatchTransactionAttributeSource MatchTransactionAttributeSource = (NameMatchTransactionAttributeSource) TransactionAttributeSource; Champ namemapfield = réflexionutils.findfield (namematchTransactionAttributesource.class, "namemap"); NameMapField.SetAccessible (true); // Définissez ce champ sur accéder // Obtenez la valeur de NameMap <String, transactionAttribute> map = (map <string, transactionAttribute>) nameMapField.get (MatchTransactionAttributeSource); // transactionAttribute> Entrée: map.entrySet ()) {if (! Entrée.getValue (). IsReadOnly ()) {// Après le jugement, la politique ReadOnly est définie avant de l'ajouter à SaveMethodPattern continue; } SlaveMethodPattern.Add (entry.getKey ()); }} / ** * Exécuter avant d'entrer dans la méthode de service * @param point de face point * / public void avant (point joinPoint) {// Obtenez la méthode de méthode actuellement exécutée méthodyname = point.getSignature (). GetName (); booléen isslave = false; if (slavemethodpattern.isempty ()) {// Aucune stratégie de transaction n'est configurée dans le conteneur actuel de ressort, et la méthode de correspondance du nom de la méthode ISSLAVE = ISSLAVE (MethodName); } else {// Utiliser des règles de stratégie pour correspondre à (String mappedName: SlaveMethodPattern) {if (isMatch (méthodyName, mappEdName)) {isslave = true; casser; }}}} if (isslave) {// marquer comme lire la bibliothèque dynamicdatasourceholder.markslave (); } else {// Mark as Write Library DynamicDataSourceHolder.markmaster (); }} / ** * Déterminez s'il s'agit d'une bibliothèque de lecture * * @param methodname * @return * / private boolean isslave (String methodname) {// Le nom de la méthode commence par la question, find, get return stringUtils.startswithany (méthodyname, getLaveMethodStart ()); } / ** * La correspondance de la carte générique * * renvoie si le nom de la méthode donné correspond au nom mappé. * <p> * L'implémentation par défaut vérifie "xxx *", "* xxx" et "* xxx *" correspond, ainsi que l'égalité directe *. Peut être remplacé dans les sous-classes. * * @param Methodnname Le nom de la méthode de la classe * @param mappedName le nom dans le descripteur * @return si les noms correspondent * @see org.springframework.util.patternmatchutils # simplematch (String, String) * / Protected boolean ismatch (String MethodName (mappedname) {return PattemMatchUtils.Simplemat MethodName); } / ** * Le préfixe de nom de méthode de l'esclave spécifié par l'utilisateur * @param slaveMethodStart * / public void setsLaveMethodStart (String [] SlaveMethodStart) {this.slavemethodstart = SlaveMethodStart; } public String [] getSlaveMethodStart () {if (this.slavemethodstart == null) {// non spécifié, utilisez le return par défaut defaultSlaveMethodStart; } return SlaveMethodStart; }}5. Implémentation d'un maître et de plusieurs esclaves
Dans de nombreux scénarios d'utilisation pratiques, nous utilisons l'architecture "One Master, Multiple Slave", nous soutenons donc désormais cette architecture, et nous n'avons actuellement besoin que de modifier la dynamicdatasource.
5.1. Mise en œuvre
import java.lang.reflect.field; import java.util.arraylist; import java.util.list; import java.util.map; import java.util.concurrent.atomic.atomicinteger; org.springframework.jdbc.datasource.lookup.abstractroutingdatasource; import org.springframework.util.reflectionutils; / ** * définir les sources de données dynamiques et implémenter AbstractroutingDatasource fourni par le printemps par l'intégration, vous avez uniquement besoin de mettre en œuvre la méthode de détermination de l'écurrent de la Lookupke * * car la dynamique est unique pour un chant de déterminer la méthode Lookupke Et l'inscription par thread, ThreadLocal est utilisée pour assurer la sécurité de thread, qui est complétée par DynamicDataSourceHolder. * * @author zhijun * * / classe publique DynamicDataSource étend AbstractroutingDataSource {private static final logger = loggerfactory.getLogger (dynamicDataSource.class); Slavecount entier privé; // Nombre de sondages, initialement -1, ATOMICInteger est un compteur privé atomicInteger en filetage = nouveau atomicInteger (-1); // Enregistrez la liste privée clé <Bobile> SlaveDataSources = new ArrayList <Bject> (0); @Override Protected Object DeterMectionCurrentLookUpKey () {// Utilisez DynamicDataSourceHolder pour assurer la sécurité du thread et obtenir la touche de source de données dans le thread actuel if (dynamicdatasourceHolder.ismaster ()) {object key = dynamicdatasourceholder.getDataSourceKey (); if (logger.isdebugeNable ()) {logger.debug ("La clé de la source de données actuelle est:" + key); } return key; } Objet key = getLaveKey (); if (logger.isdebugeNable ()) {logger.debug ("La clé de la source de données actuelle est:" + key); } return key; } @SuppressWarnings ("Unchecked") @Override public void afterpropertiesset () {super.afterpropertiesset (); // Étant donné que la propriété ResolvedDataSources de la classe parent est une sous-classe privée qui ne peut pas être obtenue, vous devez utiliser la réflexion pour obtenir le champ de champ = réflexionutils.findfield (abstratroutingDatasource.class, "résolveddatasources"); field.setAccessible (true); // Définir l'accessibilité essayez {map <objet, dataSource> résolvedDataSources = (map <object, dataSource>) field.get (this); // La quantité de données dans la bibliothèque Read est égale au nombre total de sources de données moins le nombre de bibliothèques d'écriture this.slavecount = résolveddatasources.size () - 1; for (map.entry <objet, dataSource> entrée: résolveddatasources.entryset ()) {if (dynamicDataSourceHolder.master.equals (entry.getKey ())) {continué; } SlaveDataSources.Add (Entry.GetKey ()); }} catch (exception e) {logger.error ("Erreur AfterProperTesset!", e); }} / ** * Implémentation de l'algorithme de sondage * * @return * / objet public getLaveKey () {// Les indices résultants sont: 0, 1, 2, 3 ... INTEGER INDEX = COMPTEND.IncrementAndget ()% SlaveCount; if (counter.get ()> 9999) {// pour éviter de dépasser la plage entière compteur.set (-1); // restaurer} return slavedataSources.get (index); }}6. Replication MySQL Master-Slave
6.1. Principe
Le principe de la copie de l'esclave MySQL Master (appelé maître) (appelé esclave):
1. Le maître enregistre les données se transforment dans le journal binaire, c'est-à-dire le fichier spécifié par le journal du fichier de configuration (ces enregistrements sont appelés événements de journal binaire, événements de journal binaire)
2. Slave Copy Master's Binary Logvents dans son journal de relais (journal de relais)
3.
6.2. À quoi devrait être prêté attention lors de la configuration de Mach
1. Les versions du serveur DB principal et de la base de données du serveur DB Slave sont les mêmes
2. Les données de base de données du serveur DB Master et du serveur DB esclave sont les mêmes [ici, vous pouvez restaurer la sauvegarde du maître sur l'esclave, ou vous pouvez copier directement le répertoire de données du maître dans le répertoire de données de l'esclave correspondant]
3. Le serveur DB principal permet les journaux binaires, et le serveur DB principal et le serveur de serveur DB Slave doivent être uniques.
6.3. Configuration de la bibliothèque principale (similaire à Windows, Linux)
Certains amis peuvent ne pas avoir une adresse IP, un nom d'utilisateur et une configuration de compte très clairs de la base de données maître et esclave. Ce qui suit est la configuration maître et esclave que j'ai testée. Les IP sont tous 127.0.0.1. Après avoir terminé mon exemple, je l'écrirai.
Une IP maître-esclave est un exemple de différentes configurations. Vous pouvez utiliser cet exemple pour comprendre la méthode de configuration plus intuitivement.
Modifier sous my.ini [mysqld] (ainsi que dans la bibliothèque):
#Enable Replication Master-Slave, La configuration de la bibliothèque principale Log-Bin = MySQL3306-BIN # Spécifiez la bibliothèque principale ServerIdServer-ID = 101 # Spécifiez la base de données synchronisée. S'il n'est pas spécifié, toutes les bases de données sont synchronisées binlog-do-db = mybatis_1128
(Les commandes entrées dans My.ini doivent avoir une ligne d'espace ci-dessous, sinon MySQL ne le reconnaîtra pas)
Exécuter l'état de la requête de l'instruction SQL: afficher l'état du maître
La valeur de position doit être enregistrée et la valeur de démarrage de synchronisation doit être définie dans la bibliothèque.
Permettez-moi de dire encore une chose. Si vous exécutez Show Master Status sur MySQL et constatez que le contenu configuré dans My.ini n'a pas fonctionné. Il se peut que vous n'ayez pas choisi le fichier My.ini, ou il se peut que vous n'ayez pas redémarré le service. Il est très probable qu'il soit causé par ce dernier.
Pour rendre la configuration à effet, vous devez désactiver le service MySQL et le redémarrer.
Comment fermer le service:
Ouvrez la touche Win, entrez des services.msc pour appeler le service:
Démarrez à nouveau SQLYOG et constatez que la configuration a pris effet.
6.4. Créer un utilisateur synchrone dans la bibliothèque principale
#Authorized User Slave01 utilise un mot de passe 123456 pour se connecter à l'esclave de réplication MySqlGrant sur *. * À 'Slave01'@'127.0.0.1' identifié par '123456'; Flush Privileges;
6.5. Configuration de la bibliothèque
Modifier dans My.ini:
#Specify ServerId, tant qu'il n'est pas répété, il n'y a qu'une seule configuration de la bibliothèque, et les autres sont exploités dans la déclaration SQL Server-ID = 102
Le suivant exécute SQL (exécute à l'aide du compte racine de l'esclave):
ChangeMaterTomater_Hot = '127.0.0.1', // L'adresse IP de l'hôte Material_Uer = 'Lave01', // L'utilisateur de l'hôte (le compte vient de créer sur l'hôte via ql) mater_paword = '123456', mater_port = 3306, mater_log_file = 'myql3306-bin.000006', // filemate_log_po = 1120; // poignée
#Start Slave Synchronization Start Slave; #View Synchronization Status Show Slave Status;
Voici les méthodes de configuration maître et esclave pour deux ordinateurs IP différents:
Le système d'exploitation où réside la base de données principale: Win7
Version de la base de données principale: 5.0
L'adresse IP de la base de données principale: 192.168.1.111
Du système d'exploitation où réside la base de données: Linux
À partir de la version des données: 5.0
Adresse IP de la base de données: 192.168.1.112
Après avoir introduit l'environnement, parlons des étapes de configuration:
1. Assurez-vous que la base de données maître est exactement la même que la base de données des esclaves.
Par exemple: la base de données de A dans la base de données principale a les tableaux B, C et D, de sorte que la base de données de A et les tableaux B, C et D doit être gravée avec un moule.
2. Créez un compte synchrone sur la base de données principale.
La copie de code est la suivante:
Slave de réplication de la subvention, fichier sur *. * À 'mstest'@'192.168.1.112' identifié par '123456';
192.168.1.112: C'est l'adresse IP qui s'exécute à l'aide de l'utilisateur
mstest: est le nom d'utilisateur nouvellement créé
123456: C'est le mot de passe du nom d'utilisateur nouvellement créé
L'explication détaillée de la commande ci-dessus est mieux effectuée sur Baidu. Si vous écrivez trop, cela le rendra plus clair.
3. Configurez mon.ini de la base de données principale (car c'est sous la fenêtre, c'est mon.ini et non my.cnf).
[mysqld] server-id = 1log-bin = logbinlog-do-db = mstest // pour synchroniser la base de données mstest, si vous souhaitez synchroniser plusieurs bases de données, ajoutez quelques autres binlog-do-db = name de base de données binlog-ingnore-db = messql // pour ignorer la base de données
4. Configurez My.cnf à partir de la base de données.
[mysqld] server-id = 2Master-host = 192.168.1.111master-user = mstest // Étape 1. Créez le nom d'utilisateur du compte Master-Password = 123456 // Étape 1. Bases de données, ajoutez quelques autres reprodues-db = nom de base de données reprodu-ingnore-db = mysql // la base de données à ignorer
5. Vérifiez si elle réussit
Entrez MySQL et entrez la commande: Afficher le statut d'esclave / g. L'image suivante sera affichée. Si Slave_io_Running et Slave_Sql_Running sont oui, cela signifie que la synchronisation peut être avec succès
6. Tester les données synchrones.
Entrez la base de données principale et entrez la commande: insérer dans une (nom) valeurs («beijing»);
Entrez ensuite la commande d'entrée de la base de données: sélectionnez * dans un;
Si les données sont extraites de la base de données pour le moment, cela signifie que la synchronisation a été réussie et que le maître et l'esclave seront implémentés.
Ce qui précède est tout le contenu de cet article. J'espère que cela sera utile à l'apprentissage de tous et j'espère que tout le monde soutiendra davantage Wulin.com.