1. Ziele Mit diesem Artikel werden die folgenden Ziele erreicht:
Architekturdiagramm: Die Tabellenstruktur ist wie folgt: CREATE TABLE `order_XXX` ( `order_id` bigint(20) unsigned NICHT NULL, `user_id` int(11) DEFAULT '0' COMMENT 'Bestell-ID', `status` int(11) DEFAULT '0' COMMENT 'Bestellstatus', `booking_date` Datum/Uhrzeit DEFAULT NULL, `create_time` Datum/Uhrzeit DEFAULT NULL, `update_time` Datum/Uhrzeit DEFAULT NULL, PRIMÄRSCHLÜSSEL (`order_id`), SCHLÜSSEL `idx_user_id` (`Benutzer-ID`), SCHLÜSSEL `idx_bdate` (`Buchungsdatum`), SCHLÜSSEL `idx_ctime` (`Erstellungszeit`), SCHLÜSSEL `idx_utime` (`update_time`) )ENGINE=InnoDB STANDARD-CHARSET=utf8; Hinweis: 000 <= XXX <= 255. Dieser Artikel konzentriert sich auf die Praxis des Shardings von Datenbanken und Tabellen. Nur repräsentative Felder werden beibehalten. Andere Szenarien können auf dieser Grundlage verbessert werden. Weltweit einzigartiges ID-Design Voraussetzungen: 1. Weltweit eindeutig 2: Grob geordnet 3: Umkehrbare ausgehende Nummer
Maximale QPS einer einzelnen Maschine: 256.000 Lebensdauer: 17 Jahre 2. Umweltvorbereitung1. Grundlegende Informationen
2. Vorbereitung der Datenbankumgebung Geben Sie mysql ein: #Hauptdatenbank mysql -h 172.30.1.21 -uroot -pbytearch #Aus der Bibliothek mysql -h 172.30.1.31 -uroot -pbytearch Betreten des Containers # Haupt-Docker exec -it db_1_master /bin/bash #Von Docker exec -it db_1_slave /bin/bash Überprüfen des Ausführungsstatus #Haupt-Docker exec db_1_master sh -c 'mysql -u root -pbytearch -e "SHOW MASTER STATUS \G"' #Von Docker exec db_1_slave sh -c 'mysql -u root -pbytearch -e "SHOW SLAVE STATUS \G"' 3. Datenbank erstellen und Untertabellen importieren(1) Erstellen Sie Datenbanken in der MySQL-Masterinstanz 172.30.1.21(Auftragsdatenbank_1), 172.30.1.22(Auftragsdatenbank_2), 172.30.1.23(Bestelldatenbank_3) , 172.30.1.24(Bestelldatenbank_4) (2) Importieren Sie die SQL-Befehle zum Erstellen der Tabellen nacheinander: mysql -uroot -pbytearch -h172.30.1.21 order_db_1<fast-cloud-mysql-sharding/doc/sql/order_db_1.sql; mysql -uroot -pbytearch -h172.30.1.22 order_db_2<fast-cloud-mysql-sharding/doc/sql/order_db_2.sql; mysql -uroot -pbytearch -h172.30.1.23 order_db_3<fast-cloud-mysql-sharding/doc/sql/order_db_3.sql; mysql -uroot -pbytearch -h172.30.1.24 order_db_4<fast-cloud-mysql-sharding/doc/sql/order_db_4.sql; 3. Konfiguration und Praxis 1. POM-Datei<!-- Mango-Datenbank- und Tabellen-Sharding-Middleware --> <Abhängigkeit> <groupId>org.jfaster</groupId> <artifactId>Mango-Spring-Boot-Starter</artifactId> <version>2.0.1</version> </Abhängigkeit> <!-- Verteilter ID-Generator --> <Abhängigkeit> <groupId>com.bysearch</groupId> <artifactId>schneller Cloud-ID-Generator</artifactId> <version>${version}</version> </Abhängigkeit> <!-- https://mvnrepository.com/artifact/mysql/mysql-connector-java --> <Abhängigkeit> <groupId>mysql</groupId> <artifactId>mysql-connector-java</artifactId> <version>6.0.6</version> </Abhängigkeit> 2. Konstante KonfigurationPaket com.bytearch.fast.cloud.mysql.sharding.common; /** * Gemeinsame Konstanten für Datenbank- und Tabellen-Sharding-Strategien*/ öffentliche Klasse ShardingStrategyConstant { /** * logischer Datenbankname, der tatsächliche Datenbankname ist order_db_XXX */ öffentliche statische endgültige Zeichenfolge LOGIC_ORDER_DATABASE_NAME = "order_db"; /** * Die Anzahl der Untertabellen beträgt 256. Nach der Bestätigung kann sie nicht mehr geändert werden.*/ öffentliche statische endgültige Int SHARDING_TABLE_NUM = 256; /** * Es wird nicht empfohlen, die Anzahl der Unterdatenbanken zu ändern. Sie kann geändert werden, aber der DBA muss die Daten migrieren*/ öffentliche statische endgültige Int SHARDING_DATABASE_NODE_NUM = 4; } 3. YML-Konfiguration4 Master- und 4 Slave-Datenbankkonfigurationen. Hier testen wir nur das Standardkennwort des Root-Benutzers. Es wird nicht empfohlen, den Root-Benutzer in einer Produktionsumgebung zu verwenden. Mango: Scan-Paket: com.bytearch.fast.cloud.mysql.sharding.dao Datenquellen: - Name: order_db_1 Master: Treiberklassenname: com.mysql.cj.jdbc.Driver jdbc-url: jdbc:mysql://172.30.1.21:3306/order_db_1?useUnicode=true&characterEncoding=utf8&autoReconnect=true&rewriteBatchedState&connectTimeout=1000&socketTimeout=5000&useSSL=false Benutzername: root Passwort: bytearch maximale Poolgröße: 10 Verbindungs-Timeout: 3000 Sklaven: - Treiberklassenname: com.mysql.cj.jdbc.Driver jdbc-URL: jdbc:mysql://172.30.1.31:3306/order_db_1?useUnicode=true&characterEncoding=utf8&autoReconnect=true&rewriteBatchedState&connectTimeout=1000&socketTimeout=5000&useSSL=false Benutzername: root Passwort: bytearch maximale Poolgröße: 10 Verbindungs-Timeout: 3000 - Name: order_db_2 Master: Treiberklassenname: com.mysql.cj.jdbc.Driver jdbc-url: jdbc:mysql://172.30.1.22:3306/order_db_2?useUnicode=true&characterEncoding=utf8&autoReconnect=true&rewriteBatchedState&connectTimeout=1000&socketTimeout=5000&useSSL=false Benutzername: root Passwort: bytearch maximale Poolgröße: 10 Verbindungs-Timeout: 3000 Sklaven: - Treiberklassenname: com.mysql.cj.jdbc.Driver jdbc-URL: jdbc:mysql://172.30.1.32:3306/order_db_2?useUnicode=true&characterEncoding=utf8&autoReconnect=true&rewriteBatchedState&connectTimeout=1000&socketTimeout=5000&useSSL=false Benutzername: root Passwort: bytearch maximale Poolgröße: 10 Verbindungs-Timeout: 3000 - Name: order_db_3 Master: Treiberklassenname: com.mysql.cj.jdbc.Driver jdbc-url: jdbc:mysql://172.30.1.23:3306/order_db_3?useUnicode=true&characterEncoding=utf8&autoReconnect=true&rewriteBatchedState&connectTimeout=1000&socketTimeout=5000&useSSL=false Benutzername: root Passwort: bytearch maximale Poolgröße: 10 Verbindungs-Timeout: 3000 Sklaven: - Treiberklassenname: com.mysql.cj.jdbc.Driver jdbc-url: jdbc:mysql://172.30.1.33:3306/order_db_3?useUnicode=true&characterEncoding=utf8&autoReconnect=true&rewriteBatchedState&connectTimeout=1000&socketTimeout=5000&useSSL=false Benutzername: root Passwort: bytearch maximale Poolgröße: 10 Verbindungs-Timeout: 3000 - Name: order_db_4 Master: Treiberklassenname: com.mysql.cj.jdbc.Driver jdbc-URL: jdbc:mysql://172.30.1.24:3306/order_db_4?useUnicode=true&characterEncoding=utf8&autoReconnect=true&rewriteBatchedState&connectTimeout=1000&socketTimeout=5000&useSSL=false Benutzername: root Passwort: bytearch maximale Poolgröße: 10 Verbindungs-Timeout: 3000 Sklaven: - Treiberklassenname: com.mysql.cj.jdbc.Driver jdbc-url: jdbc:mysql://172.30.1.34:3306/order_db_4?useUnicode=true&characterEncoding=utf8&autoReconnect=true&rewriteBatchedState&connectTimeout=1000&socketTimeout=5000&useSSL=false Benutzername: root Passwort: bytearch maximale Poolgröße: 10 Verbindungs-Timeout: 300 4. Strategie zum Sharding von Datenbanken und Tabellen1). Verwenden Sie order_id als ShardKey, um Datenbank und Tabelle zu trennen Paket com.bytearch.fast.cloud.mysql.sharding.strategy; importiere com.bytearch.fast.cloud.mysql.sharding.common.ShardingStrategyConstant; importiere com.bytearch.id.generator.IdEntity; importiere com.bytearch.id.generator.SeqIdUtil; importiere org.jfaster.mango.sharding.ShardingStrategy; /** * Bestellnummer Unterbibliothek und Untertabelle Strategie */ öffentliche Klasse OrderIdShardingStrategy implementiert ShardingStrategy<Long, Long> { @Überschreiben öffentliche Zeichenfolge getDataSourceFactoryName(Lange Bestell-ID) { wenn (Bestell-ID == null || Bestell-ID < 0L) { throw new IllegalArgumentException("order_id ist ungültig!"); } idEntity idEntity = SeqIdUtil.decodeId(orderId); wenn (idEntity.getExtraId() >= ShardingStrategyConstant.SHARDING_TABLE_NUM) { throw new IllegalArgumentException("Sharding-Tabelle Num ist ungültig, tableNum:" + idEntity.getExtraId()); } //1. Schrittlänge berechnen int step = ShardingStrategyConstant.SHARDING_TABLE_NUM / ShardingStrategyConstant.SHARDING_DATABASE_NODE_NUM; //2. Berechnen Sie die Bibliotheksnummer long dbNo = Math.floorDiv(idEntity.getExtraId(), step) + 1; //3. Gibt den Datenquellennamen zurück return String.format("%s_%s", ShardingStrategyConstant.LOGIC_ORDER_DATABASE_NAME, dbNo); } @Überschreiben public String getTargetTable(String logicTableName, Lange Bestell-ID) { wenn (Bestell-ID == null || Bestell-ID < 0L) { throw new IllegalArgumentException("order_id ist ungültig!"); } idEntity idEntity = SeqIdUtil.decodeId(orderId); wenn (idEntity.getExtraId() >= ShardingStrategyConstant.SHARDING_TABLE_NUM) { throw new IllegalArgumentException("Sharding-Tabelle Num ist ungültig, tableNum:" + idEntity.getExtraId()); } // Der tatsächliche Tabellenname lautet gemäß der Konvention logicTableName_XXX. Wenn XXX weniger als drei Ziffern hat, fügen Sie 0 hinzu. return String.format("%s_%03d", logicTableName, idEntity.getExtraId()); } } 2). Verwenden Sie user_id als ShardKey, um die Datenbank und die Tabelle zu sharden Paket com.bytearch.fast.cloud.mysql.sharding.strategy; importiere com.bytearch.fast.cloud.mysql.sharding.common.ShardingStrategyConstant; importiere org.jfaster.mango.sharding.ShardingStrategy; /** *Geben Sie den Sharding-Schlüssel und die Sharding-Strategie für Datenbank/Tabelle an*/ öffentliche Klasse UserIdShardingStrategy implementiert ShardingStrategy<Integer, Integer> { @Überschreiben public String getDataSourceFactoryName(Integer Benutzer-ID) { //1. Berechnen Sie die Schrittlänge, d. h. die Anzahl der Tabellen in einer einzelnen Datenbank int step = ShardingStrategyConstant.SHARDING_TABLE_NUM / ShardingStrategyConstant.SHARDING_DATABASE_NODE_NUM; //2. Berechnen Sie die Datenbanknummer long dbNo = Math.floorDiv(userId % ShardingStrategyConstant.SHARDING_TABLE_NUM, step) + 1; //3. Gibt den Datenquellennamen zurück return String.format("%s_%s", ShardingStrategyConstant.LOGIC_ORDER_DATABASE_NAME, dbNo); } @Überschreiben public String getTargetTable(String logicTableName, Integer userId) { // Der tatsächliche Tabellenname lautet gemäß Konvention logicTableName_XXX. Wenn XXX weniger als drei Ziffern hat, addieren Sie 0. return String.format("%s_%03d", Logiktabellenname, Benutzer-ID % ShardingStrategyConstant.SHARDING_TABLE_NUM); } } 5. Dao-Schicht-Schreiben1). OrderPartitionByIdDao Paket com.bytearch.fast.cloud.mysql.sharding.dao; importiere com.bytearch.fast.cloud.mysql.sharding.common.ShardingStrategyConstant; importiere com.bytearch.fast.cloud.mysql.sharding.pojo.entity.OrderEntity; importiere com.bytearch.fast.cloud.mysql.sharding.strategy.OrderIdShardingStrategy; importiere org.jfaster.mango.annotation.*; @DB(Name = ShardingStrategyConstant.LOGIC_ORDER_DATABASE_NAME, Tabelle = "Bestellung") @Sharding(shardingStrategy = OrderIdShardingStrategy.Klasse) öffentliche Schnittstelle OrderPartitionByIdDao { @SQL("INSERT INTO #table (Bestell-ID, Benutzer-ID, Status, Buchungsdatum, Erstellungszeit, Aktualisierungszeit) WERTE" + "(:Bestell-ID,:Benutzer-ID,:Status,:Buchungsdatum,:Erstellungszeit,:Aktualisierungszeit)" ) int insertOrder(@TableShardingBy("orderId") @DatabaseShardingBy("orderId") Bestellentity Bestellentity); @SQL("UPDATE #table setze update_time = jetzt()" + "#wenn(:Buchungsdatum != null),Buchungsdatum = :Buchungsdatum #Ende " + "#wenn (:status != null), status = :status #ende" + „WO Bestell-ID = :Bestell-ID“ ) int updateOrderByOrderId(@TableShardingBy("orderId") @DatabaseShardingBy("orderId") OrderEntity orderEntity); @SQL("AUSWÄHLEN * AUS #Tabelle WO Bestell-ID = :1") OrderEntity getOrderById(@TableShardingBy @DatabaseShardingBy Lange Bestell-ID); @SQL("AUSWÄHLEN * AUS #Tabelle WO Bestell-ID = :1") @UseMaster OrderEntity getOrderByIdFromMaster(@TableShardingBy @DatabaseShardingBy Lange Bestell-ID); 6. Unit-Tests@SpringBootTest(Klassen = {Anwendung.Klasse}) @RunWith(SpringJUnit4ClassRunner.class) öffentliche Klasse ShardingTest { @Autowired OrderPartitionByIdDao orderPartitionByIdDao; @Autowired OrderPartitionByUserIdDao orderPartitionByUserIdDao; @Prüfen öffentliche void testCreateOrderRandom() { für (int i = 0; i < 20; i++) { Int Benutzer-ID = ThreadLocalRandom.current().nextInt(1000,1000000); Bestellentity Bestellentity = neue Bestellentity(); orderEntity.setOrderId(SeqIdUtil.nextId(userId % ShardingStrategyConstant.SHARDING_TABLE_NUM)); orderEntity.setStatus(1); orderEntity.setUserId(Benutzer-ID); orderEntity.setCreateTime(neues Datum()); orderEntity.setUpdateTime(neues Datum()); orderEntity.setBookingDate(neues Datum()); int ret = orderPartitionByIdDao.insertOrder(orderEntity); Assert.assertEquals(1, ret); } } @Prüfen public void testOrderAll() { //einfügen Int Benutzer-ID = ThreadLocalRandom.current().nextInt(1000,1000000); Bestellentity Bestellentity = neue Bestellentity(); orderEntity.setOrderId(SeqIdUtil.nextId(userId % ShardingStrategyConstant.SHARDING_TABLE_NUM)); orderEntity.setStatus(1); orderEntity.setUserId(Benutzer-ID); orderEntity.setCreateTime(neues Datum()); orderEntity.setUpdateTime(neues Datum()); orderEntity.setBookingDate(neues Datum()); int i = orderPartitionByIdDao.insertOrder(orderEntity); : Assert.assertEquals(1, i); //vom Master holen OrderEntity orderInfo = orderPartitionByIdDao.getOrderByIdFromMaster(orderEntity.getOrderId()); Assert.assertNotNull(orderInfo); Assert.assertEquals(orderInfo.getOrderId(), orderEntity.getOrderId()); //vom Slave holen OrderEntity slaveOrderInfo = orderPartitionByIdDao.getOrderById(orderEntity.getOrderId()); Assert.assertNotNull(slaveOrderInfo); //aktualisieren OrderEntity updateEntity = neue OrderEntity(); updateEntity.setOrderId(orderInfo.getOrderId()); updateEntity.setStatus(2); updateEntity.setUpdateTime(neues Datum()); int affectRows = orderPartitionByIdDao.updateOrderByOrderId(updateEntity); Assert.assertTrue( affectRows > 0); } @Prüfen öffentliche void testGetListByUserId() { Int Benutzer-ID = ThreadLocalRandom.current().nextInt(1000,1000000); für (int i = 0; i < 5; i++) { Bestellentity Bestellentity = neue Bestellentity(); orderEntity.setOrderId(SeqIdUtil.nextId(userId % ShardingStrategyConstant.SHARDING_TABLE_NUM)); orderEntity.setStatus(1); orderEntity.setUserId(Benutzer-ID); orderEntity.setCreateTime(neues Datum()); orderEntity.setUpdateTime(neues Datum()); orderEntity.setBookingDate(neues Datum()); orderPartitionByIdDao.insertOrder(orderEntity); } versuchen { //Verhindern Sie durch Master-Slave-Verzögerung verursachte Überprüfungsfehler Thread.sleep(1000); } Fang (UnterbrocheneAusnahme e) { e.printStackTrace(); } Liste<OrderEntity> orderListByUserId = orderPartitionByUserIdDao.getOrderListByUserId(userId); Assert.assertNotNull(orderListByUserId); Assert.assertTrue(orderListByUserId.size() == 5); } } Sie sind fertig: IV. FazitDieser Artikel stellt hauptsächlich die praktische Implementierung von MySQL-Sharding unter Verwendung des Mango-Frameworks in der Java-Version vor. Die Sharding-Middleware kann auch etwas Ähnliches wie ShardingJDBC verwenden oder selbst entwickelt werden. Die obige Anzahl der Unterdatenbanken und Untertabellen dient nur zu Demonstrationszwecken. In der Praxis wird die Anzahl der Untertabellen und Unterdatenbanken auf Grundlage der tatsächlichen Wachstumsrate der Geschäftsdaten des Unternehmens, des Spitzen-QPS, der physischen Maschinenkonfiguration und anderer Faktoren berechnet. Damit ist dieser Artikel über die praktische Anwendung von MySQL-Sharding bei der Auftragsrekonstruktion abgeschlossen. 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:
|
<<: Wissenspunkte und Nutzungsdetails zu globalen Variablen und globalen Objekten von Nodejs
Inhaltsverzeichnis Eröffnungsszene Direktes Rende...
Vorwort 1. Entprellen: Nach dem Auslösen eines Ho...
Natives js-gekapseltes nahtloses Karussell-Plug-I...
Dies ist eine Website, die ich nachgeahmt habe, a...
Rendern Häufig verwendete Stile im Blog Garden /*...
Inhaltsverzeichnis 1. Technischer Überblick 2. Te...
In diesem Artikelbeispiel wird der spezifische Co...
Inhaltsverzeichnis Hintergrund Virtuelle Dateien ...
1. IE-Browsermodus Hack-Logo 1. CSS-Hack-Logo Code...
Ich lerne derzeit etwas über Redis und Container ...
1. CDN Es ist die am häufigsten verwendete Beschl...
Dieser Artikel beschreibt hauptsächlich, wie die ...
Inhaltsverzeichnis 1.watch überwacht Änderungen i...
Linux-Grep-Befehl Mit dem Linux-Befehl grep könne...
Dieser Artikel stellt hauptsächlich vor, wie pagi...