DynamoDB
Clase 44 de 75 • Curso de AWS Certified Solutions Architect Associate
DynamoDB: Diseño y Optimización de Bases de Datos NoSQL en AWS
Durante el lanzamiento de su programa de recompensas en 2024, Nexia Bank enfrentó uno de sus días de mayor tráfico, con millones de transacciones de canje, consulta de puntos y movimientos financieros ocurriendo simultáneamente. Para garantizar un rendimiento constante sin importar la carga, la arquitectura del banco se apoyó en Amazon DynamoDB, una base de datos NoSQL completamente administrada que escala automáticamente.
Durante los picos más altos, DynamoDB procesó más de 85 millones de solicitudes por segundo sin degradación del servicio, permitiendo que los usuarios experimentaran tiempos de respuesta bajos y una experiencia completamente fluida. Esta capacidad de escalar sin comprometer el rendimiento convirtió a DynamoDB en un componente clave de la infraestructura digital de Nexia Bank, especialmente en iniciativas que exigen velocidad, resiliencia y disponibilidad en tiempo real.
Fundamentos de DynamoDB
DynamoDB es un servicio de base de datos NoSQL completamente administrado por AWS que proporciona un rendimiento predecible y escalable. A diferencia de las bases de datos relacionales tradicionales, DynamoDB utiliza un modelo de datos key-value y document, lo que permite una flexibilidad significativa en el diseño de esquemas.
La característica más destacada de DynamoDB es su capacidad para ofrecer latencias consistentes de milisegundos de un solo dígito, independientemente del tamaño de los datos. Esto lo convierte en una opción ideal para aplicaciones que requieren tiempos de respuesta rápidos y predecibles, como juegos en línea, aplicaciones móviles o sistemas de comercio electrónico.
En DynamoDB, los datos se organizan en tablas, y cada tabla contiene elementos (items) que son similares a las filas en bases de datos relacionales. Cada elemento tiene un atributo de clave primaria que lo identifica de manera única dentro de la tabla. La clave primaria puede ser simple (solo una partition key) o compuesta (una partition key y una sort key).
Particiones y Rendimiento
DynamoDB distribuye automáticamente los datos en múltiples particiones para lograr escalabilidad. Cada partición es una unidad de almacenamiento asignada por el servicio, y AWS maneja completamente este proceso de particionamiento.
El rendimiento en DynamoDB se mide y aprovisiona mediante unidades de capacidad:
- Read Capacity Units (RCU): Una RCU representa una lectura fuertemente consistente por segundo para elementos de hasta 4 KB.
- Write Capacity Units (WCU): Una WCU representa una escritura por segundo para elementos de hasta 1 KB.
DynamoDB ofrece dos modos de capacidad:
- Modo aprovisionado: Se especifica la cantidad de RCUs y WCUs que la aplicación necesita.
- Modo bajo demanda: Se paga por solicitud, sin necesidad de planificar la capacidad.
El auto scaling de DynamoDB permite ajustar automáticamente la capacidad aprovisionada en respuesta a los patrones de tráfico reales. Esto es particularmente útil para aplicaciones con patrones de tráfico variables o impredecibles.
// Ejemplo de configuración de Auto Scaling en CloudFormation "ScalableTarget": { "Type": "AWS::ApplicationAutoScaling::ScalableTarget", "Properties": { "MaxCapacity": 100, "MinCapacity": 5, "ResourceId": {"Fn::Join": ["", ["table/", {"Ref": "MiTablaDynamoDB"}]]}, "RoleARN": {"Fn::GetAtt": ["AutoScalingRole", "Arn"]}, "ScalableDimension": "dynamodb:table:WriteCapacityUnits", "ServiceNamespace": "dynamodb" } }
Índices Secundarios
DynamoDB ofrece dos tipos de índices secundarios que permiten consultar los datos utilizando atributos diferentes a la clave primaria:
Índices Secundarios Locales (LSI)
Los LSI se crean en el momento de la creación de la tabla y no se pueden añadir, modificar o eliminar posteriormente. Comparten la misma partition key que la tabla base, pero utilizan una sort key diferente.
Características clave de los LSI:
- Deben crearse al mismo tiempo que la tabla.
- Comparten la capacidad de rendimiento con la tabla base.
- Están limitados a 10 GB por valor de partition key.
- Máximo 5 LSI por tabla.
Índices Secundarios Globales (GSI)
Los GSI son más flexibles y pueden tener una partition key y sort key completamente diferentes a las de la tabla base. Se pueden crear, modificar o eliminar en cualquier momento.
Características clave de los GSI:
- Pueden crearse o eliminarse en cualquier momento.
- Tienen su propia configuración de capacidad de rendimiento.
- No tienen limitaciones de tamaño.
- Máximo 20 GSI por tabla (límite que puede aumentarse).
// Ejemplo de definición de GSI { "AttributeDefinitions": [ {"AttributeName": "UserId", "AttributeType": "S"}, {"AttributeName": "GameTitle", "AttributeType": "S"}, {"AttributeName": "TopScore", "AttributeType": "N"} ], "GlobalSecondaryIndexes": [ { "IndexName": "GameTitleIndex", "KeySchema": [ {"AttributeName": "GameTitle", "KeyType": "HASH"}, {"AttributeName": "TopScore", "KeyType": "RANGE"} ], "Projection": {"ProjectionType": "ALL"}, "ProvisionedThroughput": { "ReadCapacityUnits": 5, "WriteCapacityUnits": 5 } } ] }
Patrones de Acceso y Hot Partitions
Un desafío común en DynamoDB es el problema de las "hot partitions" o particiones calientes, que ocurre cuando una partición específica recibe significativamente más tráfico que otras, lo que puede provocar limitaciones (throttling).
Para evitar las hot partitions, es importante diseñar el modelo de datos y los patrones de acceso adecuadamente:
- Distribución uniforme de la clave de partición: Elegir claves de partición que distribuyan los datos y el tráfico uniformemente.
- Write sharding: Añadir un sufijo aleatorio o calculado a la clave de partición para distribuir las escrituras.
// Ejemplo de write sharding const shardId = Math.floor(Math.random() * 10); // 0-9 const partitionKey = `user_${userId}_${shardId}`;
- Caché de resultados: Utilizar servicios como ElastiCache para reducir la carga en DynamoDB.
- Diseño de tablas para patrones de acceso específicos: A veces, es mejor duplicar datos en múltiples tablas optimizadas para diferentes patrones de acceso que intentar hacer que una sola tabla sirva para todos los casos de uso.
DynamoDB Streams y Lambda
DynamoDB Streams captura una secuencia ordenada en el tiempo de modificaciones a nivel de elemento en cualquier tabla DynamoDB y almacena esta información en un log durante 24 horas. Las aplicaciones pueden acceder a este log y ver los elementos de datos tal como aparecían antes y después de ser modificados.
DynamoDB Streams se integra perfectamente con AWS Lambda para crear arquitecturas event-driven:
- Habilitación de Streams: Se configura a nivel de tabla con diferentes vistas (KEYS_ONLY, NEW_IMAGE, OLD_IMAGE, NEW_AND_OLD_IMAGES).
- Función Lambda: Se crea una función que procesa los eventos del stream.
- Mapeo de eventos: Se configura un Event Source Mapping que conecta el stream con la función Lambda.
// Ejemplo de función Lambda para procesar eventos de DynamoDB Streams exports.handler = async (event) => { for (const record of event.Records) { if (record.eventName === 'INSERT') { console.log('Nuevo elemento insertado:', JSON.stringify(record.dynamodb.NewImage)); // Lógica para procesar el nuevo elemento } else if (record.eventName === 'MODIFY') { console.log('Elemento modificado:', JSON.stringify({ old: record.dynamodb.OldImage, new: record.dynamodb.NewImage }) ); // Lógica para procesar la modificación } else if (record.eventName === 'REMOVE') { console.log('Elemento eliminado:', JSON.stringify(record.dynamodb.OldImage)); // Lógica para procesar la eliminación } } return { status: 'success' }; };
Este patrón permite implementar casos de uso como:
- Replicación de datos entre regiones
- Auditoría de cambios
- Notificaciones en tiempo real
- Materialización de vistas
- Análisis de datos en tiempo real
DynamoDB es una herramienta poderosa en el arsenal de un arquitecto de soluciones AWS. Su capacidad para escalar horizontalmente mientras mantiene latencias consistentes la hace ideal para aplicaciones modernas con altas demandas de rendimiento. Sin embargo, aprovechar todo su potencial requiere comprender sus principios de diseño y patrones de uso. Al dominar conceptos como particionamiento, índices secundarios, patrones de acceso eficientes y la integración con servicios como Lambda, podrán diseñar soluciones que sean no solo escalables y de alto rendimiento, sino también rentables.