[JAVA] Eine Geschichte darüber, wie Spring + Hibernate + MySQL-Apps die Replikation unterstützen

Überblick

Hier finden Sie eine Zusammenfassung der Ergebnisse, wenn eine ältere Java-Anwendung mit einer Standardkonfiguration vor etwa 10 Jahren mit der DB-Replikation kompatibel gemacht wurde. Die verwendete Technologie und Version sind wie folgt.

Informationen zur Replikation

Bevor wir uns mit den Einzelheiten befassen, überprüfen wir die Replikation.

Die Datenbankreplikation ist ein Konzept, das von vielen Datenbankverwaltungssystemen übernommen wird und eine Master-Slave-Beziehung zwischen dem Original und der Kopie der Datenbank bedeutet. Der Master zeichnet die Aktualisierung auf und benachrichtigt die Slaves. Die Slave-Seite sendet eine Nachricht, dass das Update korrekt empfangen wurde, und benachrichtigt, dass das nächste Update zur Annahme bereit ist.

Quelle: [Wikipedia](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)

Das Konfigurieren einer Datenbank mit einem Master, der angezeigt und aktualisiert werden kann, und einem Slave, der immer mit dem Master synchronisiert ist [^ 1] und nur angezeigt werden kann, wird als Replikation bezeichnet. Aktualisierungsverarbeitung wie "INSERT" und "UPDATE" wird auf dem Master ausgeführt, und Referenzverarbeitung wie "SELECT" wird auf dem Slave ausgeführt, um die Last auf die DB zu verteilen, oder wenn der Master aus irgendeinem Grund ausfällt. Durch die Vorbereitung eines Failover-Replikats als Ersatz für den Master können Ausfallzeiten minimiert und eine hohe Verfügbarkeit erreicht werden. Außerdem wird es eine Kopie des Masters geben, wodurch die Daten redundant werden können.

[^ 1]: Tatsächlich gibt es eine Synchronisationsverzögerung von mehreren Millisekunden, daher kann es erforderlich sein, diese auf der Anwendungsseite zu berücksichtigen.

Sie können verschiedene Vorteile nutzen, wenn Sie eine Replikationskonfiguration verwenden. Die Anwendung muss jedoch auch entsprechend erstellt werden, z. B. verteilte Abfragen und Maßnahmen gegen die Zeitverzögerung bei der Synchronisierung.

Implementierung

Durch Angabe der Option "readOnly" in "@ Transactional" von Spring wird der Kontakt für jede Transaktion bestimmt.

Wie bereits erwähnt, waren die Anforderungen für die Implementierung "verteilte Abfragen" und "Gegenmaßnahmen zur Verzögerung der Synchronisationszeit".

Letzteres wurde durch die Erweiterung des Transaktionsumfangs angegangen. Insbesondere wurden in der vorherigen Implementierung Transaktionen für jede Repository-Schicht (= 1 Abfrage) erstellt, jedoch so geändert, dass sie für jede Service-Schicht (= mehrere Abfragen) erstellt werden. Dies bedeutet, dass selbst wenn Aktualisierungen und Referenzen in mehreren Abfragen gemischt werden, der Kontakt für jede Transaktion als Master oder Slave bestimmt wird. Da der Slave Readonly ist, wird es zwangsläufig eine Abfrage an den Master geben, wenn gemischte Update-Systeme vorhanden sind. Daher stellt das Referenzsystem bei einer Transaktion, bei der Aktualisierungssysteme gemischt werden, auch eine Anfrage an den Master, was bedeutet, dass eine strikte Lastverteilung nicht möglich ist, sondern die Synchronisationszeitverzögerung, also die Last, nicht berücksichtigt werden muss Aufgrund der Abwägung der Größe und Komplexität der Implementierung haben wir uns entschlossen, die Implementierung zu vereinfachen.

Perspektive 1 Transaktion/1 Anfrage 1 Transaktion/n Anfragen
Lastverteilung Kann streng zwischen Update-System und Referenzsystem verteilt werden Streng nicht verteilt (Master, wenn es ein Update-System gibt, Slave, wenn es kein Update-System gibt)
Einfache Implementierung Dies wird kompliziert, da die Synchronisationszeitverzögerung berücksichtigt werden muss (im Fall von Aktualisierung → Referenz ist zu berücksichtigen, dass es sich zum Zeitpunkt der Referenz um die neuesten Daten handelt). Einfach ohne Berücksichtigung der Synchronisationsverzögerung (auch beim Aktualisieren → Referenzieren werden immer die neuesten Daten angezeigt)

Daher schreibe ich in diesem Artikel, was ich für "verteilte Abfragen" getan habe.

Über @ Transactional

Ich musste darüber Bescheid wissen, um Spring's @ Transactional verwenden zu können, also habe ich ein wenig recherchiert.

Offizielles Dokument

@ Transactional fügt der Methode Code hinzu, der sich auf das Transaktionsmanagement bezieht, wie z. B. begin und commit, die bisher im Quellcode enthalten waren, und Spring AOP ermöglicht begin zu Beginn der Methode. Es ist eine Funktion, die das Transaktionsmanagement aus dem Quellcode ausschließen und die Sichtbarkeit verbessern kann, indem am Ende "Festschreiben" ausgeführt wird.

Sie können verschiedene Optionen für dieses "@ Transactional" festlegen, aber das diesmal verwendete "readOnly" kann "true / false (Standard)" angeben, wodurch der Kontakt zu einem Master oder Slave wird. Du kannst entscheiden. Der Standardwert ist "false", wodurch der Master abgefragt wird. Sie können jedoch "true" angeben, um den Slave abzufragen.

Wie benutzt man

Wenn die Klasse im Spring-Container Bean verwaltet wird (= Spring AOP kann ausgeführt werden), fügen Sie sie einfach wie folgt zur Methode hinzu. Es kann auch der Klasse selbst gegeben werden. In diesem Fall ist es gleichbedeutend damit, es allen Methoden der Klasse zu geben.

UserService.java


public class UserService implements Service {

    @Transactional(readOnly = false) //Begonnen, wenn diese Methode beim Beenden aufgerufen und festgeschrieben wird
    public User createUser() {
        // INSERT
    }

    @Transactional(readOnly = true) //Da es sich um ein Referenzsystem handelt, wenden Sie sich an den Slave
    public User getUser() {
        // SELECT
    }

    @Transactional(readOnly = false) //Da es sich um ein Update-System handelt, wenden Sie sich an den Master
    public void updateUser() {
        // UPDATE
    }

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

Fügen Sie der Spring-Konfigurationsdatei die folgende Beschreibung hinzu und aktivieren Sie die Anmerkung.

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>

Die Verbindung wird von MySQL Connector / J hergestellt, aber die DataSource wird wie folgt als Verbindungsziel beschrieben. → Offizielles Dokument

Schreiben Sie zuerst den Master-Host und dann die durch Kommas getrennten Slave-Hosts.

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>

Zusammenfassung

Da es sich um eine Unterstützung für ältere Apps handelte, scheint der spezifische Teil in Zukunft nicht sehr hilfreich zu sein, aber ich denke, dass die Replikation selbst eine Standardkonfiguration ist, sodass ich das Konzept kannte und wusste, welche Art von Unterstützung erforderlich ist. Ich denke, es ist eine Ernte. Ich denke, DB wird in den meisten Apps verwendet, daher möchte ich das Wissen nutzen, das ich diesmal gewonnen habe.

Recommended Posts

Eine Geschichte darüber, wie Spring + Hibernate + MySQL-Apps die Replikation unterstützen
Eine Geschichte darüber, wie catkin_make von Rosjava offline kompatibel gemacht wird
Eine Geschichte über eine BeanNotOfRequiredTypeException, die nach der Anwendung von AOP im Frühjahr aufgetreten ist
Eine Geschichte über die Herstellung eines Taschenrechners zur Berechnung der Muschelhügelrate
Eine Geschichte über ein in Java geschriebenes Spring Boot-Projekt, das Kotlin unterstützt