Solución:
Hay un par de enfoques, pero primero debe comprender que no puede cambiar el esquema de una tabla existente. Para obtener un esquema diferente, debe crear una nueva tabla. Es posible que pueda reutilizar su tabla existente, pero el resultado sería el mismo que si creara una tabla diferente.
- Migración diferida a la misma tabla, sin Streams. Cada vez que modifique una entrada en la tabla Persona, cree un nuevo elemento en la tabla Persona utilizando UPI y no SSN como valor para la clave hash, y elimine el elemento anterior con clave en SSN. Esto supone que UPI se basa en un rango de valores diferente al SSN. Si el SSN se parece a XXX-XX-XXXX, siempre que UPI tenga un número de dígitos diferente al SSN, nunca se superpondrá.
- Migración diferida a la misma tabla mediante Streams. Cuando las transmisiones estén disponibles de forma generalizada, podrá activar una transmisión para su tabla de personas. Cree una transmisión con el tipo de vista de transmisión NEW_AND_OLD_IMAGES y cada vez que detecte un cambio en un elemento que agregue un UPI a una persona existente en la tabla Person, cree una función Lambda que elimine a la persona con clave en SSN y agregue una persona con la misma atributos codificados en UPI. Este enfoque tiene condiciones de carrera que se pueden mitigar agregando un atributo atómico de contraversión al artículo y condicionando la llamada DeleteItem en el atributo de versión.
- Migración preventiva (con script) a una tabla diferente, utilizando Streams. Ejecute un script que escanee su tabla y agregue un UPI único a cada elemento Persona en la tabla Persona. Cree una secuencia en la tabla Person con el tipo de vista de secuencia NEW_AND_OLD_IMAGES y suscriba una función lambda a esa secuencia que escribe todas las nuevas Personas en una nueva tabla Person_UPI cuando la función lambda detecta que se cambió una Persona con un UPI o cuando una Persona tuvo una Agregó UPI. Las mutaciones en la tabla base suelen tardar cientos de milisegundos en aparecer en una transmisión como registros de transmisión, por lo que puede realizar una conmutación por error en caliente a la nueva tabla Person_UPI en su aplicación. Rechace las solicitudes durante unos segundos, apunte su aplicación a la tabla Person_UPI durante ese tiempo y vuelva a habilitar las solicitudes.
Los flujos de DynamoDB nos permiten migrar tablas sin ningún tiempo de inactividad. He hecho esto con gran eficacia, y los pasos que he seguido son:
- Cree una nueva tabla (llamémosla NewTable), con la estructura de claves deseada, LSI, GSI.
- Habilite las transmisiones de DynamoDB en la tabla original
- Asocie un Lambda a la secuencia, que inserta el registro en NewTable. (Esta Lambda debe recortar la marca de migración en el Paso 5)
- [Optional] Cree un GSI en la mesa original para acelerar el escaneo de elementos. Asegúrese de que este GSI solo tenga atributos: Clave principal y Migrado (consulte el Paso 5).
-
Escanee el GSI creado en el paso anterior (o la tabla completa) y use el siguiente filtro:
FilterExpression = “atributo_no_existe (migrado)”
Actualice cada elemento de la tabla con una marca de migración (es decir, “Migrado”: {“S”: “0”}, que lo envía a DynamoDB Streams (mediante la API UpdateItem, para garantizar que no se produzcan pérdidas de datos).
NOTA: Es posible que desee aumentar las unidades de capacidad de escritura en la mesa durante las actualizaciones.
- Lambda recogerá todos los elementos, recortará el indicador Migrado y lo insertará en NewTable.
- Una vez que se hayan migrado todos los elementos, vuelva a apuntar el código a la nueva tabla
- Elimine la tabla original y la función Lambda una vez feliz, todo está bien.
Seguir estos pasos debería garantizar que no se pierdan datos ni se produzcan tiempos de inactividad.
He documentado esto en mi blog, con código para ayudar: https://www.abhayachauhan.com/2018/01/dynamodb-changing-table-schema/
Estoy usando una variante del tercer enfoque de Alexander. Nuevamente, crea una nueva tabla que se actualizará a medida que se actualice la tabla anterior. La diferencia es que usa código en el servicio existente para escribir en ambas tablas mientras realiza la transición en lugar de usar una función lambda. Es posible que tenga un código de persistencia personalizado que no desee reproducir en una función lambda temporal y es probable que tenga que escribir el código de servicio para esta nueva tabla de todos modos. Dependiendo de su arquitectura, es posible que incluso pueda cambiar a la nueva tabla sin tiempo de inactividad.
Sin embargo, lo bueno de usar una función lambda es que cualquier carga introducida por escrituras adicionales en la nueva tabla estaría en la lambda, no en el servicio.