paint-brush
Cuándo utilizar índices secundarios de DynamoDBpor@rocksetcloud
4,384 lecturas
4,384 lecturas

Cuándo utilizar índices secundarios de DynamoDB

por Rockset16m2024/05/23
Read on Terminal Reader

Demasiado Largo; Para Leer

Los índices secundarios de DynamoDB son una herramienta poderosa para habilitar nuevos patrones de acceso a sus datos.
featured image - Cuándo utilizar índices secundarios de DynamoDB
Rockset HackerNoon profile picture

Los índices son una parte crucial del modelado de datos adecuado para todas las bases de datos y DynamoDB no es una excepción. Los índices secundarios de DynamoDB son una herramienta poderosa para habilitar nuevos patrones de acceso a sus datos.


En esta publicación, veremos los índices secundarios de DynamoDB . Primero, comenzaremos con algunos puntos conceptuales sobre cómo pensar en DynamoDB y los problemas que resuelven los índices secundarios. Luego, veremos algunos consejos prácticos para utilizar índices secundarios de forma eficaz. Finalmente, cerraremos con algunas ideas sobre cuándo debería utilizar índices secundarios y cuándo debería buscar otras soluciones.


Empecemos.

¿Qué es DynamoDB y qué son los índices secundarios de DynamoDB?

Antes de entrar en los casos de uso y las mejores prácticas para los índices secundarios, primero debemos comprender qué son los índices secundarios de DynamoDB . Y para ello, debemos entender un poco cómo funciona DynamoDB.


Esto supone algunos conocimientos básicos de DynamoDB. Cubriremos los puntos básicos que necesita saber para comprender los índices secundarios, pero si es nuevo en DynamoDB, es posible que desee comenzar con una introducción más básica.

Lo mínimo que necesita saber sobre DynamoDB

DynamoDB es una base de datos única. Está diseñado para cargas de trabajo OLTP, lo que significa que es excelente para manejar un gran volumen de operaciones pequeñas: piense en cosas como agregar un artículo a un carrito de compras, darle me gusta a un video o agregar un comentario en Reddit. De esa manera, puede manejar aplicaciones similares a otras bases de datos que haya utilizado, como MySQL, PostgreSQL, MongoDB o Cassandra.


La promesa clave de DynamoDB es su garantía de rendimiento consistente a cualquier escala . Ya sea que su tabla tenga 1 megabyte de datos o 1 petabyte de datos, DynamoDB quiere tener la misma latencia para sus solicitudes tipo OLTP. Esto es un gran problema: muchas bases de datos verán un rendimiento reducido a medida que aumente la cantidad de datos o la cantidad de solicitudes simultáneas. Sin embargo, ofrecer estas garantías requiere algunas compensaciones y DynamoDB tiene algunas características únicas que es necesario comprender para utilizarlo de forma eficaz.


En primer lugar, DynamoDB escala horizontalmente sus bases de datos al distribuir sus datos en varias particiones internas. Estas particiones no son visibles para usted como usuario, pero son la base del funcionamiento de DynamoDB. Especificará una clave principal para su tabla (ya sea un elemento único, llamado "clave de partición", o una combinación de una clave de partición y una clave de clasificación), y DynamoDB usará esa clave principal para determinar en qué partición residen sus datos. . Cualquier solicitud que realice pasará por un enrutador de solicitudes que determinará qué partición debe manejar la solicitud. Estas particiones son pequeñas (generalmente 10 GB o menos), por lo que se pueden mover, dividir, replicar y administrar de otro modo de forma independiente.




La escalabilidad horizontal mediante fragmentación es interesante, pero de ninguna manera es exclusiva de DynamoDB. Muchas otras bases de datos, tanto relacionales como no relacionales, utilizan fragmentación para escalar horizontalmente. Sin embargo, lo que es exclusivo de DynamoDB es cómo le obliga a utilizar su clave principal para acceder a sus datos. En lugar de utilizar un planificador de consultas que traduce sus solicitudes en una serie de consultas, DynamoDB le obliga a utilizar su clave principal para acceder a sus datos. Básicamente, obtiene un índice direccionable directamente para sus datos.


La API de DynamoDB refleja esto. Hay una serie de operaciones en elementos individuales ( GetItem , PutItem , UpdateItem , DeleteItem ) que le permiten leer, escribir y eliminar elementos individuales. Además, existe una operación Query que le permite recuperar varios elementos con la misma clave de partición. Si tiene una tabla con una clave primaria compuesta, los elementos con la misma clave de partición se agruparán en la misma partición. Se ordenarán según la clave de clasificación, lo que le permitirá manejar patrones como "Obtener los pedidos más recientes de un usuario" o "Obtener las últimas 10 lecturas de sensores para un dispositivo IoT".


Por ejemplo, imaginemos una aplicación SaaS que tiene una tabla de Usuarios. Todos los Usuarios pertenecen a una única Organización. Podríamos tener una tabla que se vea así:



Estamos usando una clave primaria compuesta con una clave de partición de 'Organización' y una clave de clasificación de 'Nombre de usuario'. Esto nos permite realizar operaciones para buscar o actualizar un Usuario individual proporcionando su Organización y Nombre de Usuario. También podemos recuperar todos los usuarios de una única organización proporcionando solo la organización a una operación Query .

¿Qué son los índices secundarios y cómo funcionan?

Con algunos conceptos básicos en mente, veamos ahora los índices secundarios. La mejor manera de comprender la necesidad de índices secundarios es comprender el problema que resuelven. Hemos visto cómo DynamoDB divide sus datos según su clave principal y cómo lo obliga a usar la clave principal para acceder a sus datos. Eso está muy bien para algunos patrones de acceso, pero ¿qué sucede si necesita acceder a sus datos de una manera diferente?


En nuestro ejemplo anterior, teníamos una tabla de usuarios a los que accedimos por su organización y nombre de usuario. Sin embargo, es posible que también necesitemos buscar un único usuario por su dirección de correo electrónico. Este patrón no encaja con el patrón de acceso a la clave principal al que nos empuja DynamoDB. Debido a que nuestra tabla está dividida por diferentes atributos, no existe una manera clara de acceder a nuestros datos de la manera que queremos. Podríamos hacer un escaneo completo de la tabla, pero eso es lento e ineficiente. Podríamos duplicar nuestros datos en una tabla separada con una clave principal diferente, pero eso agrega complejidad.


Aquí es donde entran los índices secundarios. Un índice secundario es básicamente una copia completamente administrada de sus datos con una clave primaria diferente. Especificará un índice secundario en su tabla declarando la clave principal para el índice. A medida que las escrituras ingresan a su tabla, DynamoDB replicará automáticamente los datos en su índice secundario.


Nota *: Todo lo contenido en esta sección se aplica a los índices secundarios globales . DynamoDB también proporciona índices secundarios locales , que son un poco diferentes. En casi todos los casos, querrás un índice secundario global. Para obtener más detalles sobre las diferencias, consulte este artículo sobre cómo elegir un índice secundario global o local .*


En este caso, agregaremos un índice secundario a nuestra tabla con una clave de partición de "Correo electrónico". El índice secundario tendrá el siguiente aspecto:



Tenga en cuenta que se trata de los mismos datos, pero se han reorganizado con una clave principal diferente. Ahora podemos buscar un usuario de manera eficiente por su dirección de correo electrónico.


En cierto modo, esto es muy similar a un índice en otras bases de datos. Ambos proporcionan una estructura de datos optimizada para búsquedas de un atributo en particular. Pero los índices secundarios de DynamoDB son diferentes en algunos aspectos clave.


Primero, y lo más importante, los índices de DynamoDB se encuentran en particiones completamente diferentes a las de su tabla principal. DynamoDB quiere que cada búsqueda sea eficiente y predecible, y quiere proporcionar escalamiento horizontal lineal. Para hacer esto, necesita volver a dividir sus datos según los atributos que usará para consultarlos.



En otras bases de datos distribuidas, generalmente no vuelven a fragmentar sus datos para el índice secundario. Por lo general, simplemente mantendrán el índice secundario de todos los datos del fragmento. Sin embargo, si sus índices no usan la clave de fragmento, está perdiendo algunos de los beneficios de escalar sus datos horizontalmente, ya que una consulta sin la clave de fragmento necesitará realizar una operación de dispersión y recopilación en todos los fragmentos para encontrar los datos que necesita. 'que estas buscando.


Una segunda forma en que los índices secundarios de DynamoDB son diferentes es que (a menudo) copian el elemento completo en el índice secundario. Para los índices en una base de datos relacional, el índice a menudo contendrá un puntero a la clave principal del elemento que se indexa. Después de localizar un registro relevante en el índice, la base de datos deberá buscar el elemento completo. Debido a que los índices secundarios de DynamoDB están en nodos diferentes a los de la tabla principal, quieren evitar un salto de red al elemento original. En su lugar, copiará todos los datos que necesite en el índice secundario para manejar su lectura.


Los índices secundarios en DynamoDB son potentes, pero tienen algunas limitaciones. En primer lugar, son de sólo lectura: no se puede escribir directamente en un índice secundario. Más bien, escribirá en su tabla principal y DynamoDB se encargará de la replicación en su índice secundario. En segundo lugar, se le cobra por las operaciones de escritura en sus índices secundarios. Por lo tanto, agregar un índice secundario a su tabla a menudo duplicará los costos totales de escritura de su tabla.

Consejos para usar índices secundarios

Ahora que entendemos qué son los índices secundarios y cómo funcionan, hablemos sobre cómo utilizarlos de forma eficaz. Los índices secundarios son una herramienta poderosa, pero pueden usarse incorrectamente. A continuación se ofrecen algunos consejos para utilizar índices secundarios de forma eficaz.

Intente tener patrones de solo lectura en índices secundarios

El primer consejo parece obvio: los índices secundarios solo se pueden usar para lecturas, por lo que debes intentar tener patrones de solo lectura en tus índices secundarios. Y, sin embargo, veo este error todo el tiempo. Los desarrolladores primero leerán desde un índice secundario y luego escribirán en la tabla principal. Esto genera un costo adicional y una latencia adicional y, a menudo, puede evitarlo con una planificación previa.


Si ha leído algo sobre el modelado de datos de DynamoDB, probablemente sepa que primero debe pensar en sus patrones de acceso. No es como una base de datos relacional donde primero se diseñan tablas normalizadas y luego se escriben consultas para unirlas. En DynamoDB, debe pensar en las acciones que realizará su aplicación y luego diseñar sus tablas e índices para respaldar esas acciones.


Al diseñar mi tabla, me gusta comenzar primero con los patrones de acceso basados en escritura. Con mis escritos, a menudo mantengo algún tipo de restricción: unicidad en un nombre de usuario o un número máximo de miembros en un grupo. Quiero diseñar mi tabla de una manera que lo haga sencillo, idealmente sin usar DynamoDB Transactions o usar un patrón de lectura, modificación y escritura que podría estar sujeto a condiciones de carrera.


A medida que los revise, generalmente encontrará que existe una forma "principal" de identificar su elemento que coincide con sus patrones de escritura. Esta terminará siendo su clave principal. Luego, agregar patrones de lectura secundarios adicionales es fácil con índices secundarios.


En nuestro ejemplo de Usuarios anterior, cada solicitud de Usuario probablemente incluirá la Organización y el Nombre de Usuario. Esto me permitirá buscar el registro de Usuario individual y autorizar acciones específicas por parte del Usuario. La búsqueda de direcciones de correo electrónico puede ser para patrones de acceso menos destacados, como un flujo de "contraseña olvidada" o un flujo de "búsqueda de un usuario". Estos son patrones de sólo lectura y encajan bien con un índice secundario.

Utilice índices secundarios cuando sus claves sean mutables

Un segundo consejo para usar índices secundarios es usarlos para valores mutables en sus patrones de acceso. Primero comprendamos el razonamiento detrás de esto y luego veamos las situaciones en las que se aplica.


DynamoDB le permite actualizar un elemento existente con la operación UpdateItem . Sin embargo, no puede cambiar la clave principal de un elemento en una actualización . La clave principal es el identificador único de un artículo y cambiar la clave principal es básicamente crear un artículo nuevo. Si desea cambiar la clave principal de un elemento existente, deberá eliminar el elemento anterior y crear uno nuevo. Este proceso de dos pasos es más lento y costoso. A menudo, primero deberá leer el elemento original y luego utilizar una transacción para eliminar el elemento original y crear uno nuevo en la misma solicitud.


Por otro lado, si tiene este valor mutable en la clave principal de un índice secundario, DynamoDB manejará este proceso de eliminación y creación por usted durante la replicación. Puede emitir una solicitud UpdateItem simple para cambiar el valor y DynamoDB se encargará del resto.


Veo que este patrón surge en dos situaciones principales. La primera, y la más común, es cuando tienes un atributo mutable que deseas ordenar. Los ejemplos canónicos aquí son una tabla de clasificación para un juego donde las personas acumulan puntos continuamente, o para una lista de elementos que se actualiza continuamente donde desea mostrar primero los elementos actualizados más recientemente. Piense en algo como Google Drive, donde puede ordenar sus archivos por "última modificación".


Un segundo patrón en el que esto surge es cuando tienes un atributo mutable por el que quieres filtrar. En este caso, puede pensar en una tienda de comercio electrónico con un historial de pedidos de un usuario. Es posible que desee permitir que el usuario filtre sus pedidos por estado: muéstreme todos mis pedidos que están "enviados" o "entregados". Puede incorporar esto en su clave de partición o al comienzo de su clave de clasificación para permitir el filtrado de coincidencias exactas. A medida que el elemento cambia de estado, puede actualizar el atributo de estado y apoyarse en DynamoDB para agrupar los elementos correctamente en su índice secundario.


En ambas situaciones, mover este atributo mutable a su índice secundario le ahorrará tiempo y dinero. Ahorrará tiempo al evitar el patrón de lectura-modificación-escritura y ahorrará dinero al evitar los costos adicionales de escritura de la transacción.


Además, tenga en cuenta que este patrón encaja bien con el consejo anterior. Es poco probable que identifique un elemento para escribir basándose en el atributo mutable, como su puntuación anterior, su estado anterior o la última vez que se actualizó. Más bien, actualizará mediante un valor más persistente, como el ID del usuario, el ID del pedido o el ID del archivo. Luego, utilizará el índice secundario para ordenar y filtrar según el atributo mutable.

Evita la partición 'gorda'

Vimos anteriormente que DynamoDB divide sus datos en particiones según la clave principal. DynamoDB pretende mantener estas particiones pequeñas (10 GB o menos) y usted debe intentar distribuir las solicitudes entre sus particiones para obtener los beneficios de la escalabilidad de DynamoDB.


Generalmente, esto significa que debe utilizar un valor de cardinalidad alta en su clave de partición. Piense en algo como un nombre de usuario, un ID de pedido o un ID de sensor. Hay una gran cantidad de valores para estos atributos y DynamoDB puede distribuir el tráfico entre sus particiones.


A menudo, veo personas que entienden este principio en su tabla principal, pero luego lo olvidan por completo en sus índices secundarios. A menudo, quieren realizar pedidos en toda la mesa para un tipo de artículo. Si quieren recuperar usuarios alfabéticamente, usarán un índice secundario donde todos los usuarios tienen USERS como clave de partición y el nombre de usuario como clave de clasificación. O, si quieren ordenar los pedidos más recientes en una tienda de comercio electrónico, usarán un índice secundario donde todos los pedidos tienen ORDERS como clave de partición y la marca de tiempo como clave de clasificación.


Este patrón puede funcionar para aplicaciones con poco tráfico en las que no se acercará a los límites de rendimiento de la partición de DynamoDB , pero es un patrón peligroso para una aplicación con mucho tráfico. Todo su tráfico puede canalizarse a una única partición física y puede alcanzar rápidamente los límites de rendimiento de escritura para esa partición.


Además, y lo más peligroso, esto puede causar problemas en su mesa principal. Si su índice secundario sufre una limitación de escritura durante la replicación, la cola de replicación realizará una copia de seguridad. Si esta cola realiza demasiadas copias de seguridad, DynamoDB comenzará a rechazar escrituras en su tabla principal.


Esto está diseñado para ayudarle: DynamoDB quiere limitar el estancamiento de su índice secundario, por lo que evitará que utilice un índice secundario con una gran cantidad de retraso. Sin embargo, puede ser una situación sorprendente que surge cuando menos lo esperas.

Utilice índices dispersos como filtro global

La gente suele pensar en los índices secundarios como una forma de replicar todos sus datos con una nueva clave primaria. Sin embargo, no es necesario que todos sus datos terminen en un índice secundario. Si tiene un elemento que no coincide con el esquema clave del índice, no se replicará en el índice.


Esto puede resultar realmente útil para proporcionar un filtro global de sus datos. El ejemplo canónico que uso para esto es una bandeja de entrada de mensajes. En su tabla principal, puede almacenar todos los mensajes de un usuario en particular ordenados por el momento en que se crearon.


Pero si eres como yo, tienes muchos mensajes en tu bandeja de entrada. Además, puedes tratar los mensajes no leídos como una lista de "cosas por hacer", como pequeños recordatorios para comunicarte con alguien. En consecuencia, normalmente sólo quiero ver los mensajes no leídos en mi bandeja de entrada.


Podría utilizar su índice secundario para proporcionar este filtro global donde unread == true . Quizás su clave de partición de índice secundario sea algo así como ${userId}#UNREAD y la clave de clasificación sea la marca de tiempo del mensaje. Cuando cree el mensaje inicialmente, incluirá el valor de la clave de partición del índice secundario y, por lo tanto, se replicará en el índice secundario de mensajes no leídos. Más adelante, cuando un usuario lea el mensaje, puede cambiar el status a READ y eliminar el valor de la clave de partición del índice secundario. Luego, DynamoDB lo eliminará de su índice secundario.


Utilizo este truco todo el tiempo y es notablemente efectivo. Además, un índice escaso le permitirá ahorrar dinero. Cualquier actualización para leer mensajes no se replicará en el índice secundario y ahorrará en costos de escritura.

Limite sus proyecciones de índice secundario para reducir el tamaño del índice y/o las escrituras

Para nuestro último consejo, llevemos el punto anterior un poco más allá. Acabamos de ver que DynamoDB no incluirá un elemento en su índice secundario si el elemento no tiene los elementos clave principales para el índice. ¡Este truco se puede utilizar no solo para elementos de clave principal sino también para atributos no clave en los datos!


Cuando crea un índice secundario, puede especificar qué atributos de la tabla principal desea incluir en el índice secundario. Esto se llama proyección del índice. Puede optar por incluir todos los atributos de la tabla principal, solo los atributos de clave principal o un subconjunto de los atributos.


Si bien resulta tentador incluir todos los atributos en su índice secundario, esto puede resultar un error costoso. Recuerde que cada escritura en su tabla principal que cambie el valor de un atributo proyectado se replicará en su índice secundario. Un único índice secundario con proyección completa duplica efectivamente los costos de escritura de su tabla. Cada índice secundario adicional aumenta sus costos de escritura en 1/N + 1 , donde N es el número de índices secundarios antes del nuevo.


Además, sus costos de escritura se calculan en función del tamaño de su artículo. Cada 1 KB de datos escritos en su tabla utiliza una WCU. Si está copiando un elemento de 4 KB a su índice secundario, pagará las 4 WCU completas tanto en su tabla principal como en su índice secundario.


Por lo tanto, existen dos formas de ahorrar dinero reduciendo las proyecciones del índice secundario. En primer lugar, puedes evitar ciertas escrituras por completo. Si tiene una operación de actualización que no afecta ningún atributo en su proyección de índice secundario, DynamoDB omitirá la escritura en su índice secundario. En segundo lugar, para aquellas escrituras que se replican en su índice secundario, puede ahorrar dinero reduciendo el tamaño del elemento que se replica.


Este puede ser un equilibrio difícil de conseguir. Las proyecciones del índice secundario no se pueden modificar una vez creado el índice. Si descubre que necesita atributos adicionales en su índice secundario, deberá crear un nuevo índice con la nueva proyección y luego eliminar el índice anterior.

¿Debería utilizar un índice secundario?

Ahora que hemos explorado algunos consejos prácticos sobre los índices secundarios, demos un paso atrás y hagamos una pregunta más fundamental: ¿debería utilizar un índice secundario?


Como hemos visto, los índices secundarios le ayudan a acceder a sus datos de una manera diferente. Sin embargo, esto tiene el costo de las escrituras adicionales. Por tanto, mi regla general para los índices secundarios es:


Utilice índices secundarios cuando los costos de lectura reducidos superen los costos de escritura aumentados.


Esto parece obvio cuando lo dices, pero puede resultar contradictorio cuando estás modelando. Parece muy fácil decir "Tírelo en un índice secundario" sin pensar en otros enfoques.


Para aclarar esto, veamos dos situaciones en las que los índices secundarios podrían no tener sentido.

Muchos atributos filtrables en colecciones de artículos pequeños

Con DynamoDB, generalmente desea que sus claves principales hagan el filtrado por usted. Me molesta un poco cada vez que uso una consulta en DynamoDB pero luego realizo mi propio filtrado en mi aplicación. ¿Por qué no podría simplemente integrar eso en la clave principal?


A pesar de mi reacción visceral, hay algunas situaciones en las que es posible que desees leer demasiado tus datos y luego filtrarlos en tu aplicación.

El lugar más común en el que verá esto es cuando desea proporcionar muchos filtros diferentes en sus datos para sus usuarios, pero el conjunto de datos relevante está limitado.


Piense en un rastreador de ejercicios. Es posible que desee permitir que los usuarios filtren muchos atributos, como el tipo de entrenamiento, la intensidad, la duración, la fecha, etc. Sin embargo, la cantidad de entrenamientos que realiza un usuario será manejable: incluso un usuario avanzado tardará un tiempo en superar los 1000 entrenamientos. En lugar de poner índices en todos estos atributos, puedes simplemente buscar todos los entrenamientos del usuario y luego filtrarlos en tu aplicación.


Aquí es donde recomiendo hacer los cálculos . DynamoDB facilita el cálculo de estas dos opciones y tiene una idea de cuál funcionará mejor para su aplicación.

Muchos atributos filtrables en grandes colecciones de artículos

Cambiemos un poco nuestra situación: ¿qué pasa si nuestra colección de artículos es grande? ¿Qué pasa si estamos creando un rastreador de ejercicios para un gimnasio y queremos permitir que el propietario del gimnasio filtre todos los atributos que mencionamos anteriormente para todos los usuarios del gimnasio ?


Esto cambia la situación. Ahora estamos hablando de cientos o incluso miles de usuarios, cada uno con cientos o miles de entrenamientos. No tendrá sentido sobreleer toda la colección de elementos y realizar un filtrado post hoc de los resultados.


Pero aquí tampoco tienen sentido los índices secundarios. Los índices secundarios son buenos para patrones de acceso conocidos en los que puede contar con la presencia de filtros relevantes. Si queremos que el propietario de nuestro gimnasio pueda filtrar una variedad de atributos, todos los cuales son opcionales, necesitaríamos crear una gran cantidad de índices para que esto funcione.


Ya hemos hablado antes de las posibles desventajas de los planificadores de consultas, pero los planificadores de consultas también tienen sus ventajas. Además de permitir consultas más flexibles, también pueden hacer cosas como intersecciones de índices para ver resultados parciales de múltiples índices al componer estas consultas. Puede hacer lo mismo con DynamoDB, pero esto generará muchos idas y venidas con su aplicación, junto con una lógica de aplicación compleja para resolverlo.


Cuando tengo este tipo de problemas, generalmente busco una herramienta más adecuada para este caso de uso. Rockset y Elasticsearch son mis recomendaciones aquí para proporcionar un filtrado flexible similar a un índice secundario en todo su conjunto de datos.

Conclusión

En esta publicación, aprendimos sobre los índices secundarios de DynamoDB. Primero, analizamos algunos aspectos conceptuales para comprender cómo funciona DynamoDB y por qué se necesitan índices secundarios. Luego, revisamos algunos consejos prácticos para comprender cómo utilizar los índices secundarios de manera efectiva y aprender sus peculiaridades específicas. Finalmente, analizamos cómo pensar en los índices secundarios para ver cuándo se deben utilizar otros enfoques.


Los índices secundarios son una herramienta poderosa en su caja de herramientas de DynamoDB, pero no son una solución milagrosa. Al igual que con todo el modelado de datos de DynamoDB, asegúrese de considerar cuidadosamente sus patrones de acceso y contar los costos antes de comenzar.


Obtenga más información sobre cómo puede usar Rockset para un filtrado similar a un índice secundario en el blog de Alex DeBrie Filtrado de DynamoDB y consultas de agregación usando SQL en Rockset .