En la mayoría de las firmas financieras, el procesamiento de transacciones en línea (OLTP) suele basarse en datos estáticos o poco actualizados, también conocidos como datos de referencia. Las fuentes de datos de referencia no siempre requieren capacidades de transacción ACID, sino que necesitan apoyo para consultas de lectura rápida a menudo basadas en patrones de acceso de datos simples y arquitectura orientada a eventos para garantizar que los sistemas objetivo permanezcan actualizados. Bases de datos NoSQL surgen como candidatos ideales para cumplir con estos requisitos, y las plataformas en la nube como AWS ofrecen ecosistemas de datos gestionados y altamente resilientes.
En este artículo, no voy a determinar cuál base de datos NoSQL de AWS es mejor: el concepto de una base de datos mejor solo existe dentro de un contexto específico y con un propósito determinado. Compartiré un laboratorio de codificación para medir el rendimiento de las bases de datos NoSQL gestionadas por AWS, como DynamoDB, Cassandra, Redis y MongoDB.
Pruebas de Rendimiento
I will start by defining the performance test case, which will concurrently insert a JSON payload 200 times and then read it 200 times.
Carga JSON
La clase base
/parent
en base_db.py implementa la lógica del caso de prueba de ejecutar 10 hilos concurrentes para crear y leer 200 registros.
#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()
Cada hilo ejecuta la rutina de escritura/lectura en el create_records
y read_records
, respectivamente. Tenga en cuenta que estas funciones no incluyen ninguna lógica específica de base de datos, sino que miden el rendimiento de cada ejecución de lectura y escritura.
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 vez ejecutado el caso de prueba, la función print_stats
imprime las métricas de ejecución, como la media de lectura/escritura y los valores de desviación estándar (stdev
), que indican el rendimiento y la consistencia de la base de datos (una stdev
menor implica un rendimiento de ejecución más consistente).
def print_stats(self):
if len(self.performance_data) > 0:
# Crear un DataFrame de Pandas a partir de los datos de rendimiento
df = pd.DataFrame.from_dict(self.performance_data, orient='index')
if not df.empty:
df.sort_index(inplace=True)
# Calcular la media y la desviación estándar para cada columna
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}")
Código NoSQL
A diferencia de las bases de datos relacionales que admiten SQL estándar, cada base de datos NoSQL tiene su propio SDK. Las clases de casos de prueba secundarios para cada base de datos NoSQL solo necesitan implementar un constructor y las funciones create_record/read_recod
que contienen el SDK de base de datos propietario para crear una conexión con la base de datos y crear/leer registros en unas pocas líneas de código.
Caso de Prueba de 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()
Configuración de AWS
Para ejecutar estos casos de prueba de rendimiento en una cuenta de AWS, debe seguir estos pasos:
- Crear un rol de IAM de EC2 con privilegios para acceder a los servicios de datos de AWS requeridos.
- Iniciar una instancia de EC2 y asignar el rol de IAM recién creado.
- Crear cada instancia de base de datos NoSQL.
Rol de IAM
Tabla de DynamoDB
Espacio de claves/Tabla de Cassandra
Tenga en cuenta que el host y las credenciales de la base de datos fueron codificados de forma rígida y eliminados en los módulos mongo_db.py y redis_db.py y necesitarán ser actualizados con la configuración de conexión de la base de datos correspondiente para su cuenta de AWS. Para conectarse a DynamoDB y Cassandra, opté por usar las credenciales de la sesión de Boto3 temporalmente asignadas al Rol de IAM db_performnace_iam_role
. Este código se ejecutará en cualquier cuenta de AWS en la región Este 1 sin ninguna modificación.
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()
# Configuración de Espacios de Claves de 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)
Conéctese a la instancia de EC2 (utilicé el Gestor de Sesión), y ejecute el siguiente script de Shell para realizar estas tareas:
- Instalar Git.
- Instalar Pythion3.
- Clonar el repositorio de GitHub performance_db.
- Instalar y activar el entorno virtual de Python3.
- Instalar bibliotecas/dependencias de terceros.
- Ejecutar cada caso de prueba.
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
Debería ver la siguiente salida para los dos primeros casos de prueba:
(venv) sh-5.2$ sudo python3 -m dynamo_db Datos de Rendimiento: 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 filas x 2 columnas] Media de Create Time: 0.0858926808834076, desv. est.: 0.07714510154026173 Media de Read Time: 0.04880355834960937, desv. est.: 0.028805479258627295 Tiempo de ejecución: 11.499964714050293 |
(venv) sh-5.2$ sudo python3 -m cassandra_db Datos de rendimiento: 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 filas x 2 columnas] Tiempo de creación promedio: 0.009145524501800537, desv. est: 0.005201661271831082 Tiempo de lectura promedio: 0.007248317003250122, desv. est: 0.003557610695674452 Tiempo de ejecución: 1.6279327869415283 |
Resultados de la prueba
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 |
Mis observaciones
- 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 tiene un SDK muy simple, es divertido de usar y tiene el mejor soporte para el tipo de datos JSON. Puedes crear índices y ejecutar consultas complejas en atributos JSON anidados. A medida que surgen nuevos formatos de datos binarios, MongoDB podría perder su atractivo.
- Redis tiene un rendimiento sorprendentemente rápido, sin embargo, al final del día, es una caché de clave/valor, incluso si soporta tipos de datos complejos. Redis ofrece características poderosas como la canalización y la ejecución de scripts para mejorar aún más el rendimiento de las consultas al enviar código a Redis para que lo ejecute en el servidor.
Conclusión
En conclusión, elegir la base de datos NoSQL administrada por AWS para tu plataforma de datos de referencia empresarial depende de tus prioridades específicas. Si el rendimiento y la replicación entre regiones son tu principal preocupación, AWS Cassandra se destaca como un claro ganador. DynamoDB se integra bien con otros servicios de AWS como Lambda y Kinesis y, por lo tanto, es una excelente opción para arquitecturas nativas de AWS o sin servidor. Para aplicaciones que requieren un soporte robusto para tipos de datos JSON, MongoDB toma la delantera. Sin embargo, si tu enfoque es en la búsqueda rápida o la administración de sesiones para alta disponibilidad, Redis demuestra ser una excelente opción. En última instancia, la decisión debe alinearse con las necesidades únicas de tu organización.
Como siempre, puedes encontrar el código en el repositorio de GitHub vinculado anteriormente en este artículo (ver tarea del script de Shell #3 arriba). No dudes en contactarme si necesitas ayuda para ejecutar este código o con la configuración de AWS.
Source:
https://dzone.com/articles/aws-nosql-performance-lab-using-python