MySQL-Sharding-Details

MySQL-Sharding-Details

1. Einführung in das Geschäftsszenario

Angenommen, es gibt ein E-Commerce-System, das MySQL verwendet. Sie müssen eine Lösung entwerfen, die große Datenmengen speichern kann, eine hohe Parallelität aufweist und hochgradig skalierbar ist. In der Datenbank gibt es eine Benutzertabelle. Es wird viele Benutzer geben und eine hohe Skalierbarkeit muss erreicht werden. Wie würden Sie das gestalten? OK, schauen wir uns zunächst die traditionelle Art des Shardings an

Natürlich wissen einige Freunde, wie man die Datenbank nach Provinzen/Regionen oder bestimmten Geschäftsbeziehungen aufteilt.

OK, jetzt stellt sich die Frage, wie sichergestellt werden kann, dass Daten in unterschiedlichen Tabellen in unterschiedlichen Bibliotheken gespeichert werden? Soll die Bibliothek den Parallelitätsdruck reduzieren? Wie sollen die Regeln für die Teilbibliotheks- und Tischaufteilung formuliert werden? Keine Sorge, es kommt bald

2. Horizontale Datenbank- und Tabellenaufteilungsmethode

1.BEREICH

Die erste Methode besteht darin, einen Datenbereich anzugeben, in den die Tabelle aufgeteilt werden soll, z. B. von 1 bis 1000000, 1000001-2000000, wobei eine Tabelle für eine Million verwendet wird, wie in der folgenden Abbildung dargestellt

Bildbeschreibung hier einfügen Natürlich erfordert diese Methode die Pflege der Tabellen-ID, insbesondere in einer verteilten Umgebung. Für diese verteilte ID wird empfohlen, Redis zu verwenden, ohne ein Tabellen-Sharding-Tool von Drittanbietern zu verwenden. incr Vorgang von Redis kann die verteilte Tabellen-ID problemlos pflegen.

Vorteile der RANGE-Methode: Einfache Erweiterung, Datenbank und Tabelle müssen nur im Voraus erstellt werden

Nachteile der RANGE-Methode: Die meisten Lese- und Schreibvorgänge greifen auf neue Daten zu, was zu einem IO-Engpass führt. Dies führt zu übermäßigem Druck auf die neue Datenbank und wird nicht empfohlen.

2. HASH-Modul

Um das IO-Engpassproblem der RANGE Tabellenpartitionierung zu lösen, können wir die Datenbank und die Tabelle mit der Methode des Modulus der Benutzer ID HASG partitionieren, wie in der Abbildung gezeigt:

Auf diese Weise können die Daten auf verschiedene Datenbanken und Tabellen verteilt werden, wodurch das Problem von E/A-Engpässen vermieden wird.

Vorteile der HASH-Modulmethode: Sie kann sicherstellen, dass die Daten gleichmäßig auf verschiedene Datenbanken und Tabellen verteilt sind, wodurch der Datenbankdruck verringert wird

Nachteile der HASH-Modulmethode: Die Erweiterung ist schwierig und der Hashwert muss bei jeder Datenmigration neu berechnet und verschiedenen Datenbanken und Tabellen zugewiesen werden

3. Konsistentes HASH

Modulo durch HASH ist nicht die perfekteste Methode, also was ist es?

Die Verwendung eines konsistenten HASH-Algorithmus kann das Problem perfekt lösen

Allgemeiner HASH-Algorithmus:

Ein gängiger Hash-Algorithmus bildet einen Binärwert beliebiger Länge auf einen kürzeren Binärwert fester Länge ab. Dieser kleine Binärwert wird als Hash-Wert bezeichnet. Ein Hashwert ist eine eindeutige und äußerst kompakte numerische Darstellung eines Datenelements.

Die Mängel gewöhnlicher hash -Algorithmen in verteilten Anwendungen: In einem verteilten Speichersystem müssen Daten auf bestimmten Knoten gespeichert werden. Wenn wir gewöhnliche hash -Algorithmen zum Routing verwenden und Daten bestimmten Knoten zuordnen, wie z. B. key%n , ist key key der Daten und n die Anzahl der Maschinenknoten. Wenn eine Maschine dem Cluster beitritt oder ihn verlässt, sind alle Datenzuordnungen ungültig. Wenn es sich um persistenten Speicher handelt, muss eine Datenmigration durchgeführt werden. Wenn es sich um einen verteilten Cache handelt, werden andere Caches ungültig.

Konsistenter HASH-Algorithmus: Verwenden Sie den allgemein verwendeten hash -Algorithmus, um den entsprechenden Schlüssel in einen Bereich mit 2^32 Knoten zu hashen, d. h. einen digitalen Bereich von 0 bis (2^32)-1. Jetzt können wir diese Zahlen Ende an Ende verbinden und sie uns als geschlossenen Kreis vorstellen, wie in der Abbildung unten gezeigt.

Dieser Ring ist Ende an Ende verbunden. Angenommen, es gibt drei Datenbankserverknoten: node1 , node2 und node3 . Jeder Knoten ist für die Speicherung seines eigenen Teils der Benutzerdaten verantwortlich. Angenommen, es gibt die Benutzer Benutzer1, Benutzer2 und Benutzer3. Wir können HASH-Operationen auf den Serverknoten durchführen. Angenommen, nach der HASH-Berechnung fällt Benutzer1 auf node1 , user2 auf node2 und Benutzer3 auf Benutzer3.

OK, nehmen wir jetzt an, dass Knoten3 ausfällt.

user3 landet auf Knoten1 und die vorherigen Daten von Knoten1 und Knoten2 ändern sich nicht. Angenommen, Knoten4 wird hinzugefügt

Sie werden feststellen, dass Benutzer3 auf Knoten4 fällt. Sie werden feststellen, dass der konsistente Hashing-Algorithmus durch die Analyse des Hinzufügens und Löschens von Knoten die Datenmigration minimieren und gleichzeitig die Monotonie aufrechterhalten kann. Ein solcher Algorithmus eignet sich sehr gut für verteilte Cluster, da er die Migration großer Datenmengen vermeidet und den Serverdruck verringert.

Natürlich gibt es noch ein Problem, das gelöst werden muss: das Gleichgewicht. Aus der Abbildung können wir erkennen, dass bei relativ wenigen Serverknoten ein Problem auftritt. Das heißt, dass sich zwangsläufig eine große Datenmenge auf einem Knoten konzentriert und nur sehr wenige Daten auf einem anderen Knoten.

Um dieses Datenschiefeproblem zu lösen, führt der konsistente Hashing-Algorithmus einen virtuellen Knotenmechanismus ein, der mehrere Hashes für jeden Serviceknoten berechnet und an jedem Berechnungsergebnisort einen Knoten platziert, der als virtueller Knoten bezeichnet wird. Der konkrete Ansatz besteht darin, zunächst die Anzahl der mit jedem physischen Knoten verknüpften virtuellen Knoten zu ermitteln und dann nach der IP oder dem Hostnamen eine Zahl hinzuzufügen. Beispielsweise können im obigen Fall für jeden Server drei virtuelle Knoten berechnet werden, sodass die Hashwerte von „ node 1-1 “, „ node 1-2 “, „ node 1-3 node 2-1 “, „ node 2-2 “, „Knoten 2-2“, „ node 2-3 , „ node 3-1 “, „ node 3-2 “ und „ node 3-3 “ jeweils berechnet werden können, wodurch neun virtuelle Knoten gebildet werden.

Beispielsweise befindet sich Benutzer1 auf node 1-1 , node 1-2 und node 1-3 , die sich tatsächlich alle auf node1 befinden. Dies kann das Problem der Datenverzerrung lösen, wenn nur wenige Serviceknoten vorhanden sind. Natürlich ist die Anzahl der virtuellen Knoten nicht auf drei oder höchstens oder mindestens drei festgelegt. Dies ist nur ein Beispiel. Die genaue Anzahl der virtuellen Knoten muss entsprechend der tatsächlichen Geschäftssituation bestimmt werden.

Vorteile der konsistenten HASH-Methode: Virtuelle Knoten können sicherstellen, dass die Daten gleichmäßig auf verschiedene Datenbanken und Tabellen verteilt sind. Das Hinzufügen oder Löschen von Knoten wirkt sich nicht auf die Daten anderer Knoten aus und bietet eine hohe Verfügbarkeit und starke Katastrophentoleranz.

Nachteile der konsistenten Modulmethode: Im Vergleich zu den beiden oben genannten kann davon ausgegangen werden, dass es keine gibt.

3. Unit-Tests

OK, kein Unsinn mehr, als nächstes kommt der Unit-Test. Angenommen, es gibt drei Knoten, jeder Knoten hat drei virtuelle Knoten

Paket com.hyh.core.test;

importiere com.hyh.utils.common.StringUtils;
importiere org.junit.Test;

importiere java.util.LinkedList;
importiere java.util.List;
importiere java.util.SortedMap;
importiere java.util.TreeMap;

/**
 * Konsistenz-HASH-TEST
 *
 * @Autor heyuhua
 * @erstellen 31.01.2021 19:50
 */
öffentliche Klasse ConsistentHashTest {

    //Liste der Server, die zum Hash-Ring hinzugefügt werden sollen private static String[] servers = {"192.168.5.1", "192.168.5.2", "192.168.5.3"};

    // Echte Knotenliste. In Anbetracht der Szenarien, in denen der Server online und offline geht, d. h. Szenarien zum Hinzufügen und Löschen häufiger auftreten, ist es hier besser, LinkedList zu verwenden private static List<String> realNodes = new LinkedList<>();

    //Virtueller Knoten, Schlüssel stellt den Hash-Wert des virtuellen Knotens dar, Wert stellt den Namen des virtuellen Knotens dar private static SortedMap<Integer, String> virtualNodes = new TreeMap<>();

    //Ein realer Knoten entspricht 3 virtuellen Knoten private static final int VIRTUAL_NODES = 3;

    /**
     * Testen Sie die Konsistenz von HASH mit virtuellen Knoten
     */
    @Prüfen
    öffentliche void testConsistentHash() {
        : InitNodes();
        String[] Benutzer = {"Benutzer1", "Benutzer2", "Benutzer3", "Benutzer4", "Benutzer5", "Benutzer6", "Benutzer7", "Benutzer8", "Benutzer9"};
        für (int i = 0; i < Benutzer.Länge; i++)
            System.out.println("[" + users[i] + "]'s Hashwert ist " +
                    getHash(users[i]) + ", weitergeleitet zu node[" + getServer(users[i]) + "]");
    }

    /**
     * Fügen Sie zuerst den Originalserver zur realen Knotenliste hinzu */
    öffentliche void initNodes() {
        für (int i = 0; i < Serverlänge; i++)
            realNodes.add(servers[i]);
        für (String str : realNodes) {
            für (int i = 0; i < VIRTUAL_NODES; i++) {
                String virtualNodeName = str + "-virtueller Knoten" + String.valueOf(i);
                int hash = getHash(virtuellerKnotenname);
                System.out.println("Virtueller Knoten [" + virtualNodeName + "] wird hinzugefügt, Hash-Wert ist " + hash);
                virtualNodes.put(hash, virtuellerKnotenname);
            }
        }
        System.out.println();
    }

    //Verwende den FNV1_32_HASH-Algorithmus, um den Hash-Wert des Servers zu berechnen. Die Methode zum Umschreiben von HashCode wird hier nicht verwendet und der endgültige Effekt ist nicht unterschiedlich private static int getHash(String str) {
        endgültige Ganzzahl p = 16777619;
        int hash = (int) 2166136261L;
        für (int i = 0; i < str.length(); i++)
            Hash = (Hash ^ str.charAt(i)) * p;
        Hash += Hash << 13;
        Hash ^= Hash >> 7;
        Hash += Hash << 3;
        Hash ^= Hash >> 17;
        Hash += Hash << 5;

        // Wenn der berechnete Wert negativ ist, nehmen Sie seinen Absolutwert, wenn (Hash < 0)
            hash = Math.abs(hash);
        Hash zurückgeben;
    }

    //Den Knoten abrufen, zu dem weitergeleitet werden soll private static String getServer(String key) {
        //Den Hash-Wert des Schlüssels abrufen int hash = getHash(key);
        // Alle Maps holen, die größer sind als der Hash-Wert
        SortedMap<Integer, String> subMap = virtualNodes.tailMap(hash);
        Zeichenfolge virtueller Knoten;
        wenn (subMap.isEmpty()) {
            //Wenn es keinen Hash-Wert gibt, der größer als der Schlüssel ist, beginnen Sie beim ersten Knoten. Integer i = virtualNodes.firstKey();
            //Gib den entsprechenden Server zurück virtualNode = virtualNodes.get(i);
        } anders {
            //Der erste Schlüssel ist der Knoten, der dem Knoten im Uhrzeigersinn am nächsten ist. Integer i = subMap.firstKey();
            //Gib den entsprechenden Server zurück virtualNode = subMap.get(i);
        }
        //Der Name des virtuellen Knotens virtualNode muss abgefangen werden, wenn (StringUtils.isNotBlank(virtualNode)) {
            returniere virtualNode.substring(0, virtualNode.indexOf("-"));
        }
        gibt null zurück;
    }
}

Hier simulieren wir die Situation, in der 9 Benutzerobjekte nach dem Hashen weitergeleitet werden. Sehen Sie sich die Ergebnisse an

Zusammenfassen:

Es wird dringend empfohlen, einen konsistenten HASH -Algorithmus für das Sharding in einer Umgebung mit verteilter Mikroservice-Architektur zu verwenden. Natürlich treten auch in einer verteilten Umgebung Probleme mit der Konsistenz geschäftlicher Daten und verteilten Transaktionen auf. In der nächsten Ausgabe werden wir Lösungen für Datenkonsistenz und verteilte Transaktionen besprechen.

Dies ist das Ende dieses Artikels über die Details von MySQL Sharding. Weitere Informationen zu MySQL Sharding finden Sie in früheren Artikeln auf 123WORDPRESS.COM oder in den folgenden verwandten Artikeln. Ich hoffe, Sie werden 123WORDPRESS.COM auch in Zukunft unterstützen!

Das könnte Sie auch interessieren:
  • Erste Schritte mit MySQL Sharding
  • Eine kurze Diskussion zur Auftragsrekonstruktion: MySQL-Sharding
  • Zusammenfassung der häufig verwendeten Datenbank- und Tabellen-Sharding-Lösungen von MySQL
  • MySQL-Datenbank-Sharding und Tabellen-Sharding sind vollständig zusammengebrochen
  • Mehrere Methoden der Primärschlüsselverarbeitung nach MySQL-Datenbank- und Tabellen-Sharding
  • SpringBoot+MybatisPlus+Mysql+Sharding-JDBC-Sharding
  • Mehrere Möglichkeiten zum Sharding von MySQL-Datenbanken und -Tabellen

<<:  Unterschiede zwischen FLOW CHART und UI FLOW

>>:  Lösung für großen Zeilenabstand (5 Pixel mehr im IE)

Artikel empfehlen

Java importiert Daten aus Excel in MySQL

Manchmal müssen wir bei unserer tatsächlichen Arb...

Allgemeine Tags in XHTML

Was sind XHTML-Tags? XHTML-Tag-Elemente sind die ...

1 Minute Vue implementiert Rechtsklickmenü

Inhaltsverzeichnis Rendern Installieren Code-Impl...

Detaillierte Erläuterung des Lernens von CSS-Zählerattributen

Das CSS-Zählerattribut wird von fast allen Browse...

So betten Sie Dateien im Flash-Videoformat (FLV, SWF) in HTML-Dateien ein

Flash-Dateiformate: .FLV und .SWF Für das Flash-Vi...

Welche Codes sollte ich beherrschen, wenn ich Webdesign lerne?

In diesem Artikel werden einige der Techniken ausf...

Häufige Ursachen und Lösungen für langsame MySQL-SQL-Anweisungen

1. Langsame Abfrage aufgrund fehlenden oder ungül...

Linux-Installation, MongoDB-Start und Lösung allgemeiner Probleme

MongoDB-Installationsprozess und Problemaufzeichn...

Einführung in den strikten Modus von JavaScript verwenden Sie strikt

Inhaltsverzeichnis 1. Übersicht 1.1 Was ist der s...

js, um eine einfache Produkt-Screening-Funktion zu erreichen

In diesem Artikelbeispiel wird der spezifische JS...

Tutorial zur Installation von phpMyAdmin unter Linux centos7

yum install httpd php mariadb-server –y Notieren ...