Skip to content
Open
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
241 changes: 241 additions & 0 deletions ticdc/ticdc-debezium-avro-protocol.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,241 @@
# TiCDC Debezium Avro Protocol

TiCDC Debezium Avro protocol combines Debezium-style change event semantics with Confluent Avro wire format.

In this protocol, TiCDC still produces Debezium envelope fields such as `before`, `after`, `source`, `op`, and `ts_ms`, but message bytes are encoded in Avro binary and schema ids are managed by Schema Registry.

Compared with `protocol=debezium`, `protocol=debezium-avro` is better suited for downstream systems that already use Avro deserializers and Schema Registry.
Comment on lines +3 to +7

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

medium

According to the technical writing style guide, we should prefer active voice and ensure consistent terminology. Let's use active voice, correct 'schema ids' to 'schema IDs', and add appropriate articles ('the') for better clarity.

Suggested change
TiCDC Debezium Avro protocol combines Debezium-style change event semantics with Confluent Avro wire format.
In this protocol, TiCDC still produces Debezium envelope fields such as `before`, `after`, `source`, `op`, and `ts_ms`, but message bytes are encoded in Avro binary and schema ids are managed by Schema Registry.
Compared with `protocol=debezium`, `protocol=debezium-avro` is better suited for downstream systems that already use Avro deserializers and Schema Registry.
The TiCDC Debezium Avro protocol combines Debezium-style change event semantics with the Confluent Avro wire format.\n\nIn this protocol, TiCDC still produces Debezium envelope fields such as `before`, `after`, `source`, `op`, and `ts_ms`, but TiCDC encodes message bytes in Avro binary and manages schema IDs using the Schema Registry.\n\nCompared with `protocol=debezium`, `protocol=debezium-avro` is better suited for downstream systems that already use Avro deserializers and the Schema Registry.
References
  1. Prefer present tense and active voice. Avoid passive voice overuse. (link)


## Use Debezium Avro

When you use Kafka as the downstream sink, specify `protocol=debezium-avro` in `sink-uri`, and provide the Schema Registry endpoint.

The configuration example is as follows:
Comment on lines +11 to +13

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

low

Let's improve the clarity and flow by adding appropriate articles and using active phrasing.

Suggested change
When you use Kafka as the downstream sink, specify `protocol=debezium-avro` in `sink-uri`, and provide the Schema Registry endpoint.
The configuration example is as follows:
When you use Kafka as the downstream sink, specify `protocol=debezium-avro` in the `sink-uri`, and provide the Schema Registry endpoint.\n\nThe following is a configuration example:
References
  1. Clarity, simplicity, completeness, and readability. (link)


```shell
cdc cli changefeed create \
--server=http://127.0.0.1:8300 \
--changefeed-id="kafka-debezium-avro" \
--sink-uri="kafka://127.0.0.1:9092/topic-name?protocol=debezium-avro&avro-decimal-handling-mode=precise&avro-bigint-unsigned-handling-mode=string" \
--schema-registry=http://127.0.0.1:8081 \
--config changefeed_config.toml
```

The value of `--schema-registry` supports the `https` protocol and `username:password` authentication. The username and password must be URL-encoded. For example, `--schema-registry=https://username:password@schema-registry-uri.com`.

> **Note:**
>
> Debezium Avro uses Schema Registry topic-name subject behavior. One Kafka topic should contain data for only one table. You need to configure topic dispatchers to route each table to an independent topic.
Comment on lines +26 to +28

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

medium

To maintain consistency with other documentation files (such as ticdc-avro-protocol.md), let's refer to the specific subject naming strategy TopicNameStrategy in backticks.

Suggested change
> **Note:**
>
> Debezium Avro uses Schema Registry topic-name subject behavior. One Kafka topic should contain data for only one table. You need to configure topic dispatchers to route each table to an independent topic.
> **Note:**\n>\n> Debezium Avro uses the Schema Registry `TopicNameStrategy` subject naming strategy. One Kafka topic should contain data for only one table. You need to configure topic dispatchers to route each table to an independent topic.
References
  1. Use consistent terminology. Code snippets, command names, options, and paths should be in backticks. (link)


```toml
[sink]
dispatchers = [
{matcher = ['*.*'], topic = "tidb_{schema}_{table}"},
]
```

## Definition of the data format

TiCDC converts a DML event into a Kafka event. The key and value are encoded as Debezium-model payloads over Avro wire format.

### Wire format

Each Kafka message is encoded as:
Comment on lines +39 to +43

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

medium

Let's rewrite this section to use active voice and improve readability.

Suggested change
TiCDC converts a DML event into a Kafka event. The key and value are encoded as Debezium-model payloads over Avro wire format.
### Wire format
Each Kafka message is encoded as:
TiCDC converts a DML event into a Kafka event. TiCDC encodes the key and value as Debezium-model payloads over the Avro wire format.\n\n### Wire format\n\nTiCDC encodes each Kafka message as follows:
References
  1. Prefer present tense and active voice. Avoid passive voice overuse. (link)


```text
[magic byte][schema id][avro binary payload]
```

### Key data format

The key contains only primary key columns or unique index columns.

The following JSON is the Debezium Connect schema model used before Avro binary encoding.

```json
{
"schema": {
"type": "struct",
"optional": false,
"name": "{{ClusterID}}.{{SchemaName}}.{{TableName}}Key",
"fields": [
{
"field": "id",
"type": "int64",
"optional": false
}
]
},
"payload": {
"id": 1
}
}
```

#### Avro record naming (key)

When TiCDC converts this key schema to Avro and registers it in Schema Registry:

- `connect.name` keeps the full logical name: `{{ClusterID}}.{{SchemaName}}.{{TableName}}Key`
- Avro `name` becomes: `{{TableName}}Key`
- Avro `namespace` becomes: `{{ClusterID}}.{{SchemaName}}`

All parts are sanitized to Avro-compatible identifiers.
Comment on lines +77 to +83

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

medium

Let's use active voice and add appropriate articles to improve the clarity of the record naming rules.

Suggested change
When TiCDC converts this key schema to Avro and registers it in Schema Registry:
- `connect.name` keeps the full logical name: `{{ClusterID}}.{{SchemaName}}.{{TableName}}Key`
- Avro `name` becomes: `{{TableName}}Key`
- Avro `namespace` becomes: `{{ClusterID}}.{{SchemaName}}`
All parts are sanitized to Avro-compatible identifiers.
When TiCDC converts this key schema to Avro and registers it in the Schema Registry:\n\n- `connect.name` keeps the full logical name: `{{ClusterID}}.{{SchemaName}}.{{TableName}}Key`\n- The Avro `name` becomes: `{{TableName}}Key`\n- The Avro `namespace` becomes: `{{ClusterID}}.{{SchemaName}}`\n\nTiCDC sanitizes all parts to Avro-compatible identifiers.
References
  1. Prefer present tense and active voice. Avoid passive voice overuse. (link)


### Value data format

The value is a Debezium envelope and includes `before`, `after`, `source`, `op`, and `ts_ms`.

The following JSON is the Debezium Connect schema model used before Avro binary encoding.

```json
{
"schema": {
"type": "struct",
"optional": false,
"name": "{{ClusterID}}.{{SchemaName}}.{{TableName}}Envelope",
"version": 1,
"fields": [
{
"field": "before",
"type": "struct",
"optional": true,
"name": "{{ClusterID}}.{{SchemaName}}.{{TableName}}Value",
"fields": [
{{RowFields}}
]
},
{
"field": "after",
"type": "struct",
"optional": true,
"name": "{{ClusterID}}.{{SchemaName}}.{{TableName}}Value",
"fields": [
{{RowFields}}
]
},
{
"field": "source",
"type": "struct",
"optional": false,
"name": "{{ClusterID}}.{{SchemaName}}.Source",
"fields": [
...
]
},
{
"field": "op",
"type": "string",
"optional": false
},
{
"field": "ts_ms",
"type": "int64",
"optional": false
}
]
},
"payload": {
"source": {
"version": "2.4.0.Final",
"connector": "TiCDC",
"name": "default",
"ts_ms": 1707103832263,
"snapshot": null,
"db": "test",
"table": "t2",
"server_id": 0,
"file": "",
"pos": 0,
"row": 0,
"gtid": null,
"query": null,
"thread": null,
"commit_ts": 447507027004751877,
"cluster_id": "default"
},
"ts_ms": 1707103832957,
"op": "c",
"before": null,
"after": {
"{{ClusterID}}.{{SchemaName}}.{{TableName}}": {
"id": 1,
"name": "Alice"
}
}
}
}
```

#### Avro record naming (value)

For value-related records, TiCDC applies the same conversion rule:

- Envelope `connect.name`: `{{ClusterID}}.{{SchemaName}}.{{TableName}}Envelope`
- Envelope Avro `name`: `{{TableName}}Envelope`
- Envelope Avro `namespace`: `{{ClusterID}}.{{SchemaName}}`

Nested row records follow the same pattern (for example, `{{TableName}}` under the same namespace).

Debezium Avro encodes DML event types as follows:

- For insert events, `op = "c"`, `before = null`, and `after` contains new row data.
- For update events, `op = "u"`, and `after` contains updated row data. If old value output is enabled, `before` is included.
- For delete events, `op = "d"`, `after = null`, and `before` contains deleted row data.
Comment on lines +172 to +184

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

medium

Let's use active voice, add appropriate articles, and capitalize the event types ('Insert', 'Update', 'Delete') to maintain consistency with the rest of the TiCDC documentation.

Suggested change
For value-related records, TiCDC applies the same conversion rule:
- Envelope `connect.name`: `{{ClusterID}}.{{SchemaName}}.{{TableName}}Envelope`
- Envelope Avro `name`: `{{TableName}}Envelope`
- Envelope Avro `namespace`: `{{ClusterID}}.{{SchemaName}}`
Nested row records follow the same pattern (for example, `{{TableName}}` under the same namespace).
Debezium Avro encodes DML event types as follows:
- For insert events, `op = "c"`, `before = null`, and `after` contains new row data.
- For update events, `op = "u"`, and `after` contains updated row data. If old value output is enabled, `before` is included.
- For delete events, `op = "d"`, `after = null`, and `before` contains deleted row data.
For value-related records, TiCDC applies the same conversion rules:\n\n- The envelope `connect.name` becomes: `{{ClusterID}}.{{SchemaName}}.{{TableName}}Envelope`\n- The envelope Avro `name` becomes: `{{TableName}}Envelope`\n- The envelope Avro `namespace` becomes: `{{ClusterID}}.{{SchemaName}}`\n\nNested row records follow the same pattern (for example, `{{TableName}}` under the same namespace).\n\nDebezium Avro encodes DML event types as follows:\n\n- For Insert events, `op = "c"`, `before = null`, and `after` contains new row data.\n- For Update events, `op = "u"`, and `after` contains updated row data. If `debezium-output-old-value` is enabled, `before` is included.\n- For Delete events, `op = "d"`, `after = null`, and `before` contains deleted row data.
References
  1. Use consistent terminology. (link)


## Configuration

The following parameters affect Debezium Avro:

| Parameter | Description | Default |
| ------------------------------------ | --------------------------------------------------------------------------------------------------------------------- | --------- |
| `protocol=debezium-avro` | Enables the Debezium Avro protocol | N/A |
| `schema-registry` | Confluent Schema Registry URL | Required |
| `enable-tidb-extension` | Adds TiDB-specific metadata such as `tidb_type`, and enables internal watermark / DDL encoding paths when used with `avro-enable-watermark` | `false` |
| `avro-decimal-handling-mode` | Decimal handling mode, `precise` or `string` | `precise` |
| `avro-bigint-unsigned-handling-mode` | Unsigned BIGINT handling mode, `long` or `string` | `long` |
| `avro-enable-watermark` | Enables watermark / DDL messages for internal testing | `false` |
Comment on lines +190 to +197

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

medium

Let's improve the parameter descriptions in the table by using active voice, adding articles, and ending descriptions with periods for consistency.

Suggested change
| Parameter | Description | Default |
| ------------------------------------ | --------------------------------------------------------------------------------------------------------------------- | --------- |
| `protocol=debezium-avro` | Enables the Debezium Avro protocol | N/A |
| `schema-registry` | Confluent Schema Registry URL | Required |
| `enable-tidb-extension` | Adds TiDB-specific metadata such as `tidb_type`, and enables internal watermark / DDL encoding paths when used with `avro-enable-watermark` | `false` |
| `avro-decimal-handling-mode` | Decimal handling mode, `precise` or `string` | `precise` |
| `avro-bigint-unsigned-handling-mode` | Unsigned BIGINT handling mode, `long` or `string` | `long` |
| `avro-enable-watermark` | Enables watermark / DDL messages for internal testing | `false` |
| Parameter | Description | Default |\n| ------------------------------------ | --------------------------------------------------------------------------------------------------------------------- | --------- |\n| `protocol=debezium-avro` | Enables the Debezium Avro protocol. | N/A |\n| `schema-registry` | The Confluent Schema Registry URL. | Required |\n| `enable-tidb-extension` | Adds TiDB-specific metadata such as `tidb_type`, and enables internal watermark and DDL encoding paths when used with `avro-enable-watermark`. | `false` |\n| `avro-decimal-handling-mode` | The decimal handling mode, which can be `precise` or `string`. | `precise` |\n| `avro-bigint-unsigned-handling-mode` | The unsigned `BIGINT` handling mode, which can be `long` or `string`. | `long` |\n| `avro-enable-watermark` | Enables watermark and DDL messages for internal testing. | `false` |
References
  1. Clarity, simplicity, completeness, and readability. (link)


The `debezium-output-old-value` setting is controlled by sink configuration and decides whether update events include old row values in `before`.

`enable-tidb-extension` is optional in normal Debezium Avro scenarios. Base Debezium envelope fields are available without it.

### Constraints

- Debezium Avro requires a Schema Registry endpoint.
- A Kafka topic should carry one table schema.
- `force-replicate` must be disabled when using Avro or Debezium Avro.
Comment on lines +199 to +207

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

medium

Let's use active voice and second person ('you') to make the constraints and configuration descriptions clearer and more direct.

Suggested change
The `debezium-output-old-value` setting is controlled by sink configuration and decides whether update events include old row values in `before`.
`enable-tidb-extension` is optional in normal Debezium Avro scenarios. Base Debezium envelope fields are available without it.
### Constraints
- Debezium Avro requires a Schema Registry endpoint.
- A Kafka topic should carry one table schema.
- `force-replicate` must be disabled when using Avro or Debezium Avro.
The sink configuration controls the `debezium-output-old-value` setting, which determines whether update events include old row values in `before`.\n\n`enable-tidb-extension` is optional in normal Debezium Avro scenarios. You can access the base Debezium envelope fields without enabling it.\n\n### Constraints\n\n- Debezium Avro requires a Schema Registry endpoint.\n- A Kafka topic should carry only one table schema.\n- You must disable `force-replicate` when using the Avro or Debezium Avro protocol.
References
  1. Write in second person ('you') when addressing users. Avoid passive voice overuse. (link)


## DDL events and schema changes

Debezium Avro does not rely on downstream DDL event consumption. When table schema changes, TiCDC generates and registers new schemas through Schema Registry during DML processing.

If schema compatibility checks fail in Schema Registry, changefeed enters an error state.

For operational details, read:

- [TiCDC Avro Protocol - DDL events and schema changes](/ticdc/ticdc-avro-protocol.md#ddl-events-and-schema-changes)
Comment on lines +209 to +217

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

medium

Let's add appropriate articles and use 'see' instead of 'read' for referring to other sections, which is more standard in technical documentation.

Suggested change
## DDL events and schema changes
Debezium Avro does not rely on downstream DDL event consumption. When table schema changes, TiCDC generates and registers new schemas through Schema Registry during DML processing.
If schema compatibility checks fail in Schema Registry, changefeed enters an error state.
For operational details, read:
- [TiCDC Avro Protocol - DDL events and schema changes](/ticdc/ticdc-avro-protocol.md#ddl-events-and-schema-changes)
## DDL events and schema changes\n\nDebezium Avro does not rely on downstream DDL event consumption. When a table schema changes, TiCDC generates and registers new schemas through the Schema Registry during DML processing.\n\nIf schema compatibility checks fail in the Schema Registry, the changefeed enters an error state.\n\nFor operational details, see:\n\n- [TiCDC Avro Protocol - DDL events and schema changes](/ticdc/ticdc-avro-protocol.md#ddl-events-and-schema-changes)
References
  1. Clarity, simplicity, completeness, and readability. (link)


## Data type mapping

Debezium Avro follows Debezium-style type semantics, with TiCDC-specific behavior controlled by Avro options such as decimal and unsigned bigint handling.

For exact type mapping details and differences, see:

- [TiCDC Debezium Protocol - Data type mapping](/ticdc/ticdc-debezium.md#data-type-mapping)

## Consumer implementation

Use Confluent-compatible Avro deserializers and Schema Registry APIs to decode message payloads.

Reference:

- [TiCDC Avro Protocol - Consumer implementation](/ticdc/ticdc-avro-protocol.md#consumer-implementation)

## Compatibility

Schema evolution compatibility is determined by Schema Registry policy. Incompatible schema changes can stop the changefeed.

Reference:

- [TiCDC Avro Protocol - Compatibility](/ticdc/ticdc-avro-protocol.md#compatibility)
Comment on lines +235 to +241

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

medium

Let's use active voice and add a newline at the end of the file to follow standard POSIX file formatting.

Suggested change
## Compatibility
Schema evolution compatibility is determined by Schema Registry policy. Incompatible schema changes can stop the changefeed.
Reference:
- [TiCDC Avro Protocol - Compatibility](/ticdc/ticdc-avro-protocol.md#compatibility)
## Compatibility\n\nThe Schema Registry policy determines the schema evolution compatibility. Incompatible schema changes can cause the changefeed to stop.\n\nReference:\n\n- [TiCDC Avro Protocol - Compatibility](/ticdc/ticdc-avro-protocol.md#compatibility)\n
References
  1. Clarity, simplicity, completeness, and readability. Avoid passive voice overuse. (link)

Loading