View a markdown version of this page

Noções básicas sobre os registros de CDC - Amazon Aurora DSQL

Noções básicas sobre os registros de CDC

Importante

Esse recurso é fornecido como visualização prévia da AWS e está sujeito a alterações. Para obter mais informações, consulte a seção 2, Versões beta e visualizações prévias, nos Termos de serviço da AWS. Para saber mais sobre precificação para fluxos de CDC, consulte a página de precificação do Aurora DSQL.

Antes da disponibilidade geral, adicionaremos novos tipos de operação ("op": "u" para atualizações) à carga útil do fluxo. Para garantir que seu aplicativo processe essas alterações sem modificações, trate qualquer valor op não reconhecido como um acréscimo aplicando a carga útil after. Para mais detalhes, consulte Noções básicas sobre os registros de CDC.

A CDC do Aurora DSQL entrega cada alteração como um registro JSON. O registro usa uma estrutura de envelope com tipo de operação, imagens da linha antes e depois e metadados de origem.

Como os registros são mapeados para o Amazon Kinesis

O Aurora DSQL grava cada registro de CDC como um único registro do Kinesis. O campo Data do registro do Kinesis contém a carga útil JSON. O Aurora DSQL usa uma chave de partição do Kinesis aleatória para distribuir os registros de CDC uniformemente entre os fragmentos. Para ler todas as alterações, consuma todos os fragmentos no fluxo de dados do Kinesis. Se um registro exceder o limite de tamanho do registro do Kinesis, o Aurora DSQL o dividirá em vários registros do Kinesis. Para obter detalhes, consulte Processamento de registros de tamanho grande.

nota

Um registro do Kinesis tem um blob Data. Os valores da chave primária aparecem no campo before da carga útil JSON para exclusões ou no campo after para inserções e atualizações. Para extrair a chave primária para processamento posterior, leia-a no campo apropriado na carga útil.

Chave primária na carga útil

Para tabelas com uma chave primária, os valores da coluna da chave primária aparecem na carga útil:

  • Para inserções e atualizações, a carga útil inclui as colunas da chave primária junto com todas as outras colunas no campo after.

  • Para exclusões, as colunas da chave primária aparecem no campo before.

Por exemplo, considere uma tabela com uma chave primária composta:

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

Uma exclusão nessa tabela produz uma carga útil onde "before": {"order_id": 1001, "item_id": 42}.

Carga útil de registros

A carga útil usa o seguinte formato de envelope JSON.

Exemplo de INSERT

O exemplo a seguir mostra um registro de CDC para uma operação de inserção:

{ "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 }
Exemplo de UPDATE

O exemplo a seguir mostra a aparência de um registro de CDC produzido por uma instrução UPDATE depois que o Aurora DSQL começar a emitir op: "u":

Importante

Atualmente, o Aurora DSQL emite op: "c" tanto para inserções quanto para atualizações. Uma versão subsequente vai emitir op: "u" para atualizações e op: "c" para inserções. Projete seu aplicativo para lidar com c, u e d para que seu consumidor continue trabalhando durante a transição.

{ "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 }
Exemplo de DELETE

Para exclusões em tabelas com uma chave primária, o campo before contém os valores da chave primária da linha excluída:

{ "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 Descrição
type The record type. full for a complete record that includes inline antes and after 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 Processamento de registros de tamanho grande.
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 nulo for inserts, updates, and deletes on tables without a primary key.
after The full row state after the change, including all columns. Aurora DSQL sets this field to nulo for deletes.
chunked Present only when type is chunked. Contains reassembly metadata for the antes image, the after image, or both. Aurora DSQL omits the chunked image from the top-level antes or after field and places it under chunked instead. For details, see Processamento de registros de tamanho grande.
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ública).
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.

Detalhes do formato

Os detalhes a seguir descrevem como a CDC do Aurora DSQL formata registros. Crie seu aplicativo para lidar com esses comportamentos.

  • Imagem posterior completa para inserções e atualizações. O Aurora DSQL inclui o estado completo da linha no campo after para todas as gravações. O campo before é null para inserções e atualizações. Atualmente, tanto as inserções quanto as atualizações usam op: "c", mas uma versão subsequente vai emitir op: "u" para atualizações. Projete seu aplicativo para usar source.ts_ns por chave primária para classificação, em vez de confiar no campo op para distinguir entre inserções e atualizações.

  • Somente o estado da linha após a alteração. Os registros de CDC incluem o estado completo da linha após cada alteração. O estado da linha antes de uma atualização não é incluído. Para exclusões em tabelas com uma chave primária, o campo before contém os valores da chave primária.

  • Tipos numéricos serializados como strings. O Aurora DSQL serializa os valores numeric e decimal como strings JSON para preservar a precisão exata.

  • Dados binários codificados como Base64. O Aurora DSQL codifica valores bytea como strings Base64.

  • Valores numéricos e de ponto flutuante especiais. O Aurora DSQL serializa NaN e ±Infinity como strings "NaN", "Infinity" e "-Infinity". Isso se aplica aos tipos real, double precision e numeric.

  • Colunas JSON serializadas como strings JSON. O Aurora DSQL serializa os valores de coluna json como strings JSON que contêm o texto JSON bruto armazenado na coluna. Analise o valor da string em seu aplicativo (por exemplo, com JSON.parse em JavaScript ou json.loads em Python) para acessar o valor JSON subjacente.

  • Valores de estouro emitidos como nulos. Se um valor não puder ser representado no tipo JSON de destino durante a serialização, o Aurora DSQL emitirá null JSON para essa coluna. Isso se aplica a valores interval cujo total de microssegundos excede a faixa de números inteiros assinados de 64 bits (±9.223.372.036.854.375.807 microssegundos, aproximadamente ±292.271 anos). Projete seu aplicativo para lidar com valores null inesperados em colunas que não são anuláveis no esquema do banco de dados.

  • Registros grandes divididos em blocos. Se um registro exceder o limite de tamanho do registro do Amazon Kinesis, o Aurora DSQL dividirá a imagem before ou after afetada em fragmentos e os entregará como registros separados do Kinesis para que você ainda receba a alteração. Projete seu aplicativo para remontar as imagens. Para obter detalhes, consulte Processamento de registros de tamanho grande.

Processamento de registros de tamanho grande

Quando o JSON serializado de um registro de CDC excede 9 MiB, o Aurora DSQL divide as imagens before e/ou after, entregando vários registros do Kinesis. Cada registro contém um campo type de nível superior que indica a estrutura: full para um registro completo, chunked para um registro principal que faz referência a fragmentos e fragment para uma parte individual de uma imagem fragmentada. Os campos op, source, ts_ms e ts_ns em um registro principal fragmentado se comportam da mesma forma que em um registro completo. Os registros que cabem em um único registro do Kinesis possuem type definido como full e não exigem nenhum tratamento adicional.

chunk_id é estável em todas as tentativas. Se o Aurora DSQL reentregar um fragmento, ele carregará o mesmo chunk_id que a entrega original, para que seu aplicativo possa continuar armazenando em buffer com o mesmo identificador sem processar conjuntos parciais de tentativas anteriores.

Registro principal

Um registro principal fragmentado substitui o campo before ou after de nível superior da imagem dividida por um objeto chunked que descreve como remontá-la. Cada entrada em chunked tem um chunk_id (o identificador que vincula fragmentos a esse registro), total_fragments (o número de fragmentos que compõem essa imagem) e crc32c (uma soma de verificação CRC32C, como uma string decimal, sobre o texto da imagem remontada). Se uma imagem estiver em linha e a outra estiver fragmentada, a imagem em linha ainda aparecerá no nível superior como um valor ou 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 fragmentado

Cada fragmento é seu próprio registro do Kinesis com type definido como fragment e três campos: chunk_id corresponde ao valor no registro chunked.before.chunk_id ou chunked.after.chunk_id correspondente no registro principal, index é a posição com base em zero do fragmento na imagem e data é um segmento do texto JSON da imagem dividido em limites de caracteres UTF-8 (o valor data de cada fragmento é uma string UTF-8 válida por si só). Como a CDC do Aurora DSQL usa chaves de partição de modo UNORDERED e aleatórias, os fragmentos e o registro principal podem chegar a fragmentos diferentes e em qualquer ordem. Para ler todos os fragmentos, consuma todos os fragmentos no fluxo de dados do Kinesis. Para obter mais informações sobre a ordem de entrega, consulte Ordem.

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

Para remontar uma imagem grande, armazene cada registro em buffer com type fragment por chunk_id. Ao receber um registro principal com type chunked, espere até ter fragmentos total_fragments para cada chunk_id referenciado em chunked.before ou chunked.after, classifique os fragmentos por index em ordem ascendente e concatene as strings data. O resultado concatenado é o objeto before ou after original como texto JSON. Analise-o para acessar os valores da coluna. Para verificar a integridade da entrega, calcule o CRC32C na string concatenada e compare o resultado com chunked.before.crc32c ou chunked.after.crc32c.

Serialização de tipo de dados

As tabelas a seguir descrevem como o Aurora DSQL serializa cada tipo de dados do PostgreSQL nos registros de CDC.

Tipos de inteiros

Tipo de PostgreSQL Representação JSON Exemplo
smallint (int2) JSON number 42
integer (int4) JSON number 1001
bigint (int8) JSON number 9223372036854775807
oid JSON number (unsigned) 16384

Valores de bigint acima de ±2^53 podem perder a precisão em ambientes JavaScript. Use BigInt ou bibliotecas de precisão arbitrária nesses casos.

Tipos de ponto flutuante

Tipo de PostgreSQL Representação JSON Exemplo Observações
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.
numeric / 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 Representação JSON Exemplo
booliano JSON boolean verdadeiro or false

Tipos de caracteres

Tipo de PostgreSQL Representação JSON Exemplo
varchar / texto JSON string "Hello, world!"
bpchar (char(n)) JSON string "ABC" (trailing spaces stripped)
name JSON string "pg_class"
“char” (single-byte) JSON string “A”

Binário

Tipo de PostgreSQL Representação JSON Exemplo
bytea JSON string (Base64) "SGVsbG8gV29ybGQh"

Tipos de data e hora

Tipo de PostgreSQL Representação JSON Exemplo Observações
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.
horário 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.
timestamp 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 timestamp.
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 + dias × 86.400) × 1.000.000 + microssegundos. 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 nulo for the column.

Outros tipos

Tipo de PostgreSQL Representação JSON Exemplo
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 qualquer tipo de dados, os valores das colunas NULL são representados como null JSON.

Evolução do esquema nos registros de CDC

Quando você modifica o esquema de uma tabela (por exemplo, adicionando, eliminando ou renomeando uma coluna), os registros de CDC refletem a alteração a partir da transação que confirmou a alteração de DDL. Os registros de transações confirmadas antes da alteração de DDL usam o esquema anterior. Por exemplo:

  • Se você adicionar uma coluna, os registros de transações anteriores não incluirão a nova coluna. Os registros da transação de adição em diante incluem a nova coluna.

  • Se você eliminar uma coluna, os registros da transação de descarte em diante não incluirão mais essa coluna.

  • Se você renomear uma coluna, os registros da transação de renomeação em diante usarão o novo nome da coluna.

Acompanhe as alterações de esquema em seu consumidor posterior inspecionando os nomes das colunas presentes nos campos after e before de cada registro. O campo source.version em cada registro identifica o formato do envelope de CDC.