Approcci di partizionamento orizzontale MySQL?


89

Qual è l'approccio migliore per la condivisione di tabelle MySQL. Gli approcci a cui riesco a pensare sono:

  1. Sharding a livello di applicazione?
  2. Sharding a livello proxy MySQL?
  3. Server di ricerca centrale per lo sharding?

Conoscete progetti o strumenti interessanti in quest'area?

Risposte:


116

L'approccio migliore per lo sharding delle tabelle MySQL non lo fa a meno che non sia totalmente inevitabile farlo.

Quando si scrive un'applicazione, di solito si desidera farlo in modo da massimizzare la velocità, la velocità dello sviluppatore. Ottimizzi la latenza (tempo fino a quando la risposta è pronta) o il throughput (numero di risposte per unità di tempo) solo quando necessario.

Si partiziona e quindi si assegnano le partizioni a host diversi (= frammento) solo quando la somma di tutte queste partizioni non si adatta più a una singola istanza del server di database, il motivo per cui è in scrittura o in lettura.

Il caso di scrittura è a) la frequenza delle scritture sovraccarica i dischi di questo server in modo permanente oppure b) ci sono troppe scritture in corso in modo che la replica ritardi permanentemente in questa gerarchia di replica.

Il caso di lettura per lo sharding è quando la dimensione dei dati è così grande che il working set di essi non si adatta più alla memoria e le letture dei dati iniziano a colpire il disco invece di essere servite dalla memoria la maggior parte del tempo.

Solo quando si ha a coccio voi farlo.


Nel momento in cui dividi, stai pagando per questo in diversi modi:

Gran parte del tuo SQL non è più dichiarativo.

Normalmente, in SQL si dice al database quali dati si desidera e si lascia all'ottimizzatore il compito di trasformare quella specifica in un programma di accesso ai dati. Questa è una buona cosa, perché è flessibile e perché scrivere questi programmi di accesso ai dati è un lavoro noioso che danneggia la velocità.

Con un ambiente frammentato probabilmente stai unendo una tabella sul nodo A ai dati sul nodo B, oppure hai una tabella più grande di un nodo, sui nodi A e B e stai unendo i dati da essa ai dati che si trovano sul nodo B e C. Stai iniziando a scrivere manualmente risoluzioni di join basate su hash lato applicazione per risolverlo (o stai reinventando il cluster MySQL), il che significa che ti ritroverai con un sacco di SQL che non è più dichiarativo, ma esprime la funzionalità SQL in modo procedurale (ad esempio, stai usando le istruzioni SELECT nei cicli).

Stai riscontrando molta latenza di rete.

Normalmente, una query SQL può essere risolta localmente e l'ottimizzatore conosce i costi associati agli accessi al disco locale e risolve la query in modo da ridurre al minimo i costi.

In un ambiente frammentato, le query vengono risolte eseguendo accessi chiave-valore attraverso una rete a più nodi (si spera con accessi chiave in batch e non ricerche di chiavi individuali per round trip) o spingendo parti della WHEREclausola in avanti nei nodi dove possono essere applicato (che si chiama 'condizione pushdown'), o entrambi.

Ma anche nel migliore dei casi ciò comporta molti più viaggi di andata e ritorno di rete rispetto a una situazione locale, ed è più complicato. Soprattutto perché l'ottimizzatore MySQL non sa nulla della latenza di rete (Ok, il cluster MySQL sta lentamente migliorando in questo, ma per MySQL vanilla al di fuori del cluster questo è ancora vero).

Stai perdendo molta forza espressiva di SQL.

Ok, questo è probabilmente meno importante, ma i vincoli di chiave esterna e altri meccanismi SQL per l'integrità dei dati non sono in grado di estendersi su più frammenti.

MySQL non ha API che consentono query asincrone che funzionano.

Quando i dati dello stesso tipo risiedono su più nodi (ad es. Dati utente sui nodi A, B e C), spesso le query orizzontali devono essere risolte su tutti questi nodi ("Trova tutti gli account utente che non sono stati collegati per 90 giorni o più"). Il tempo di accesso ai dati cresce linearmente con il numero di nodi, a meno che non sia possibile richiedere più nodi in parallelo e i risultati aggregati man mano che arrivano ("Map-Reduce").

La condizione preliminare per questo è un'API di comunicazione asincrona, che non esiste per MySQL in una buona forma funzionante. L'alternativa è un sacco di biforcazioni e connessioni nei processi figlio, che sta visitando il mondo del succhiare con un abbonamento stagionale.


Una volta avviato lo sharding, la struttura dei dati e la topologia di rete diventano visibili come punti di prestazioni per la tua applicazione. Per funzionare ragionevolmente bene, la tua applicazione deve essere consapevole di queste cose, e questo significa che in realtà solo il partizionamento orizzontale a livello di applicazione ha senso.

La domanda è più se vuoi auto-shard (determinare quale riga va in quale nodo eseguendo l'hashing delle chiavi primarie, ad esempio) o se vuoi dividere funzionalmente in modo manuale ("Le tabelle relative alla user story xyz vanno a master, mentre le tabelle relative ad abc e def vanno a quel master ").

Lo sharding funzionale ha il vantaggio che, se fatto correttamente, è invisibile alla maggior parte degli sviluppatori il più delle volte, perché tutte le tabelle relative alla loro storia utente saranno disponibili localmente. Ciò consente loro di trarre vantaggio dall'SQL dichiarativo il più a lungo possibile e incorrerà anche in una minore latenza di rete perché il numero di trasferimenti tra reti è ridotto al minimo.

Il partizionamento orizzontale funzionale ha lo svantaggio di non consentire a una singola tabella di essere più grande di un'istanza e richiede l'attenzione manuale di un designer.

Il partizionamento orizzontale funzionale ha il vantaggio di essere eseguito in modo relativamente semplice su una base di codice esistente con un numero di modifiche non eccessivamente grande. http://Booking.com lo ha fatto più volte negli ultimi anni e ha funzionato bene per loro.


Detto questo, guardando la tua domanda, credo che tu stia facendo le domande sbagliate, o sto completamente fraintendendo la tua dichiarazione del problema.


2
Questa è una buona risposta. Ma voglio sottolineare che lo sharding è davvero necessario solo per applicazioni ad alto volume ed è probabile che stiano generando qualche tipo di entrate. Un'applicazione di partizionamento orizzontale di terze parti gestirà tutte le preoccupazioni che hai con join, transazioni tra partizioni, ecc. E se ne ottieni una buona, manterrà l'integrità di un database "relazionale". Altre applicazioni, hai ragione, trasformeranno semplicemente il tuo database in una coppia chiave-valore e quindi vanificheranno lo scopo di SQL.
chantheman

3
Devo ancora imbattermi in un'applicazione di sharding, commerciale o meno, che riesca a nascondere il fatto che i dati sono ora sparsi sulla rete e soggetti a latenza o incoerenza a causa della mancanza di attese indotte dalla latenza. Se stai eseguendo lo sharding, la tua applicazione noterà e richiederà modifiche. Potresti anche controllarlo da solo. Non esiste un proiettile d'argento, ma c'è molto olio di serpente.
Isotopp

1
Dovresti controllare dbShards. Scala meglio che linearmente per il numero di "frammenti" aggiunti. Avrai bisogno di pochissime modifiche sul lato dell'applicazione e sì, l'applicazione non conosce la differenza. Invia e ottiene le transazioni come faresti con ODBC o JDBC. dbShards consente anche i suggerimenti di shard se si desidera un maggiore controllo su una transazione. Puoi dire a dbShards esattamente da quale shard vuoi leggere o scrivere.
chantheman

1
@Gigala, beh, passare del tempo a comporre una risposta ben definita come questa, indipendentemente dall'ampiezza, non è necessario, ma sono contento che sia stato fatto, poiché questa risposta si è dimostrata utile per me. Si prega di non scoraggiare gli utenti a non "pensare fuori dagli schemi" quando rispondono.
mewm

12
  1. Sharding a livello di applicazione: dbShards è l'unico prodotto che conosco che esegue lo "sharding consapevole dell'applicazione". Ci sono alcuni buoni articoli sul sito web. Per definizione, il partizionamento orizzontale consapevole delle applicazioni sarà più efficiente. Se un'applicazione sa esattamente dove andare con una transazione senza doverla cercare o essere reindirizzata da un proxy, quella di per sé sarà più veloce. E la velocità è spesso una delle preoccupazioni principali, se non l'unica, quando qualcuno sta esaminando lo sharding.

  2. Alcune persone "scheggiano" con un proxy, ma ai miei occhi questo vanifica lo scopo dello sharding. Stai semplicemente usando un altro server per dire alle tue transazioni dove trovare i dati o dove archiviarli. Con lo sharding che riconosce l'applicazione, la tua applicazione sa dove andare da sola. Molto più efficiente.

  3. Questo è lo stesso del n. 2 in realtà.


dbShards è in uso nella produzione da qualche parte? inoltre non è open source.
Sheki

Anche l'approccio 2 e 3 possono essere diversi se il proxy cerca in base a un hash invece che al DB o a un negozio.
sheki

1
dbShards è in produzione con una varietà di client, ma no, non è open source. Non credo che troverai un buon prodotto di sharding open source. E sì, hai ragione sul fatto che un hash potrebbe essere usato come ricerca, ma in quel caso devi ancora fare un altro "stop" per ottenere la tua transazione nel database. Ecco perché lo sharding "application aware" sarà quasi sempre più veloce.
chantheman

Ma come ho detto, se riesci a ottenere un'applicazione di partizionamento orizzontale che mantiene l'integrità delle relazioni, allora sarai in buona forma. Cito dbShards perché è l'unico che conosco che lo fa. E poiché lo fa, ridimensiona le velocità di scrittura e lettura in modo lineare. Aggiungi 4 "frammenti" o dividi il tuo unico server MySQL in 4 e verrà eseguito 4 volte più velocemente.
chantheman

7

Conoscete progetti o strumenti interessanti in quest'area?

Diversi nuovi progetti in questo spazio:

  • citusdata.com
  • spockproxy.sourceforge.net
  • github.com/twitter/gizzard/

5

Shard-Query è una soluzione di partizionamento orizzontale basata su OLAP per MySQL. Consente di definire una combinazione di tabelle frammentate e tabelle non modificate. Le tabelle non codificate (come le tabelle di ricerca) sono liberamente unibili a tabelle frammentate e le tabelle frammentate possono essere unite tra loro purché le tabelle siano unite dalla chiave di partizione (nessuna partizione incrociata o auto join che attraversano i confini del frammento). Essendo una soluzione OLAP, Shard-Query di solito ha tempi di risposta minimi di 100 ms o meno, anche per query semplici, quindi non funzionerà per OLTP. Shard-Query è progettato per analizzare in parallelo set di big data.

Esistono soluzioni di sharding OLTP anche per MySQL. Le soluzioni closed source includono ScaleDB , DBShards . La soluzione OLTP open source include JetPants , Cubrid o Flock / Gizzard (infrastruttura Twitter).


3

Livello di applicazione ovviamente.

Il miglior approccio che abbia mai trovato in questo libro rosso

MySQL ad alte prestazioni http://www.amazon.com/High-Performance-MySQL-Jeremy-Zawodny/dp/0596003064

Breve descrizione: puoi dividere i tuoi dati in molte parti e memorizzare circa 50 parti su ogni server. Ti aiuterà a evitare il secondo problema più grande dello sharding: il riequilibrio. Basta spostarne alcuni sul nuovo server e andrà tutto bene :)

Ti consiglio vivamente di acquistarlo e di leggere la parte "mysql scaling".


Il libro che hai consigliato ha 8 anni ... copre lo sharding rilevante per le tecnologie odierne?
raffian

1
Copre alcuni approcci di base per ridimensionare mysql. Per quanto ne so, nulla è cambiato nel ridimensionamento di mysql. Le stesse tecniche di sharding e replica a livello di app sono ampiamente utilizzate oggigiorno.
Andrey Frolov

Potrei sbagliarmi, ma ho fatto un sacco di ricerche su questo nell'ultima settimana e sembra che mySQL stesso abbia apportato molti cambiamenti negli ultimi 8 anni, specialmente per quanto riguarda il partizionamento e il caching. C'è una nuova versione che è uscita quest'anno: amazon.com/High-Performance-MySQL-Optimization-Replication/dp/… Non l'ho letto ma penso che copra i nuovi modelli di replica disponibili.
NateDSaint

4
Libri .. perché non spiegarlo qui.
DDD

2

A partire dal 2018, sembra esserci una soluzione nativa di MySql a questo. In realtà ce ne sono almeno 2: InnoDB Cluster e NDB Cluster (esiste una versione commerciale e una versione comunitaria).

Poiché la maggior parte delle persone che utilizzano la community edition di MySql hanno più familiarità con il motore InnoDB, questo è ciò che dovrebbe essere esplorato come priorità assoluta. Supporta la replica e il partizionamento / partizionamento orizzontale e si basa su MySql Router per diverse opzioni di routing / bilanciamento del carico.

La sintassi per la creazione delle tabelle dovrebbe cambiare, ad esempio:

    CREATE TABLE t1 (col1 INT, col2 CHAR(5), col3 DATETIME) PARTITION BY HASH ( YEAR(col3) );

(questo è solo uno dei quattro tipi di partizionamento )

Una limitazione molto importante:

Le chiavi esterne InnoDB e il partizionamento MySQL non sono compatibili. Le tabelle InnoDB partizionate non possono avere riferimenti a chiavi esterne, né possono avere colonne referenziate da chiavi esterne. Le tabelle InnoDB che hanno o sono referenziate da chiavi esterne non possono essere partizionate.


Tieni presente che PARTITION BY HASH(YEAR...)eseguirà la scansione di tutte le partizioni se hai un intervallo di date. Che schifo.
Rick James
Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.