1
Fork 0
mirror of https://github.com/Steffo99/unimore-bda-2.git synced 2024-11-25 09:24:22 +00:00
This commit is contained in:
Steffo 2022-11-23 22:31:25 +01:00
commit 7c79a3e476
Signed by: steffo
GPG key ID: 6965406171929D01

View file

@ -162,11 +162,11 @@ Le repliche si connettono al database originale, richiedono ad esso una **sincro
Nel caso una replica perdesse la connessione all'originale, essa continuerebbe a funzionare indipendentemente, e al ripristino della connessione essa può richiedere una **sincronizzazione parziale**, ricevendo i cambiamenti avvenuti al database dal momento della disconnessione. Nel caso una replica perdesse la connessione all'originale, essa continuerebbe a funzionare indipendentemente, e al ripristino della connessione essa può richiedere una **sincronizzazione parziale**, ricevendo i cambiamenti avvenuti al database dal momento della disconnessione.
Questo permette a Redis grandi benefici di scalabilità, rendendo possibile ad esempio: Questo modello di replicazione offre notevoli benefici di scalabilità, rendendo possibile ad esempio:
* distribuire il carico di lavoro geograficamente, minimizzando la latenza tra utente e servizio * **distribuzione geografica** del carico di lavoro, minimizzando la latenza tra utente e servizio
* delegare query di letture computazionalmente costose a una replica, conservando potenza computazionale dell'originale per gestire più scritture * **delegarazione a repliche** di query di letture computazionalmente costose, conservando potenza computazionale dell'originale per la gestione delle scritture
* eseguire una replica mentre il software del database originale viene aggiornato, mantenendo così il database accessibile tutto il tempo * **sostituzione dell'originale con una replica** mentre il software del database viene aggiornato, mantenendolo accessibile tutto il tempo
La sincronizzazione tra le repliche è effettuata asincronamente: ciò significa che la **consistenza non è garantita**, ma che, con il passare del tempo, il database convergerà alla consistenza. La sincronizzazione tra le repliche è effettuata asincronamente: ciò significa che la **consistenza non è garantita**, ma che, con il passare del tempo, il database convergerà alla consistenza.
@ -177,13 +177,13 @@ A questo sistema può essere aggiunto il servizio [*Redis Sentinel*](https://red
* monitora il database originale e le sue repliche * monitora il database originale e le sue repliche
* notifica l'amministratore automaticamente nel caso di downtime di un'istanza di Redis * notifica l'amministratore automaticamente nel caso di downtime di un'istanza di Redis
* promuove una delle repliche a "principale" nel caso il database originale smettesse di essere accessibile * promuove una delle repliche a "principale" nel caso il database originale smettesse di essere accessibile
* comunica autorevolmente alle altre repliche l'indirizzo del nuovo database principale nel caso di un cambio, prevenendo il [problema dei due generali](https://en.wikipedia.org/wiki/Two_Generals'_Problem) * comunica autorevolmente alle altre repliche l'indirizzo del nuovo database principale nel caso di un cambio, facendo da coordinatore per evitare che la rete di repliche si frammenti
### Clustering ### Clustering
È possibile configurare più istanze di Redis perchè funzionino come un unico database utilizzando [*Redis Cluster*](https://redis.io/docs/management/scaling/). È possibile configurare più istanze di Redis perchè funzionino come un unico database utilizzando [*Redis Cluster*](https://redis.io/docs/management/scaling/).
Attraverso di esso, le istanze si spartiscono l'autorità su determinate chiavi, effettuando l'hash su di esse per determinare quale istanza è la "originale" per la data chiave. In modalità Cluster, i Redis si spartiscono l'autorità sulle chiavi inserite, effettuandone l'hash per determinare qual è il Redis con l'autorità per modificarla.
In particolare, l'hash viene effettuato sulla parte di chiave contenuta tra parentesi graffe, permettendo a una data istanza di avere l'autorità su tutte le chiavi relative a una certa entità. In particolare, l'hash viene effettuato sulla parte di chiave contenuta tra parentesi graffe, permettendo a una data istanza di avere l'autorità su tutte le chiavi relative a una certa entità.
@ -210,18 +210,18 @@ Come per le repliche, essendo la sincronizzazione tra i cluster effettuata asinc
Per testare le caratteristiche di Redis, si è sviluppato una piccola applicazione che lo utilizza. Per testare le caratteristiche di Redis, si è sviluppato una piccola applicazione che lo utilizza.
L'applicazione, [**Distributed Arcade**](https://github.com/Steffo99/distributed-arcade), è un servizio di gestione classifiche in grado di processare l'immissione di numerosissimi punteggi senza avere grossi costi di performance sulle macchine su cui è ospitato. L'applicazione, [***Distributed Arcade***](https://github.com/Steffo99/distributed-arcade), è un servizio di gestione classifiche in grado di processare l'immissione di numerosissimi punteggi senza avere grossi costi di performance sulle macchine su cui è ospitato.
L'applicazione è intesa per essere utilizzata da videogiochi disponibili su svariate piattaforme (*user agent*): browser web, desktop computer, smartphone e tablet... L'applicazione è intesa per essere utilizzata da videogiochi disponibili su svariate piattaforme (*user agent*): browser web, desktop computer, smartphone, tablet...
A tale scopo, si è scelto di realizzarla come una web API attraverso la quale essi possano interfacciarsi in modo controllato con il database Redis. A tale scopo, si è scelto di realizzarla come una web API, attraverso la quale gli user agent possono interfacciarsi in modo controllato al database Redis.
![Diagramma di funzionamento di Distributed Arcade](media/diagram-app.png) ![Diagramma di funzionamento di Distributed Arcade](media/diagram-app.png)
### Linguaggio e dipendenze ### Linguaggio e dipendenze
Al fine di minimizzare il tempo richiesto per l'esecuzione di una richiesta, si è deciso di realizzarla con [Rust](http://rust-lang.org/), un nuovo linguaggio di programmazione compilato ed efficiente, e in particolare con il framework web [Axum](https://crates.io/crates/axum). Al fine di minimizzare il tempo richiesto per l'esecuzione di una richiesta, si è deciso di realizzare l'applicazione in [Rust](http://rust-lang.org/), un linguaggio di programmazione compilato, sicuro ed efficiente, e in particolare con il framework web [Axum](https://crates.io/crates/axum).
Per permettere all'applicazione di interfacciarsi con Redis, si è scelto di usare la crate [`redis`](https://crates.io/crates/redis) di Rust, che gestisce i dettagli a basso livello di connessione e permette di chiamare comandi Redis all'interno del codice come se fossero funzioni. Per permettere all'applicazione di interfacciarsi con Redis, si è scelto di usare la [crate `redis`](https://crates.io/crates/redis), che gestisce i dettagli a basso livello di connessione e permette di chiamare comandi Redis all'interno del codice come se fossero coroutine.
```rust ```rust
// Un esempio di chiamata del comando Redis ZSCORE da Rust // Un esempio di chiamata del comando Redis ZSCORE da Rust
@ -233,8 +233,6 @@ let score: f64 = rconn.zscore("board:example:scores", "player:steffo").await
Distributed Arcade permette agli user agent che vi si connettono di effettuare [6 tipi di operazioni](https://petstore.swagger.io/?url=https://raw.githubusercontent.com/Steffo99/distributed-arcade/main/docs/openapi.yaml). Distributed Arcade permette agli user agent che vi si connettono di effettuare [6 tipi di operazioni](https://petstore.swagger.io/?url=https://raw.githubusercontent.com/Steffo99/distributed-arcade/main/docs/openapi.yaml).
![Screenshot della documentazione OpenAPI di Distributed Arcade, renderizzata attraverso Swagger UI](media/screenshot-openapi.png)
#### Ping semplice #### Ping semplice
Effettuando una richiesta `HTTP GET /`, è possibile verificare che la parte web dell'applicazione sia configurata correttamente. Effettuando una richiesta `HTTP GET /`, è possibile verificare che la parte web dell'applicazione sia configurata correttamente.
@ -247,18 +245,18 @@ In caso positivo, essa risponderà all'user agent con il codice di successo `HTT
Effettuando una richiesta `HTTP POST /`, è possibile verificare che sia l'applicazione sia Redis siano configurati correttamente. Effettuando una richiesta `HTTP POST /`, è possibile verificare che sia l'applicazione sia Redis siano configurati correttamente.
Se l'applicazione è configurata correttamente, essa invia il comando [`PING`](https://redis.io/commands/ping/) al database Redis, e se anch'esso è configurato correttamente, risponderà con la stringa `PONG`, che sarà verificata da Distributed Arcade, rispondendo all'user agent con `HTTP 204`. Se l'applicazione è configurata correttamente, essa invierà il comando [`PING`](https://redis.io/commands/ping/) a Redis, e se anch'esso è configurato correttamente, risponderà con la stringa `PONG`, che sarà verificata da Distributed Arcade, rispondendo all'user agent con `HTTP 204`.
![Diagramma di funzionamento del ping completo](media/diagram-post-ping.png) ![Diagramma di funzionamento del ping completo](media/diagram-post-ping.png)
#### Creazione di board #### Creazione di board
Nell'applicazione, amministratori autorizzati possono creare ***board*** ("tabelloni", da *leaderboard*, "classifica"), ricevendo un ***token*** (una stringa di testo url-safe generata in modo crittograficamente sicuro) per l'immissione di punteggi in quello specifico board. Nell'applicazione, amministratori autorizzati possono creare ***board*** ("tabelloni", da *leaderboard*, "classifica"), ricevendo un ***token*** (una stringa di testo url-safe generata in modo crittograficamente sicuro) per l'immissione di punteggi in esso.
Perchè venga creato un board, l'amministratore dovrà inviare una richiesta `HTTP POST /board/` verso l'applicazione con i dati del board che si vuole creare: Per creare un board, l'amministratore deve inviare una richiesta `HTTP POST /board/` verso l'applicazione, contenente i dati del board che vuole creare:
* il nome del board * il ***nome*** del board
* l'ordinamento del board, ovvero se i punteggi migliori sono quelli più bassi (***crescente***, come nel golf o nelle gare di corsa) o quelli più alti (***decrescente***, come nel salto in alto o nel calcio) * l'***ordinamento*** del board, ovvero se devono essere considerati migliori i punteggi più bassi (***crescente***, come nel golf o nelle gare di corsa) o più alti (***decrescente***, come nel salto in alto o nel calcio)
Per ostacolare attacchi [denial-of-service](https://en.wikipedia.org/wiki/Denial-of-service_attack) al database Redis, si richiede all'amministratore di allegare alla richiesta (nell'header `Authorization`) una password, impostata all'installazione di Distributed Arcade. Per ostacolare attacchi [denial-of-service](https://en.wikipedia.org/wiki/Denial-of-service_attack) al database Redis, si richiede all'amministratore di allegare alla richiesta (nell'header `Authorization`) una password, impostata all'installazione di Distributed Arcade.
@ -268,7 +266,7 @@ Per la creazione effettiva del board, internamente vengono effettuate alcune ope
2. viene verificato che nessuna delle chiavi utilizzate dal board contengano già dati 2. viene verificato che nessuna delle chiavi utilizzate dal board contengano già dati
3. viene salvato l'ordinamento nella chiave `board:{name}:order` con il comando [`SET`] 3. viene salvato l'ordinamento nella chiave `board:{name}:order` con il comando [`SET`]
4. viene generata in modo crittograficamente sicuro una stringa detta ***token*** che viene archiviata nella chiave `board:{name}:token` con il comando [`SET`] 4. viene generata in modo crittograficamente sicuro una stringa detta ***token*** che viene archiviata nella chiave `board:{name}:token` con il comando [`SET`]
5. viene eseguita in blocco la transazione attraverso il comando [`EXEC`] 5. viene eseguita la transazione attraverso il comando [`EXEC`]
Terminata la creazione, l'user agent riceve una risposta `HTTP 201` contenente il token generato. Terminata la creazione, l'user agent riceve una risposta `HTTP 201` contenente il token generato.
@ -373,9 +371,11 @@ Al fine di verificare correttezza ed efficacia del software, sono stati effettua
### Richieste manuali ### Richieste manuali
All'applicazione è stata allegato un file [`openapi.yaml`](https://github.com/Steffo99/distributed-arcade/blob/main/docs/openapi.yaml), che descrive tutti i metodi dell'API e può essere interpretato da software esterni [per essere renderizzato](https://petstore.swagger.io/?url=https://raw.githubusercontent.com/Steffo99/distributed-arcade/main/docs/openapi.yaml) o perchè essi forniscano [assistenza allo sviluppo di consumatori dell'API](https://www.jetbrains.com/help/idea/openapi.html). All'applicazione è stata allegato un file [`openapi.yaml`](https://github.com/Steffo99/distributed-arcade/blob/main/docs/openapi.yaml), che descrive tutti i metodi dell'API e può essere interpretato da software esterni [per essere renderizzato](https://swagger.io/tools/swagger-ui/) o perchè essi forniscano [assistenza allo sviluppo di consumatori dell'API](https://www.jetbrains.com/help/idea/openapi.html).
Per effettuare test manuali di correttezza dell'API, si è fatto particolare uso di uno di questi renderer, [Swagger UI](https://swagger.io/tools/swagger-ui/). Per effettuare test manuali di correttezza dell'API, si è fatto particolare uso di uno di questi renderer, [**Swagger UI**](https://petstore.swagger.io/?url=https://raw.githubusercontent.com/Steffo99/distributed-arcade/main/docs/openapi.yaml).
![Screenshot della documentazione OpenAPI di Distributed Arcade, renderizzata attraverso Swagger UI](media/screenshot-openapi.png)
### Richieste HTTP di esempio ### Richieste HTTP di esempio
@ -385,18 +385,17 @@ All'applicazione è stato anche allegato un file [`examples.http`](https://githu
Per verificare l'efficienza dell'applicazione e del database Redis ad essa connesso, è stato utilizzato [Siege](https://www.joedog.org/siege-home/), un tool per lo stress testing di siti web, configurandolo in modo che inviasse più richieste HTTP possibili di [invio di punteggi](invio-di-punteggi). Per verificare l'efficienza dell'applicazione e del database Redis ad essa connesso, è stato utilizzato [Siege](https://www.joedog.org/siege-home/), un tool per lo stress testing di siti web, configurandolo in modo che inviasse più richieste HTTP possibili di [invio di punteggi](invio-di-punteggi).
I risultati ottenuti sono stati eccellenti: è stato raggiunto prima un collo di bottiglia nell'invio delle richieste che nell'elaborazione di esse, raggiungendo le **2400 richieste processate/secondo** in locale su un `AMD Ryzen 5 1600X Six-Core @ 12x 3.6GHz`! I risultati ottenuti sono stati eccellenti: è stato raggiunto prima un collo di bottiglia nell'invio delle richieste che nell'elaborazione di esse, superando le **2400 richieste processate/secondo** in locale su un `AMD Ryzen 5 1600X Six-Core @ 12x 3.6GHz`!
## Possibile estensione: clustering ## Possibile estensione: clustering
Nel caso sia necessaria una capacità di elaborazione ancora più elevata, modificando leggermente il nome delle chiavi utilizzate per i board, dovrebbe essere possibile realizzare un [cluster](clustering) di client Redis, permettendo un maggiore throughput in scrittura su diversi board. Nel caso fosse necessaria una capacità di elaborazione ancora più elevata, modificando leggermente il nome delle chiavi utilizzate per i board per renderle compatibili, dovrebbe essere possibile realizzare un [cluster](clustering) di client Redis, permettendo un maggiore throughput in scrittura.
## Conclusione ## Conclusione
Redis rispetta le caratteristiche con cui si presenta, ovvero di **semplicità**, **efficienza**, **velocità** e **scalabilità**, confermandosi una buona scelta sia nella sua tipica funzione di database secondario, sia nella meno convenzionale funzione di database secondario. Redis rispetta le caratteristiche con cui si presenta, ovvero di **semplicità**, **efficienza**, **velocità** e **scalabilità**, confermandosi una buona scelta sia nella sua tipica funzione di database secondario, sia nella meno convenzionale funzione di database secondario.
L'applicazione sviluppata ha soddisfatto tutti i requisiti che ci si era posti all'inizio dello sviluppo, ed è stata messa in produzione con successo: è raggiungibile all'indirizzo *https://arcade.steffo.eu/*. L'applicazione sviluppata ha soddisfatto tutti i requisiti che ci si era posti all'inizio dello sviluppo, ed è stata messa in produzione con successo: è raggiungibile all'indirizzo *[https://arcade.steffo.eu/](https://arcade.steffo.eu/)*, e si spera di utilizzarla in applicazioni future.
Si spera di utilizzarla per applicazioni future.
## Bibliografia ## Bibliografia