• 从 MySQL 到 ClickHouse 实时数据同步 —— MaterializeMySQL + Materialized View


    目录

    一、总体架构

    二、安装配置 MySQL

    1. 创建 mysql 用户

    2. 建立 MySQL 使用的目录

    3. 解压安装包

    4. 配置环境变量

    5. 创建 MySQL 配置文件

    6. MySQL 系统初始化

    7. 启动 mysql 服务器

    8. 创建 dba 用户

    三、配置 MySQL 主从复制

    四、在 ClickHouse 中创建 MySQL 引擎数据库

    五、在 ClickHouse 中创建物化视图

    六、物化视图数据刷新

    1. 初始数据装载

    2. 增量数据刷新

    参考:


            本篇演示使用 ClickHouse 的 MaterializeMySQL 数据库引擎和物化视图,实时将 MySQL 库表中的数据同步到 ClickHouse 的库表中。相关软件版本如下:

    • MySQL:8.0.16
    • ClickHouse:24.1.8

            这种方案的好处是操作简单,几乎不需要额外配置即可实现。


    一、总体架构

            总体结构如下图所示。

            ClickHouse 是由四个实例构成的两分片、没分片两副本集群,票选和协调器使用 ClickHouse 自带的 keeper 组件。分片、副本、keeper 节点部署如下表所示。

    IP

    主机名

    实例角色

    ClickHouse Keeper

    172.18.4.126

    node1

    分片1副本1

    *

    172.18.4.188

    node2

    分片1副本2

    *

    172.18.4.71

    node3

    分片2副本1

    *

    172.18.4.86

    node4

    分片2副本2

            ClickHouse 集群部署过程参见“ClickHouse 集群部署(不需要 Zookeeper)”。另外在 172.18.16.156 上安装 MySQL,并启动两个实例做主从复制,主库实例用3306端口,从库实例用3307端口。

    二、安装配置 MySQL

            安装配置 MySQL 一主一从双实例。

    1. 创建 mysql 用户

    1. # root 用于执行
    2. useradd mysql
    3. passwd mysql

    2. 建立 MySQL 使用的目录

    1. # 创建数据目录,确保数据目录 mysqldata 为空
    2. mkdir -p /data/3306/mysqldata
    3.  
    4. # 创建 binlog 目录
    5. mkdir -p /data/3306/dblog
    6.  
    7. # 创建临时目录
    8. mkdir -p /data/3306/tmp
    9.  
    10. # 修改目录属主为 mysql
    11. chown -R mysql:mysql /data
    12.  
    13. # 使用 mysql 用户执行下面的安装过程
    14. su - mysql

    3. 解压安装包

    1. # 进入安装目录
    2. cd ~
    3.  
    4. # 从tar包中把提取文件
    5. tar xvf mysql-8.0.16-linux-glibc2.12-x86_64.tar.xz
    6.  
    7. # 建立软连接
    8. ln -s mysql-8.0.16-linux-glibc2.12-x86_64 mysql-8.0.16

    4. 配置环境变量

    1. # 将 MySQL 可执行文件所在目录添加到 $PATH 环境变量中
    2. # 编辑文件
    3. vim ~/.bash_profile
    4.  
    5. # 修改或添加如下两行
    6. PATH=$PATH:$HOME/.local/bin:$HOME/bin:/home/mysql/mysql-8.0.16/bin
    7. export PATH
    8.  
    9. # 使配置生效
    10. source ~/.bash_profile

    5. 创建 MySQL 配置文件

    1. # 编辑文件
    2. vim /home/mysql/my_3306.cnf
    3. 文件内容如下:
    4. [mysqld]
    5. max_allowed_packet=1G
    6. log_timestamps=system
    7. binlog_transaction_dependency_tracking  = WRITESET
    8. transaction_write_set_extraction        = XXHASH64
    9.  
    10. binlog_expire_logs_seconds=259200
    11. lower_case_table_names=1
    12. secure_file_priv=''
    13. log_bin_trust_function_creators=on
    14. character-set-server = utf8mb4
    15. default_authentication_plugin=mysql_native_password
    16. basedir=/home/mysql/mysql-8.0.16-linux-glibc2.12-x86_64
    17. datadir=/data/3306/mysqldata
    18. socket=/data/3306/mysqldata/mysql.sock
    19.  
    20. wait_timeout=30
    21. innodb_buffer_pool_size = 16G
    22. max_connections = 1000
    23.  
    24. default-time-zone = '+8:00'
    25.  
    26. port = 3306
    27. skip-name-resolve 
    28. user=mysql
    29.  
    30. innodb_print_all_deadlocks=1
    31. log_output='table'
    32. slow_query_log = 1
    33. long_query_time = 1
    34.  
    35. tmp_table_size = 32M
    36.  
    37. # 开启 binlog
    38. log-bin=/data/3306/dblog/mysql-bin
    39. log-bin-index = /data/3306/dblog/mysql-bin.index 
    40.  
    41. tmpdir = /data/3306/tmp
    42.  
    43. server-id = 1563306
    44.  
    45. innodb_data_file_path = ibdata1:1G:autoextend
    46. innodb_data_home_dir = /data/3306/mysqldata
    47.  
    48. innodb_log_buffer_size = 16M
    49. innodb_log_file_size = 1G
    50. innodb_log_files_in_group = 3
    51. innodb_log_group_home_dir=/data/3306/dblog
    52. innodb_max_dirty_pages_pct = 90
    53. innodb_lock_wait_timeout = 120
    54.  
    55. gtid-mode = on
    56. enforce_gtid_consistency=true
    57.  
    58. local_infile=0
    59. log_error='/data/3306/mysqldata/master.err'
    60. skip_symbolic_links=yes
    61.  
    62. [mysqldump]
    63. quick
    64. max_allowed_packet = 1G
    65.  
    66. [mysqld_safe]
    67. open-files-limit = 8192

            以下这三个参数必须设置:

    1. default_authentication_plugin=mysql_native_password
    2. gtid-mode = on
    3. enforce_gtid_consistency=true

            如果不设置 default_authentication_plugin,在 ClickHouse 中创建 MySQL 引擎数据库会报以下错误:

    1. Received exception from server (version 24.1.8):
    2. Code: 695. DB::Exception: Received from localhost:9000. DB::Exception: There was an error on [node2:9000]: Code: 695. DB::Exception: Load job 'startup MaterializedMySQL database test_mysql' failed: Code: 537. DB::Exception: Illegal MySQL variables, the MaterializedMySQL engine requires default_authentication_plugin='mysql_native_password'. (ILLEGAL_MYSQL_VARIABLE),. (ASYNC_LOAD_FAILED) (version 24.1.8.22 (official build)). (ASYNC_LOAD_FAILED)

            如果不启用 GTID,在 ClickHouse 中创建 MySQL 引擎数据库会报以下错误:

    1. Received exception from server (version 24.1.8):
    2. Code: 1002. DB::Exception: Received from localhost:9000. DB::Exception: The replication sender thread cannot start in AUTO_POSITION mode: this server has GTID_MODE = OFF instead of ON.. ()

    6. MySQL 系统初始化

    mysqld --defaults-file=/home/mysql/my_3306.cnf --initialize

    7. 启动 mysql 服务器

    mysqld_safe --defaults-file=/home/mysql/my_3306.cnf &

    8. 创建 dba 用户

    1. # 连接 mysql 服务器
    2. mysql -u root -p -S /data/3306/mysqldata/mysql.sock
    3.  
    4. -- 修改 root 用户密码
    5. alter user user() identified by "123456";
    6.  
    7. -- 创建一个新的 dba 账号
    8. create user 'dba'@'%' identified with mysql_native_password by '123456';
    9. grant all on *.* to 'dba'@'%' with grant option;

            重复执行 2 - 8 步,将 3306 换成 3307,创建从库实例。

    三、配置 MySQL 主从复制

            3306 主库实例执行:

    1. -- 查看复制位点
    2. show master status;
    3. -- 创建复制用户并授权
    4. create user 'repl'@'%' identified with mysql_native_password by '123456';
    5. grant replication client,replication slave on *.* to 'repl'@'%';
    6. -- 创建测试库表及数据
    7. create database test;
    8. create table test.t1 (
    9.   id bigint(20) not null auto_increment,
    10.   remark varchar(32) default null comment '备注',
    11.   createtime timestamp not null default current_timestamp comment '创建时间',
    12.   primary key (id));
    13. insert into test.t1 (remark) values ('第一行:row1'),('第二行:row2'),('第三行:row3');

            输出:

    1. mysql> show master status;
    2. +------------------+----------+--------------+------------------+------------------------------------------+
    3. | File             | Position | Binlog_Do_DB | Binlog_Ignore_DB | Executed_Gtid_Set                        |
    4. +------------------+----------+--------------+------------------+------------------------------------------+
    5. | mysql-bin.000001 |      977 |              |                  | ba615057-e11c-11ee-b80e-246e961c91f8:1-3 |
    6. +------------------+----------+--------------+------------------+------------------------------------------+
    7. 1 row in set (0.00 sec)
    8.  
    9. mysql> create user 'repl'@'%' identified with mysql_native_password by '123456';
    10. Query OK, 0 rows affected (0.01 sec)
    11.  
    12. mysql> grant replication client,replication slave on *.* to 'repl'@'%';
    13. Query OK, 0 rows affected (0.00 sec)
    14.  
    15. mysql> create database test;
    16. Query OK, 1 row affected (0.00 sec)
    17.  
    18. mysql> create table test.t1 (
    19.     ->   id bigint(20) not null auto_increment,
    20.     ->   remark varchar(32) default null comment '备注',
    21.     ->   createtime timestamp not null default current_timestamp comment '创建时间',
    22.     ->   primary key (id));
    23. Query OK, 0 rows affected (0.01 sec)
    24.  
    25. mysql> insert into test.t1 (remark) values ('第一行:row1'),('第二行:row2'),('第三行:row3');
    26. Query OK, 3 rows affected (0.00 sec)
    27. Records: 3  Duplicates: 0  Warnings: 0

            3307 从库实例执行:

    1. change master to
    2. master_host='172.18.16.156',
    3. master_port=3306,
    4. master_user='repl',
    5. master_password='123456',
    6. master_log_file='mysql-bin.000001',
    7. master_log_pos=977;
    8.  
    9. start slave;
    10. show slave status\G
    11. select user,host from mysql.user;
    12. select * from test.t1;

            输出:

    1. mysql> change master to
    2.     -> master_host='172.18.16.156',
    3.     -> master_port=3306,
    4.     -> master_user='repl',
    5.     -> master_password='123456',
    6.     -> master_log_file='mysql-bin.000001',
    7.     -> master_log_pos=977;
    8. Query OK, 0 rows affected, 2 warnings (0.00 sec)
    9.  
    10. mysql> start slave;
    11. Query OK, 0 rows affected (0.01 sec)
    12.  
    13. mysql> show slave status\G
    14. *************************** 1. row ***************************
    15.                Slave_IO_State: Waiting for master to send event
    16.                   Master_Host: 172.18.16.156
    17.                   Master_User: repl
    18.                   Master_Port: 3306
    19.                 Connect_Retry: 60
    20.               Master_Log_File: mysql-bin.000001
    21.           Read_Master_Log_Pos: 2431
    22.                Relay_Log_File: vvgg-z2-music-mysqld-relay-bin.000002
    23.                 Relay_Log_Pos: 1776
    24.         Relay_Master_Log_File: mysql-bin.000001
    25.              Slave_IO_Running: Yes
    26.             Slave_SQL_Running: Yes
    27.               Replicate_Do_DB: 
    28.           Replicate_Ignore_DB: 
    29.            Replicate_Do_Table
    30.        Replicate_Ignore_Table
    31.       Replicate_Wild_Do_Table
    32.   Replicate_Wild_Ignore_Table
    33.                    Last_Errno: 0
    34.                    Last_Error
    35.                  Skip_Counter: 0
    36.           Exec_Master_Log_Pos: 2431
    37.               Relay_Log_Space: 1999
    38.               Until_Condition: None
    39.                Until_Log_File
    40.                 Until_Log_Pos: 0
    41.            Master_SSL_Allowed: No
    42.            Master_SSL_CA_File
    43.            Master_SSL_CA_Path: 
    44.               Master_SSL_Cert: 
    45.             Master_SSL_Cipher: 
    46.                Master_SSL_Key
    47.         Seconds_Behind_Master: 0
    48. Master_SSL_Verify_Server_Cert: No
    49.                 Last_IO_Errno: 0
    50.                 Last_IO_Error
    51.                Last_SQL_Errno: 0
    52.                Last_SQL_Error
    53.   Replicate_Ignore_Server_Ids: 
    54.              Master_Server_Id: 1563306
    55.                   Master_UUID: ba615057-e11c-11ee-b80e-246e961c91f8
    56.              Master_Info_File: mysql.slave_master_info
    57.                     SQL_Delay: 0
    58.           SQL_Remaining_Delay: NULL
    59.       Slave_SQL_Running_State: Slave has read all relay log; waiting for more updates
    60.            Master_Retry_Count: 86400
    61.                   Master_Bind: 
    62.       Last_IO_Error_Timestamp: 
    63.      Last_SQL_Error_Timestamp: 
    64.                Master_SSL_Crl: 
    65.            Master_SSL_Crlpath: 
    66.            Retrieved_Gtid_Set: ba615057-e11c-11ee-b80e-246e961c91f8:4-8
    67.             Executed_Gtid_Set: ba615057-e11c-11ee-b80e-246e961c91f8:4-8,
    68. c2df1946-e11c-11ee-8026-246e961c91f8:1-3
    69.                 Auto_Position: 0
    70.          Replicate_Rewrite_DB: 
    71.                  Channel_Name: 
    72.            Master_TLS_Version: 
    73.        Master_public_key_path: 
    74.         Get_master_public_key: 0
    75.             Network_Namespace: 
    76. 1 row in set (0.00 sec)
    77.  
    78. mysql> select user,host from mysql.user;
    79. +------------------+-----------+
    80. | user             | host      |
    81. +------------------+-----------+
    82. | dba              | %         |
    83. | repl             | %         |
    84. | mysql.infoschema | localhost |
    85. | mysql.session    | localhost |
    86. | mysql.sys        | localhost |
    87. | root             | localhost |
    88. +------------------+-----------+
    89. 6 rows in set (0.00 sec)
    90.  
    91. mysql> select * from test.t1;
    92. +----+------------------+---------------------+
    93. | id | remark           | createtime          |
    94. +----+------------------+---------------------+
    95. |  1 | 第一行:row1     | 2024-04-19 08:46:25 |
    96. |  2 | 第二行:row2     | 2024-04-19 08:46:25 |
    97. |  3 | 第三行:row3     | 2024-04-19 08:46:25 |
    98. +----+------------------+---------------------+
    99. 3 rows in set (0.00 sec)

            MySQL主从复制相关配置参见“配置异步复制”。

    四、在 ClickHouse 中创建 MySQL 引擎数据库

    1. set allow_experimental_database_materialized_mysql=1;
    2. create database test_mysql on cluster cluster_2S_2R
    3. engine = MaterializeMySQL('172.18.16.156:3307', 'test', 'dba', '123456');

            如果不设置 allow_experimental_database_materialized_mysql=1 会报如下错误:

    1. Received exception from server (version 24.1.8):
    2. Code: 336. DB::Exception: Received from localhost:9000. DB::Exception: There was an error on [node3:9000]: Code: 336. DB::Exception: MaterializedMySQL is an experimental database engine. Enable allow_experimental_database_materialized_mysql to use it. (UNKNOWN_DATABASE_ENGINE) (version 24.1.8.22 (official build)). (UNKNOWN_DATABASE_ENGINE)

            输出:

    1. vvml-yz-hbase-test.172.18.4.188 :) set allow_experimental_database_materialized_mysql=1;
    2. SET allow_experimental_database_materialized_mysql = 1
    3. Query id: 7ce08dff-8d1e-496f-a1af-39c5bec41643
    4. Ok.
    5. 0 rows in set. Elapsed: 0.001 sec. 
    6. vvml-yz-hbase-test.172.18.4.188 :) create database test_mysql on cluster cluster_2S_2R
    7. engine = MaterializeMySQL('172.18.16.156:3307', 'test', 'dba', '123456');
    8. CREATE DATABASE test_mysql ON CLUSTER cluster_2S_2R
    9. ENGINE = MaterializeMySQL('172.18.16.156:3307', 'test', 'dba', '123456')
    10. Query id: 610e3c86-c5b6-477c-b4a3-33624809d05c
    11. ┌─host──┬─port─┬─status─┬─error─┬─num_hosts_remaining─┬─num_hosts_active─┐
    12. │ node49000 │      0 │       │                   3 │                0
    13. │ node39000 │      0 │       │                   2 │                0
    14. │ node29000 │      0 │       │                   1 │                0
    15. │ node19000 │      0 │       │                   0 │                0
    16. └───────┴──────┴────────┴───────┴─────────────────────┴──────────────────┘
    17. 4 rows in set. Elapsed: 0.086 sec. 
    18. vvml-yz-hbase-test.172.18.4.188 :)

            现在可以查询 MySQL 的库表数据:

    1. vvml-yz-hbase-test.172.18.4.188 :) select * from test_mysql.t1;
    2. SELECT *
    3. FROM test_mysql.t1
    4. Query id: bae55b87-6e80-4e7f-a2c7-b9312ffef999
    5. ┌─id─┬─remark───────┬──────────createtime─┐
    6. │  1 │ 第一行:row12024-04-19 08:46:25
    7. │  2 │ 第二行:row22024-04-19 08:46:25
    8. │  3 │ 第三行:row32024-04-19 08:46:25
    9. └────┴──────────────┴─────────────────────┘
    10. 3 rows in set. Elapsed: 0.002 sec. 
    11. vvml-yz-hbase-test.172.18.4.188 :) 

    五、在 ClickHouse 中创建物化视图

    1. -- 创建数据库
    2. create database db1 on cluster cluster_2S_2R;
    3. -- 创建本地表
    4. create table db1.t1 on cluster cluster_2S_2R
    5.   id Int64,
    6.   remark Nullable(String),
    7.   createtime timestamp,
    8.   primary key id)
    9. engine = ReplicatedMergeTree(
    10.     '/clickhouse/tables/{shard}/t1',
    11.     '{replica}')
    12. order by id;
    13. -- 创建分布式表
    14. create table db1.t1_replica_all ON CLUSTER 'cluster_2S_2R'
    15. as db1.t1
    16. engine = Distributed(cluster_2S_2R, db1, t1, rand());
    17. -- 创建物化视图
    18. create materialized view db1.t1_mv on cluster cluster_2S_2R
    19. to db1.t1_replica_all
    20. as
    21. select * from test_mysql.t1;

            注意创建本地表时的数据类型及其是否允许为空的属性,都要与 MySQL 表的数据类型匹配,否则会报类似下面的错误:

    1. Received exception from server (version 24.1.8):
    2. Code: 53. DB::Exception: Received from localhost:9000. DB::Exception: Type mismatch for column id. Column has type Int64, got type UInt64. (TYPE_MISMATCH)
    3. Received exception from server (version 24.1.8):
    4. Code: 53. DB::Exception: Received from localhost:9000. DB::Exception: Type mismatch for column remark. Column has type Nullable(String), got type String. (TYPE_MISMATCH)

            数据类型的对应如下图所示:

    六、物化视图数据刷新

    1. 初始数据装载

            ClickHouse 物化视图创建时缺省不会进行初始数据装载。初始装载的方法有两个,一是在创建物化视图时使用 POPULATE。POPULATE 关键字决定了物化视图的更新策略:

    • 若有 POPULATE 则在创建视图的过程会将源表已经存在的数据一并导入,类似于create table ... as
    • 若无 POPULATE 则物化视图在创建之后没有数据,只会同步物化视图创建之后写入源表的数据

            ClickHouse 官方并不推荐使用 POPULATE,因为在创建物化视图的过程中同时写入的数据不能被插入物化视图。本例使用 TO [db].[table] 语法,物化视图创建后手工执行初始数据装载。

    1. -- MySQL 从库停止复制
    2. stop slave;
    3. -- ClickHouse 初始装载物化视图
    4. insert into db1.t1_mv(id,remark,createtime) select * from test_mysql.t1;
    5. -- MySQL 从库开启复制
    6. start slave;

            这么简单的一句却是实现初始数据装载的关键所在。从库停止复制,不影响主库的正常使用,也就不会影响业务。此时从库的数据处于静止状态,不会产生变化,这使得获取存量数据变得轻而易举。然后执行普通的 insert ... select 语句向物化视图插入数据,数据实际是被写入 db1.t1_replica_all 表。之后在 ClickHouse 集群中的任一实例上,都能从物化视图中查询到一致的 MySQL 存量数据。

    1. vvml-yz-hbase-test.172.18.4.86 :) select * from db1.t1_replica_all;
    2. SELECT *
    3. FROM db1.t1_replica_all
    4. Query id: 5063cd12-6eba-4a81-9c75-d892cb152b17
    5. ┌─id─┬─remark───────┬──────────createtime─┐
    6. │  1 │ 第一行:row12024-04-19 08:46:25
    7. │  2 │ 第二行:row22024-04-19 08:46:25
    8. │  3 │ 第三行:row32024-04-19 08:46:25
    9. └────┴──────────────┴─────────────────────┘
    10. 3 rows in set. Elapsed: 0.004 sec. 
    11. vvml-yz-hbase-test.172.18.4.86 :) select * from db1.t1_mv;
    12. SELECT *
    13. FROM db1.t1_mv
    14. Query id: e319f96b-f299-41a1-b730-737a42ceedb0
    15. ┌─id─┬─remark───────┬──────────createtime─┐
    16. │  1 │ 第一行:row12024-04-19 08:46:25
    17. │  2 │ 第二行:row22024-04-19 08:46:25
    18. │  3 │ 第三行:row32024-04-19 08:46:25
    19. └────┴──────────────┴─────────────────────┘
    20. 3 rows in set. Elapsed: 0.006 sec. 
    21. vvml-yz-hbase-test.172.18.4.86 :) 

    2. 增量数据刷新

            ClickHouse 的物化视图能够在底层数据更新后,自动更新自己的数据。数据更新包括两个方面的变化:基础表的数据修改和基础表的数据新增。

    • 基础表的数据修改

            如果基础表的数据修改,物化视图会自动更新。这是通过 ClickHouse 的引擎和存储方式来实现的。当基础表的一行记录被修改,ClickHouse 会将这个修改转化为一个新的 INSERT 语句,并且将其发送到物化视图中。这样,物化视图就能够自动更新自己的数据。

    • 基础表的数据新增

            如果基础表的数据新增,物化视图同样会自动更新。这是通过设置物化视图的刷新机制来实现的。刷新机制有两种类型:定时刷新和自动刷新。

            需要注意的是,ClickHouse 的物化视图虽然能够自动更新数据,但是会带来一些性能上的损失,尤其是在基础表数据量较大的情况下。因此,在设计物化视图时,需要考虑这个因素,同时选择合适的刷新机制来平衡性能和数据实时性的需求。

            当然既然选择了 ClickHouse,使用场景就应该是数据新增比较多,而极少去修改或删除。对于一般对实时要求不高的业务场景,定时刷新完全够用了。

    1. -- MySQL 主库修改数据
    2. insert into test.t1 (remark) values ('第四行:row4');
    3. update test.t1 set remark = '第五行:row5' where id = 4;
    4. delete from test.t1 where id =1;
    5. insert into test.t1 (remark) values ('第六行:row6');
    6. 此时 MySQL 的数据如下:
    7. mysql> select * from test.t1;
    8. +----+------------------+---------------------+
    9. | id | remark           | createtime          |
    10. +----+------------------+---------------------+
    11. |  2 | 第二行:row2     | 2024-04-19 08:46:25 |
    12. |  3 | 第三行:row3     | 2024-04-19 08:46:25 |
    13. |  4 | 第五行:row5     | 2024-04-19 11:24:33 |
    14. |  5 | 第六行:row6     | 2024-04-19 11:56:20 |
    15. +----+------------------+---------------------+
    16. 4 rows in set (0.00 sec)

            ClickHouse 查询数据,所有实例上查询物化视图返回相同的数据:

    1. vvml-yz-hbase-test.172.18.4.86 :) select * from db1.t1_mv order by id;
    2. SELECT *
    3. FROM db1.t1_mv
    4. ORDER BY id ASC
    5. Query id: 1e3f8bb3-6fdd-4f3e-a494-af8c72e3dab2
    6. ┌─id─┬─remark───────┬──────────createtime─┐
    7. │  1 │ 第一行:row12024-04-19 08:46:25
    8. └────┴──────────────┴─────────────────────┘
    9. ┌─id─┬─remark───────┬──────────createtime─┐
    10. │  1 │ 第一行:row12024-04-19 08:46:25
    11. │  1 │ 第一行:row12024-04-19 08:46:25
    12. │  1 │ 第一行:row12024-04-19 08:46:25
    13. │  1 │ 第一行:row12024-04-19 08:46:25
    14. │  2 │ 第二行:row22024-04-19 08:46:25
    15. │  3 │ 第三行:row32024-04-19 08:46:25
    16. └────┴──────────────┴─────────────────────┘
    17. ┌─id─┬─remark───────┬──────────createtime─┐
    18. │  4 │ 第四行:row42024-04-19 11:24:33
    19. └────┴──────────────┴─────────────────────┘
    20. ┌─id─┬─remark───────┬──────────createtime─┐
    21. │  4 │ 第五行:row52024-04-19 11:24:33
    22. └────┴──────────────┴─────────────────────┘
    23. ┌─id─┬─remark───────┬──────────createtime─┐
    24. │  4 │ 第四行:row42024-04-19 11:24:33
    25. │  4 │ 第五行:row52024-04-19 11:24:33
    26. │  4 │ 第四行:row42024-04-19 11:24:33
    27. │  4 │ 第四行:row42024-04-19 11:24:33
    28. │  4 │ 第五行:row52024-04-19 11:24:33
    29. │  4 │ 第五行:row52024-04-19 11:24:33
    30. └────┴──────────────┴─────────────────────┘
    31. ┌─id─┬─remark───────┬──────────createtime─┐
    32. │  5 │ 第六行:row62024-04-19 11:56:20
    33. └────┴──────────────┴─────────────────────┘
    34. ┌─id─┬─remark───────┬──────────createtime─┐
    35. │  5 │ 第六行:row62024-04-19 11:56:20
    36. └────┴──────────────┴─────────────────────┘
    37. 17 rows in set. Elapsed: 0.005 sec. 

            查询本地表,同一分片的副本返回相同的结果,不同分片的数据不同:

    1. -- node1
    2. vvml-yz-hbase-test.172.18.4.126 :) select * from db1.t1 order by id;
    3. SELECT *
    4. FROM db1.t1
    5. ORDER BY id ASC
    6. Query id: c4d50038-f73f-4989-948e-031d6ff5d5ee
    7. ┌─id─┬─remark───────┬──────────createtime─┐
    8. │  1 │ 第一行:row12024-04-19 08:46:25
    9. │  1 │ 第一行:row12024-04-19 08:46:25
    10. │  1 │ 第一行:row12024-04-19 08:46:25
    11. │  1 │ 第一行:row12024-04-19 08:46:25
    12. │  2 │ 第二行:row22024-04-19 08:46:25
    13. │  3 │ 第三行:row32024-04-19 08:46:25
    14. │  4 │ 第四行:row42024-04-19 11:24:33
    15. │  4 │ 第五行:row52024-04-19 11:24:33
    16. │  4 │ 第四行:row42024-04-19 11:24:33
    17. │  4 │ 第四行:row42024-04-19 11:24:33
    18. │  4 │ 第五行:row52024-04-19 11:24:33
    19. │  4 │ 第五行:row52024-04-19 11:24:33
    20. └────┴──────────────┴─────────────────────┘
    21. ┌─id─┬─remark───────┬──────────createtime─┐
    22. │  5 │ 第六行:row62024-04-19 11:56:20
    23. └────┴──────────────┴─────────────────────┘
    24. 13 rows in set. Elapsed: 0.002 sec. 
    25. vvml-yz-hbase-test.172.18.4.126 :) 
    26. -- node3
    27. vvml-yz-hbase-test.172.18.4.71 :) select * from db1.t1 order by id;
    28. SELECT *
    29. FROM db1.t1
    30. ORDER BY id ASC
    31. Query id: e91e72b7-508a-48a2-b08f-779e49b7cd01
    32. ┌─id─┬─remark───────┬──────────createtime─┐
    33. │  1 │ 第一行:row12024-04-19 08:46:25
    34. └────┴──────────────┴─────────────────────┘
    35. ┌─id─┬─remark───────┬──────────createtime─┐
    36. │  4 │ 第四行:row42024-04-19 11:24:33
    37. └────┴──────────────┴─────────────────────┘
    38. ┌─id─┬─remark───────┬──────────createtime─┐
    39. │  4 │ 第五行:row52024-04-19 11:24:33
    40. └────┴──────────────┴─────────────────────┘
    41. ┌─id─┬─remark───────┬──────────createtime─┐
    42. │  5 │ 第六行:row62024-04-19 11:56:20
    43. └────┴──────────────┴─────────────────────┘
    44. 4 rows in set. Elapsed: 0.002 sec. 
    45. vvml-yz-hbase-test.172.18.4.71 :) 

            MySQL 中只有三行数据,ClickHouse 却有17行。ID=1 的行在 MySQL 中被删除,而在 ClickHouse 中并没有删除,而是变为了5行。虽然定义本地表时指定了 id 字段为主键,但 ClickHouse 中自定义的主键并不保证唯一性,即便本地表也是如此。ID=2 和 ID=3 的行在 MySQL 中没有变化,在 ClickHouse 中也分别是唯一的一行。ID=4 的行在 MySQL 中先新增后修改,在 ClickHouse 中都是新增数据。ID=6 的行在 MySQL 中新增一行,在 ClickHouse 中却增加了两行。分布式表的分片规则用的是随机,为什么 MySQL 端新增一条数据,到 ClickHouse 中两个分片都写了呢?

            实验到此实现了数据实时同步,但 ClickHouse 中的数据明显多了很多行,这与选择的表引擎、使用的分片规则都有关系,比较复杂,对数据的解释也变得很重要。所以这里得出的结论是,要用 ClickHouse,最好还是定期从源端导入数据比较靠谱,而且源端最好是只新增数据。

    参考:

  • 相关阅读:
    Hutool工具包导入excel文件数据到数据库
    数据结构之手撕顺序表(讲解➕源代码)
    智能外呼系统、rgb摄像头
    Mac下根目录和家目录的区别
    增删卜易——八宫六十四卦
    typescript核心
    《分治中的典型题型-求字符串的最大子段和》
    js节流和防抖
    常用的云安全防护措施盘点
    企业快速开发平台Spring Cloud+Spring Boot+Mybatis+ElementUI 之浅谈代码语言的魅力
  • 原文地址:https://blog.csdn.net/wzy0623/article/details/137959646