TiDB

TiDB TiDB e' un Database Open Source compatibile con MySQL progettato per supportare transazioni OLTP e per scalare linearmente distribuendo su piu' nodi i dati.

Dal punto di vista tecnico TiDB utilizza... insomma volete distribuire la vostra base dati in Cloud? Allora continuate a leggere!

Questo documento presenta gli aspetti introduttivi di TiDB: Introduzione, Installazione, Utilizzo, ... utilizzando un approccio pratico con molti esempi.

Il documento si riferisce alla versione di TiDB 2.1 ma i contenuti valgono anche per altre versioni.

Introduzione

TiDB e' un NewSQL database hybrid transactional and analytical processing (HTAP) Open Source sviluppato da PingCAP.

TiDB e' progettato per un carico HTAP ovvero per supportare sia query OLTP (On-Line Transaction Processing) che OLAP (On-Line Analytical Processing).
In pratica TiDB ha buone prestazioni con un numero elevato di query CRUD e soddisfa le proprieta' ACID (Atomicity, Consistency, Isolation, Durability) delle transazioni; nello stesso tempo e' adatto ad eseguire query OLAP distribuendo l'elaborazione su piu' nodi come opportuno.

TiDB - Componenti: TiDB, TiKV, PD Dal punto di vista architetturale sono presenti tre tipologie di nodi:

TiDB e' la componente di database che si occupa di raccogliere le connessioni utente, di analizzare la sintassi delle richieste, di eseguire i passi di ottimizzazione e richiedere i dati agli Engine di Storage.
Il protocollo di connessione a TiDB cosi' come il dialetto SQL utilizzato sono quelli MySQL. Questo significa che qualsiasi applicazione o tool utilizzato con MySQL puo' essere utilizzato con TiDB.
Deve essere notato che TiDB tecnicamente *non* e' un fork MySQL, anche se si comporta come un database MySQL le funzionalita' sono implementate in modo diverso e sono presenti alcune differenze significative.

TiKV e' lo storage Engine. Per la memorizzazione dei dati utilizza la tecnica Key-Value di RocksDB [NdA un database embedded disponibile anche come Engine su MySQL Percona Server e su MariaDB]. I dati sono replicati su piu' nodi utilizzando il protocollo di consenso Raft. Le coppie chiave-valore vengono divise per range in Region di dimensioni fisse, la region e' l'unita' minima di replicazione. Per ogni region vi e' un nodo Leader a cui vengono indirizzate tutte le letture e le scritture, mentre le altre copie del Region Group saranno sincronizzate in two-phase-commit per garantire i dati anche in caso di fault.
Per la gestione delle transazioni viene usato il multi-version concurrency control (MVCC) ed il locking ottimistico: sono due tecniche consolidate che garantiscono le propieta' ACID e buone prestazioni.

Il Placement Driver si occupa tra le altre cose di gestire i metadati, schedulare le migrazioni delle region per evitare hotspot e riconfigurare i componenti nel caso di failure. Tutti compiti importanti!

Le metriche di utilizzo, da tutti i componenti, sono pubblicate per Prometheus sull'URL localhost:10080/metrics [NdA ed ovviamente sono facilmente visualizzabili in Grafana]. Se si utilizza il deploy con Ansible Prometheus e Grafana vengono installati in automatico.

Anche se non e' presente in tutte le configurazioni vi sono moduli aggiuntivi. Particolarmente interessanti e' TiSpark che risponde alle query OLAP utilizzando sempre i dati mantenuti dai TiKV.

Abbiamo visto un'accenno dell'architettura, che non e' cosi' semplice... al contrario l'utilizzo di TiDB e' molto semplice per le applicazioni!
Basta connettersi ad un qualsiasi nodo TiDB con un client o un driver MySQL e funziona senza differenze o quasi!

Installazione

L'installazione di TiDB e' semplice... se si effettua per un ambiente di test su un Mac!

brew tap pingcap/brew brew install tidb-server ... brew services start tidb-server ... ==> Successfully started `tidb-server` (label: homebrew.mxcl.tidb-server)

In realta' e' stato installato il solo componente TiDB con un engine locale... l'affidabilita', le prestazioni e l'architettura complessiva sono notevolmente diverse; ma e' cosi' possibile sperimentare le funzionalita' del database TiDB.
Ora basta collegarsi con un qualsiasi client MySQL alla porta 4000! [NdA la porta di default di TiDB e' 4000 e non 3306]

Un deployment di produzione richiede un minimo di progettazione per definire il numero di nodi da dedicare a ciascun compito. TiDB permette diverse modalita' di installazione (eg. Kubernetes, Ansible, ...) e la scelta dipende anche dall'infrastruttura gia' presente.

Per un'installazione di produzione l'HA e' un requisito fondamentale e quindi i vari componenti vanno configurati in modo che non si abbiano SPOF. Il numero di nodi di database e di store e' indipendente: in generale verranno aggiunti a seconda del tipo di carico.
Un aspetto importante per la scalabilita' e' che i componenti TiDB sono stateless quindi possono essere aggiunti in modo dinamico. I nodi TiKV ovviamente non sono stateless ma il PD li gestisce in modo automatico: all'aggiunta di un nuovo nodo vengono replicate le region e, quando sincronizzate, possono diventare Leader del Raft Group. TiDB - Architettura

La configurazione di base di un nodo sono 16 core, 32GB di RAM, schede 10Gb e, per i nodi TiKV, fino a 2TB di dischi SSD. Alcune indicazioni sono minimali (eg. RAM), altre fortemente consigliabili (eg. schede 10Gb).

Sono disponibili diverse modalita' di installazione (Kubernetes, Ansible, Docker, Binary) come riportato nella documentazione ufficiale.

Utilizzo

Per utilizzare TiDB bastano... semplici comandi SQL!

Vediamo come accedere:

$ mysql -h127.0.0.1 -P4000 -uroot mysql> select version(); +--------------------------+ | version() | +--------------------------+ | 5.7.25-TiDB-v2.1.7-dirty | +--------------------------+ 1 row in set (0.00 sec) mysql> show databases; +--------------------+ | Database | +--------------------+ | INFORMATION_SCHEMA | | PERFORMANCE_SCHEMA | | mysql | | test | +--------------------+ mysql> select * from mysql.TIDB_INDEXES; +--------------+----------------------+------------+-------------------------+--------------+---------------+----------+---------------+----------+ | TABLE_SCHEMA | TABLE_NAME | NON_UNIQUE | KEY_NAME | SEQ_IN_INDEX | COLUMN_NAME | SUB_PART | INDEX_COMMENT | INDEX_ID | +--------------+----------------------+------------+-------------------------+--------------+---------------+----------+---------------+----------+ | mysql | columns_priv | 0 | PRIMARY | 1 | Host | NULL | | 1 | | mysql | columns_priv | 0 | PRIMARY | 2 | DB | NULL | | 1 | | mysql | columns_priv | 0 | PRIMARY | 3 | User | NULL | | 1 | | mysql | columns_priv | 0 | PRIMARY | 4 | Table_name | NULL | | 1 | | mysql | columns_priv | 0 | PRIMARY | 5 | Column_name | NULL | | 1 | | mysql | GLOBAL_VARIABLES | 0 | PRIMARY | 1 | VARIABLE_NAME | NULL | | 1 | | mysql | tidb | 0 | PRIMARY | 1 | VARIABLE_NAME | NULL | | 1 | ... mysql> select * from mysql.tidb; +---------------------+----------------+-----------------------------------+ | VARIABLE_NAME | VARIABLE_VALUE | COMMENT | +---------------------+----------------+-----------------------------------+ | bootstrapped | True | Bootstrap flag. Do not delete. | | tidb_server_version | 24 | Bootstrap version. Do not delete. | | system_tz | Europe/Rome | TiDB Global System Timezone. | +---------------------+----------------+-----------------------------------+ mysql> explain select * from test.emp; +-------------------+----------+------+----------------------------------------------------------------+ | id | count | task | operator info | +-------------------+----------+------+----------------------------------------------------------------+ | TableReader_5 | 10000.00 | root | data:TableScan_4 | | └─TableScan_4 | 10000.00 | cop | table:emp, range:[-inf,+inf], keep order:false, stats:pseudo | +-------------------+----------+------+----------------------------------------------------------------+

A prima vista le differenze sono poche ma in realta' alcune sono semplicemente mascherate per ottenere una maggiore compatibilita' con i tool MySQL. Ad esempio creando una tabella sembrera' utilizzare l'Engine InnoDB... pero' non e' cosi!

Differenze con MySQL

Deve essere notato che TiDB *non* e' un fork MySQL, anche se si comporta come un MySQL 5.7, le funzionalita' sono implementate in modo diverso e sono presenti molteplici differenze.

mysql -h 127.0.0.1 -P4000 -uroot Welcome to the MySQL monitor. Commands end with ; or \g. Your MySQL connection id is 1 Server version: 5.7.25-TiDB-v2.1.7-dirty MySQL Community Server (Apache License 2.0) Copyright (c) 2000, 2019, Oracle and/or its affiliates. All rights reserved. Oracle is a registered trademark of Oracle Corporation and/or its affiliates. Other names may be trademarks of their respective owners. Type 'help;' or '\h' for help. Type '\c' to clear the current input statement. mysql>

Nella maggior parte dei casi il dialetto SQL, i datatype, le funzioni, gli errori, gli isolation level, ... anche il risultato della funzione version() sono come quelli MySQL.
Vediamo nel seguito le differenze piu' significative.

Nella CREATE TABLE TiDB accetta la clausola ENGINE ed il comando SHOW CREATE TABLE mostra le tabelle come se fossero tutte InnoDB. In realta' le tabelle utilizzano lo Storage TiKV.
I campi SERIAL non crescono per valori consecutivi e crescenti ma sono allocati a gruppi dai diversi server.
L'EXPLAIN e' molto differente [NdA personalmente preferisco quello di TiDB].
Le DDL sono asincrone! La modifica di una struttura di una tabella, per un database distribuito, e' un'attivita' complessa e potenzialmente rischiosa. TiDB ha risolto il problema spezzando ogni richiesta in passi successivi eseguiti in modo asincrono.
In TiDB il character set utilizzato e' UTF8 (quello vero e quindi equivalente a utf8mb4 di MySQL) con collation binary.
Il locking di TiDB e' ottimistico, quindi vi sono minori condizioni di attesa ma possono verificarsi rollback: le applicazioni debbono evitare i conflitti e/o gestire l'eventuale segnalazione.

Una importante serie di funzionalita' MySQL non sono presenti in TiDB: Stored Procedures, Functions, Views, Triggers, Events, FOREIGN KEY constraints, FULLTEXT, CREATE TABLE AS SELECT, ...

Alcune delle incompatibilita' riportate verranno colmate a breve (eg. view in TiDB 3.0) ma altre sono dovute alle differenti architetture presenti e quindi resteranno tali. E' anche previsto vengano inserite in TiDB nuove funzionalita' che non sono presenti in MySQL 5.7; tra queste le windows function che sono molto utili per le query analitiche [NdA in effetti le windows functions sono presenti in MySQL 8 ed in MariaDB 10.2].

Maggiori dettagli sono riportati nella documentazione ufficiale.

Scalabilita'

Un'installazione di produzione prevede almeno tre nodi TiKV e due TiDB ma questo e' solo il punto di partenza. La principale caratteristica di TiDB e' quella di poter scalare orrizzontalmente aggiungendo ulteriori nodi quando necessario.

MySQL ha un'elevata scalabilita' e puo' essere utilizzato in Cloud con migliaia o milioni di accessi. E' infatti possibile replicare in cascata decine o centinaia di database MySQL.
Tuttavia questo vale solo per le letture. La parte di scrittura deve essere eseguita su un solo master che quindi puo' scalare solo verticalmente. Anche le piu' recenti evoluzioni quali Galera Cluster e MySQL InnoDB Cluster non scalano prestazionalmente sulle scritture. In effetti le prestazioni massime le fornisce la replica asincrona con un solo master...
L'alternativa e' lo sharding, che con MySQL puo' essere effettuato in modo applicativo.

Con TiDB lo sharding e' nativo e non richiede nessuna modifica applicativa. Le Region sono l'unita' minima utilizzata per bilanciare il carico. Il Placement Driver si occupa di definire le repliche leader sui TiKV cui vengono dirette le letture e le scritture dei TiDB. Se il carico non e' bilanciato e vi sono degli Hot Spot il PD modifica le assegnazioni delle Region. Quando viene aggiunto un nuovo TiKV inizialmente vengono solo replicati i dati, quindi il PD promuovera' alcune sue region a leader indirizzando cosi' il carico. In questo modo tutte le attivita' sui dati, sia di lettura che di scrittura, scalano in modo lineare all'aggiunta di nodi.

Ancora piu' semplice e' la gestione dei nodi di tipo TiDB: poiche' sono componenti stateless possono essere aggiunti quando necessario ed un normale load balancer puo' gestirne il bilanciamento.
I nodi PD non sono tipicamente un bottleneck e quindi tre nodi, eventualmente in condivisione con i TiDB, sono sempre sufficienti.

I deploy piu' significativi di TiDB utilizzano centinaia di nodi fisici distribuiti su piu' datacenter.

Replica da MySQL

TiDB e' adatto ad installazioni significative quando MySQL non puo' piu' scalare verticalmente o quando si ha un carico significativo di query OLAP.
Sono situazioni che si verificano con grandi basi dati di produzione accedute da applicazioni complesse. In tali ambienti e' difficile eseguire una minor update del database... figuriamoci cambiarne l'architettura!

C'e' un'importante funzionalita' di TiDB: la possibilita' di configurarlo come Slave di una replica MySQL. In questo modo e' possibile effettuare un PoC (Proof of Concept) efficace su un ambiente complesso di grandi dimensioni.

In questo caso si utilizza il tool DM-worker che puo' connettersi come Slave verso un server MySQL or MariaDB.
Un singolo DM-worker sincronizza i dati da un instanza MySQL su una o piu' istanze TiDB. E' anche possibile utilizzare piu' DM-workers per raccogliere i dati da diverse istanze MySQL e consolidarle su un unica istanza TiDB.

La tecnica adottata per il PoC puo' anche essere utilizzata per la migrazione definitiva dei dati riducendo il periodo di disservizio.

Varie ed eventuali

TiDB e' un database giovane: ha buone prestazioni, e' scalabile ma presenta anche qualche limite... vedremo!

E' consigliata infine la lettura di uno dei primi articoli su TiDB che descrive l'implementazione delle modifiche asincrone delle strutture dati [NdA tranquilli: non e' in inglese :]


Titolo: TiDB
Livello: Medio (2/5)
Data: 1 Aprile 2019
Versione: 1.0.0 - 1 Aprile 2019
Autore: mail [AT] meo.bogliolo.name