La maggior parte dei database cresce di dimensioni nel tempo. La crescita non è sempre abbastanza veloce da incidere sulle prestazioni del database, ma ci sono sicuramente casi in cui ciò accade. Quando lo fa, spesso ci chiediamo cosa si potrebbe fare per ridurre tale impatto e come possiamo garantire operazioni di database fluide quando si tratta di dati su larga scala.
Prima di tutto, proviamo a definire cosa si intende per “grande volume di dati”? Per MySQL o MariaDB è InnoDB non compresso. InnoDB funziona in modo da beneficiare fortemente della memoria disponibile, principalmente il pool di buffer InnoDB. Finché i dati si trovano lì, l'accesso al disco è ridotto al minimo per gestire solo le scritture:le letture vengono servite fuori dalla memoria. Cosa succede quando i dati superano la memoria? Sempre più dati devono essere letti dal disco quando è necessario accedere a righe, che non sono attualmente memorizzate nella cache. Quando la quantità di dati aumenta, il carico di lavoro passa da vincolato alla CPU a vincolato a I/O. Significa che il collo di bottiglia non è più la CPU (come accadeva quando i dati si adattano alla memoria - l'accesso ai dati in memoria è veloce, la trasformazione e l'aggregazione dei dati è più lenta) ma piuttosto è il sottosistema di I/O (le operazioni della CPU sui dati sono molto più veloce dell'accesso ai dati dal disco.) Con la maggiore adozione della flash, i carichi di lavoro legati all'I/O non sono così terribili come ai tempi delle unità rotanti (l'accesso casuale è molto più veloce con SSD), ma il calo delle prestazioni è ancora lì .
Un'altra cosa che dobbiamo tenere a mente è che in genere ci preoccupiamo solo del set di dati attivo. Certo, potresti avere terabyte di dati nel tuo schema, ma se devi accedere solo agli ultimi 5 GB, questa è in realtà una buona situazione. Certo, pone ancora sfide operative, ma dal punto di vista delle prestazioni dovrebbe comunque essere ok.
Assumiamo solo ai fini di questo blog, e questa non è una definizione scientifica, che per grande volume di dati intendiamo il caso in cui la dimensione dei dati attivi supera significativamente la dimensione della memoria. Può essere 100 GB quando hai 2 GB di memoria, può essere 20 TB quando hai 200 GB di memoria. Il punto critico è che il carico di lavoro è strettamente legato all'I/O. Abbi pazienza mentre discutiamo di alcune delle opzioni disponibili per MySQL e MariaDB.
Partizionamento
L'approccio storico (ma perfettamente valido) alla gestione di grandi volumi di dati consiste nell'implementare il partizionamento. L'idea alla base è quella di dividere la tabella in partizioni, una sorta di sottotabelle. La suddivisione avviene secondo le regole definite dall'utente. Diamo un'occhiata ad alcuni esempi (gli esempi SQL sono presi dalla documentazione di MySQL 8.0)
MySQL 8.0 viene fornito con i seguenti tipi di partizionamento:
- GAMMA
- ELENCO
- COLONNE
- HASH
- CHIAVE
Può anche creare sottopartizioni. Non riscriveremo la documentazione qui, ma vorremmo comunque darti un'idea di come funzionano le partizioni. Per creare partizioni, devi definire la chiave di partizione. Può essere una colonna o in caso di RANGE o LIST più colonne che verranno utilizzate per definire come i dati devono essere suddivisi in partizioni.
Il partizionamento HASH richiede all'utente di definire una colonna, che verrà sottoposta a hash. Quindi, i dati verranno suddivisi in un numero di partizioni definito dall'utente in base a quel valore hash:
CREATE TABLE employees (
id INT NOT NULL,
fname VARCHAR(30),
lname VARCHAR(30),
hired DATE NOT NULL DEFAULT '1970-01-01',
separated DATE NOT NULL DEFAULT '9999-12-31',
job_code INT,
store_id INT
)
PARTITION BY HASH( YEAR(hired) )
PARTITIONS 4;
In questo caso l'hash verrà creato in base al risultato generato dalla funzione YEAR() nella colonna "assunta".
Il partizionamento KEY è simile con l'eccezione che l'utente definisce quale colonna deve essere sottoposta a hash e il resto spetta a MySQL da gestire.
Mentre le partizioni HASH e KEY distribuiscono i dati in modo casuale sul numero di partizioni, RANGE e LIST consentono all'utente di decidere cosa fare. RANGE è comunemente usato con l'ora o la data:
CREATE TABLE quarterly_report_status (
report_id INT NOT NULL,
report_status VARCHAR(20) NOT NULL,
report_updated TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP
)
PARTITION BY RANGE ( UNIX_TIMESTAMP(report_updated) ) (
PARTITION p0 VALUES LESS THAN ( UNIX_TIMESTAMP('2008-01-01 00:00:00') ),
PARTITION p1 VALUES LESS THAN ( UNIX_TIMESTAMP('2008-04-01 00:00:00') ),
PARTITION p2 VALUES LESS THAN ( UNIX_TIMESTAMP('2008-07-01 00:00:00') ),
PARTITION p3 VALUES LESS THAN ( UNIX_TIMESTAMP('2008-10-01 00:00:00') ),
PARTITION p4 VALUES LESS THAN ( UNIX_TIMESTAMP('2009-01-01 00:00:00') ),
PARTITION p5 VALUES LESS THAN ( UNIX_TIMESTAMP('2009-04-01 00:00:00') ),
PARTITION p6 VALUES LESS THAN ( UNIX_TIMESTAMP('2009-07-01 00:00:00') ),
PARTITION p7 VALUES LESS THAN ( UNIX_TIMESTAMP('2009-10-01 00:00:00') ),
PARTITION p8 VALUES LESS THAN ( UNIX_TIMESTAMP('2010-01-01 00:00:00') ),
PARTITION p9 VALUES LESS THAN (MAXVALUE)
);
Può essere utilizzato anche con altri tipi di colonne:
CREATE TABLE employees (
id INT NOT NULL,
fname VARCHAR(30),
lname VARCHAR(30),
hired DATE NOT NULL DEFAULT '1970-01-01',
separated DATE NOT NULL DEFAULT '9999-12-31',
job_code INT NOT NULL,
store_id INT NOT NULL
)
PARTITION BY RANGE (store_id) (
PARTITION p0 VALUES LESS THAN (6),
PARTITION p1 VALUES LESS THAN (11),
PARTITION p2 VALUES LESS THAN (16),
PARTITION p3 VALUES LESS THAN MAXVALUE
);
Le partizioni LIST funzionano in base a un elenco di valori che ordina le righe su più partizioni:
CREATE TABLE employees (
id INT NOT NULL,
fname VARCHAR(30),
lname VARCHAR(30),
hired DATE NOT NULL DEFAULT '1970-01-01',
separated DATE NOT NULL DEFAULT '9999-12-31',
job_code INT,
store_id INT
)
PARTITION BY LIST(store_id) (
PARTITION pNorth VALUES IN (3,5,6,9,17),
PARTITION pEast VALUES IN (1,2,10,11,19,20),
PARTITION pWest VALUES IN (4,12,13,14,18),
PARTITION pCentral VALUES IN (7,8,15,16)
);
Qual è il punto nell'usare le partizioni che potresti chiedere? Il punto principale è che le ricerche sono significativamente più veloci rispetto a tabelle non partizionate. Diciamo che vuoi cercare le righe che sono state create in un determinato mese. Se nella tabella sono archiviati diversi anni di dati, questa sarà una sfida:sarà necessario utilizzare un indice e, come sappiamo, gli indici aiutano a trovare le righe, ma l'accesso a tali righe risulterà in un mucchio di letture casuali da l'intero tavolo. Se hai partizioni create su base annuale, MySQL può semplicemente leggere tutte le righe da quella particolare partizione - non è necessario accedere all'indice, non è necessario eseguire letture casuali:basta leggere tutti i dati dalla partizione, in sequenza, e siamo tutto pronto.
Le partizioni sono anche molto utili per gestire la rotazione dei dati. Se MySQL è in grado di identificare facilmente le righe da eliminare e mapparle su una singola partizione, invece di eseguire DELETE FROM table WHERE …, che utilizzerà l'indice per individuare le righe, è possibile troncare la partizione. Questo è estremamente utile con il partizionamento RANGE:attenendosi all'esempio sopra, se vogliamo conservare i dati solo per 2 anni, possiamo facilmente creare un lavoro cron, che rimuoverà la vecchia partizione e ne creerà una nuova vuota per il mese prossimo.
Compressione InnoDB
Se abbiamo un grande volume di dati (non necessariamente pensando ai database), la prima cosa che ci viene in mente è comprimerlo. Esistono numerosi strumenti che offrono un'opzione per comprimere i file, riducendone notevolmente le dimensioni. InnoDB ha anche un'opzione per questo:sia MySQL che MariaDB supportano la compressione InnoDB. Il principale vantaggio dell'utilizzo della compressione è la riduzione dell'attività di I/O. I dati, quando compressi, sono più piccoli, quindi sono più veloci da leggere e da scrivere. La pagina tipica di InnoDB ha una dimensione di 16 KB, per SSD si tratta di 4 operazioni di I/O da leggere o scrivere (l'SSD utilizza in genere pagine da 4 KB). Se riusciamo a comprimere 16 KB in 4 KB, abbiamo semplicemente ridotto di quattro le operazioni di I/O. Non aiuta molto per quanto riguarda il rapporto tra set di dati e memoria. In realtà, potrebbe anche peggiorare le cose:MySQL, per poter operare sui dati, deve decomprimere la pagina. Eppure legge la pagina compressa dal disco. Ciò si traduce in un pool di buffer InnoDB che memorizza 4 KB di dati compressi e 16 KB di dati non compressi. Naturalmente, ci sono algoritmi in atto per rimuovere i dati non necessari (la pagina non compressa verrà rimossa quando possibile, mantenendone solo una compressa in memoria) ma non puoi aspettarti un miglioramento eccessivo in quest'area.
È anche importante tenere a mente come funziona la compressione per quanto riguarda l'archiviazione. Le unità a stato solido sono la norma per i server di database al giorno d'oggi e hanno un paio di caratteristiche specifiche. Sono veloci, non si preoccupano molto se il traffico è sequenziale o casuale (anche se preferiscono comunque l'accesso sequenziale al casuale). Sono costosi per grandi volumi. Soffrono di "usura" in quanto possono gestire un numero limitato di cicli di scrittura. La compressione aiuta in modo significativo in questo caso:riducendo la dimensione dei dati su disco, riduciamo il costo del livello di archiviazione per il database. Riducendo la dimensione dei dati che scriviamo su disco, aumentiamo la durata dell'SSD.
Sfortunatamente, anche se la compressione aiuta, per volumi di dati maggiori potrebbe comunque non essere sufficiente. Un altro passo sarebbe cercare qualcos'altro oltre a InnoDB.
MyRocks
MyRocks è un motore di archiviazione disponibile per MySQL e MariaDB che si basa su un concetto diverso da InnoDB. Il mio collega, Sebastian Insausti, ha un bel blog sull'utilizzo di MyRocks con MariaDB. Il succo è che, grazie al suo design (usa Log Structured Merge, LSM), MyRocks è significativamente migliore in termini di compressione rispetto a InnoDB (che si basa sulla struttura B+Tree). MyRocks è progettato per la gestione di grandi quantità di dati e per ridurre il numero di scritture. Ha avuto origine da Facebook, dove i volumi di dati sono grandi e i requisiti per accedere ai dati sono elevati. Quindi l'archiviazione SSD, tuttavia, su una scala così ampia ogni guadagno in compressione è enorme. MyRocks può fornire una compressione fino a 2 volte migliore rispetto a InnoDB (il che significa che il numero di server è ridotto di due). È inoltre progettato per ridurre l'amplificazione della scrittura (numero di scritture necessarie per gestire una modifica del contenuto della riga):richiede 10 volte meno scritture rispetto a InnoDB. Questo, ovviamente, riduce il carico di I/O ma, cosa ancora più importante, aumenterà la durata di vita di un SSD di dieci volte rispetto alla gestione dello stesso carico utilizzando InnoDB). Dal punto di vista delle prestazioni, più piccolo è il volume dei dati, più veloce è l'accesso, quindi i motori di archiviazione come quelli possono anche aiutare a estrarre i dati dal database più velocemente (anche se non era la massima priorità durante la progettazione di MyRocks).
Archivi dati a colonna
Risorse correlate Gestione delle prestazioni di ClusterControl Capire gli effetti dell'elevata latenza nelle soluzioni MySQL e MariaDB ad alta disponibilità Cheat sheet sulle prestazioni di MySQLAd un certo punto tutto ciò che possiamo fare è ammettere che non possiamo gestire un tale volume di dati utilizzando MySQL. Certo, puoi frantumarlo, puoi fare cose diverse ma alla fine non ha più senso. È tempo di cercare soluzioni aggiuntive. Uno di questi sarebbe l'utilizzo di datastore colonnari, database progettati pensando all'analisi dei big data. Certo, non aiuteranno con il tipo di traffico OLTP, ma al giorno d'oggi le analisi sono praticamente standard poiché le aziende cercano di essere basate sui dati e prendono decisioni basate su numeri esatti, non su dati casuali. Esistono numerosi datastore colonnari, ma vorremmo menzionarne qui due. MariaDB AX e ClickHouse. Abbiamo un paio di blog che spiegano cos'è MariaDB AX e come può essere utilizzato MariaDB AX. Ciò che è importante, MariaDB AX può essere ampliato in forma di cluster, migliorando le prestazioni. ClickHouse è un'altra opzione per l'esecuzione di analisi:ClickHouse può essere facilmente configurato per replicare i dati da MySQL, come abbiamo discusso in uno dei nostri post sul blog. È veloce, è gratuito e può essere utilizzato anche per formare un cluster e per dividere i dati per prestazioni ancora migliori.
Conclusione
Ci auguriamo che questo post del blog ti abbia fornito informazioni su come è possibile gestire grandi volumi di dati in MySQL o MariaDB. Fortunatamente, ci sono un paio di opzioni a nostra disposizione e, alla fine, se non riusciamo davvero a farlo funzionare, ci sono buone alternative.