Blog de Amazon Web Services (AWS)

Eligiendo la Clave de Partición Correcta en DynamoDB

Por Gowri Balasubramanian, Arquitecto de Soluciones Senior en AWS

 

Esta publicación de blog cubre consideraciones y estrategias importantes para elegir la clave de partición adecuada al diseñar un esquema de bases de datos NoSQL que utilice Amazon DynamoDB. Elegir la clave de partición correcta es un paso importante en el diseño y la creación de aplicaciones escalables y confiables sobre DynamoDB.

 

¿Qué es una clave de partición (partition key)?

DynamoDB soporta dos tipos de clave primarias:

  • Clave de partición: Una clave primaria simple, compuesta por un solo atributo denominado clave de partición. Atributos en DynamoDB son similares en muchas formas a lo que conocemos como columnas en otros sistemas de bases de datos.
  • Clave de partición y clave de ordenamiento: Denominada clave principal compuesta, este tipo de clave se compone de dos atributos. El primer atributo es la clave de partición y el segundo atributo es la clave de ordenamiento (sort key). A continuación se presenta un ejemplo.

 

 

¿Por qué necesito una clave de partición?

DynamoDB almacena los datos como grupos de atributos, conocidos como elementos. Los elementos son similares a las filas o registros de otros sistemas de bases de datos. DynamoDB almacena y recupera cada elemento en función del valor de la clave principal, que debe ser único. Los elementos se distribuyen entre unidades de almacenamiento de 10 GB cada una, denominadas particiones (almacenamiento físico interno de DynamoDB). Cada tabla tiene una o más particiones, como se muestra en la siguiente ilustración. Para obtener más información, consulte Particiones y distribución de datos en la Guía para Desarrolladores de DynamoDB.

DynamoDB utiliza el valor de la clave de partición como parámetro de entrada para una función hash interna. El resultado de la función hash determina la partición en la que se almacena el elemento. La ubicación de cada elemento viene determinada por el valor hash de su clave de partición

Todos los elementos con la misma clave de partición se almacenan juntos y, para las claves de partición compuestas, se ordenan por el valor de la clave de ordenación. DynamoDB divide las particiones por clave de ordenación si el tamaño de la colección crece más de 10 GB

 

 

Claves de partición y limitación de solicitudes

DynamoDB distribuye uniformemente el desempeño aprovisionado (unidades de capacidad de lectura (RCUs) y unidades de capacidad de escritura (WCUs)) entre las particiones y admite automáticamente los patrones de acceso mediante el rendimiento que ha aprovisionado. Sin embargo, si el patrón de acceso supera los 3,000 RCU o 1,000 WCU para un único valor de clave de partición, es posible que las solicitudes se demoren (throttle) retornando un mensaje de error ProvisionedThroughputExceededException.

Leer o escribir por encima del límite puede deberse a alguno de los siguientes problemas:

  • Distribución desigual de los datos debido a la elección incorrecta de la clave de partición
  • Acceso frecuente de la misma clave en una partición (el elemento más popular, también conocido como “clave de partición caliente”)
  • Una tasa de solicitud mayor que el rendimiento aprovisionado

Para evitar la limitación de solicitudes (throttling), diseñe la tabla de DynamoDB con la clave de partición adecuada para satisfacer sus requisitos de acceso y proporcionar una distribución uniforme de los datos.

 

Recomendaciones para claves de partición

Utilice atributos de cardinalidad alta. Se trata de atributos que tienen valores distintos para cada elemento, como dirección de correo electrónico, código de empleado, código de cliente, número de sesión, número de orden, etc.

Utilice atributos compuestos. Intente combinar más de un atributo para formar una clave única, si cumple con su patrón de acceso. Por ejemplo, considere una tabla Ordenes con codigocliente+codigoproducto+codigopais como clave de partición y fecha_orden como clave de ordenamiento.

Almacene en caché los elementos más populares. Cuando exista un gran volumen de tráfico de lectura considere utilizar Amazon DynamoDB Accelerator (DAX). La memoria caché actúa como un filtro de bajo impacto que impide que las lecturas de elementos inusualmente populares inunden las particiones. Por ejemplo, considere una tabla que tiene información de transacciones para productos. Se espera que algunas ofertas sean más populares que otras durante los principales eventos de promoción como el Viernes Negro (Black Friday) o el Lunes Cibernético (Cyber Monday). DAX es un servicio administrado de memoria caché especialmente diseñado para DynamoDB que no requiere que los desarrolladores administren la invalidación de la memoria caché, actualización de datos o la administración de los clústeres. Adicionalmente, DAX es nativamente compatible con las llamadas a la API de DynamoDB, por lo que los desarrolladores pueden incorporarlo fácilmente en aplicaciones preexistentes.

Agregue números aleatorios o dígitos de un intervalo predeterminado para casos de uso con mucha escritura. Supongamos que espera un gran volumen de escrituras para una clave de partición (por ejemplo, más de 1000 escrituras de 1 KB por segundo). En este caso, use un prefijo o sufijo adicional (un número fijo del rango predeterminado, por ejemplo, 1–10) y agréguelo a la clave de partición.

Por ejemplo, considere una tabla de transacciones de facturación. Una sola factura puede contener miles de transacciones por cliente. ¿Cómo garantizamos la unicidad y la capacidad de consultar y actualizar los detalles de la factura para clientes de alto volumen?

A continuación se indica el diseño de tabla recomendado para este escenario:

  • Clave de partición: Agregue un sufijo aleatorio (1–10 o 1–100) con el NumeroFactura, dependiendo del número de transacciones por NumeroFactura. Por ejemplo, supongamos que un único NumeroFactura contiene hasta 50,000 elementos de 1 KB y que espera 5,000 escrituras por segundo. En este caso, puede utilizar la siguiente fórmula para estimar el intervalo de sufijos: (Número de escrituras por segundo * (redondeo (tamaño del elemento en KB),0)* 1 KB ) /1000). El uso de esta fórmula requiere un mínimo de cinco particiones para distribuir las escrituras y, por lo tanto, es posible que desee establecer el intervalo como 1-5
  • Clave de ordenamiento: CodigoTransaccionCliente

 

Clave de Partición

Clave de Ordenación Atributo1
NumeroFactura+Sufijo CodigoTransaccionCliente FechaFactura
121212-1 Cliente1_trans1 2016-05-17 01.36.45
121212-1 Cliente1-trans2 2016-05-18 01.36.30
121212-2 Cliente2_trans1 2016-06-15 01.36.20
121212-2 Cliente2_trans2

2016-07-1 01.36.15

 

  • Esta combinación nos da una buena distribución a través de las particiones. También nos ofrece la posibilidad de usar la clave de ordenamiento para filtrar por un cliente específico (por ejemplo, donde NumeroFactura=“121212-1” y CodigoTransaccionCliente comienza con “Cliente1”).
  • Debido a que tenemos un número aleatorio anexado a nuestra clave de partición (1–5), necesitamos consultar la tabla cinco veces para un NumeroFactura determinado. Nuestra clave de partición podría ser “121212-[1-5]”, por lo que necesitamos consultar dónde está la clave de partición “121212-1” y CodigoTransaccionCliente comienza con “Cliente1”. Necesitamos repetir esto para 121212-2, hasta 121212-5 y luego fusionar los resultados.

Nota:

Una vez decidido el intervalo de sufijos, no hay manera fácil de distribuir aún más los datos porque las modificaciones de sufijo también requieren cambios en la aplicación. Por lo tanto, considere qué tan caliente podría ser cada clave de partición (hot partition key) y agregue un sufijo aleatorio suficiente (con búfer) como para acomodar el crecimiento futuro anticipado.

Esta opción induce latencia adicional para las lecturas debido al número X de solicitudes de lectura por consulta

Como se menciona en la documentación de DynamoDB, una estrategia de escritura aleatorizado puede mejorar considerablemente el rendimiento. Pero es difícil leer un elemento específico porque no se sabe qué valor de sufijo se usó al escribir el elemento.

Para facilitar la lectura de elementos individuales, considere la posibilidad de particionar mediante sufijos calculados, como se explica en Uso del particionamiento de escritura para distribuir cargas de trabajo de forma uniforme en la Guía para desarrolladores de DynamoDB.  Por ejemplo, supongamos que se está procesando un gran número de transacciones de factura pero el patrón de lectura es retornar un pequeño número de elementos para un CodigoFuente determinado por intervalo de fechas. En este caso, es más eficaz distribuir los elementos entre un rango de particiones mediante un atributo determinado, en este caso CodigoFuente.  Puede aplicar un algoritmo hash al CodigoFuente para coplementar la clave de partición en lugar de utilizar la estrategia de números aleatorios.  De esta manera, sabrá qué partición consultar y recuperar los resultados de la tabla.

Al igual que con las tablas, se recomienda considerar un enfoque de particionamiento mediante sufijos para los índices secundarios globales si está anticipando un escenario de clave de partición caliente (hot partition key) con un índice secundario global.

Por ejemplo, considere el siguiente diseño de esquema de una tabla TransaccionesFacturas. Tiene una fila de encabezado para cada factura y contiene atributos como el importe total adeudado y país de la transacción (PaisTransaccion), que son únicos para cada factura. Suponiendo que necesitamos encontrar la lista de facturas emitidas para cada país de transacción, podemos crear un índice secundario global con PaisTransaccion como la clave de partición. Sin embargo, este enfoque conduce a un escenario de escritura de clave de partición caliente, porque el número de facturas por país se distribuye de forma desigual.

En la tabla siguiente se muestra el diseño recomendado con un enfoque de particionamiento de escritura.

 

Clave de Partición Tabla Clave de Ordenamiento Tabla Atributo1 Atributo 2 (clave de partición GSI) Atributo 3 (clave de ordenamiento GSI) Atributo 4 Atributo 5
NumeroFactura ClaveOrdenacion FechaFactura PrefijoAleatorio PaisTransaccion MontoTotal Moneda
121212 ElementoMaestro 2018-05-17 T1 (1-N) USA 10,000 USD
121213 ElementoMaestro 2018-04-01 T2 (1-N) USA 500,000 USD
121214 ElementoMaestro 2018-04-01 T2 (1-N) FRA 500,000 EUR

 

A continuación se muestran los índices secundarios globales (GSI) del escenario anterior

Clave de Partición GSI Clave de Ordenamiento GSI Atributo Projectado 1 Atributo Projectado 2
ClaveParticion PaisTransaccion NumeroFactura OtroAtributo
(1-N) USA 121212
(1-N) USA 121213
(1-N) FRA 121214

 

En el ejemplo anterior, es posible que desee identificar la lista de números de factura asociados con los EE. UU. En este caso, puede emitir una consulta al índice secundario global con ClaveParticion = (1-N) y PaisTransaccion = USA.

 

Antipatrones para claves de partición

Utilizar secuencias o ID únicos generados por el motor de base de datos como clave de partición, especialmente cuando esté migrando desde bases de datos relacionales. Es habitual usar secuencias (schema.sequence.NEXTVAL) como clave principal para requerir la unicidad en las tablas de Oracle. Las secuencias no se suelen utilizar para acceder a los datos.

A continuación se muestra un diseño de esquema de ejemplo para una tabla de pedidos que se ha migrado de Oracle a DynamoDB. La clave de partición de la tabla principal (IdTransaccion) se está actualizando con un UID. Se crea un GSI con los atributos IdOrden y FechaOrden con fines de consulta.

Clave de Partición Atributo 1 Atributo 2
IdTransaccion IdOrden FechaOrden
1111111 Cliente1-1 2016-05-17 01.36.45
1111112 Cliente1-2 2016-05-18 01.36.30
1111113 Cliente2-1 2016-05-18 01.36.30

 

A continuación se presentan los posibles problemas con este enfoque:

  • No puede usar IdTransaccion para fines de consulta, por lo que pierde la capacidad de usar la clave de partición para realizar una búsqueda rápida de datos
  • Los GSIs solo admiten consistencia eventual, con costos adicionales para lecturas y escrituras

Nota:  Puede utilizar la característica de escrituras condicionales en lugar de secuencias para exigir la unicidad y evitar la sobreescritura de un elemento

El uso de atributos de baja cardinalidad como código de producto como clave de partición y fecha de orden como clave de ordenación aumenta en gran medida la probabilidad de problemas de partición caliente (hot partition). Por ejemplo, si un producto es más popular, las lecturas y escrituras para esa clave son altas, lo que da lugar a problemas de limitación de solicitudes (throttling).

A excepción del comando scan, las operaciones de la API de DynamoDB requieren un operador  igual (EQ) en la clave de partición para las tablas y las GSI. En consecuencia, la clave de partición debe ser algo que la aplicación pueda consultar fácilmente con una búsqueda simple. Un ejemplo es el uso de key=value, que devuelve un elemento único o pocos elementos. Hay un límite de 1 MB en los elementos que se pueden retornar a través de una sola operación de consulta. Esto significa que debe paginar mediante el atributo LastEvaluatedKey si se excede este límite, lo cual no es óptimo

En resumen: No traslade directamente (lift and shift) las claves principales de la base de datos de origen sin analizar el modelo de datos y los patrones de acceso de la tabla de DynamoDB de destino.

 

Conclusión

Cuando se trata de estrategias de clave de partición de DynamoDB, ninguna solución única se adapta a todos los casos de uso. Debe evaluar varios enfoques en función de la ingesta de datos y el patrón de acceso y, a continuación, elegir la clave más adecuada con la menor probabilidad de llegar a problemas de limitación de solicitudes (throttling). Junto con el mejor diseño de clave de partición, la capacidad adaptable de DynamoDB puede proteger su aplicación de problemas de limitación de solicitudes frente a un patrón de acceso a datos desigual.

Para obtener más instrucciones sobre el diseño de esquemas para varios escenarios, consulte Diseño NoSQL para DynamoDB en la Guía para Desarrolladores de DynamoDB.

 

Este artículo fue traducido del Blog de AWS en Inglés.

 


Sobre el autor

Gowri Balasubramanian es arquitecto de soluciones sénior en Amazon Web Services. Trabaja con los clientes de AWS para proporcionar orientación y asistencia técnica sobre NoSQL y servicios de bases de datos relacionales, ayudándoles a mejorar el valor de sus soluciones cuando utilizan AWS.

 

 

 

 

Sobre el traductor

Camilo Leon es Arquitecto de Soluciones Senior especializado en base de datos en AWS.