View a markdown version of this page

Descripción de los registros de CDC - Amazon Aurora DSQL

Descripción de los registros de CDC

importante

Esta característica se ofrece como versión preliminar de AWS y está sujeta a cambios. Para obtener más información, consulte la sección 2, Betas y versiones preliminares, del documento Términos de servicio de AWS. Para obtener más información acerca de los precios de los flujos de CDC, visite la página Precios de Amazon Aurora DSQL.

Antes de la disponibilidad general, añadiremos nuevos tipos de operaciones ("op": "u" para actualizaciones) a la carga útil de su flujo. Para garantizar que su aplicación gestione estos cambios sin necesidad de modificaciones, trate cualquier valor op no reconocido como una operación upsert aplicando la carga útil after. Para obtener más información, consulte Descripción de los registros de CDC.

La CDC de Aurora DSQL entrega cada cambio como un registro JSON. El registro utiliza una estructura de sobre que incluye el tipo de operación, imágenes de la fila antes y después, y metadatos de origen.

Cómo se asignan los registros a Amazon Kinesis

Aurora DSQL escribe cada registro de CDC como un único registro de Kinesis. El campo Data del registro de Kinesis contiene la carga útil JSON. Aurora DSQL utiliza una clave de partición de Kinesis asignada al azar para distribuir los registros de CDC de manera uniforme entre las particiones. Para leer todos los cambios, consuma todas las particiones del flujo de datos de Kinesis. Si un registro supera el límite de tamaño de los registros de Kinesis, Aurora DSQL lo divide en varios registros de Kinesis. Para obtener más información, consulte Gestión de los registros sobredimensionados.

nota

Un registro de Kinesis contiene un solo blob Data. Los valores de la clave principal aparecen en el campo before de la carga útil JSON en el caso de las eliminaciones, o en el campo after en el caso de las inserciones y actualizaciones. Para extraer la clave principal para el procesamiento posterior, léala en el campo correspondiente de la carga útil.

Clave principal de la carga útil

En el caso de las tablas con una clave principal, los valores de la columna de la clave principal aparecen en la carga útil:

  • En el caso de las inserciones y actualizaciones, la carga útil incluye las columnas de clave principal junto con todas las demás columnas en el campo after.

  • En el caso de las eliminaciones, las columnas de la clave principal aparecen en el campo before.

Veamos como ejemplo una tabla con una clave primaria compuesta:

CREATE TABLE order_items ( order_id INT, item_id INT, quantity INT, price NUMERIC, PRIMARY KEY (order_id, item_id) );

Si se realiza una eliminación en esta tabla, se genera una carga útil, donde "before": {"order_id": 1001, "item_id": 42}.

Carga útil de registro

La carga útil utiliza el siguiente formato de sobre JSON.

Ejemplo de INSERT

En el siguiente ejemplo, se muestra un registro de CDC para una operación de inserción:

{ "type": "full", "op": "c", "before": null, "after": {"order_id": 1001, "item_id": 42, "quantity": 5, "price": "29.99"}, "source": { "version": "1.0", "ts_ms": 1705318200000, "ts_ns": 1705318200000000000, "txId": "ffthunp5stx6ffs2vyfqoatmfu", "schema": "public", "table": "order_items", "db": "postgres", "cluster": "kmabugltfmjdaj2siqr2qbxgju" }, "ts_ms": 1705318200125, "ts_ns": 1705318200125483291 }
Ejemplo de UPDATE

En el siguiente ejemplo, se muestra cómo será un registro de CDC generado por una instrucción UPDATE una vez que Aurora DSQL comience a emitir op: "u":

importante

Actualmente, Aurora DSQL emite op: "c" tanto para inserciones como para actualizaciones. En una versión posterior, se emitirá op: "u" para las actualizaciones y op: "c" para las inserciones. Diseñe la aplicación para que gestione c, u y d, de modo que el consumidor siga funcionando durante la transición.

{ "type": "full", "op": "u", "before": null, "after": {"order_id": 1001, "item_id": 42, "quantity": 10, "price": "29.99"}, "source": { "version": "1.0", "ts_ms": 1705318300000, "ts_ns": 1705318300000000000, "txId": "qvtiesgmd55cvlfukm3dfuotji", "schema": "public", "table": "order_items", "db": "postgres", "cluster": "kmabugltfmjdaj2siqr2qbxgju" }, "ts_ms": 1705318300125, "ts_ns": 1705318300125483291 }
Ejemplo de DELETE

En el caso de las eliminaciones en tablas con una clave principal, el campo before contiene los valores de la clave principal de la fila eliminada:

{ "type": "full", "op": "d", "before": {"order_id": 1001, "item_id": 42}, "after": null, "source": { "version": "1.0", "ts_ms": 1705318400000, "ts_ns": 1705318400000000000, "txId": "xyzabc123def456ghi789jklmno", "schema": "public", "table": "order_items", "db": "postgres", "cluster": "kmabugltfmjdaj2siqr2qbxgju" }, "ts_ms": 1705318400125, "ts_ns": 1705318400125483291 }

Campos de carga útil

Campo Descripción
tipo The record type. completo for a complete record that includes inline antes and después values. chunked for a main record that references fragment records for one or both images. fragment for an individual piece of a chunked image. For details, see Gestión de los registros sobredimensionados.
op Operation type. c = create (insert), u = update, d = delete. Currently Aurora DSQL emits c for both inserts and updates. A subsequent release will emit u for updates, and c for inserts. Design your app to handle all three values.
antes For deletes on tables with a primary key, contains the primary key values of the deleted row. Aurora DSQL sets this field to null for inserts, updates, and deletes on tables without a primary key.
después The full row state after the change, including all columns. Aurora DSQL sets this field to null for deletes.
chunked Present only when tipo is chunked. Contains reassembly metadata for the antes image, the después image, or both. Aurora DSQL omits the chunked image from the top-level antes or después field and places it under chunked instead. For details, see Gestión de los registros sobredimensionados.
source.version The CDC source metadata format version. The current version is 1.0.
source.ts_ms The transaction commit timestamp in milliseconds since the Unix epoch, Coordinated Universal Time (UTC).
source.ts_ns Transaction commit timestamp in nanoseconds, UTC. The highest precision timestamp available. Use this field to establish a total order of transactions.
source.txId A unique transaction identifier, encoded as base32. All records from the same transaction share the same txId value. Use this field to group records that belong to the same transaction.
source.schema The PostgreSQL schema name (for example, público).
source.table The table name.
source.db The database name. Always postgres for Aurora DSQL.
source.cluster The Aurora DSQL cluster identifier.
ts_ms The time at which the CDC system processed the record, in milliseconds, UTC. The difference between ts_ms and source.ts_ms is a measure of replication lag.
ts_ns The time at which the CDC system processed the record, in nanoseconds, UTC.

Detalles del formato

En los siguientes detalles se describe cómo la CDC de Aurora DSQL formatea los registros. Diseñe la aplicación para gestionar estos comportamientos.

  • Imagen completa posterior para inserciones y actualizaciones. Aurora DSQL incluye el estado completo de la fila en el campo after para todas las escrituras. El campo before es null para inserciones y actualizaciones. Actualmente, tanto las inserciones como las actualizaciones utilizan op: "c", pero en una versión posterior se emitirá op: "u" para las actualizaciones. Diseñe la aplicación para utilizar source.ts_ns por clave principal para la ordenación, en lugar de basarse en el campo op para distinguir entre inserciones y actualizaciones.

  • Solo el estado de la fila después del cambio. Los registros de CDC incluyen el estado completo de la fila después de cada cambio. No se incluye el estado de la fila antes de una actualización. En el caso de las eliminaciones en tablas con una clave principal, el campo before contiene los valores de la clave principal.

  • Tipos numéricos serializados como cadenas. Aurora DSQL serializa los valores numeric y decimal como cadenas JSON para conservar la precisión exacta.

  • Datos binarios codificados como Base64. Aurora DSQL codifica los valores bytea como cadenas de Base64.

  • Valores numéricos y de punto flotante especiales. Aurora DSQL serializa NaN y ±Infinity como cadenas "NaN", "Infinity" y "-Infinity". Esto se aplica a los tipos real, double precision y numeric.

  • Columnas JSON serializadas como cadenas JSON. Aurora DSQL serializa los valores de las columnas json como cadenas JSON que contienen el texto JSON sin procesar almacenado en la columna. Analice el valor de la cadena en su aplicación (por ejemplo, con JSON.parse en JavaScript o json.loads en Python) para acceder al valor JSON subyacente.

  • Los valores de desbordamiento se emiten como nulos. Si no se puede representar un valor en el tipo JSON de destino durante la serialización, Aurora DSQL emite un null JSON para esa columna. Esto se aplica a los valores de interval cuyos microsegundos totales superen el rango de los enteros con signo de 64 bits (±9 223 372 036 854 775 807 microsegundos, aproximadamente ± 292 271 años). Diseñe la aplicación para gestionar valores null inesperados en columnas que no admiten valores null en el esquema de la base de datos.

  • Los registros sobredimensionados se dividen en fragmentos. Si un registro supera el límite de tamaño de registro de Amazon Kinesis, Aurora DSQL divide la imagen before o after afectada en fragmentos y los entrega como registros de Kinesis independientes para que usted siga recibiendo el cambio. Diseñe la aplicación para volver a ensamblar las imágenes. Para obtener más información, consulte Gestión de los registros sobredimensionados.

Gestión de los registros sobredimensionados

Cuando el JSON serializado de un registro de CDC supera los 9 MiB, Aurora DSQL divide las imágenes before y after, y entrega varios registros de Kinesis. Cada registro contiene un campo type de nivel superior que indica su estructura: full para un registro completo, chunked para un registro principal que hace referencia a fragmentos y fragment para una parte individual de una imagen fragmentada. Los campos op, source, ts_ms y ts_ns de un registro principal fragmentado se comportan igual que en un registro completo. Los registros que caben en un único registro de Kinesis tienen type establecido en full y no requieren ningún tratamiento adicional.

Un chunk_id es estable en todos los reintentos. Si Aurora DSQL vuelve a entregar un fragmento, este contiene el mismo chunk_id que la entrega original, por lo que su aplicación puede continuar almacenando en búfer bajo el mismo identificador sin tener que gestionar conjuntos parciales de intentos anteriores.

Registro principal

Un registro principal fragmentado sustituye el campo before o after de nivel superior de la imagen dividida por un objeto chunked que describe cómo volver a ensamblarla. Cada entrada bajo chunked tiene chunk_id (el identificador que vincula los fragmentos a este registro), total_fragments (el número de fragmentos que componen esa imagen) y crc32c (una suma de comprobación de CRC32C, como cadena decimal, sobre el texto de la imagen reensamblada). Si una imagen está en línea y la otra está fragmentada, la imagen en línea sigue apareciendo en el nivel superior como un valor o como null.

{ "type": "chunked", "op": "c", "before": null, "after": null, "source": { "version": "1.0", "ts_ms": 1705318200000, "ts_ns": 1705318200000000000, "txId": "ffthunp5stx6ffs2vyfqoatmfu", "schema": "public", "table": "order_items", "db": "postgres", "cluster": "cluster-id" }, "chunked": { "after": { "chunk_id": "chunk-id", "total_fragments": 3, "crc32c": "2073618257" } }, "ts_ms": 1705318200125, "ts_ns": 1705318200125483291 }
Registro de fragmentos

Cada fragmento constituye un registro independiente de Kinesis con type establecido en fragment y tres campos: chunk_id coincide con el valor del campo chunked.before.chunk_id o chunked.after.chunk_id del registro principal; index es la posición, contada a partir de cero, del fragmento dentro de la imagen; y data es un segmento del texto JSON de la imagen dividido de acuerdo con los límites de caracteres UTF-8 (el valor data de cada fragmento es, por sí mismo, una cadena UTF-8 válida). Dado que CDC de Aurora DSQL utiliza el modo UNORDERED y claves de partición asignadas al azar, los fragmentos y el registro principal pueden llegar a diferentes particiones y en cualquier orden. Para leer todos los fragmentos, consuma todas las particiones del flujo de datos de Kinesis. Para obtener más información acerca del orden de entrega, consulte Ordenación.

{ "type": "fragment", "chunk_id": "chunk-id", "index": 0, "data": "partial-JSON-text" }

Para volver a ensamblar una imagen sobredimensionada, almacene cada registro en búfer con type fragment por su chunk_id. Cuando reciba un registro principal con type chunked, espere hasta tener total_fragments fragmentos para cada chunk_id al que se hace referencia en chunked.before o chunked.after, ordene los fragmentos por index en orden ascendente y concatene las cadenas data. El resultado concatenado es el objeto original before o after como texto JSON; analícelo para acceder a los valores de las columnas. Para verificar la integridad de la entrega, calcule el CRC32C sobre la cadena concatenada y compare el resultado con chunked.before.crc32c o chunked.after.crc32c.

Serialización de tipos de datos

En las siguientes tablas se describe cómo Aurora DSQL serializa cada tipo de datos de PostgreSQL en registros de CDC.

Tipos de enteros

Tipo de PostgreSQL Representación JSON Ejemplo
smallint (int2) JSON number 42
entero (int4) JSON number 1001
bigint (int8) JSON number 9223372036854775807
oid JSON number (unsigned) 16384

Los valores de bigint superiores a ±2^53 pueden perder precisión en los entornos de JavaScript. En esos casos, utilice BigInt o bibliotecas de precisión arbitraria.

Tipos de números en coma flotante

Tipo de PostgreSQL Representación JSON Ejemplo Notas
real (float4) JSON number 3.14159 NaN and ±Infinity are serialized as the strings "NaN", "Infinity", "-Infinity".
double precision (float8) JSON number 3,141592653589793 Same special value handling as real.
numérico / decimal JSON string "123,45" Always a string to preserve exact precision. NaN and ±Infinity are serialized as the strings "NaN", "Infinity", "-Infinity".

Booleano

Tipo de PostgreSQL Representación JSON Ejemplo
booleano JSON boolean true or false

Tipos de caracteres

Tipo de PostgreSQL Representación JSON Ejemplo
varchar / text JSON string "Hello, world!"
BPCHAR (char(n)) JSON string "ABC" (trailing spaces stripped)
name JSON string "pg_class"
“char” (single-byte) JSON string “A”

Binario

Tipo de PostgreSQL Representación JSON Ejemplo
bytea JSON string (Base64) "SGVsbG8gV29ybGQh"

Tipos de fecha y hora

Tipo de PostgreSQL Representación JSON Ejemplo Notas
date JSON number (days since Unix epoch) 19797 +infinity and -infinity are represented as sentinel day counts derived from epoch-offset arithmetic. These values don't correspond to meaningful calendar dates.
hora JSON number (microseconds since midnight) 52200123456
timetz JSON number (microseconds since midnight, UTC) 52200123456 The local time is adjusted to UTC by applying the stored timezone offset (seconds west of UTC). The result is wrapped to the range [0, 86400000000) microseconds.
marca de tiempo JSON number (microseconds since Unix epoch) 1710510600123456 ±Infinity maps to sentinel values: 9223372036825200000 for +infinity and -9223372036832400000 for -infinity.
timestamptz JSON number (microseconds since Unix epoch) 1710510600123456 Stored and emitted in UTC. Same ±infinity sentinel values as marca de tiempo.
intervalo JSON number (approximate total microseconds) 2802603000000 Months are approximated as 30.4375 days (2,629,800 seconds). The total is computed as (meses × 2 629 800 + días × 86 400) × 1 000 000 + microsegundos. If the result exceeds the 64-bit signed integer range (±9,223,372,036,854,775,807 microseconds, approximately ±292,271 years), Aurora DSQL emits JSON null for the column.

Otros tipos

Tipo de PostgreSQL Representación JSON Ejemplo
uuid JSON string (standard 8-4-4-4-12 hex format) "550e8400-e29b-41d4-a716-446655440000"
oidvector JSON empty array []
json JSON string containing the raw JSON text "{\"key\": \"value\"}"

Valores NULL

Para cualquier tipo de datos, los valores de las columnas NULL se representan como JSON null.

Evolución del esquema en los registros de CDC

Cuando se modifica el esquema de una tabla —por ejemplo, al añadir, eliminar o renombrar una columna—, los registros de CDC reflejan el cambio a partir de la transacción que confirmó el cambio de DDL. Los registros de las transacciones confirmadas antes del cambio de DDL utilizan el esquema anterior. Por ejemplo:

  • Si se añade una columna, los registros de las transacciones anteriores no incluyen la nueva columna. Los registros a partir de la transacción en la que se añadió la columna incluyen la nueva columna.

  • Si elimina una columna, los registros a partir de la transacción de eliminación ya no incluirán dicha columna.

  • Si cambia el nombre de una columna, los registros a partir de la transacción de cambio de nombre utilizarán el nuevo nombre de columna.

Realice un seguimiento de los cambios de esquema en su consumidor posterior inspeccionando los nombres de columna presentes en los campos after y before de cada registro. El campo source.version de cada registro identifica el formato del sobre de CDC.