Por qué DynamoDB garantiza milisegundos de un dígito - Estructura interna del particionamiento y el router de solicitudes
Explicamos el mecanismo por el cual DynamoDB mantiene latencia de milisegundos de un dígito independientemente de la escala, desde la arquitectura de 3 capas: algoritmo de particionamiento, router de solicitudes y nodos de almacenamiento.
Lo que significa la promesa de milisegundos de un dígito
DynamoDB declara públicamente que puede leer y escribir con latencia de milisegundos de un dígito independientemente del tamaño de la tabla o la cantidad de solicitudes. Esta promesa se cumple tanto para una tabla de 1KB como para una de 100TB, y tanto para 10 solicitudes por segundo como para 10 millones. En bases de datos relacionales, a medida que crece el tamaño de la tabla, la profundidad del índice aumenta, el I/O de disco se incrementa y la latencia se degrada. DynamoDB puede evitar este problema porque la forma de almacenar datos y la ruta de acceso son fundamentalmente diferentes. DynamoDB divide los datos en unidades pequeñas llamadas particiones y coloca cada partición en nodos de almacenamiento independientes. Como las solicitudes siempre se ejecutan contra una sola partición, el tamaño total de la tabla no afecta la latencia de solicitudes individuales. Este es el núcleo de la latencia constante independiente de la escala.
Particionamiento - Mecanismo de distribución horizontal automática de datos
El particionamiento de DynamoDB está completamente automatizado y los usuarios no necesitan preocuparse por ello. Cada partición almacena un máximo de 10GB de datos y puede procesar un throughput máximo de 3,000 RCU (Read Capacity Units) o 1,000 WCU (Write Capacity Units). Cuando la cantidad de datos o el throughput de la tabla alcanza estos límites, DynamoDB divide automáticamente las particiones. Los datos se distribuyen a cada partición basándose en el valor hash de la clave de partición. Lo importante aquí es el diseño de la clave de partición. Si todas las solicitudes se concentran en la misma clave de partición, solo esa partición se convierte en un hotspot y se produce throttling al alcanzar el límite de throughput. Con la capacidad adaptativa introducida en 2019, se realiza la redistribución automática del throughput hacia particiones calientes, pero la solución fundamental es distribuir el acceso uniformemente mediante el diseño de la clave de partición. Por ejemplo, si se usa la fecha como clave de partición, el acceso se concentra en la partición de hoy. El patrón de write sharding que añade un sufijo aleatorio a la fecha es la técnica estándar para distribuir.
Router de solicitudes - Identificación instantánea de la partición correcta
El router de solicitudes de DynamoDB es el componente que recibe las solicitudes del cliente, identifica la partición objetivo a partir del valor hash de la clave de partición y reenvía la solicitud al nodo de almacenamiento que contiene esa partición. AWS publicó la estructura interna del router de solicitudes en su paper de 2022 "Amazon DynamoDB: A Scalable, Predictably Performant, and Fully Managed NoSQL Database Service". El router de solicitudes cachea en memoria el mapa de particiones (qué rango de claves de partición está en qué nodo de almacenamiento), y la decisión de enrutamiento se completa en microsegundos. Cuando ocurre una división o movimiento de partición, el mapa se actualiza asincrónicamente. Si temporalmente se referencia un mapa antiguo, el nodo de almacenamiento devuelve una respuesta de redirección y el router actualiza el mapa y reintenta. Este mecanismo asegura que el procesamiento de solicitudes no se interrumpa durante la reubicación de particiones. Múltiples instancias del router operan en paralelo, sin constituir un punto único de fallo.
Nodos de almacenamiento y replicación - Mecanismo de escritura triple
Los datos de cada partición se replican en 3 nodos de almacenamiento. Las solicitudes de escritura son recibidas primero por el nodo líder y replicadas a 2 nodos seguidores. Cuando la escritura se completa en 2 de los 3 nodos (líder + 1 seguidor), se devuelve la respuesta de éxito al cliente. Esto es la escritura de quórum 2 de 3. La lectura tiene 2 modos. La lectura eventualmente consistente (Eventually Consistent Read) lee de cualquiera de los 3 nodos. Puede que la escritura más reciente no esté reflejada, pero la latencia es la más baja. La lectura fuertemente consistente (Strongly Consistent Read) lee del nodo líder, por lo que siempre devuelve los datos más recientes, pero como la carga se concentra en el nodo líder, el throughput se reduce a la mitad comparado con la lectura eventualmente consistente. En el paper de DynamoDB publicado en 2023, se reveló que los nodos de almacenamiento utilizan un motor basado en B-tree. La adopción de B-tree en lugar de LSM-tree (Log-Structured Merge-tree) es una decisión de diseño que prioriza la predictibilidad de la latencia de lectura.
Global Tables y DAX - Reduciendo aún más los milisegundos de un dígito
Los milisegundos de un dígito de DynamoDB se refieren a la latencia dentro de la misma región. Para aplicaciones desplegadas globalmente, existe la necesidad de leer y escribir datos en la región más cercana al usuario. Global Tables crea automáticamente réplicas de la tabla en múltiples regiones, proporcionando replicación multi-master que permite leer y escribir desde cualquier región. Una escritura en la región de Tokio se propaga a las réplicas de Virginia y Frankfurt en segundos. La consistencia entre réplicas es eventual, pero las lecturas y escrituras dentro de la misma región se procesan con la misma latencia de milisegundos de un dígito que DynamoDB normal. Si se necesita latencia aún menor, se utiliza DAX (DynamoDB Accelerator). DAX es una caché en memoria colocada delante de DynamoDB que reduce la latencia de lectura a microsegundos (cientos de microsegundos). DAX es compatible con la API de DynamoDB, por lo que el cambio en el código de la aplicación es solo reemplazar el endpoint. Sin embargo, como DAX es una caché, las lecturas inmediatamente después de una escritura pueden devolver datos antiguos. Es necesario un diseño que considere la configuración de TTL de la caché y los patrones de lectura después de escritura. Para comprender en profundidad los patrones de diseño de bases de datos NoSQL, pueden ser útiles libros especializados (Amazon).