To capture events from the ByteHouse Cloud Data Warehouse (CDW) Database for Data Copy and Sync between Data, or to forward these Events as Message streams to different consumers for Processing, ByteHouse provides the Binlog Function. Consuming ByteHouse CDW Binlog can enhance data reuse capabilities and allows detection of insert, delete, and update operations on related ByteHouse CDW tables. This article will explain how to subscribe to the Binlog and related operations in ByteHouse.
ByteHouse CDW Binlog is similar to MySQL Binlog and supports recording all data change event logs in the Database. With ByteHouse CDW Binlog, Data Copy and Sync can be achieved very conveniently and flexibly. However, ByteHouse CDW Binlog is typically only used for Data synchronization, while MySQL Binlog is also used for primary and secondary instance synchronization, data recovery, and other high-availability scenarios. Therefore, there are certain differences in their implementation, mainly reflected in the following aspects:
Meanwhile, in big data scenarios, Flink can directly consume ByteHouse CDW Binlog. Compared to traditional data warehouse layering, Flink + ByteHouse CDW Binlog enables complete event-driven processing, achieving real-time processing from the operational data storage layer (ODS) to the data warehouse dimension layer (DWD), from DWD to the data service layer (DWS), and so on. This meets the requirements of layered governance, achieves unified storage, enhances data reuse, shortens end-to-end data processing latency, and provides users with a one-stop real-time data warehouse solution.
ByteHouse CDW Binlog recommended use cases are as follows:
Please ensure that the ByteHouse CDW engine version you are using is v2.3.1 or above. You can log in to the ByteHouse CDW console, click the top Tenant management tab, and view the engine version in Basic info. Launching the Binlog function with an engine version lower than this will result in an error. To upgrade, please submit a ticket.
Currently, only CnchMergeTree is supported. For new tables, the ENGINE must be set to CnchMergeTree when creating; for existing tables, you can use the following command to query the table engine in use.
SHOW CREATE TABLE your_table_name;
ByteHouse CDW Binlog is at the table level, and DDL actions are not recorded.
After ByteHouse CDW Binlog is activated, it cannot be terminated. Please evaluate business requirements before activating. To terminate after activation, please submit a ticket to contact the ByteHouse team.
Function list of supported (✅) and not supported (❌) Binlog output.
Statement | Non-unique key table | Unique key table |
|---|---|---|
INSERT | ✅ | |
UPSERT, partial column update | ❌ | ✅ |
UPDATE、DELETE | ❌ | ✅ |
DDL
| ❌ | |
TTL expression | ❌ tip Data deleted by TTL expressions does not generate Binlog. | |
Currently, ByteHouse CDW Binlog only supports incremental data consumption. Unified full incremental consumption scenarios are not supported yet.
After activating Binlog, when executing Data Manipulation Language (DML), ByteHouse will perform write, delete, or update operations on the original table, and simultaneously write to Binlog, converting the generated data into Binlog and assigning a BSN (Binlog Sequence Number).
warning
After enabling Binlog, DML operations need to be performed on both the original table and the Binlog, which will have some impact on write performance. In addition, Binlog data itself will occupy some storage space. Please enable Binlog as needed and configure an appropriate time-to-live (TTL).
Binlog records consist of Binlog system fields and user table fields. The specific field definitions are shown in the following table.
Column name | Data type | Description |
|---|---|---|
| UInt64 | Binlog system fields that indicate the BSN of the Binlog to which the current record belongs and the row number within that BSN.
|
| UInt16 | Binlog system field that indicates the shard number of the Binlog to which the current record belongs. This is used to support multiple consumers for parallel consumption (each consumer thread reads data within its own
|
| Enum8 | Binlog system field that indicates the type of change represented by the current record. There are 4 possible values:
tip Update operations generate two Binlog records, corresponding to the record before and after the update ( |
| User-defined | User table field. |
... | ... | ... |
| User-defined | User table field. |
ByteHouse Binlog supports configuration of the following parameters:
Configuration | Required | Default | Description |
|---|---|---|---|
enable_binlog | Yes | 0 | Whether to enable Binlog. If this parameter is set to 1, Binlog is enabled; if set to 0, Binlog is not enabled. Once enabled, it cannot be disabled. |
binlog_lifetime | No | 86400 | TTL of Binlog, in seconds. |
binlog_shard_num | No | 64 | The number of Binlog shards, used to increase the parallelism of Binlog consumption. Supports Flink multi-consumer parallel consumption**.** This parameter must be set before enabling Binlog via the |
binlog_row_deduplicate | No | false | After enabling this option, if the values before and after an update ('U-' and 'U+') are completely identical, Binlog will not output these records. warning This configuration change only takes effect for newly generated Binlogs and does not affect historical Binlogs. |
Example 1: Enable Binlog when creating a new table.
CREATE TABLE binlog_test( `id` Int32, `a` Int64, `b` String ) ENGINE = CnchMergeTree ORDER BY a UNIQUE KEY id SETTINGS enable_binlog = 1, -- Required, enable Binlog binlog_lifetime = 86400, -- Optional binlog_shard_num = 4, -- Optional binlog_row_deduplicate = false; -- Optional
Example 2: Enable Binlog for existing tables.
ALTER TABLE binlog_test MODIFY SETTING binlog_lifetime = 3600; -- Optional, adjust TTL ALTER TABLE binlog_test MODIFY SETTING binlog_shard_num = 4; -- Optional, adjust the number of shards ALTER TABLE binlog_test MODIFY SETTING enable_binlog = 1; -- Required, enable Binlog
After enabling Binlog, you can use ALTER TABLE to modify Binlog configuration.
ALTER TABLE binlog_test MODIFY SETTING binlog_lifetime = 7200;
ALTER TABLE binlog_test MODIFY SETTING binlog_row_deduplicate = true;
ByteHouse supports viewing all Binlog data for a table, and also supports querying Binlog for a specified BSN range only. If you are not sure about the BSN range, you can first query the system table system.cnch_table_info to determine the BSN range to query. You can also query system tables system.cnch_binlogs to view detailed information about the corresponding binlog part. For example, you can query the number of shard records in the current binlog part in advance and customize your reading behavior accordingly to improve query efficiency.
After enabling Binlog, you can query the Binlog of a table by adding $binlog after the table name. For example, you can query the Binlog of db_test.binlog_test using the following SQL statement.
SELECT * FROM db_test.binlog_test$binlog;
ByteHouse supports querying Binlog within a specified BSN range. When querying, you need to add a hint in the form bsn(table_name$binlog, A, B), indicating that you are querying the Binlog whose BSN range in the table is within (A,B]. For example, you can query the Binlog in db_test.binlog_test where BSN is 2 or 3 using the following command.
SELECT /*+ bsn(db_test.binlog_test$binlog, 1, 3) */ * FROM db_test.binlog_test$binlog;
The following examples demonstrate how to query Binlog in several common scenarios.
Suppose we have already executed some DML operations on the table db_test.binlog_test:
INSERT INTO binlog_test VALUES (1,2,'string1-1'),(2,1,'string2-1'),(3,3,'string3-1'); INSERT INTO binlog_test VALUES (1,1,'string1-1'),(2,1,'string2-2'),(4,2,'string4-1'); DELETE FROM binlog_test WHERE id < 3;
Query all Binlog in db_test.binlog_test.
SELECT _binlog_bsn, _part_row_number, * FROM `db_test.binlog_test$binlog` ORDER BY _binlog_bsn ASC
The query result is as follows:
┌─_binlog_bsn─┬─_part_row_number─┬─binlog_shard_id─┬─binlog_event_type─┬─id─┬─a─┬─b─────┐ │ 1 │ 0 │ 1 │ I │ 1 │ 2 │ string1-1 │ │ 1 │ 1 │ 2 │ I │ 2 │ 1 │ string2-1 │ │ 1 │ 2 │ 3 │ I │ 3 │ 3 │ string3-1 │ └────────┴────────────┴───────────┴────────────┴────┴──┴───────┘ ┌─_binlog_bsn─┬─_part_row_number─┬─binlog_shard_id─┬─binlog_event_type─┬─id─┬─a─┬─b─────┐ │ 2 │ 0 │ 1 │ U- │ 1 │ 2 │ string1-1 │ │ 2 │ 1 │ 1 │ U+ │ 1 │ 1 │ string1-1 │ │ 2 │ 2 │ 1 │ I │ 4 │ 2 │ string4-1 │ │ 2 │ 3 │ 2 │ U- │ 2 │ 1 │ string2-1 │ │ 2 │ 4 │ 2 │ U+ │ 2 │ 1 │ string2-2 │ └────────┴─────────────┴──────────┴────────────┴────┴──┴───────┘ ┌─_binlog_bsn─┬─_part_row_number─┬─binlog_shard_id─┬─binlog_event_type─┬─id─┬─a─┬─b─────┐ │ 3 │ 0 │ 1 │ D │ 1 │ 1 │ string1-1 │ │ 3 │ 1 │ 2 │ D │ 2 │ 1 │ string2-2 │ └────────┴────────────┴───────────┴────────────┴────┴──┴───────┘
Query the Binlog in db_test.binlog_test where BSN is 2 or 3.
SELECT /*+ bsn(db_test.binlog_test$binlog, 1, 3) */ _binlog_bsn, _part_row_number, * FROM `db_test.binlog_test$binlog` ORDER BY _binlog_bsn ASC
The query result is as follows:
┌─_binlog_bsn─┬─_part_row_number─┬─binlog_shard_id─┬─binlog_event_type─┬─id─┬─a─┬─b─────┐ │ 2 │ 0 │ 1 │ U- │ 1 │ 2 │ string1-1 │ │ 2 │ 1 │ 1 │ U+ │ 1 │ 1 │ string1-1 │ │ 2 │ 2 │ 1 │ I │ 4 │ 2 │ string4-1 │ │ 2 │ 3 │ 2 │ U- │ 2 │ 1 │ string2-1 │ │ 2 │ 4 │ 2 │ U+ │ 2 │ 1 │ string2-2 │ └────────┴─────────────┴──────────┴─────────────┴───┴──┴───────┘ ┌─_binlog_bsn─┬─_part_row_number─┬─binlog_shard_id─┬─binlog_event_type─┬─id─┬─a─┬─b─────┐ │ 3 │ 0 │ 1 │ D │ 1 │ 1 │ string1-1 │ │ 3 │ 1 │ 2 │ D │ 2 │ 1 │ string2-2 │ └────────┴────────────┴───────────┴────────────┴────┴──┴───────┘
Query the Binlog in db_test.binlog_test where BSN is 2 or 3 and binlog_shard_id is 2.
SELECT /*+ bsn(db_test.binlog_test$binlog, 1, 3) */ _binlog_bsn, _part_row_number, * FROM `db_test.binlog_test$binlog` WHERE binlog_shard_id = 2 ORDER BY _binlog_bsn ASC
The query result is as follows:
┌─_binlog_bsn─┬─_part_row_number─┬─binlog_shard_id─┬─binlog_event_type─┬─id─┬─a─┬─b─────┐ │ 2 │ 3 │ 2 │ U- │ 2 │ 1 │ string2-1 │ │ 2 │ 4 │ 2 │ U+ │ 2 │ 1 │ string2-2 │ └────────┴────────────┴───────────┴────────────┴───┴───┴───────┘ ┌─_binlog_bsn─┬─_part_row_number─┬─binlog_shard_id─┬─binlog_event_type─┬─id─┬─a─┬─b─────┐ │ 3 │ 1 │ 2 │ D │ 2 │ 1 │ string2-2 │ └────────┴────────────┴───────────┴─────────────┴───┴──┴───────┘
Query all newly inserted data in db_test.binlog_test (binlog_event_type is 'I'), and do not output Binlog system fields.
SELECT * EXCEPT (binlog_event_type, binlog_shard_id) FROM `db_test.binlog_test$binlog` WHERE binlog_event_type = 'I'
The query result is as follows:
┌─id─┬─a─┬─b─────┐ │ 1 │ 2 │ string1-1 │ │ 2 │ 1 │ string2-1 │ │ 3 │ 3 │ string3-1 │ └───┴──┴───────┘ ┌─id─┬─a─┬─b─────┐ │ 4 │ 2 │ string4-1 │ └───┴───┴───────┘
ByteHouse CDW currently supports consuming ByteHouse CDW Binlog via Flink. For operation details, please refer to Real-time consumption of ByteHouse CDW Binlog with Flink.
ByteHouse provides two system tables, system.cnch_table_info and system.cnch_binlogs, to display the status information of a table's Binlog.
System table | Purpose | Speed | Recommended use cases |
|---|---|---|---|
| Displays the current maximum and minimum BSN of a table. | Fast | Only need to query the maximum and minimum BSN of the table. |
| Displays detailed information for each Binlog part of a table. | Slow | You can query detailed information before reading a Binlog part to customize the reading method. |
Displays the current maximum and minimum BSN of a table.
Column name | Data type | Description |
|---|---|---|
database | String | Database name |
table | String | Table name |
min_bsn | Nullable(UInt64) | Minimum BSN within TTL. For tables where Binlog is not enabled or does not exist, this field is NULL. |
max_bsn | Nullable(UInt64) | Maximum BSN within TTL. For tables where Binlog is not enabled or does not exist, this field is NULL. |
Example: Query the maximum and minimum BSN of db_test.binlog_test.
SELECT database, table, min_bsn, max_bsn FROM system.cnch_table_info WHERE (database = 'db_test') AND (table = 'binlog_test')
The query result is as follows:
┌─database─┬─table───┬─min_bsn─┬─max_bsn─┐ │ db_test │ binlog_test│ 10 │ 20 │ └──────┴────────┴──────┴──────┘
Displays detailed information about each Binlog part of a table. When querying this system table, you must use equality filter conditions for database and table.
Column name | Data type | Description |
|---|---|---|
database | String | Name of the database being queried. |
table | String | Name of the table being queried. |
part_name | String | Name of the current Binlog part. |
bsn | UInt64 | BSN of the current Binlog part. |
rows | UInt64 | Number of records in the current Binlog part. |
bytes | UInt64 | Storage bytes of the current Binlog part. |
txn_id | UInt64 | Transaction ID that generated the current Binlog part. |
commit_time | DateTime | Commit time of the transaction that generated the current Binlog part. |
published_time | DateTime | Time when the current Binlog part was published. |
active | UInt8 | Whether the current Binlog part is active (within TTL and published). |
is_staged | UInt8 | Whether the current Binlog part is published. |
shard_stats | String | Number of records for each Shard in the current Binlog part. |
Example: Query information about all Binlog parts of db_test.binlog_test.
SELECT database, table, bsn, rows, bytes, active, shard_stats FROM system.cnch_binlogs WHERE (database = 'db_test') AND (table = 'binlog_test')
The query result is as follows:
┌─database─┬─table───┬─bsn─┬─rows─┬─bytes─┬─active─┬─shard_stats────┐ │ db_test │ binlog_test │ 1 │ 3 │ 1416 │ 1 │ [ 0, 1, 1, 1 ] │ │ db_test │ binlog_test │ 2 │ 5 │ 1437 │ 1 │ [ 0, 3, 2, 0 ] │ │ db_test │ binlog_test │ 3 │ 2 │ 1403 │ 1 │ [ 0, 1, 1, 0 ] │ └──────┴────────┴───┴────┴──────┴─────┴────────────┘