为了强化实时数仓的能力,便于将 MySQL 中的表映射到 ByteHouse 企业版中,ByteHouse 引入了MaterializedMySQL 数据库引擎,ByteHouse 服务作为MySQL副本,可以读取 Binlog 并执行 DDL 和 DML 请求,实现了基于 MySQL Binlog 机制的业务数据库实时同步功能。
ByteHouse 企业版在实现 MaterializedMySQL 时,底层引擎采用了自研的 HaUniqueMergeTree 引擎,支持自定义版本字段以及根据 UNIQUE KEY 实时删除数据功能,无需引入其他额外字段。同时,ByteHouse 增强了 MaterializedMySQL 引擎的稳定性和易用性。
相对于原生MaterializedMySQL引擎,ByteHouse有如下优势:
默认禁止对MaterializedMySQL Database中的表直接进行操作,可通过session参数set force_manipulate_materialize_mysql_table = 1, distributed_ddl_entry_format_version = 2操作底表。
下面将演示将MySQL库中的若干张表同步至ByteHouse的全过程。
当前支持的 MySQL 版本为 5.6、5.7、8.0。
在MySQL数据库端需要配置的参数如下。
登录MySQL查看是否开启Binlog日志
[root@node1 ~]# mysql -u root -password mysql> show variables like 'log_%';
如果查询结果 log_bin字段为off则说明没有开启Binlog日志。
Parameter | Value |
---|---|
log_bin | ON |
binlog_format | ROW |
binlog_row_image | FULL |
Parameter | Value |
---|---|
default_authentication_plugin | mysql_native_password |
Parameter | Value |
---|---|
gtid-mode | ON |
enforce-gtid-consistency | ON |
配置样例:
在/etc/my.cnf文件中[mysqld]下写入以下配置。
[mysqld] #指定一个不重名的server-id server-id=123 #配置Binlog的日志目录 log-bin=/var/lib/mysql/mysql-bin #设置Binglog的格式为Row binlog_format=ROW binlog_row_image=FULL *#设置默认的认证插件为mysql_native_password default_authentication_plugin=mysql_native_password #开启GTID模式 gtid-mode=on enforce-gtid-consistency=1
重启MySQL 服务,可以重新查看Binlog日志情况。
[root@node1 ~]# service mysqld restart [root@node1 ~]# mysql -u root -password mysql> show variables like 'log_%';
注意
CREATE DATABASE [IF NOT EXISTS] db_name [ON CLUSTER cluster] ENGINE = MaterializeMySQL('host:port', ['database' | database], 'user', 'password') [SETTINGS ...] [TABLE OVERRIDE table1 (...), TABLE OVERRIDE table2 (...)]
参数 | 说明 |
---|---|
host:port | MySQL数据库的URL和端口号 |
database | MySQL数据库名称 |
user | MySQL数据库账号 |
password | 账号密码 |
设置 | 类型 | 默认值 | 说明 |
---|---|---|---|
max_rows_in_buffer | UInt64 | 65505 | 内存中允许缓存数据的最大行数(针对单表且缓存数据无法查询)。 当超过这个数字时,数据就会被具体化。 默认值:65505 |
max_bytes_in_buffer | UInt64 | 1048576 | 允许数据在内存中缓存的最大字节数(针对单表且缓存数据无法查询)。 当超过这个数字时,数据就会被具体化。 默认值:1048576 |
max_flush_data_time | UInt64 | 1000 | 允许数据在内存中缓存的最大毫秒数(对于数据库和无法查询的缓存数据)。 当超过这个时间时,数据就会被具体化。 默认值:1000 |
max_wait_time_when_mysql_unavailable | Int64 | 1000 | MySQL不可用时的重试间隔(毫秒)。 负值禁用重试。 默认值:1000 |
allows_query_when_mysql_lost | Bool | true | 允许在 MySQL 丢失时查询物化表。 默认值:0(false) |
skip_error_count | Int64 | 0 | 跳过MaterializedMySQL数据同步中的DML和DDL错误。负值将跳过所有错误。其他值将跳过特定错误。默认值:0 |
include_tables | String | "" | 如果配置了该参数,则只会同步符合条件的表。 表名称以逗号分隔。 表名支持正则表达式。 用户可以设置 include_tables 或 except_tables,如果同时设置这两个参数,将会抛出错误。 如果这两个参数都没有设置,数据库将同步所有表。 默认:'' |
exclude_tables | String | "" | 如果配置了该参数,则不会同步所有符合条件的表。 表名称以逗号分隔。 表名支持正则表达式。 用户可以设置 include_tables 或 except_tables,如果同时设置这两个参数,将会抛出错误。 如果这两个参数都没有设置,数据库将同步所有表。 默认:'' |
skip_ddl_patterns | String | "" | 如果配置了该参数,则所有符合条件的DDL查询都不会被执行。 DDL 模式以逗号分隔。 DDL 模式支持正则表达式并且不区分大小写。 如果该参数未设置或为空,则将执行所有 DDL 查询。 |
skip_unsupported_ddl | Bool | true | 是否跳过不支持的 ddl(CREATE/DROP/RENAME/TRUNCATE TABLE 除外)。 |
skip_unsupported_tables | Bool | true | 是否跳过不支持的表,例如没有主键。 |
skip_sync_failed_tables | Bool | false | 是否跳过同步失败的表,以免阻止整个同步过程。 |
resync_table_task_schedule_time_ms | UInt64 | 1000 | 安排重新同步表任务的毫秒间隔。 |
resync_table_task_fail_retry_time | UInt64 | 5 | 重新同步表失败时的重试时间。 |
max_insert_wait_seconds_for_unique_table_leader | UInt64 | 30 | unique表成为领导者的最大等待时间。 |
shard_mode | Bool | false | 物化数据库是否分布式同步MySQL数据到ByteHouse |
zookeeper_session_expiration_check_period_s | UInt64 | 60 | 分片模式下ZooKeeper会话过期检查周期,单位为秒。 |
execute_dml_fail_max_retry_timeout_s | UInt64 | 600 | 执行 dml 操作失败时重试超时,以秒为单位。 |
retry_execute_dml_sleep_ms | UInt64 | 2000 | 重试执行 dml cmd 之间的睡眠时间 |
inner_query_distributed_ddl_task_timeout | UInt64 | 30 | 集群中所有主机的 DDL 查询响应超时。 如果未在所有主机上执行 ddl 请求,则响应将包含超时错误,并且请求将以异步模式执行。 负值意味着无穷大。 零表示异步模式。 |
max_concurrent_resync_task_num | UInt64 | 5 | 最大并发执行resync任务数(针对数据库)。 |
resync_table_per_task | UInt64 | 5 | 一个MaterializeMySQLResyncTask包含的最大resync表数量,每次调度时,都会从MaterializeMySQL数据库中选择resync_table_per_task数量的resync表来生成任务并进行表同步 |
parallel_in_resync_task | Bool | false | 同一resync任务中多个表的全量同步是否可以并行 |
表覆盖可用于自定义ByteHouse DDL查询,从而允许您对应用程序进行模式优化。这对于控制分区特别有用,分区对MaterializedMySQL的整体性能非常重要。
您可以对MaterializedMySQL表重写的模式转换进行以下操作:
当使用分布式模式时,默认会使用配置文件中的第一个集群信息,也可以通过在config文件中配置以下信息来指定集群信息:
<materialize_mysql><primary_cluster_name>...</primary_cluster_name></materialize_mysql>
注意
使用的cluster_name可以通过查询系统运维表system.materialize_mysql_status来获取。
MySQL | ByteHouse 企业版 |
---|---|
TINY | Int8 |
SHORT,SMALLINT | Int16 |
MEDIUMINT,INT,INTEGER,INT32 | Int32 |
BIGINT | Int64 |
LONG | UInt32 |
LONGLONG | UInt64 |
FLOAT | Float32 |
DOUBLE | Float64 |
DECIMAL,NEWDECIMAL | Decimal |
DATE,NEWDATE | Date |
DATETIME,TIMESTAMP | DateTime |
DATETIME2,TIMESTAMP2 | DateTime64 |
ENUM | Enum |
STRING | String |
VARCHAR,VAR_STRING | String |
BLOB | String |
BINARY | FixedString |
以上所有类型均支持为可空(nullable)。
MySQL DDL | ByteHouse 企业版 |
---|---|
CREATE TABLE | ✔️ |
DROP TABLE | ✔️ |
RENAME TABLE | ✔️ |
ADD COLUMN | ✔️ |
DROP COLUMN | ✔️ |
RENAME COLUMN | ✘ |
MODIFY COLUMN | ✘ |
ByteHouse企业版 底层引擎采用 HaUniqueMergeTree,因此直接支持insert、update和delete操作。
配置项 | 类型 | 说明 |
---|---|---|
mysql_info | String | MySQL连接信息,格式为ip:port |
mysql_database | String | 被同步的mysql库名 |
database | String | 云数据库ByteHouse中同步的数据库名 |
shard_mode | UInt8 | 是否为分布式模式 |
cluster_name | String | 选择的集群名称 |
zookeeper_path | String | zookeeper路径 |
sync_type | String | 同步状态,取值说明如下:
|
include_tables | Array | 同步包含的表名 |
exclude_tables | Array | 同步排除的表名 |
resync_tables | Array | 正在resync的表 |
seconds_behind_mysql | Int64 | 和mysql的主从延时,含义同mysql的Seconds_Behind_Master。当库处于非IncrementSync状态时值为-1 |
last_committed_position | String | 最后commit的binlog位置 |
last_executed_event | String | 最后执行的binlog event内容 |
total_position | String | MySQL中binlog的最新位置 |
error_count | UInt64 | 同步过程中出错的次数 |
already_skip_errors | UInt64 | 已经跳过的错误数 |
last_error_msg | String | 最后一次错误的信息 |
last_error_time | DataTime | 最后一次错误的发生时间 |
sync_failed_tables | Array | 同步失败的表 |
skipped_unsupported_tables | Array | 已跳过的不支持的表 |
分布式模式下,只有leader节点可以查询到该信息,因此想要获取这个系统表的信息需要执行以下SQL:
select * from cluster('<cluster_name>', system.materialize_mysql_status, (1,2))
部分列与 system.materialize_mysql_status 有相同的语义,但是指示范围不同。如 error_count:
配置项 | 类型 | 说明 |
---|---|---|
mysql_info | String | MySQL连接信息,格式为ip:port |
mysql_database | String | 被同步的mysql库名 |
database | String | 云数据库ByteHouse中同步的数据库名 |
shard_mode | UInt8 | 是否为分布式模式 |
cluster_name | String | 选择的集群名称 |
zookeeper_path | String | zookeeper路径 |
sync_type | String | 同步状态,取值说明如下:
|
last_committed_position | String | 最后commit的binlog位置 |
last_executed_event | String | 最后执行的binlog event内容 |
total_position | String | MySQL中binlog的最新位置 |
error_count | UInt64 | 同步过程中出错的次数 |
already_skip_errors | UInt64 | 已经跳过的错误数 |
last_error_msg | String | 最后一次错误的信息 |
last_error_time | DataTime | 最后一次错误的发生时间 |
resync_tables_in_task | Array | MaterializeMySQLResyncTask 任务中的待 resync table |
sync_failed_tables_in_task | Array | 任务中同步失败的表 |
skipped_unsupported_tables_in_task | Array | 任务中已跳过的不支持的表 |
分布式模式下,只有leader节点可以查询到该信息,因此想要获取这个系统表的信息需要执行以下SQL:
select * from cluster('<cluster_name>', system.materialize_mysql_resync_task_status, (1,2))
需要在config文件中配置如下:
<materialize_mysql_log> <database>system</database> <table>materialize_mysql_log</table> <partition_by>toYYYYMM(event_date)</partition_by> <flush_interval_milliseconds>7500</flush_interval_milliseconds> </materialize_mysql_log>
配置项 | 类型 | 说明 |
---|---|---|
database | String | 云数据库ByteHouse中同步的数据库。 |
event_type | String | 日志类型,取值说明如下:
|
event_date | Date | 发生日期 |
event_time | DateTime | 发生时间 |
resync_table | String | resync表名 |
exception | String | 详细的异常信息 |
分布式模式下,log只会记录在leader节点上,因此想要获取这个系统表的信息需要执行以下SQL:
select * from cluster('<cluster_name>', system.materialize_mysql_log, (1,2)) order by event_time desc limit 10;
shard_mode = 0: alter database
db
modify setting
setting_name
=
value
[, ...]
shard_mode = 1: alter database
db
on cluster
cluster_name
modify setting
setting_name
=
value
[, ...]
修改include_tables和exclude_tables时,引擎会检查互斥性,即不能同时设置include_tables和exclude_tables。此外,引擎会检查参数调整后是否有新的表需要同步,如果有,操作同下面的表同步。
注意:不允许通过此方式修改shard_mode参数
shard_mode = 0: system [stop] resync materialize mysql table
db
.
table
shard_mode = 1: system [stop] resync materialize mysql table on cluster
cluster_name db
.
table
此操作会重新/取消全量同步表,引擎会维护一份待resync table的列表并有一个后台线程来异步执行resync过程,待resync table的列表可以通过system.materialize_mysql_status系统表查询。
注意
若执行此命令时表处于FullSync状态会跳过此命令。
shard_mode = 0: system start/stop/restart sync materialize mysql
db
shard_mode = 1: system start/stop/restart sync materialize mysql on cluster
cluster_name
db
手动启动/停止/重启库同步任务,当库处于TableSync状态时仅会标记状态。
在MySQL中执行以下SQL:
mysql> CREATE DATABASE db; mysql> CREATE TABLE db.test (a INT PRIMARY KEY, b INT); mysql> INSERT INTO db.test VALUES (1, 11), (2, 22); mysql> DELETE FROM db.test WHERE a=1; mysql> ALTER TABLE db.test ADD COLUMN c VARCHAR(16); mysql> UPDATE db.test SET c='Wow!', b=222; mysql> SELECT * FROM test; 查询结果: +---+------+------+ | a | b | c | +---+------+------+ | 2 | 222 | Wow! | +---+------+------+
创建数据库并查询表:
CREATE DATABASE mysql ENGINE = MaterializeMySQL('localhost:3306', 'db', 'user', '***'); SHOW TABLES FROM mysql; 查询结果: ┌─name─┐ │ test │ └──────┘
MySQL插入数据后,在ByteHouse中查询数据:
SELECT * FROM mysql.test; 查询结果: ┌─a─┬──b─┐ │ 1 │ 11 │ │ 2 │ 22 │ └───┴────┘
MySQL删除数据、添加列并更新后,在ByteHouse中查询数据:
SELECT * FROM mysql.test; 查询结果: ┌─a─┬───b─┬─c────┐ │ 2 │ 222 │ Wow! │ └───┴─────┴──────┘