摘要: MySQL到ClickHouse資料同步原理及實踐
引言
熟悉MySQL的朋友應該都知道,MySQL叢集主從間資料同步機制十分完善。令人驚喜的是,ClickHouse作為近年來炙手可熱的大資料分析引擎也可以挂載為MySQL的從庫,作為MySQL的 "協處理器" 面向OLAP場景提供高效資料分析能力。早先的方案比較直截了當,通過第三方插件将所有MySQL上執行的操作進行轉化,然後在ClickHouse端逐一回放達到資料同步。終于在2020年下半年,Yandex 公司在 ClickHouse 社群釋出了MaterializeMySQL引擎,支援從MySQL全量及增量實時資料同步。MaterializeMySQL引擎目前支援 MySQL 5.6/5.7/8.0 版本,相容 Delete/Update 語句,及大部分常用的 DDL 操作。
基礎概念
- MySQL & ClickHouse
MySQL一般特指完整的MySQL RDBMS,是開源的關系型資料庫管理系統,目前屬于Oracle公司。MySQL憑借不斷完善的功能以及活躍的開源社群,吸引了越來越多的企業和個人使用者。
ClickHouse是由Yandex公司開源的面向OLAP場景的分布式列式資料庫。ClickHouse具有實時查詢,完整的DBMS及高效資料壓縮,支援批量更新及高可用。此外,ClickHouse還較好地相容SQL文法并擁有開箱即用等諸多優點。
- Row Store & Column Store
MySQL存儲采用的是Row Store,表中資料按照 Row 為邏輯存儲單元在存儲媒體中連續存儲。這種存儲方式适合随機的增删改查操作,對于按行查詢較為友好。但如果選擇查詢的目标隻涉及一行中少數幾個屬性,Row 存儲方式也不得不将所有行全部周遊再篩選出目标屬性,當表屬性較多時查詢效率通常較低。盡管索引以及緩存等優化方案在 OLTP 場景中能夠提升一定的效率,但在面對海量資料背景的 OLAP 場景就顯得有些力不從心了。
ClickHouse 則采用的是 Column Store,表中資料按照Column為邏輯存儲單元在存儲媒體中連續存儲。這種存儲方式适合采用 SIMD (Single Instruction Multiple Data) 并發處理資料,尤其在表屬性較多時查詢效率明顯提升。列存方式中實體相鄰的資料類型通常相同,是以天然适合資料壓縮進而達到極緻的資料壓縮比。

使用方法
-
部署Master-MySQL
開啟BinLog功能:ROW模式
開啟GTID模式:解決位點同步時MySQL主從切換問題(BinLog reset導緻位點失效)
# my.cnf關鍵配置
gtid_mode=ON
enforce_gtid_consistency=1
binlog_format=ROW
-
部署Slave-ClickHouse
擷取 ClickHouse/Master 代碼編譯安裝
推薦使用GCC-10.2.0,CMake 3.15,ninja1.9.0及以上
- 建立Master-MySQL中database及table
creat databases master_db;
use master_db;
CREATE TABLE IF NOT EXISTS `runoob_tbl`(
`runoob_id` INT UNSIGNED AUTO_INCREMENT,
`runoob_` VARCHAR(100) NOT NULL,
`runoob_author` VARCHAR(40) NOT NULL,
`submission_date` DATE,
PRIMARY KEY ( `runoob_id` )
)ENGINE=InnoDB DEFAULT CHARSET=utf8;
# 插入幾條資料
INSERT INTO runoob_tbl (runoob_, runoob_author, submission_date) VALUES ("MySQL-learning", "Bob", NOW());
INSERT INTO runoob_tbl (runoob_, runoob_author, submission_date) VALUES ("MySQL-learning", "Tim", NOW());
- 建立 Slave-ClickHouse 中 MaterializeMySQL database
# 開啟materialize同步功能
SET allow_experimental_database_materialize_mysql=1;
# 建立slave庫,參數分别是("mysqld服務位址", "待同步庫名", "授權賬戶", "密碼")
CREATE DATABASE slave_db ENGINE = MaterializeMySQL('192.168.6.39:3306', 'master_db', 'root', '3306123456');
此時可以看到ClickHouse中已經有從MySQL中同步的資料了:
DESKTOP:) select * from runoob_tbl;
SELECT *
FROM runoob_tbl
Query id: 6e2b5f3b-0910-4d29-9192-1b985484d7e3
┌─runoob_id─┬─runoob_title───┬─runoob_author─┬─submission_date─┐
│ 1 │ MySQL-learning │ Bob │ 2021-01-06 │
└───────────┴────────────────┴───────────────┴─────────────────┘
┌─runoob_id─┬─runoob_title───┬─runoob_author─┬─submission_date─┐
│ 2 │ MySQL-learning │ Tim │ 2021-01-06 │
└───────────┴────────────────┴───────────────┴─────────────────┘
2 rows in set. Elapsed: 0.056 sec.
工作原理
- BinLog Event
MySQL中BinLog Event主要包含以下幾類:
1. MYSQL_QUERY_EVENT -- DDL
2. MYSQL_WRITE_ROWS_EVENT -- insert
3. MYSQL_UPDATE_ROWS_EVENT -- update
4. MYSQL_DELETE_ROWS_EVENT -- delete
事務送出後,MySQL 将執行過的 SQL 處理 BinLog Event,并持久化到 BinLog 檔案
ClickHouse通過消費BinLog達到資料同步,過程中主要考慮3個方面問題:
- DDL相容:由于ClickHouse和MySQL的資料類型定義有差別,DDL語句需要做相應轉換
- Delete/Update 支援:引入_version字段,控制版本資訊
- Query 過濾:引入_sign字段,标記資料有效性
- DDL操作
對比一下MySQL的DDL語句以及在ClickHouse端執行的DDL語句:
mysql> show create table runoob_tbl\G;
*************************** 1. row ***************************
Table: runoob_tbl
Create Table: CREATE TABLE `runoob_tbl` (
`runoob_id` int unsigned NOT NULL AUTO_INCREMENT,
`runoob_` varchar(100) NOT NULL,
`runoob_author` varchar(40) NOT NULL,
`submission_date` date DEFAULT NULL,
PRIMARY KEY (`runoob_id`)
) ENGINE=InnoDB AUTO_INCREMENT=3 DEFAULT CHARSET=utf8
1 row in set (0.00 sec)
---------------------------------------------------------------
cat /metadata/slave_db/runoob_tbl.sql
ATTACH TABLE _ UUID '14dbff59-930e-4aa8-9f20-ccfddaf78077'
(
`runoob_id` UInt32,
`runoob_` String,
`runoob_author` String,
`submission_date` Nullable(Date),
`_sign` Int8 MATERIALIZED 1,
`_version` UInt64 MATERIALIZED 1
)
ENGINE = ReplacingMergeTree(_version)
PARTITION BY intDiv(runoob_id, 4294967)
ORDER BY tuple(runoob_id)
SETTINGS index_granularity = 8192
可以看到:
1、在DDL轉化時預設增加了2個隐藏字段:_sign(-1删除, 1寫入) 和 _version(資料版本)
2、預設将表引擎設定為 ReplacingMergeTree,以 _version 作為 column version
3、原DDL主鍵字段 runoob_id 作為ClickHouse排序鍵和分區鍵
此外還有許多DDL處理,比如增加列、索引等,相應代碼在Parsers/MySQL 目錄下。
- Delete/Update操作
Update:
# Mysql端:
UPDATE runoob_tbl set runoob_author='Mike' where runoob_id=2;
mysql> select * from runoob_tbl;
+-----------+----------------+---------------+-----------------+
| runoob_id | runoob_title | runoob_author | submission_date |
+-----------+----------------+---------------+-----------------+
| 1 | MySQL-learning | Bob | 2021-01-06 |
| 2 | MySQL-learning | Mike | 2021-01-06 |
+-----------+----------------+---------------+-----------------+
2 rows in set (0.00 sec)
----------------------------------------------------------------
# ClickHouse端:
DESKTOP:) select *, _sign, _version from runoob_tbl order by runoob_id;
SELECT
*,
_sign,
_version
FROM runoob_tbl
ORDER BY runoob_id ASC
Query id: c5f4db0a-eff6-4b49-a429-b55230c26301
┌─runoob_id─┬─runoob_title───┬─runoob_author─┬─submission_date─┬─_sign─┬─_version─┐
│ 1 │ MySQL-learning │ Bob │ 2021-01-06 │ 1 │ 2 │
│ 2 │ MySQL-learning │ Mike │ 2021-01-06 │ 1 │ 4 │
│ 2 │ MySQL-learning │ Tim │ 2021-01-06 │ 1 │ 3 │
└───────────┴────────────────┴───────────────┴─────────────────┴───────┴──────────┘
3 rows in set. Elapsed: 0.003 sec.
可以看到,ClickHouse資料也實時同步了更新操作。
- Delete:
# Mysql端
mysql> DELETE from runoob_tbl where runoob_id=2;
mysql> select * from runoob_tbl;
+-----------+----------------+---------------+-----------------+
| runoob_id | runoob_title | runoob_author | submission_date |
+-----------+----------------+---------------+-----------------+
| 1 | MySQL-learning | Bob | 2021-01-06 |
+-----------+----------------+---------------+-----------------+
1 row in set (0.00 sec)
----------------------------------------------------------------
# ClickHouse端
DESKTOP:) select *, _sign, _version from runoob_tbl order by runoob_id;
SELECT
*,
_sign,
_version
FROM runoob_tbl
ORDER BY runoob_id ASC
Query id: e9cb0574-fcd5-4336-afa3-05f0eb035d97
┌─runoob_id─┬─runoob_title───┬─runoob_author─┬─submission_date─┬─_sign─┬─_version─┐
│ 1 │ MySQL-learning │ Bob │ 2021-01-06 │ 1 │ 2 │
└───────────┴────────────────┴───────────────┴─────────────────┴───────┴──────────┘
┌─runoob_id─┬─runoob_title───┬─runoob_author─┬─submission_date─┬─_sign─┬─_version─┐
│ 2 │ MySQL-learning │ Mike │ 2021-01-06 │ -1 │ 5 │
└───────────┴────────────────┴───────────────┴─────────────────┴───────┴──────────┘
┌─runoob_id─┬─runoob_title───┬─runoob_author─┬─submission_date─┬─_sign─┬─_version─┐
│ 2 │ MySQL-learning │ Mike │ 2021-01-06 │ 1 │ 4 │
│ 2 │ MySQL-learning │ Tim │ 2021-01-06 │ 1 │ 3 │
└───────────┴────────────────┴───────────────┴─────────────────┴───────┴──────────┘
4 rows in set. Elapsed: 0.002 sec.
可以看到,删除id為2的行隻是額外插入了_sign == -1的一行記錄,并沒有真正删掉。
- 日志回放
MySQL 主從間資料同步時Slave節點将 BinLog Event 轉換成相應的SQL語句,Slave 模拟 Master 寫入。類似地,傳統第三方插件沿用了MySQL主從模式的BinLog消費方案,即将 Event 解析後轉換成 ClickHouse 相容的 SQL 語句,然後在 ClickHouse 上執行(回放),但整個執行鍊路較長,通常性能損耗較大。不同的是,MaterializeMySQL 引擎提供的内部資料解析以及回寫方案隐去了三方插件的複雜鍊路。回放時将 BinLog Event 轉換成底層 Block 結構,然後直接寫入底層存儲引擎,接近于實體複制。此方案可以類比于将 BinLog Event 直接回放到 InnoDB 的 Page 中。
同步政策
v20.9.1版本前是基于位點同步的,ClickHouse每消費完一批 BinLog Event,就會記錄 Event 的位點資訊到 .metadata 檔案:
[FavonianKong@Wsl[20:42:37]slave_db]
$ cat ./.metadata
Version: 2
Binlog File: mysql-bin.000003
Binlog Position:355005999
Data Version: 5
這樣當 ClickHouse 再次啟動時,它會把 {‘mysql-bin.000003’, 355005999} 二進制組通過協定告知 MySQL Server,MySQL 從這個位點開始發送資料:
s1> ClickHouse 發送 {‘mysql-bin.000003’, 355005999} 位點資訊給 MySQL
s2> MySQL 找到本地 mysql-bin.000003 檔案并定位到 355005999 偏移位置,讀取下一個 Event 發送給 ClickHouse
s3> ClickHouse 接收 binlog event 并完成同步操作
s4> ClickHouse 更新 .metadata位點
存在問題:
如果MySQL Server是一個叢集,通過VIP對外服務,MaterializeMySQL建立 database 時 host 指向的是VIP,當叢集主從發生切換後,{Binlog File, Binlog Position} 二進制組不一定是準确的,因為BinLog可以做reset操作。
s1> ClickHouse 發送 {'mysql-bin.000003’, 355005999} 給叢集新主 MySQL
s2> 新主 MySQL 發現本地沒有 mysql-bin.000003 檔案,因為它做過 reset master 操作,binlog 檔案是 mysql-bin.000001
s3> 産生錯誤複制
為了解決這個問題,v20.9.1版本後上線了 GTID 同步模式,廢棄了不安全的位點同步模式。
- GTID同步
GTID模式為每個 event 配置設定一個全局唯一ID和序号,直接告知 MySQL 這個 GTID 即可,于是.metadata變為:
[FavonianKong@Wsl[21:30:19]slave_db]
Version: 2
Binlog File: mysql-bin.000003
Executed GTID: 0857c24e-4755-11eb-888c-00155dfbdec7:1-783
Binlog Position:355005999
Data Version: 5
其中 0857c24e-4755-11eb-888c-00155dfbdec7 是生成 Event的主機UUID,1-783是已經同步的event區間
于是流程變為:
s1> ClickHouse 發送 GTID:0857c24e-4755-11eb-888c-00155dfbdec7:1-783 給 MySQL
s2> MySQL 根據 GTID 找到本地位點,讀取下一個 Event 發送給 ClickHouse
s3> ClickHouse 接收 BinLog Event 并完成同步操作
s4> ClickHouse 更新 .metadata GTID資訊
源碼分析
- 概述
在最新源碼 (v20.13.1.1) 中,ClickHouse 官方對 DatabaseMaterializeMySQL 引擎的相關源碼進行了重構,并适配了 GTID 同步模式。ClickHouse 整個項目的入口 main 函數在 /ClickHouse/programs/main.cpp 檔案中,主程式會根據接收指令将任務分發到 ClickHouse/programs 目錄下的子程式中處理。本次分析主要關注 Server 端 MaterializeMySQL 引擎的工作流程。
- 源碼目錄
與 MaterializeMySQL 相關的主要源碼路徑:
ClickHouse/src/databases/MySQL //MaterializeMySQL存儲引擎實作
ClickHouse/src/Storages/ //表引擎實作
ClickHouse/src/core/MySQL* //複制相關代碼
ClickHouse/src/Interpreters/ //Interpreters實作,SQL的rewrite也在這裡處理
ClickHouse/src/Parsers/MySQL //解析部分實作,DDL解析等相關處理在這裡
- 服務端主要流程
ClickHouse 使用 POCO 網絡庫處理網絡請求,Client連接配接的處理邏輯在 ClickHouse/src/Server/*Handler.cpp 的 hander方法裡。以TCP為例,除去握手,初始化上下文以及異常處理等相關代碼,主要邏輯可以抽象成:
// ClickHouse/src/Server/TCPHandler.cpp
TCPHandler.runImpl()
{
...
while(true) {
...
if (!receivePacket()) //line 184
continue
/// Processing Query //line 260
state.io = executeQuery(state.query, *query_context, ...);
...
}
- 資料同步預處理
Client發送的SQL在executeQuery函數處理,主要邏輯簡化如下:
// ClickHouse/src/Interpreters/executeQuery.cpp
static std::tuple executeQueryImpl(...)
{
...
// line 354,解析器可配置
ast = parseQuery(...);
...
// line 503, 根據文法樹生成interpreter
auto interpreter = InterpreterFactory::get(ast, context, ...);
...
// line 525, 執行器interpreter執行後傳回結果
res = interpreter->execute();
...
}
主要有三點:
1、解析SQL語句并生成文法樹 AST
2、InterpreterFactory 工廠類根據 AST 生成執行器
3、interpreter->execute()
跟進第三點,看看 InterpreterCreateQuery 的 excute() 做了什麼:
// ClickHouse/src/Interpreters/InterpreterCreateQuery.cpp
BlockIO InterpreterCreateQuery::execute()
{
...
// CREATE | ATTACH DATABASE
if (!create.database.empty() && create.table.empty())
// line 1133, 當使用MaterializeMySQL時,會走到這裡建庫
return createDatabase(create);
}
這裡注釋很明顯,主要執行 CREATE 或 ATTACH DATABASE,繼續跟進 createDatabase() 函數:
// ClickHouse/src/Interpreters/InterpreterCreateQuery.cpp
BlockIO InterpreterCreateQuery::createDatabase(ASTCreateQuery & create)
{
...
// line 208, 這裡會根據 ASTCreateQuery 參數,從 DatabaseFactory 工廠擷取資料庫對象
// 具體可以參考 DatabasePtr DatabaseFactory::getImpl() 函數
DatabasePtr database = DatabaseFactory::get(create, metadata_path, ...);
...
// line 253, 多态調用,在使用MaterializeMySQL時
// 上方get函數傳回的是 DatabaseMaterializeMySQL
database->loadStoredObjects(context, ...);
}
到這裡,相當于将任務分發給DatabaseMaterializeMySQL處理,接着跟蹤 loadStoredObjects 函數:
//ClickHouse/src/Databases/MySQL/DatabaseMaterializeMySQL.cpp
template
void DatabaseMaterializeMySQL::loadStoredObjects(Context & context, ...)
{
Base::loadStoredObjects(context, has_force_restore_data_flag, force_attach);
try
{
// line87, 這裡啟動了materialize的同步線程
materialize_thread.startSynchronization();
started_up = true;
}
catch (...)
...
}
跟進startSynchronization() 綁定的執行函數:
// ClickHouse/src/Databases/MySQL/MaterializeMySQLSyncThread.cpp
void MaterializeMySQLSyncThread::synchronization()
{
...
// 全量同步在 repareSynchronized() 進行
if (std::optional metadata = prepareSynchronized())
{
while (!isCancelled())
{
UInt64 max_flush_time = settings->max_flush_data_time;
BinlogEventPtr binlog_event = client.readOneBinlogEvent(...);
{
//增量同步偵聽binlog_envent
if (binlog_event)
onEvent(buffers, binlog_event, *metadata);
}
}
}
...
}
- 全量同步
MaterializeMySQLSyncThread::prepareSynchronized 負責DDL和全量同步,主要流程簡化如下:
// ClickHouse/src/Databases/MySQL/MaterializeMySQLSyncThread.cpp
std::optional MaterializeMySQLSyncThread::prepareSynchronized()
{
while (!isCancelled())
{
...
try
{
//構造函數内會擷取MySQL的狀态、MySQL端的建表語句,
MaterializeMetadata metadata(connection, ...);
// line345, DDL相關轉換
metadata.transaction(position, [&]()
{
cleanOutdatedTables(database_name, global_context);
dumpDataForTables(connection, metadata, global_context, ...);
});
return metadata;
}
...
}
}
ClickHouse作為MySQL從節點,在MaterializeMetadata構造函數中對MySQL端進行了一系列預處理:
1、将打開的表關閉,同時對表加上讀鎖并啟動事務
2、TablesCreateQuery通過SHOW CREATE TABLE 語句擷取MySQL端的建表語句
3、擷取到建表語句後釋放表鎖
繼續往下走,執行到 metadata.transaction() 函數,該調用傳入了匿名函數作為參數,一直跟進該函數會發現最終會執行匿名函數,也就是cleanOutdatedTables以及dumpDataForTables函數,主要看一下 dumpDataForTables 函數:
// ClickHouse/src/Databases/MySQL/MaterializeMySQLSyncThread.cpp
static inline void dumpDataForTables(...)
{
...
//line293, 這裡執行建表語句
tryToExecuteQuery(..., query_context, database_name, comment);
}
繼續跟蹤 tryToExecuteQuery 函數,會調用到 executeQueryImpl() 函數,上文提到過這個函數,但這次我們的上下文資訊變了,生成的執行器發生變化,此時會進行 DDL 轉化以及 dump table 等操作:
// ClickHouse/src/Interpreters/executeQuery.cpp
static std::tuple executeQueryImpl(...)
{
...
// line 354,解析器可配置
ast = parseQuery(...);
...
// line 503,這裡跟之前上下文資訊不同,生成interpreter也不同
auto interpreter = InterpreterFactory::get(ast,context, ...);
...
// line 525, 執行器interpreter執行後傳回結果
res = interpreter->execute();
...
}
此時 InterpreterFactory 傳回 InterpreterExternalDDLQuery,跟進去看 execute 函數做了什麼:
// ClickHouse/src/Interpreters/InterpreterExternalDDLQuery.cpp
BlockIO InterpreterExternalDDLQuery::execute()
{
...
if (external_ddl_query.from->name == "MySQL")
{
#ifdef USE_MYSQL
...
// line61, 當全量複制執行DDL時,會執行到這裡
else if (...->as())
return MySQLInterpreter::InterpreterMySQLCreateQuery(
external_ddl_query.external_ddl, cogetIdentifierName(arguments[0]),
getIdentifierName(arguments[1])).execute();
#endif
}
...
return BlockIO();
}
繼續跟進去看看 getIdentifierName(arguments[1])).execute() 做了什麼事情:
// ClickHouse/src/Interpreters/MySQL/InterpretersMySQLDDLQuery.h
class InterpreterMySQLDDLQuery : public IInterpreter
{
public:
...
BlockIO execute() override
{
...
// line68, 把從MySQL擷取到的DDL語句進行轉化
ASTs rewritten_queries = InterpreterImpl::getRewrittenQueries(
query, context, mapped_to_database, mysql_database);
// line70, 這裡執行轉化後的DDL語句
for (const auto & rewritten_query : rewritten_queries)
executeQuery(..., queryToString(rewritten_query), ...);
return BlockIO{};
}
...
}
進一步看 InterpreterImpl::getRewrittenQueries 是怎麼轉化 DDL 的:
// ClickHouse/src/Interpreters/MySQL/InterpretersMySQLDDLQuery.cpp
ASTs InterpreterCreateImpl::getRewrittenQueries(...)
{
...
// 檢查是否存在primary_key, 沒有直接報錯
if (primary_keys.empty())
throw Exception("cannot be materialized, no primary keys.", ...);
...
// 添加 _sign 和 _version 列.
auto sign_column_name = getUniqueColumnName(columns_name_and_type, "_sign");
auto version_column_name = getUniqueColumnName(columns_name_and_type, "_version");
// 這裡悄悄把建表引擎修改成了ReplacingMergeTree
storage->set(storage->engine, makeASTFunction("ReplacingMergeTree", ...));
...
return ASTs{rewritten_query};
}
完成DDL轉換之後就會去執行新的DDL語句,完成建表操作,再回到 dumpDataForTables:
// ClickHouse/src/Databases/MySQL/MaterializeMySQLSyncThread.cpp
static inline void dumpDataForTables(...)
{
...
//line293, 這裡執行建表語句
tryToExecuteQuery(..., query_context, database_name, comment);
...
// line29, 這裡開始 dump 資料并存放到MySQLBlockInputStream
MySQLBlockInputStream input(connection, ...);
}
- 增量同步
還記得startSynchronization() 綁定的執行函數嗎?全量同步分析都是在 prepareSynchronized()進行的,那增量更新呢?
// ClickHouse/src/Databases/MySQL/MaterializeMySQLSyncThread.cpp
void MaterializeMySQLSyncThread::synchronization()
{
...
// 全量同步在 repareSynchronized() 進行
if (std::optional metadata = prepareSynchronized())
{
while (!isCancelled())
{
UInt64 max_flush_time = settings->max_flush_data_time;
BinlogEventPtr binlog_event = client.readOneBinlogEvent(...);
{
//增量同步偵聽binlog_envent
if (binlog_event)
onEvent(buffers, binlog_event, *metadata);
}
}
}
...
}
可以看到,while 語句裡有一個 binlog_event 的偵聽函數,用來偵聽 MySQL 端 BinLog 日志變化,一旦 MySQL 端執行相關操作,其 BinLog 日志會更新并觸發 binlog_event,增量更新主要在這裡進行。
// ClickHouse/src/Databases/MySQL/MaterializeMySQLSyncThread.cpp
void MaterializeMySQLSyncThread::onEvent(Buffers & buffers, const BinlogEventPtr & receive_event, MaterializeMetadata & metadata)
{
// 增量同步通過監聽binlog event實作,目前支援四種event:MYSQL_WRITE_ROWS_EVENT、
// MYSQL_UPDATE_ROWS_EVENT、MYSQL_DELETE_ROWS_EVENT 和 MYSQL_QUERY_EVENT
// 具體的流程可以查找對應的 onHandle 函數, 不在此詳細分析
if (receive_event->type() == MYSQL_WRITE_ROWS_EVENT){...}
else if (receive_event->type() == MYSQL_UPDATE_ROWS_EVENT){...}
else if (receive_event->type() == MYSQL_DELETE_ROWS_EVENT){...}
else if (receive_event->type() == MYSQL_QUERY_EVENT){...}
else {/* MYSQL_UNHANDLED_EVENT*/}
}
小結
MaterializeMySQL 引擎是 ClickHouse 官方2020年主推的特性,由于該特性在生産環境中屬于剛需且目前剛上線不久,整個子產品處于高速疊代的狀态,是以有許多待完善的功能。例如複制過程狀态檢視以及資料的一緻性校驗等。感興趣的話可參考Github上的2021-Roadmap,裡面會更新一些社群最近得計劃。以上内容如有了解錯誤還請指正。
引用
ClickHouse社群文檔
ClickHouse社群源碼
MySQL實時複制與實作
MaterializeMySQL引擎分析
本文分享自華為雲社群《MySQL到ClickHouse的高速公路-MaterializeMySQL引擎》,原文作者:FavonianKong 。
點選關注,第一時間了解華為雲新鮮技術~