In den meisten Finanzunternehmen basiert die Online-Transaktionsverarbeitung (OLTP) oft auf statischen oder selten aktualisierten Daten, auch als Referenzdaten bezeichnet. Quellen für Referenzdaten benötigen nicht immer ACID-Transaktionsfähigkeiten, sondern unterstützen eher schnelle Leseabfragen, die oft auf einfachen Datenzugriffsmustern basieren, und ereignisgesteuerte Architektur, um sicherzustellen, dass die Zielsysteme auf dem neuesten Stand bleiben. NoSQL-Datenbanken stellen sich als ideale Kandidaten zur Erfüllung dieser Anforderungen heraus, und Cloud-Plattformen wie AWS bieten verwaltete und hochresiliente Datenökosysteme.
In diesem Artikel werde ich nicht entscheiden, welche AWS NoSQL-Datenbank besser ist: Das Konzept einer besseren Datenbank existiert nur im Kontext einer bestimmten, zweckdienlichen Situation. Ich werde einen Codierungs-Workshop teilen, um die Leistung von AWS-verwalteten NoSQL-Datenbanken wie DynamoDB, Cassandra, Redis und MongoDB zu messen.
Leistungstest
I will start by defining the performance test case, which will concurrently insert a JSON payload 200 times and then read it 200 times.
JSON-Nutzlast
Die base
/parent
-Klasse in base_db.py implementiert die Testfalllogik zur Ausführung von 10 gleichzeitigen Threads zum Erstellen und Lesen von 200 Datensätzen.
#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()
Jeder Thread führt die Schreib-/Leseroutine in den create_records
und read_records
Funktionen aus, jeweils. Beachten Sie, dass diese Funktionen keine datenbankspezifische Logik enthalten, sondern vielmehr die Leistung jedes Schreib- und Leseausführungszyklus messen.
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
Sobald der Testfall ausgeführt wird, druckt die print_stats
Funktion Ausführungsmetriken wie den Lese-/Schreib-Mittelwert und die Standardabweichung (stdev
)-Werte, die die Datenbank-Lese-/Schreibleistung und Konsistenz anzeigen (eine kleinere stdev
impliziert eine konsistentere Ausführungsleistung).
def print_stats(self):
if len(self.performance_data) > 0:
# Erstellen eines Pandas DataFrame aus Leistungsdaten
df = pd.DataFrame.from_dict(self.performance_data, orient='index')
if not df.empty:
df.sort_index(inplace=True)
# Berechnen des Mittelwerts und der Standardabweichung für jede Spalte
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}")
NoSQL-Code
Im Gegensatz zu relationalen Datenbanken, die standardmäßiges SQL unterstützen, verfügt jede NoSQL-Datenbank über ihre eigene SDK. Die Untertestfallklassen für jede NoSQL-Datenbank müssen nur einen Konstruktor und create_record/read_recod
Funktionen implementieren, die die proprietäre Datenbank-SDK enthalten, um eine Datenbankverbindung herzustellen und um in wenigen Codezeilen Datensätze zu erstellen/lesen.
DynamoDB Test Case
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()
AWS-Setup
Um diese Leistungstestfälle in einem AWS-Konto auszuführen, sollten Sie diese Schritte befolgen:
- Erstellen Sie eine EC2-IAM-Rolle mit Berechtigungen zum Zugreifen auf die erforderlichen AWS-Datendienste.
- Starten Sie eine EC2-Instanz und weisen Sie die neu erstellte IAM-Rolle zu.
- Erstellen Sie jede NoSQL-Datenbankinstanz.
IAM-Rolle
DynamoDB-Tabelle
Cassandra Keyspace/Tabelle
Bitte beachten Sie, dass die Datenbank-Host und -Zugangsdaten in den Modulen mongo_db.py und redis_db.py hartcodiert und entfernt wurden und mit den entsprechenden Datenbankverbindungseinstellungen für Ihr AWS-Konto aktualisiert werden müssen. Um eine Verbindung zu DynamoDB und Cassandra herzustellen, habe ich mich für die vorübergehend zugewiesenen Boto3-Sitzungscredentials für die db_performnace_iam_role
IAM-Rolle entschieden. Dieser Code läuft in jeder AWS-Region Ost 1 ohne Änderungen.
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()
# Konfiguration der Cassandra Keyspaces
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)
Melden Sie sich beim EC2-Instanz (ich habe den Session Manager verwendet) und führen Sie das folgende Shell-Skript aus, um diese Aufgaben durchzuführen:
- Git installieren.
- Pythion3 installieren.
- Klonen Sie das GitHub performance_db Repository.
- Installieren und aktivieren Sie die Python3 virtuelle Umgebung.
- Drittanbieterbibliotheken/Abhängigkeiten installieren.
- Führen Sie jede Testfall aus.
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
Sie sollten die folgende Ausgabe für die ersten beiden Testfälle sehen:
(venv) sh-5.2$ sudo python3 -m dynamo_db Leistungsdaten: Erstellungszeit Lesezeit 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 Zeilen x 2 Spalten] Durchschnittliche Erstellungszeit: 0.0858926808834076, Standardabweichung: 0.07714510154026173 Durchschnittliche Lesezeit: 0.04880355834960937, Standardabweichung: 0.028805479258627295 Ausführungszeit: 11.499964714050293 |
(venv) sh-5.2$ sudo python3 -m cassandra_db Leistungsdaten: Erstellungszeit Lesezeit 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 Zeilen x 2 Spalten] Durchschnittliche Erstellungszeit: 0,009145524501800537, Standardabweichung: 0,005201661271831082 Durchschnittliche Lesezeit: 0,007248317003250122, Standardabweichung: 0,003557610695674452 Ausführungszeit: 1,6279327869415283 |
Testresultate
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 |
Meine Beobachtungen
- 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 verfügt über eine sehr einfache SDK, ist eine Freude zu bedienen und bietet die beste Unterstützung für den JSON-Datentyp. Man kann Indizes erstellen und komplexe Abfragen für verschachtelte JSON-Attribute ausführen. Mit dem Aufkommen neuer binärer Datenformate könnte MongoDB jedoch an Reiz verlieren.
- Redis ist erstaunlich schnell, allerdings handelt es sich trotz Unterstützung komplexer Datentypen letztendlich um einen Schlüssel/Wert-Cache. Redis bietet leistungsstarke Funktionen wie Pipelining und Skripting, um die Abfrageleistung durch Übermittlung von Code zu Redis zur Ausführung auf Serverseite weiter zu verbessern.
Schlussfolgerung
Zusammenfassend hängt die Auswahl der AWS-verwalteten NoSQL-Datenbank für Ihre Unternehmensreferenzdatenplattform von Ihren spezifischen Prioritäten ab. Sollten Leistung und Replikation über Regionen Ihr Hauptanliegen sein, zeichnet sich AWS Cassandra als klares Sieger ab. DynamoDB integriert sich gut mit anderen AWS-Diensten wie Lambda und Kinesis und ist daher eine großartige Option für AWS-native oder serverlose Architekturen. Für Anwendungen, die eine robuste Unterstützung für JSON-Datentypen erfordern, führt MongoDB. Wenn Ihr Fokus jedoch auf schneller Suche oder Sitzungsverwaltung für hohe Verfügbarkeit liegt, erweist sich Redis als ausgezeichnete Option. Letztendlich sollte die Entscheidung sich mit den einzigartigen Anforderungen Ihres Unternehmens vereinbaren.
Wie immer findest du den Code im GitHub-Repository, das weiter oben in diesem Artikel verlinkt wurde (siehe Shell-Skriptaufgabe #3 oben). Zögere nicht, mich zu kontaktieren, wenn du Hilfe bei der Ausführung des Codes oder bei der AWS-Einrichtung benötigst.
Source:
https://dzone.com/articles/aws-nosql-performance-lab-using-python