Nella maggior parte delle aziende finanziarie, il processamento delle transazioni online (OLTP) spesso si basa su dati statici o aggiornati raramente, noti anche come dati di riferimento. Le fonti di dati di riferimento non sempre necessitano di capacità di transazione ACID, piuttosto hanno bisogno di supporto per query di lettura veloci spesso basate su pattern di accesso dati semplici, e di un’architettura a eventi per garantire che i sistemi di destinazione rimangano aggiornati. Database NoSQL emergono come candidati ideali per soddisfare queste esigenze, e piattaforme cloud come AWS offrono ecosistemi di dati gestiti e altamente resilienti.
In questo articolo, non determinerò quale database NoSQL di AWS sia migliore: il concetto di un database migliore esiste solo all’interno di un contesto specifico e funzionale. Condividerò un laboratorio di codifica per misurare le prestazioni dei database NoSQL gestiti da AWS come DynamoDB, Cassandra, Redis, e MongoDB.
Test di Prestazioni
I will start by defining the performance test case, which will concurrently insert a JSON payload 200 times and then read it 200 times.
Payload JSON
La classe base
/parent
in base_db.py implementa la logica del caso di test di esecuzione di 10 thread concorrenti per creare e leggere 200 record.
#imports
.....
class BaseDB:
def __init__(self, file_name='instrument.json', threads=10, records=20):
...................................
def execute(self):
create_threads = []
for i in range(self.num_threads):
thread = threading.Thread(
target=self.create_records, args=(i,))
create_threads.append(thread)
thread.start()
for thread in create_threads:
thread.join()
read_threads = []
for i in range(self.num_threads):
thread = threading.Thread(target=self.read_records, args=(i,))
read_threads.append(thread)
thread.start()
for thread in read_threads:
thread.join()
self.print_stats()
Ogni thread esegue la routine di scrittura/lettura rispettivamente nei metodi create_records
e read_records
. Si noti che queste funzioni non includono alcuna logica specifica del database, ma misurano piuttosto le prestazioni di ogni esecuzione di lettura e scrittura.
def create_records(self, thread_id):
for i in range(1, self.num_records + 1):
key = int(thread_id * 100 + i)
start_time = time.time()
self.create_record(key)
end_time = time.time()
execution_time = end_time - start_time
self.performance_data[key] = {'Create Time': execution_time}
def read_records(self, thread_id):
for key in self.performance_data.keys():
start_time = time.time()
self.read_record(key)
end_time = time.time()
execution_time = end_time - start_time
self.performance_data[key]['Read Time'] = execution_time
Una volta eseguito il test case, la funzione print_stats
stampa le metriche di esecuzione come la media di lettura/scrittura e i valori di deviazione standard (stdev
), che indicano le prestazioni e la consistenza del database nella lettura/scrittura (una stdev
più piccola implica una performance di esecuzione più consistente).
def print_stats(self):
if len(self.performance_data) > 0:
# Creare un DataFrame di Pandas dai dati delle prestazioni
df = pd.DataFrame.from_dict(self.performance_data, orient='index')
if not df.empty:
df.sort_index(inplace=True)
# Calcolare la media e la deviazione standard per ogni colonna
create_mean = statistics.mean(df['Create Time'])
read_mean = statistics.mean(df['Read Time'])
create_stdev = statistics.stdev(df['Create Time'])
read_stdev = statistics.stdev(df['Read Time'])
print("Performance Data:")
print(df)
print(f"Create Time mean: {create_mean}, stdev: {create_stdev}")
print(f"Read Time mean: {read_mean}, stdev: {read_stdev}")
Codice NoSQL
A differenza dei database relazionali che supportano SQL standard, ogni database NoSQL ha il proprio SDK. Le classi di test case figlie per ogni database NoSQL hanno solo bisogno di implementare un costruttore e le funzioni create_record/read_record
che contengono l’SDK del database proprietario per instaurare una connessione al database e per creare/leggere record in poche righe di codice.
Caso di Test DynamoDB
import boto3
from base_db import BaseDB
class DynamoDB (BaseDB):
def __init__(self, file_name='instrument.json', threads=10, records=20):
super().__init__(file_name, threads, records)
dynamodb = boto3.resource('dynamodb', region_name='us-east-1')
table_name = 'Instruments'
self.table = dynamodb.Table(table_name)
def create_record(self, key):
item = {
'key': key,
'data': self.json_data
}
self.table.put_item(Item=item)
def read_record(self, key):
self.table.get_item(Key={'key': key})
if __name__ == "__main__":
DynamoDB().execute()
Configurazione AWS
Per eseguire questi casi di test delle prestazioni in un account AWS, dovresti seguire questi passaggi:
- Creare un ruolo IAM per EC2 con privilegi per accedere ai servizi dati AWS richiesti.
- Avviare un’istanza EC2 e assegnare il ruolo IAM appena creato.
- Creare ogni istanza di database NoSQL.
Ruolo IAM
Tabella DynamoDB
Spazio delle chiavi Cassandra/Tabella
Si prega di notare che l’host del DB e le credenziali sono stati codificati in modo rigido e rimossi nei moduli mongo_db.py e redis_db.py e dovranno essere aggiornati con le impostazioni di connessione della banca dati corrispondenti per il tuo account AWS. Per connettersi a DynamoDB e Cassandra, ho optato per l’uso delle credenziali della sessione Boto3 temporaneamente assegnate al Ruolo IAM db_performnace_iam_role
. Questo codice verrà eseguito in qualsiasi account AWS nella regione East 1 senza alcuna modifica.
class CassandraDB(BaseDB):
def __init__(self, file_name='instrument.json', threads=10, records=20):
super().__init__(file_name=file_name, threads=threads, records=records)
self.json_data = json.dumps(
self.json_data, cls=DecimalEncoder).encode()
# Configurazione degli spazi delle chiavi Cassandra
contact_points = ['cassandra.us-east-1.amazonaws.com']
keyspace_name = 'db_performance'
ssl_context = SSLContext(PROTOCOL_TLSv1_2)
ssl_context.load_verify_locations('sf-class2-root.crt')
ssl_context.verify_mode = CERT_REQUIRED
boto_session = boto3.Session(region_name="us-east-1")
auth_provider = SigV4AuthProvider(session=boto_session)
cluster = Cluster(contact_points, ssl_context=ssl_context, auth_provider=auth_provider,
port=9142)
self.session = cluster.connect(keyspace=keyspace_name)
Connetti all’istanza EC2 (ho usato il Session Manager) e esegui il seguente script Shell per eseguire queste attività:
- Installare Git.
- Installare Pythion3.
- Clonare il repository GitHub performance_db.
- Installare e attivare l’ambiente virtuale Python3.
- Installare librerie/dipendenze di terze parti.
- Eseguire ogni caso di test.
sudo yum install git
sudo yum install python3
git clone https://github.com/dshilman/db_performance.git
sudo git pull
cd db_performance
python3 -m venv venv
source ./venv/bin/activate
sudo python3 -m pip install -r requirements.txt
cd code
sudo python3 -m dynamo_db
sudo python3 -m cassandra_db
sudo python3 -m redis_db
sudo python3 -m mongo_db
Dovresti vedere la seguente uscita per i primi due casi di test:
(venv) sh-5.2$ sudo python3 -m dynamo_db Dati sulle prestazioni: Create Time Read Time 1 0.336909 0.031491 2 0.056884 0.053334 3 0.085881 0.031385 4 0.084940 0.050059 5 0.169012 0.050044 .. … … 916 0.047431 0.041877 917 0.043795 0.024649 918 0.075325 0.035251 919 0.101007 0.068767 920 0.103432 0.037742
[200 righe x 2 colonne] Media Create Time: 0.0858926808834076, deviazione standard: 0.07714510154026173 Media Read Time: 0.04880355834960937, deviazione standard: 0.028805479258627295 Tempo di esecuzione: 11.499964714050293 |
(venv) sh-5.2$ sudo python3 -m cassandra_db Dati sulle prestazioni: Create Time Read Time 1 0.024815 0.005986 2 0.008256 0.006927 3 0.008996 0.009810 4 0.005362 0.005892 5 0.010117 0.010308 .. … … 916 0.006234 0.008147 917 0.011564 0.004347 918 0.007857 0.008329 919 0.007260 0.007370 920 0.004654 0.006049
[200 righe x 2 colonne] Tempo medio di creazione: 0,009145524501800537, deviazione standard: 0,005201661271831082 Tempo medio di lettura: 0,007248317003250122, deviazione standard: 0,003557610695674452 Tempo di esecuzione: 1,6279327869415283 |
Risultati dei test
DynamoDB | Cassandra | MongoDB | Redis | |
---|---|---|---|---|
Create | mean: 0.0859 stdev: 0.0771 |
mean: 0.0091 stdev: 0.0052 |
mean: 0.0292 std: 0.0764 |
mean: 0.0028 stdev: 0.0049 |
Read | mean: 0.0488 stdev: 0.0288 |
mean: 0.0072 stdev: 0.0036 |
mean: 0.0509 std: 0.0027 |
mean: 0.0012 stdev: 0.0016 |
Exec Time | 11.45 sec | 1.6279 sec | 10.2608 sec | 0.3465 sec |
Miei osservazioni
- I was blown away by Cassandra’s fast performance. Cassandra support for SQL allows rich access pattern queries and AWS Keyspaces offer cross-region replication.
- I find DynamoDB’s performance disappointing despite the AWS hype about it. You should try to avoid the cross-partition table scan and thus must use an index for each data access pattern. DynamoDB global tables enable cross-region data replication.
- MongoDB ha un SDK molto semplice, è divertente da usare e offre il miglior supporto per il tipo di dati JSON. È possibile creare indici e eseguire query complesse su attributi JSON nidificati. Con l’emergere di nuovi formati di dati binari, MongoDB potrebbe perdere il suo fascino.
- Redis ha prestazioni incredibilmente veloci, tuttavia, alla fine della giornata, è un cache chiave/valore anche se supporta tipi di dati complessi. Redis offre potenti funzionalità come il pipelining e la scripting per migliorare ulteriormente le prestazioni delle query passando il codice a Redis da eseguire sul lato server.
Conclusione
In conclusione, scegliere il database NoSQL gestito da AWS per la piattaforma di dati di riferimento aziendale dipende dalle tue priorità specifiche. Se le tue principali preoccupazioni sono prestazioni e replica tra regioni, AWS Cassandra si distingue come un chiaro vincitore. DynamoDB si integra bene con altri servizi AWS come Lambda e Kinesis e quindi è un’ottima opzione per architetture native AWS o serverless. Per le applicazioni che richiedono un robusto supporto per i tipi di dati JSON, MongoDB ha la meglio. Tuttavia, se il tuo focus è su ricerca veloce o gestione sessioni per alta disponibilità, Redis si rivela essere un’ottima opzione. Alla fine, la decisione dovrebbe corrispondere alle esigenze uniche della tua organizzazione.
Come sempre, potete trovare il codice nel repository GitHub collegato in precedenza in questo articolo (vedi Task #3 del script Shell sopra). Non esitate a contattarmi se avete bisogno di aiuto per eseguire questo codice o per la configurazione di AWS.
Source:
https://dzone.com/articles/aws-nosql-performance-lab-using-python