Mescolare SQL e NoSQL con MariaDB e MongoDB

Immaginiamo di avere un’applicazione sviluppata in Node.js (o qualsiasi altro ambiente). Questa applicazione si connette a un database MongoDB (NoSQL) per memorizzare valutazioni su libri (numero di stelle assegnate e un commento). Supponiamo inoltre di avere un’altra applicazione sviluppata in Java (o Python, C#, TypeScript… qualsiasi cosa). Questa applicazione si connette a un database MariaDB (SQL, relazionale) per gestire un catalogo di libri (titolo, anno di pubblicazione, numero di pagine).

Ti viene chiesto di creare un rapporto che mostri il titolo e le informazioni sul rating per ogni libro. Nota che il database MongoDB non contiene il titolo dei libri, e il database relazionale non contiene le valutazioni. Dobbiamo mescolare dati creati da un’applicazione NoSQL con dati creati da un’applicazione SQL.

A common approach to this is to query both databases independently (using different data sources) and process the data to match by, for example, ISBN (the id of a book) and put the combined information in a new object. This needs to be done in a programming language like Java, TypeScript, C#, Python, or any other imperative programming language that is able to connect to both databases.

A polyglot application

Questo approccio funziona. Tuttavia, unire i dati è un compito per un database. Sono progettati per questo tipo di operazione sui dati. Inoltre, con questo approccio, l’applicazione SQL non è più un’applicazione esclusivamente SQL; diventa un poliglotta di database, e ciò aumenta la complessità, rendendola più difficile da mantenere.

Con un proxy di database come MaxScale, puoi unire questi dati a livello di database utilizzando il miglior linguaggio per i dati — SQL. La tua applicazione SQL non ha bisogno di diventare poliglota.

Anche se questo richiede un elemento aggiuntivo nell’infrastruttura, si ottengono anche tutte le funzionalità che un database proxy ha da offrire. Cose come failover automatico, mascheramento dei dati trasparente, isolamento della topologia, cache, filtri di sicurezza e altro ancora.

MaxScale è un potente proxy di database intelligente che comprende sia SQL che NoSQL. Comprende anche Kafka (per CDC o inserimento dati), ma questo è un argomento per un’altra occasione. In breve, con MaxScale, puoi connettere il tuo applicativo NoSQL a un database relazionale pienamente conforme agli ACID relational database e memorizzare i dati proprio lì accanto alle tabelle che utilizzano altri applicativi SQL.

MaxScale consente a un applicativo SQL di consumare dati NoSQL.

Proviamo quest’ultimo approccio in un esperimento rapido ed intuitivo con MaxScale. Avrai bisogno delle seguenti installazioni sul tuo computer:

Configurazione del Database MariaDB

Usando un editor di testo normale, crea un nuovo file e salvalo con il nome docker-compose.yml. Il file dovrebbe contenere quanto segue:

YAML

 

version: "3.9"
services:
  mariadb:
    image: alejandrodu/mariadb
    environment:
      - MARIADB_CREATE_DATABASE=demo
      - MARIADB_CREATE_USER=user:Password123!
      - MARIADB_CREATE_MAXSCALE_USER=maxscale_user:MaxScalePassword123!


  maxscale:
    image: alejandrodu/mariadb-maxscale
    command: --admin_host 0.0.0.0 --admin_secure_gui false
    ports:
      - "3306:4000"
      - "27017:27017"
      - "8989:8989"
    environment:
      - MAXSCALE_USER=maxscale_user:MaxScalePassword123!
      - MARIADB_HOST_1=mariadb 3306
      - MAXSCALE_CREATE_NOSQL_LISTENER=user:Password123!

Questo è un file Docker Compose. Descrive un insieme di servizi da creare con Docker. Stiamo creando due servizi (o contenitori) — un server di database MariaDB e un proxy di database MaxScale. Saranno in esecuzione localmente sul tuo computer, ma in ambienti di produzione, è comune distribuirli su macchine fisiche separate. Tieni presente che queste immagini Docker non sono adatte per la produzione! Sono pensate per essere adatte per rapide demo e test. Puoi trovare il codice sorgente per queste immagini su GitHub. Per le immagini Docker ufficiali da MariaDB, vai alla pagina MariaDB su Docker Hub.

Il file Docker Compose precedente configura un server di database MariaDB con un database (o schema; sono sinonimi in MariaDB) chiamato demo. Viene inoltre creato un nome utente user con la password Password123!. Questo utente dispone dei privilegi adeguati sul database demo. C’è un altro utente con nome maxscale_user e password MaxScalePassword123!. Questo è l’utente che il proxy database MaxScale utilizzerà per connettersi al database MariaDB.

Il file Docker Compose configura anche il proxy database disabilitando HTTPS (non farlo in produzione!), esponendo un insieme di porte (più su questo tra un momento), e configurando l’utente del database e la posizione del proxy MariaDB (di solito un indirizzo IP, ma qui possiamo utilizzare il nome del contenitore precedentemente definito nel file Docker). L’ultima riga crea un listener NoSQL che useremo per connetterci come client MongoDB sulla porta predefinita (27017).

Per avviare i servizi (contenitori) usando la riga di comando, spostati nella directory in cui hai salvato il file Docker Compose e esegui quanto segue:

Shell

 

docker compose up -d

Dopo aver scaricato tutto il software e avviato i contenitori, avrai un database MariaDB e un proxy MaxScale, entrambi preconfigurati per questo esperimento.

Creazione di una Tabella SQL in MariaDB

Connettiamoci al database relazionale. Nella riga di comando, esegui quanto segue:

Shell

 

mariadb-shell --dsn mariadb://user:'Password123!'@127.0.0.1

Verifica che sia visibile il database demo:

MariaDB SQL

 

show databases;

Passa al database demo:

MariaDB SQL

 

use demo;

Connessione a un database con MariaDB Shell.

Crea la tabella books:

MariaDB SQL

 

CREATE TABLE books(
  isbn VARCHAR(20) PRIMARY KEY,
  title VARCHAR(256),
  year INT
);

Inserisci alcuni dati. Userò il cliché di inserire i miei libri:

MariaDB SQL

 

INSERT INTO books(title, isbn, year)
VALUES
  ("Vaadin 7 UI Design By Example", "978-1-78216-226-1", 2013),
  ("Data-Centric Applications with Vaadin 8", "978-1-78328-884-7", 2018),
  ("Practical Vaadin", "978-1-4842-7178-0", 2021);

Verifica che i libri siano memorizzati nel database eseguendo:

MariaDB SQL

 

SELECT * FROM books;

Inserimento dei dati con MariaDB Shell.

Creazione di una Collection JSON in MariaDB

Non abbiamo ancora installato MongoDB, eppure possiamo utilizzare un client MongoDB (o applicazione) per connetterci e creare collezioni e documenti come se stessimo usando MongoDB, tranne per il fatto che i dati sono memorizzati in un potente database relazionale completamente conforme ACID e scalabile. Proviamolo!

Nella riga di comando, usa lo strumento shell MongoDB per connetterti al MongoDB… aspetta… è in realtà il database MariaDB! Esegui quanto segue:

Shell

 

mongosh

Per impostazione predefinita, questo strumento cerca di connettersi a un server MongoDB (che, ancora una volta, si rivela essere MariaDB questa volta) in esecuzione sul tuo computer locale (127.0.0.1) utilizzando la porta predefinita (20017). Se tutto va bene, dovresti essere in grado di vedere il database demo elencato quando esegui il seguente comando:

Plain Text

 

show databases

Passa al database demo:

Plain Text

 

use demo

Connessione a MariaDB utilizzando Mongo Shell.

Siamo connessi a un database relazionale da un client non relazionale! Creiamo la raccolta ratings e inseriamo alcuni dati in essa:

Plain Text

 

db.ratings.insertMany([
	{
		"isbn": "978-1-78216-226-1",
		"starts": 5,
		"comment": "A good resource for beginners who want to learn Vaadin"
	},
	{
		"isbn": "978-1-78328-884-7",
		"starts": 4,
		"comment": "Explains Vaadin in the context of other Java technologies"
	},
	{
		"isbn": "978-1-4842-7178-0",
		"starts": 5,
		"comment": "The best resource to learn web development with Java and Vaadin"
	}
])

Verifica che le valutazioni siano persistenti nel database:

Plain Text

 

db.ratings.find()

Consultazione di un database MariaDB utilizzando Mongo Shell.

Utilizzo delle Funzioni JSON in MariaDB

A questo punto, abbiamo un unico database che, dall’esterno, sembra un database NoSQL (MongoDB) e un database relazionale (MariaDB). Siamo in grado di connetterci allo stesso database e scrivere e leggere dati da client MongoDB e client SQL. Tutti i dati sono memorizzati in MariaDB, quindi possiamo utilizzare SQL per unire dati da client MongoDB o applicazioni con dati da client MariaDB o applicazioni. Esploriamo come MaxScale utilizza MariaDB per memorizzare dati MongoDB (raccolte e documenti).

Connettiti al database utilizzando un client SQL come mariadb-shell e visualizza le tabelle nello schema dimostrativo:

MariaDB SQL

 

show tables in demo;

Dovresti vedere sia la tabella books che la tabella ratings elencate. ratings è stata creata come una raccolta MongoDB. MaxScale ha tradotto i comandi inviati dal client MongoDB e ha creato una tabella per memorizzare i dati in una tabella. Diamo un’occhiata alla struttura di questa tabella:

MariaDB SQL

 

describe demo.ratings;

A NoSQL collection is stored as a MariaDB relational table.

La tabella ratings contiene due colonne:

  1. id: l’ID oggetto.
  2. doc: il documento in formato JSON.

Se controlliamo il contenuto della tabella, vedremo che tutti i dati sulle valutazioni sono memorizzati nella colonna doc in formato JSON:

MariaDB SQL

 

SELECT doc FROM demo.ratings \G

I documenti NoSQL sono memorizzati in un database MariaDB.

Torniamo al nostro obiettivo originale: mostrare i titoli dei libri con le informazioni sulle valutazioni. Il seguente scenario non è quello reale, ma supponiamo per un momento che la tabella ratings sia una tabella regolare con le colonne stars e comment. Se fosse così, unire questa tabella con la tabella books sarebbe facile e il nostro lavoro sarebbe fatto:

MariaDB SQL

 

/* this doesn’t work */
SELECT b.title, r.stars, r.comment
FROM ratings r
JOIN books b USING(isbn)

Torniamo alla realtà. Dobbiamo convertire la colonna doc della tabella effettiva ratings in un’espressione relazionale che possa essere utilizzata come nuova tabella nella query. Qualcosa di simile a questo:

MariaDB SQL

 

/* this still doesn’t work */
SELECT b.title, r.stars, r.comment
FROM ratings rt
JOIN ...something to convert rt.doc to a table... AS r
JOIN books b USING(isbn)

Quel qualcosa è la funzione JSON_TABLE . MariaDB include un’ampia gamma di funzioni JSON per manipolare stringhe JSON. Utilizzeremo la funzione JSON_TABLE per convertire la colonna doc in una forma relazionale che possiamo utilizzare per eseguire join SQL. La sintassi generale della funzione JSON_TABLE è la seguente:

MariaDB SQL

 

JSON_TABLE(json_document, context_path COLUMNS (
    column_definition_1,
    column_definition_2,
    ...
  )
) [AS] the_new_relational_table

Dove:

  • json_document: una stringa o un’espressione che restituisce i documenti JSON da utilizzare.
  • context_path: una espressione JSON Path che definisce i nodi da utilizzare come fonte delle righe.

E le definizioni delle colonne (column_definition_1, column_definition_2, ecc…) hanno la seguente sintassi:

MariaDB SQL

 

new_column_name sql_type PATH path_in_the_json_doc [on_empty] [on_error]

Combinando queste conoscenze, la nostra query SQL sarebbe simile alla seguente:

MariaDB SQL

 

SELECT b.title, r.stars, r.comment
FROM ratings rt
JOIN JSON_TABLE(rt.doc, '$' COLUMNS(
    isbn VARCHAR(20) PATH '$.isbn',
    stars INT PATH '$.starts',
    comment TEXT PATH '$.comment'
  )
) AS r
JOIN books b USING(isbn);

Unire dati NoSQL e SQL in una singola query SQL.

Avremmo potuto utilizzare il valore ISBN come ObjectID MongoDB e, di conseguenza, come colonna id nella tabella ratings, ma lascerò questo a te come esercizio (suggerimento: usa _id invece di isbn quando inserisci dati utilizzando il client o l’app MongoDB).

A Word on Scalability

C’è un’errata concezione che i database relazionali non scalano orizzontalmente (aggiungendo più nodi) mentre i database NoSQL lo fanno. Ma i database relazionali scalano senza sacrificare le proprietà ACID. MariaDB ha più motori di storage adatti a diversi carichi di lavoro. Ad esempio, puoi scalare un database MariaDB implementando il partizionamento dei dati con l’aiuto di Spider. Puoi anche utilizzare una varietà di motori di storage per gestire diversi carichi di lavoro a livello di tabella. Le join tra motori sono possibili in una singola query SQL.

Combinazione di più motori di storage in un singolo database logico MariaDB.

Un’alternativa più moderna è SQL distribuito con MariaDB Xpand. Un database SQL distribuito si presenta come un singolo database relazionale logico agli applicativi attraverso lo sharding trasparente. Adotta un’architettura shared-nothing che si espande sia per la lettura che per la scrittura.

A distributed SQL database deployment.

Conclusione

Il nostro compito qui è terminato! Ora, i vostri sistemi possono avere una visione scalabile 360 gradi dei vostri dati conforme a ACID, indipendentemente dal fatto che siano stati creati da applicazioni SQL o NoSQL. C’è meno necessità di migrare le vostre app da NoSQL a SQL o di rendere le app SQL polyglot di database. Se volete saperne di più su altre caratteristiche di MaxScale, guardate questo video o visitate le documentazioni.

Source:
https://dzone.com/articles/mixing-sql-and-nosql-with-mariadb-and-mongodb