View a markdown version of this page

了解 CDC 记录 - Amazon Aurora DSQL

了解 CDC 记录

重要

此功能以 AWS 预览版形式提供,可能会发生变化。有关更多信息,请参阅 AWS Service Terms 中的第 2 部分“Betas and Previews”。要了解有关 CDC 流的定价的更多信息,请参阅 Aurora DSQL 定价页面

在正式发布之前,我们将向流有效载荷添加新的操作类型("op": "u" 表示更新)。要确保您的应用程序无需修改即可处理这些更改,请通过应用 after 有效载荷将任何无法识别的 op 值视为更新插入。有关详细信息,请参阅了解 CDC 记录。

Aurora DSQL CDC 将每项更改作为一条 JSON 记录进行传输。该记录使用信封结构,包含操作类型、更改前后的行映像以及源元数据。

记录映射到 Amazon Kinesis 的方式

Aurora DSQL 将每条 CDC 记录作为一条 Kinesis 记录写入。Kinesis 记录的 Data 字段包含 JSON 有效载荷。Aurora DSQL 使用随机化的 Kinesis 分区键将 CDC 记录均匀分布到各个分片中。要读取所有更改,请使用 Kinesis 数据流上的所有分片。如果一条记录超过 Kinesis 记录大小限制,Aurora DSQL 会将该记录拆分为多条 Kinesis 记录。有关更多信息,请参阅 处理超大记录

注意

每条 Kinesis 记录包含一个 Data blob。对于删除操作,主键值显示在 JSON 有效载荷的 before 字段中;对于插入和更新操作,主键值显示在 after 字段中。要提取主键以进行下游处理,请从有效载荷的相应字段中读取主键。

有效载荷中的主键

对于带有主键的表,主键列值将显示在有效载荷中:

  • 对于插入更新,有效载荷包括主键列以及 after 字段中的所有其他列。

  • 对于删除,主键列显示在 before 字段中。

以下面这个带复合主键的表为例:

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

在此表中执行删除操作会生成有效载荷,其中 "before": {"order_id": 1001, "item_id": 42}

记录有效载荷

有效载荷使用以下 JSON 信封格式。

INSERT 示例

以下示例显示插入操作的 CDC 记录:

{ "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 }
UPDATE 示例

以下示例显示在 Aurora DSQL 开始发出 op: "u" 后,由 UPDATE 语句生成的 CDC 记录的外观:

重要

目前,Aurora DSQL 将同时为插入和更新操作发出 op: "c"。后续版本将为更新操作发出 op: "u",并为插入操作发出 op: "c"。设计应用程序以处理 cud,确保使用者在整个转换期间能够持续正常工作。

{ "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 }
DELETE 示例

在带主键的表中执行删除操作时,before 字段将包含已删除的行的主键值:

{ "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 }

有效载荷字段

字段 描述
type The record type. full for a complete record that includes inline before 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 处理超大记录.
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.
before 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.
after The full row state after the change, including all columns. Aurora DSQL sets this field to null for deletes.
chunked Present only when type is chunked. Contains reassembly metadata for the before image, the after image, or both. Aurora DSQL omits the chunked image from the top-level before or after field and places it under chunked instead. For details, see 处理超大记录.
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, public).
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.

格式详细信息

以下详细信息描述了 Aurora DSQL CDC 设置记录格式的方式。设计应用程序以处理这些行为。

  • 插入和更新操作的完整后映像。Aurora DSQL 在 after 字段中包含所有写入操作的完整行状态。对于插入和更新操作,before 字段为 null。当前,插入和更新操作都使用 op: "c",但后续版本将为更新操作发出 op: "u"。设计您的应用程序,按主键使用 source.ts_ns 进行排序,而不是依靠 op 字段来区分插入和更新操作。

  • 仅限更改后的行状态。CDC 记录包含每次更改后的完整行状态。更新前的行状态不会包含在内。在带主键的表中执行删除操作时,before 字段将包含主键值。

  • 数值类型序列化为字符串。Aurora DSQL 将 numericdecimal 值序列化为 JSON 字符串,以保持精确精度。

  • 二进制数据编码为 Base64。Aurora DSQL 将 bytea 值编码为 Base64 字符串。

  • 特殊浮点数和数值。Aurora DSQL 将 NaN 和 ±Infinity 序列化为字符串 "NaN""Infinity""-Infinity"。这适用于 realdouble precisionnumeric 类型。

  • JSON 列序列化为 JSON 字符串。Aurora DSQL 将 json 列值序列化为 JSON 字符串,其中包含存储在列中的原始 JSON 文本。在应用程序中解析字符串值(例如,在 JavaScript 中使用 JSON.parse,或在 Python 中使用 json.loads)以访问底层 JSON 值。

  • 溢出值以 null 形式发出。如果某个值在序列化过程中无法用目标 JSON 类型表示,Aurora DSQL 会为该列发出 JSON null。这适用于其总微秒数超过 64 位有符号整数范围(±9223372036854775807 微秒,约 ±292271 年)的 interval 值。设计应用程序以处理数据库架构中不可为 null 的列中的意外 null 值。

  • 超大记录拆分为块。如果记录超出 Amazon Kinesis 记录大小限制,Aurora DSQL 会将受影响的 beforeafter 映像拆分为多个片段,然后将其作为单独的 Kinesis 记录传输,以便您仍能收到该更改。设计应用程序以重组映像。有关详细信息,请参阅处理超大记录

处理超大记录

当 CDC 记录的序列化 JSON 超过 9 MiB 时,Aurora DSQL 会拆分 before 和/或 after 映像,并传输多条 Kinesis 记录。每条记录均包含一个顶层的 type 字段,该字段可指示记录的结构:full 表示完整记录、chunked 表示引用片段的主记录,fragment 表示分块映像的单个片段。分块主记录上的 opsourcets_msts_ns 字段的行为与其在完整记录上的行为相同。单条 Kinesis 记录中包含的记录的 type 已设置为 full,无需任何额外处理。

chunk_id 在重试期间保持稳定。如果 Aurora DSQL 重新传输某个片段,该片段将携带与原始传输相同的 chunk_id,这样一来,您的应用程序便能在同一标识符下继续缓冲,而无需处理来自先前尝试的部分集合。

主记录

分块的主记录将拆分映像的顶层 beforeafter 字段替换为一个 chunked 对象,该对象描述如何重组映像。chunked 下方的每个条目均包含 chunk_id(将片段链接到此记录的标识符)、total_fragments(组成该映像的片段数量)和 crc32c(重组后的映像文本的 CRC32C 校验和,以十进制字符串形式表示)。如果一个映像是内联的,而另一个映像是分块的,则内联映像仍以值或 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 }
片段记录

每个片段均为其自己的 Kinesis 记录,其 type 设置为 fragment,并包含三个字段:chunk_id 匹配主记录上相应 chunked.before.chunk_idchunked.after.chunk_id 中的值,index 是片段在映像中的位置(从零开始计数),data 是按 UTF-8 字符边界拆分的映像 JSON 文本片段(每个片段的 data 值本身是有效的 UTF-8 字符串)。由于 Aurora DSQL CDC 使用 UNORDERED 模式和随机分区键,因此片段和主记录可按任意顺序到达不同的分片。要读取所有片段,请使用 Kinesis 数据流上的所有分片。有关传输排序的更多信息,请参阅排序

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

要重组超大映像,请按 chunk_id 缓冲每条 typefragment 的记录。在收到一条 typechunked 的主记录时,请等待,直到对于 chunked.beforechunked.after 下引用的每个 chunk_id 获得 total_fragments 个片段,按 index 升序对片段进行排序,然后将 data 字符串连接起来。连接后的结果是原始 beforeafter 对象(JSON 文本格式),解析该对象即可访问列值。要验证传输完整性,请在连接后的字符串上计算 CRC32C,然后将结果与 chunked.before.crc32cchunked.after.crc32c 进行比较。

数据类型序列化

下表描述 Aurora DSQL 如何序列化 CDC 记录中的每种 PostgreSQL 数据类型。

整数类型

PostgreSQL 类型 JSON 表示 示例
smallint (int2) JSON number 42
integer (int4) JSON number 1001
bigint (int8) JSON number 9223372036854775807
oid JSON number (unsigned) 16384

在 JavaScript 环境中,超出 ±2^53 的 bigint 值可能会丢失精度。在这种情况下,请使用 BigInt 或任意精度库。

浮点类型

PostgreSQL 类型 JSON 表示 示例 备注
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".

布尔值

PostgreSQL 类型 JSON 表示 示例
布尔值 JSON boolean true or false

字符类型

PostgreSQL 类型 JSON 表示 示例
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"

二元

PostgreSQL 类型 JSON 表示 示例
bytea JSON string (Base64) "SGVsbG8gV29ybGQh"

日期和时间类型

PostgreSQL 类型 JSON 表示 示例 备注
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.
time 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.
interval JSON number (approximate total microseconds) 2802603000000 Months are approximated as 30.4375 days (2,629,800 seconds). The total is computed as (月数 × 2629800 + 天数 × 86400)× 1000000 + 微秒数. 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.

其他类型

PostgreSQL 类型 JSON 表示 示例
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\"}"

NULL 值

对于任何数据类型,NULL 列值都表示为 JSON null

CDC 记录中的架构演变

在修改表的架构时(例如,通过添加、删除或重命名列),CDC 记录会反映自提交 DDL 更改的事务开始的更改。在 DDL 更改之前提交的事务产生的记录使用以前的架构。例如:

  • 如果您添加一个列,则早期事务产生的记录不会包含新列。从添加事务往后的记录将包含新列。

  • 如果您删除一个列,则从删除事务往后的记录将不再包含该列。

  • 如果您重命名一个列,则从重命名事务往后的记录将使用新的列名。

通过检查每条记录的 afterbefore 字段中存在的列名,跟踪下游使用者的架构更改。每条记录中的 source.version 字段均标识 CDC 信封格式。