[JAVA] Une histoire sur la prise en charge de la réplication par les applications Spring + Hibernate + MySQL

Aperçu

Voici un résumé des découvertes lorsqu'une application Java héritée avec une configuration standard il y a environ 10 ans a été rendue compatible avec la réplication de base de données. La technologie et la version utilisées sont les suivantes.

À propos de la réplication

Avant d'entrer dans les détails, passons en revue la réplication.

La réplication de base de données est un concept adopté par de nombreux systèmes de gestion de base de données et signifie une relation maître-esclave entre l'original et la copie de la base de données. Le maître enregistre la mise à jour et avertit les esclaves. Le côté esclave envoie un message indiquant que la mise à jour a été reçue correctement, notifiant que la prochaine mise à jour est prête à être acceptée.

Source: [Wikipédia](https://ja.wikipedia.org/wiki/%E3%83%AC%E3%83%97%E3%83%AA%E3%82%B1%E3%83%BC%E3 % 82% B7% E3% 83% A7% E3% 83% B3)

La configuration d'un DB avec un maître qui peut être visualisé et mis à jour et un esclave qui est toujours synchronisé avec le maître [^ 1] et ne peut être visualisé que s'appelle la réplication. Un traitement de mise à jour tel que ʻINSERT et ʻUPDATE est effectué sur le maître, et un traitement de référence tel que SELECT est effectué sur l'esclave pour répartir la charge sur la base de données ou lorsque le maître tombe en panne pour une raison quelconque. De plus, en préparant une réplique de basculement pour remplacer le maître, les temps d'arrêt peuvent être minimisés et une haute disponibilité peut être obtenue. En outre, il y aura une copie du maître, ce qui peut rendre les données redondantes.

[^ 1]: En fait, il y a un délai de synchronisation de plusieurs millisecondes, il peut donc être nécessaire de le considérer du côté de l'application.

Vous pouvez profiter de divers avantages en utilisant une configuration de réplication, mais l'application doit également être créée de manière appropriée, comme des requêtes distribuées et des mesures contre le décalage de synchronisation.

la mise en oeuvre

En spécifiant l'option readOnly dans Spring's @ Transactional, le contact est déterminé pour chaque transaction.

Comme mentionné précédemment, les exigences pour la mise en œuvre étaient des «requêtes distribuées» et des «contre-mesures de retard de synchronisation».

Parmi ceux-ci, ce dernier a été traité en élargissant la portée des transactions. Plus précisément, l'implémentation précédente a changé la transaction d'être créée pour chaque couche de référentiel (= 1 requête) à être créée pour chaque couche de service (= plusieurs requêtes). Cela signifie que même si les mises à jour et les références sont mélangées dans plusieurs requêtes, le contact est déterminé comme maître ou esclave pour chaque transaction. Puisque l'esclave est en lecture seule, ce sera inévitablement une requête au maître s'il existe des systèmes de mise à jour mixtes. Par conséquent, dans une transaction dans laquelle les systèmes de mise à jour sont mélangés, le système de référence interroge également le maître, ce qui signifie qu'une répartition stricte de la charge n'est pas possible, mais à la place, il n'est pas nécessaire de prendre en compte le délai de synchronisation, donc la charge Suite à la pondération de la taille et de la complexité de l'implémentation, nous avons choisi de simplifier l'implémentation.

Perspective 1 transaction/1 Demande 1 transaction/n Demandes de renseignements
Répartition de la charge Peut être strictement réparti entre le système de mise à jour et le système de référence Strictement non distribué (maître s'il y a un système de mise à jour, esclave s'il n'y a pas de système de mise à jour)
Simplicité de mise en œuvre Cela devient compliqué car il faut tenir compte du décalage temporel de synchronisation (dans le cas de mise à jour → référence, considérez qu'il s'agit des dernières données au moment de la référence) Simple sans tenir compte du décalage dans le temps de synchronisation (même lors de la mise à jour → référencement, ce seront toujours les dernières données)

Par conséquent, ce que j'écris dans cet article est ce que j'ai fait pour les «requêtes distribuées».

À propos de @ Transactional

J'avais besoin de savoir à ce sujet afin d'utiliser @ Transactional de Spring, alors j'ai fait un peu de recherche.

Document officiel

@ Transactional ajoute du code lié à la gestion des transactions tel que begin et commit, qui figuraient jusqu'ici dans le code source, à la méthode en tant qu'annotation, et Spring AOP autorise begin au début de la méthode. C'est une fonction qui peut expulser la gestion des transactions du code source et améliorer la visibilité en exécutant commit à la fin.

Vous pouvez définir diverses options pour ce @ Transactional, mais le readOnly utilisé cette fois peut spécifiertrue / false (default), ce qui fait du contact un maître ou un esclave. Tu peux décider. La valeur par défaut est «false», ce qui interroge le maître, mais vous pouvez spécifier «true» pour interroger l'esclave.

Comment utiliser

Si la classe est gérée par bean dans le conteneur Spring (= Spring AOP peut être exécuté), ajoutez-la simplement à la méthode comme suit. Il peut également être donné à la classe elle-même, auquel cas il est synonyme de le donner à toutes les méthodes de la classe.

UserService.java


public class UserService implements Service {

    @Transactional(readOnly = false) //Commencé lorsque cette méthode est appelée et validée à la sortie
    public User createUser() {
        // INSERT
    }

    @Transactional(readOnly = true) //Puisqu'il s'agit d'un système de référence, demandez à l'esclave
    public User getUser() {
        // SELECT
    }

    @Transactional(readOnly = false) //Puisqu'il s'agit d'un système de mise à jour, contactez le maître
    public void updateUser() {
        // UPDATE
    }

    @Transactional(readOnly = false)
    public void deleteUser() {
        // DELETE
    }
}

Ajoutez la description suivante au fichier de configuration Spring et activez l'annotation.

Spring.xml


<tx:annotation-driven transaction-manager="txManager"/>
<bean id="txManager" class="org.springframework.orm.hibernate4.HibernateTransactionManager">
    <property name="sessionFactory" ref="sessionFactory"/>
</bean>
<bean id="dataSourceTxManager" class="org.springframework.jdbc.datasource.DataSourceTransactionManager">
    <property name="dataSource" ref="dataSource"/>
</bean>

La connexion est établie par MySQL Connector / J, mais la source de données est décrite comme la destination de connexion comme suit. → Document officiel

Écrivez d'abord l'hôte maître, puis écrivez les hôtes esclaves séparés par des virgules.

Spring.xml


<bean id="dataSource" class="org.apache.commons.dbcp.BasicDataSource">
    <property name="driverClassName" value="com.mysql.jdbc.ReplicationDriver"/>
    <property name="url" value="jdbc:mysql:replication://127.0.0.1:3306,127.0.0.1:13306"/>
    <property name="username" value="user"/>
    <property name="password" value="password"/>
</bean>

Résumé

Puisqu'il s'agissait d'un support pour les applications héritées, il semble que la partie spécifique ne sera pas très utile à l'avenir, mais je pense que la réplication elle-même est une configuration standard, donc je connaissais le concept et le type de support nécessaire. Je pense que c'est une moisson. Je pense que DB est utilisé dans la plupart des applications, alors j'aimerais utiliser les connaissances que j'ai acquises cette fois.

Recommended Posts

Une histoire sur la prise en charge de la réplication par les applications Spring + Hibernate + MySQL
Une histoire de rendre catkin_make de rosjava compatible hors ligne
Une histoire sur une BeanNotOfRequiredTypeException qui s'est produite après l'application d'AOP au printemps
Une histoire sur la fabrication d'une calculatrice pour calculer le taux de monticule d'obus
Une histoire sur un projet Spring Boot écrit en Java qui prend en charge Kotlin