Dans la plupart des entreprises financières, le traitement des transactions en ligne (OLTP) repose souvent sur des données statiques ou peu mises à jour, également appelées données de référence. Les sources de données de référence n’ont pas toujours besoin de capacités de transaction ACID, mais ont plutôt besoin de soutien pour les requêtes de lecture rapides souvent basées sur des modèles d’accès aux données simples, et une architecture basée sur des événements pour garantir que les systèmes cibles restent à jour. Les bases de données NoSQL émergent comme des candidats idéaux pour répondre à ces exigences, et les plateformes cloud telles qu’AWS offrent des écosystèmes de données gérés et hautement résilients.
Dans cet article, je ne vais pas déterminer quelle base de données NoSQL AWS est meilleure : le concept d’une base de données meilleure n’existe que dans un contexte spécifiquement ciblé. Je vais partager un laboratoire de codage pour mesurer les performances des bases de données NoSQL gérées par AWS, telles que DynamoDB, Cassandra, Redis, et MongoDB.
Tests de Performance
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
dans base_db.py met en œuvre la logique du cas de test consistant à exécuter 10 threads simultanés pour créer et lire 200 enregistrements.
#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()
Chaque thread exécute la routine de lecture/écriture dans les create_records
et read_records
, respectivement. Notez que ces fonctions n’incluent aucune logique spécifique à la base de données, mais plutôt, mesurent la performance de chaque exécution de lecture et d’écriture.
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
Une fois que le cas de test est exécuté, la fonction print_stats
imprime les métriques d’exécution telles que la moyenne de lecture/écriture et la valeur de déviation standard (stdev
), qui indiquent la performance et la cohérence de la base de données (une stdev
plus petite implique une performance d’exécution plus cohérente).
def print_stats(self):
if len(self.performance_data) > 0:
# Créer un DataFrame Pandas à partir des données de performance
df = pd.DataFrame.from_dict(self.performance_data, orient='index')
if not df.empty:
df.sort_index(inplace=True)
# Calculer la moyenne et la déviation standard pour chaque colonne
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}")
Code NoSQL
Contrairement aux bases de données relationnelles qui prennent en charge SQL standard, chaque base de données NoSQL possède son propre SDK. Les classes de cas de test enfants pour chaque base de données NoSQL doivent simplement implémenter un constructeur et les fonctions create_record/read_recod
contenant l’SDK de base de données propriétaire pour instancier une connexion à la base de données et créer/lire des enregistrements en quelques lignes de code.
Cas de 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()
Configuration AWS
Pour exécuter ces cas de test de performance dans un compte AWS, vous devriez suivre ces étapes:
- Créer un rôle IAM EC2 avec des privilèges pour accéder aux services de données AWS requis.
- Lancer une instance EC2 et attribuer le rôle IAM nouvellement créé.
- Créer chaque instance de base de données NoSQL.
Rôle IAM
Table DynamoDB
Espace-clé Cassandra/Table
Veuillez noter que l’hôte et les informations d’identification de la base de données ont été hérités et supprimés dans les modules mongo_db.py et redis_db.py et devront être mis à jour avec les paramètres de connexion à la base de données correspondants pour votre compte AWS. Pour se connecter à DynamoDB et Cassandra, j’ai choisi d’utiliser les informations d’identification de session Boto3 temporairement attribuées au Rôle IAM db_performnace_iam_role
. Ce code s’exécutera dans n’importe quel compte AWS de la région Est 1 sans aucune modification.
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()
# Configuration des espaces-clés 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)
Connectez-vous à l’instance EC2 (j’ai utilisé le Gestionnaire de session), et exécutez le script Shell suivant pour effectuer ces tâches:
- Installer Git.
- Installer Pythion3.
- Cloner le dépôt GitHub performance_db.
- Installer et activer l’environnement virtuel Python3.
- Installer les bibliothèques/dépendances tierces.
- Exécuter chaque cas de 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
Vous devriez voir la sortie suivante pour les deux premiers cas de test:
(venv) sh-5.2$ sudo python3 -m dynamo_db Données de performance: Création Temps Lecture Temps 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 lignes x 2 colonnes] Moyenne du temps de création : 0.0858926808834076, écart-type : 0.07714510154026173 Moyenne du temps de lecture : 0.04880355834960937, écart-type : 0.028805479258627295 Temps d’exécution : 11.499964714050293 |
(venv) sh-5.2$ sudo python3 -m cassandra_db Données de performance: Temps de création Temps de lecture 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 lignes x 2 colonnes] Moyenne du temps de création : 0,009145524501800537, écart-type : 0,005201661271831082 Moyenne du temps de lecture : 0,007248317003250122, écart-type : 0,003557610695674452 Temps d’exécution : 1,6279327869415283 |
Résultats des tests
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 |
Mes observations
- 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 dispose d’un SDK très simple, est amusant à utiliser et offre le meilleur support pour le type de données JSON. Vous pouvez créer des index et exécuter des requêtes complexes sur des attributs JSON imbriqués. Avec l’émergence de nouveaux formats de données binaires, MongoDB pourrait perdre de son attrait.
- Redis est incroyablement rapide, cependant, à la fin de la journée, c’est une cache clé/valeur même si elle prend en charge des types de données complexes. Redis propose des fonctionnalités puissantes telles que le pipelining et le scripting pour améliorer davantage les performances des requêtes en passant du code à Redis pour l’exécuter côté serveur.
Conclusion
En conclusion, choisir la base de données NoSQL gérée par AWS pour votre plateforme de données de référence d’entreprise dépend de vos priorités spécifiques. Si la performance et la réplication entre régions sont votre principale préoccupation, AWS Cassandra se démarque clairement comme le gagnant. DynamoDB s’intègre bien avec d’autres services AWS tels que Lambda et Kinesis et est donc une excellente option pour une architecture native AWS ou sans serveur. Pour les applications nécessitant un support robuste pour les types de données JSON, MongoDB prend le dessus. Cependant, si votre objectif est d’obtenir des recherches rapides ou de gérer des sessions pour une haute disponibilité, Redis s’avère être une excellente option. En fin de compte, la décision doit correspondre aux besoins uniques de votre organisation.
Comme toujours, vous pouvez trouver le code dans le dépôt GitHub mentionné plus tôt dans cet article (voir la tâche du script Shell #3 ci-dessus). N’hésitez pas à me contacter si vous avez besoin d’aide pour exécuter ce code ou pour la configuration AWS.
Source:
https://dzone.com/articles/aws-nosql-performance-lab-using-python