sql >> Database >  >> RDS >> Mysql

MySQL-shardingbenaderingen?

De beste aanpak voor het sharden van MySQL-tabellen om het niet te doen, tenzij het absoluut onvermijdelijk is om het te doen.

Wanneer u een toepassing schrijft, wilt u dit meestal doen op een manier die de snelheid en de snelheid van de ontwikkelaar maximaliseert. Je optimaliseert alleen voor latency (tijd tot het antwoord klaar is) of throughput (aantal antwoorden per tijdseenheid) als dat nodig is.

U partitioneert en wijst vervolgens partities toe aan verschillende hosts (=shard) alleen wanneer de som van al deze partities niet langer op een enkele databaseserverinstantie past - de reden daarvoor is ofwel schrijven of lezen.

Het geval is ofwel a) de schrijffrequentie overbelast de schijven van deze server permanent of b) er zijn te veel schrijfacties, zodat replicatie permanent achterblijft in deze replicatiehiërarchie.

De leessituatie voor sharding is wanneer de grootte van de gegevens zo groot is dat de werkset ervan niet langer in het geheugen past en het lezen van gegevens de schijf raakt in plaats van meestal uit het geheugen te worden bediend.

Alleen als je hebt om je te scheren.

Op het moment dat je shard, betaal je daar op meerdere manieren voor:

Veel van uw SQL is niet langer declaratief.

Normaal gesproken vertelt u in SQL de database welke gegevens u wilt en laat u het aan de optimizer over om die specificatie om te zetten in een gegevenstoegangsprogramma. Dat is maar goed ook, want het is flexibel, en omdat het schrijven van deze data access-programma's saai werk is dat de snelheid schaadt.

Met een shard-omgeving voegt u waarschijnlijk een tabel op knooppunt A samen met gegevens op knooppunt B, of u hebt een tabel die groter is dan een knooppunt, op knooppunten A en B en voegt gegevens daaruit samen met gegevens op knooppunt B en C. U begint handmatig hash-gebaseerde join-resoluties aan de applicatiezijde te schrijven om dat op te lossen (of u vindt MySQL-cluster opnieuw uit), wat betekent dat u veel SQL krijgt die niet langer declaratief is, maar SQL-functionaliteit op een procedurele manier uitdrukt (u gebruikt bijvoorbeeld SELECT-instructies in lussen).

U loopt veel netwerklatentie op.

Normaal gesproken kan een SQL-query lokaal worden opgelost en de optimizer is op de hoogte van de kosten die gepaard gaan met lokale schijftoegang en lost de query op een manier op die de kosten daarvoor minimaliseert.

In een shard-omgeving worden query's opgelost door sleutelwaardetoegangen via een netwerk naar meerdere knooppunten uit te voeren (hopelijk met batchgewijze sleuteltoegangen en niet individuele sleutelzoekopdrachten per retour) of door delen van de WHERE te pushen clausule verder naar de knooppunten waar ze kunnen worden toegepast (dat wordt 'condition pushdown' genoemd), of beide.

Maar zelfs in het beste geval gaat het om veel meer netwerkrondreizen dan een lokale situatie, en het is ingewikkelder. Vooral omdat de MySQL-optimizer helemaal niets weet van netwerklatentie (Ok, MySQL-cluster wordt daar langzaam beter in, maar voor vanille MySQL buiten het cluster is dat nog steeds waar).

Je verliest veel expressieve kracht van SQL.

Oké, dat is waarschijnlijk minder belangrijk, maar beperkingen met externe sleutels en andere SQL-mechanismen voor gegevensintegriteit zijn niet in staat om meerdere shards te overspannen.

MySQL heeft geen API die asynchrone zoekopdrachten toestaat die in goede staat zijn.

Wanneer gegevens van hetzelfde type zich op meerdere knooppunten bevinden (bijv. gebruikersgegevens op knooppunten A, B en C), moeten horizontale zoekopdrachten vaak worden opgelost voor al deze knooppunten ("Vind alle gebruikersaccounts die gedurende 90 dagen niet zijn ingelogd of meer"). De toegangstijd tot gegevens groeit lineair met het aantal knooppunten, tenzij meerdere knooppunten parallel kunnen worden gevraagd en de resultaten worden samengevoegd zodra ze binnenkomen ("Map-Reduce").

Voorwaarde daarvoor is een asynchrone communicatie-API, die voor MySQL in goed werkende staat niet bestaat. Het alternatief is veel forking en verbindingen in de kindprocessen, namelijk een bezoek aan de wereld van suck op een seizoenspas.

Zodra u begint met sharden, worden de gegevensstructuur en netwerktopologie zichtbaar als prestatiepunten voor uw toepassing. Om redelijk goed te kunnen presteren, moet uw applicatie op de hoogte zijn van deze dingen, en dat betekent dat eigenlijk alleen sharding op applicatieniveau zinvol is.

De vraag is meer of je wilt auto-sharden (bepalen welke rij in welk knooppunt gaat door bijvoorbeeld primaire sleutels te hashen) of dat je functioneel op een handmatige manier wilt splitsen ("De tabellen gerelateerd aan het xyz-gebruikersverhaal gaan naar dit master, terwijl abc en def gerelateerde tabellen naar die master gaan").

Functionele sharding heeft het voordeel dat het, als het goed wordt gedaan, meestal onzichtbaar is voor de meeste ontwikkelaars, omdat alle tabellen die betrekking hebben op hun gebruikersverhaal lokaal beschikbaar zullen zijn. Hierdoor kunnen ze nog zo lang mogelijk profiteren van declaratieve SQL en hebben ze ook minder netwerklatentie omdat het aantal cross-network transfers minimaal wordt gehouden.

Functionele sharding heeft als nadeel dat een enkele tabel niet groter kan zijn dan één instantie, en dat het handmatige aandacht van een ontwerper vereist.

Functional sharding heeft als voordeel dat het relatief eenvoudig kan worden gedaan op een bestaande codebase met een aantal wijzigingen die niet al te groot is. http://Booking.com heeft het de afgelopen jaren meerdere keren gedaan en het werkte goed voor hen.

Dat gezegd hebbende, als ik naar uw vraag kijk, geloof ik dat u de verkeerde vragen stelt, of ik begrijp uw probleemstelling volledig verkeerd.



  1. Wat vertelt PostgreSQL mij precies?

  2. Hoe LOAD_FILE() werkt in MariaDB

  3. node-mysql meerdere instructies in één query

  4. Hoe PostgreSQL 12 op Ubuntu 20.04 DigitalOcean te installeren