MySQL 数据传输参数设置对数据一致性的影响
作者通过全面系统的测试,揭秘 lower_case_table_names 设置对数据一致性的影响。
作者:刘安
爱可生测试团队成员,主要负责 DTLE 开源项目相关测试任务,擅长 Python 自动化测试开发。
本文来源:原创投稿
- 爱可生开源社区出品,原创内容未经授权不得随意使用,转载请联系小编并注明来源。
背景
最近有客户询问:源端 MySQL 和目标端 MySQL 的 lower_case_table_names
的配置不一致时,DTLE 是否能正常同步数据?
本文就这个问题测试一下 lower_case_table_names
的设置对 DTLE 同步数据的影响。
为了简化场景这里只讨论 Linux 环境下
lower_case_table_names
配置为0
或1
的情况。
环境准备
- 部署 DTLE 4.23.04.2
- 两个 MySQL 实例,
lower_case_table_names
配置不同
# lower_case_table_names=0 $ dbdeployer deploy single 5.7 --port 3306 --sandbox-directory sandbox --port-as-server-id --remote-access % --bind-address 0.0.0.0 -c skip-name-resolve -c binlog_format=ROW -c binlog_row_image=FULL -c log_slave_updates=ON --gtid -c lower_case_table_names=0 # lower_case_table_names=1 $ dbdeployer deploy single 5.7 --port 3306 --sandbox-directory sandbox --port-as-server-id --remote-access % --bind-address 0.0.0.0 -c skip-name-resolve -c binlog_format=ROW -c binlog_row_image=FULL -c log_slave_updates=ON --gtid -c lower_case_table_names=1
第一种情况
- 源端 MySQL
@@lctn=0
- 目标端 MySQL
@@lctn=1
根据 DTLE 的开发文档 可知,此种情况下的 DTLE 行为:
- 源端按原大小写执行。
- 目标端收到 BinlogEntry - DML/DDL 按原大小写执行,MySQL 会自动转为小写。
以下是执行一些典型 SQL 的数据同步结果:
源端 SQL 与数据 | 目标段数据 |
---|---|
CREATE DATABASE ACTION_DB; <br><br>mysql> SHOW DATABASES\G <br>****** 1. row ******<br>Database: ACTION_DB | mysql> SHOW DATABASES\G <br>****** 1. row ****** <br>Database: action_db <br>****** 2. row ****** <br>Database: dtle<br/> |
CREATE TABLE ACTION_DB.A(id int(11)) <br/>ENGINE=InnoDB DEFAULT CHARSET=utf8; <br><br>mysql> SHOW TABLES\G <br>****** 1. row ****** <br>Tables_in_ACTION_DB: A | mysql> SHOW TABLES\G <br>****** 1. row ****** <br>Tables_in_action_db: a |
INSERT INTO ACTION_DB.A VALUES (1); <br><br>mysql> SELECT * FROM ACTION_DB.A\G <br>****** 1. row ****** <br>id: 1 | mysql> SELECT * FROM ACTION_DB.A\G <br>****** 1. row ****** <br>id: 1 |
ALTER TABLE ACTION_DB.A ADD D CHAR(20); <br><br>mysql> SHOW CREATE TABLE ACTION_DB.A\G <br>****** 1. row ****** <br>Table: A <br><br>Create Table: CREATE TABLE `A` ( <br>`id` int(11) DEFAULT NULL, <br>`D` char(20) DEFAULT NULL <br>) ENGINE=InnoDB DEFAULT CHARSET=utf8 | mysql> SHOW CREATE TABLE ACTION_DB.A\G <br>****** 1. row ****** <br>Table: A <br><br>Create Table: CREATE TABLE `a` (<br/>`id` int(11) DEFAULT NULL, <br/>`D` char(20) DEFAULT NULL <br>) ENGINE=InnoDB DEFAULT CHARSET=utf8 |
ALTER TABLE ACTION_DB.A RENAME TO ACTION_DB.B; <br><br>mysql> SHOW TABLES\G <br>****** 1. row ****** <br>Tables_in_ACTION_DB: B | mysql> SHOW TABLES\G <br>****** 1. row ****** <br>Tables_in_action_db: b |
DROP TABLE ACTION_DB.B; <br><br>mysql> SHOW TABLES\G <br>Empty set (0.00 sec) | mysql> SHOW TABLES\G <br>Empty set (0.00 sec) |
可以看到 DTLE 同步后的数据是符合预期。在源端 MySQL 与 SQL 的大小写一致,在目标端 MySQL 自动转为小写。
接下来看一些极端情况:
源端 SQL 和数据 | 目标端数据 |
---|---|
CREATE DATABASE ACTION_DB; <br><br>mysql> SHOW DATABASES\G <br>****** 1. row ****** <br>Database: ACTION_DB | mysql> SHOW DATABASES\G <br>****** 1. row ****** <br>Database: action_db <br>****** 2. row ****** <br/>Database: dtle |
CREATE DATABASE action_db; <br><br>mysql> SHOW DATABASES\G <br>****** 1. row ****** <br>Database: ACTION_DB <br>****** 2. row ****** <br>Database: action_db | mysql> SHOW DATABASES\G <br>****** 1. row ****** <br>Database: action_db <br>****** 2. row ****** <br>Database: dtle |
CREATE TABLE ACTION_DB.A(id int(11)) <br>ENGINE=InnoDB DEFAULT CHARSET=utf8; <br><br>mysql> use ACTION_DB <br>mysql> SHOW TABLES\G <br>****** 1. row ****** <br>Tables_in_ACTION_DB: A | mysql> use action_db <br>mysql> SHOW TABLES\G <br>****** 1. row ****** <br/>Tables_in_action_db: a |
CREATE TABLE ACTION_DB.a(id int(11)) <br>ENGINE=InnoDB DEFAULT CHARSET=utf8; <br><br>mysql> use ACTION_DB <br>mysql> SHOW TABLES\G <br>****** 1. row ****** <br>Tables_in_ACTION_DB: A <br>****** 2. row ****** <br>Tables_in_ACTION_DB: a | mysql> SHOW TABLES\G <br>****** 1. row ****** <br>Tables_in_action_db: a |
CREATE TABLE action_db.A(id int(11)) <br>ENGINE=InnoDB DEFAULT CHARSET=utf8; <br><br> mysql> USE action_db <br>mysql> SHOW TABLES\G <br>****** 1. row ****** <br>Tables_in_action_db: A | mysql> SHOW TABLES\G <br>****** 1. row ****** <br>Tables_in_action_db: a |
CREATE TABLE action_db.a(id int(11)) <br>ENGINE=InnoDB DEFAULT CHARSET=utf8; <br><br>mysql> USE action_db <br>mysql> SHOW TABLES\G <br>****** 1. row ****** <br>Tables_in_action_db: A <br>****** 2. row ****** <br>Tables_in_action_db: a | mysql> SHOW TABLES\G <br>****** 1. row ****** <br>Tables_in_action_db: a |
INSERT INTO ACTION_DB.A VALUES (1); <br><br>mysql> SELECT * FROM ACTION_DB.A\G <br>****** 1. row ****** <br>id: 1 | mysql> SELECT * FROM action_db.a\G <br>****** 1. row ****** <br>id: 1 |
INSERT INTO ACTION_DB.a VALUES (2); <br><br> mysql> SELECT * FROM ACTION_DB.a\G <br>****** 1. row ****** <br>id: 2 | mysql> SELECT * FROM action_db.a\G <br>****** 1. row ****** <br>id: 1 <br>****** 2. row ****** <br>id: 2 |
INSERT INTO action_db.A VALUES (3); <br><br>mysql> SELECT * FROM action_db.A\G <br>****** 1. row ****** <br>id: 3 | mysql> SELECT * FROM action_db.a\G <br>****** 1. row ****** <br>id: 1 <br>****** 2. row ****** <br>id: 2 <br>****** 3. row ****** <br>id: 3 |
INSERT INTO action_db.a VALUES (4); <br><br>mysql> SELECT * FROM action_db.a\G <br>****** 1. row ****** <br>id: 4 | mysql> SELECT * FROM action_db.a\G <br>****** 1. row ****** <br>id: 1 <br>****** 2. row ****** <br>id: 2 <br>****** 3. row ****** <br>id: 3 <br>****** 4. row ****** <br>id: 4 |
可以看到此时 DTLE 的行为,相当于把 ACTION_DB.A
、ACTION_DB.a
、action_db.A
和 action_db.a
四个表的数据合并到一张表。
所以为了避免此种情况,可以通过在创建 DTLE 作业的时候,为每个重名的库配置 TableSchemaRename
属性、重名表配置 Table.TableRename
属性的方式来解决。
第二种情况
- 源端 MySQL
@@lctn=1
- 目标端MySQL
@@lctn=0
根据 DTLE 的开发文档 里面介绍,此种情况下的 DTLE 行为:
- 用户填写的复制范围,应转化为小写。
- 不复制已有的大写
SCHEMA.TABLE
。 - 新增的
Schema.Table
,转化为小写后,加入复制范围。 - 目标端无论
@@lctn=0
或@@lctn=1
,都应该复制源端的效果,即小写。 - 目标端收到的 BinlogEntry 中,
schema.tableName
已为小写。
以下是执行一些典型 SQL 的数据同步结果:
源端 SQL 和数据 | 目标端数据 |
---|---|
CREATE DATABASE ACTION_DB; <br><br>mysql> SHOW DATABASES\G <br>****** 1. row ****** <br>Database: action_db | mysql> SHOW DATABASES\G <br>****** 1. row ****** <br>Database: action_db <br>****** 2. row ****** <br>Database: dtle |
CREATE TABLE ACTION_DB.A(id int(11)) <br>ENGINE=InnoDB DEFAULT CHARSET=utf8; <br><br>mysql> SHOW TABLES\G <br>****** 1. row ****** <br>Tables_in_action_db: a | mysql> SHOW TABLES\G <br>****** 1. row ****** <br>Tables_in_action_db: a |
INSERT INTO ACTION_DB.A VALUES (1); <br><br>mysql> SELECT * FROM ACTION_DB.A\G <br>****** 1. row ****** <br>id: 1 | mysql> SELECT * FROM action_db.a\G <br>****** 1. row ****** <br>id: 1 |
ALTER TABLE ACTION_DB.A ADD D CHAR(20); <br><br>mysql> SHOW CREATE TABLE ACTION_DB.A\G <br>****** 1. row ****** <br> Table: A <br><br>Create Table: CREATE TABLE `a` ( <br> `id` int(11) DEFAULT NULL, <br> `D` char(20) DEFAULT NULL <br>) ENGINE=InnoDB DEFAULT CHARSET=utf8 | mysql> SHOW CREATE TABLE action_db.a\G <br>****** 1. row ****** <br> Table: a <br><br>Create Table: CREATE TABLE `a` (<br> id int(11) DEFAULT NULL, <br> `D` char(20) DEFAULT NULL <br>) ENGINE=InnoDB DEFAULT CHARSET=utf8 |
ALTER TABLE ACTION_DB.A RENAME TO ACTION_DB.B; <br><br>mysql> SHOW TABLES\G <br>****** 1. row ****** <br>Tables_in_action_db: b | mysql> SHOW TABLES\G <br>****** 1. row ****** <br>Tables_in_action_db: b |
DROP TABLE ACTION_DB.B; <br><br>mysql> SHOW TABLES\G <br>Empty set (0.00 sec) | mysql> SHOW TABLES\G <br>Empty set (0.00 sec) |
可以看到 DTLE 同步后的数据是符合预期。在源端 MySQL 自动转为小写,在目标端 MySQL 同步的数据也是小写的。
其他限制
通过观察 general log
可以得知,DTLE 作业是在初始化作业的时候获取源端以及目标端 MySQL 的 lower_case_table_names
配置的,所以在 DTLE 作业存续期间更改 MySQL 的该参数是 DTLE 无法感知并处理的。因此禁止在 DTLE 作业存续期间更改此配置。
总结
- 原则上 DTLE 还是建议源端和目标端设置相同。
- 当源端 MySQL
@@lctn=0
且目标端 MySQL@@lctn=1
时,需要注意源端仅大小写不同的同名库表在目标端会汇聚到同一个表中的问题。 - DTLE 作业存续期间,MySQL 上的
lower_case_table_names
配置不可改变。
关于 SQLE
爱可生开源社区的 SQLE 是一款面向数据库使用者和管理者,支持多场景审核,支持标准化上线流程,原生支持 MySQL 审核且数据库类型可扩展的 SQL 审核工具。
SQLE 获取

低调大师中文资讯倾力打造互联网数据资讯、行业资源、电子商务、移动互联网、网络营销平台。
持续更新报道IT业界、互联网、市场资讯、驱动更新,是最及时权威的产业资讯及硬件资讯报道平台。
转载内容版权归作者及来源网站所有,本站原创内容转载请注明来源。
- 上一篇
文件系统考古4:如何支持多个文件系统
Steve Kleiman 在 1986 年撰写了《Vnodes: An Architecture for Multiple File System Types in Sun UNIX》一文。这篇论文幅较短,大部分内容是数据结构的列举,以及 C 语言结构之间相互指向的图表。 Steve Kleiman是分布式文件系统领域的专家,在 Sun Microsystem 工作了多年,曾参与开发 Sun Network File System(NFS)等项目,为分布式文件系统领域做出了重要贡献。 Kleiman 希望在 Unix 中能够拥有多个文件系统,并希望这些文件系统能够共享接口和内存。具体而言,他希望设计一个能够提供以下功能的架构: 一个可以支持多个实现的通用接口; 支持 BSD FFS,以及两个远程文件系统 NFS 和 RFS,还有特定的非 Unix 文件系统,如MS-DOS; 接口定义的操作需要是原子性的。 并且,能够在不影响性能的情况下动态地处理内存和数据结构,支持重入(reentrant) 和多核,并且具有一定面向对象进行编程的特性。 重入(reentrant) 是指程序或子程序在...
- 下一篇
深度剖析线上应用节点流量隔离技术
作者:谢文欣(风敬) 为什么要做流量隔离 源于一个 EDAS 客户遇到的棘手情况:他们线上的一个 Pod CPU 指标异常,为了进一步诊断问题,客户希望在不重建此 Pod 的情况下保留现场,但诊断期间流量还会经过这个异常 Pod,导致影响服务质量,于是询问我们有没有办法可以把流入异常节点的流量摘除掉,形成一个隔离的诊断环境。经诊断后,如果异常可以修复,待修复完成后,再解除流量隔离,节点恢复正常工作。 除了在诊断场景需要对所有输入流量进行隔离外,在一些线上演练中还需对特定流量进行隔离以实现模拟演练效果。面对这类流量隔离问题时,我们首先考虑的是全链路流量控制。目前,EDAS 上的全链路流控能够在不重启应用节点的情况下控制流量走向。然而,全链路流控仅能控制微服务框架流量,无法满足隔离所有或特定流量的需求。 为此,我们进行了深入研究,实现了一套开箱即用的流量隔离工具,能够动态隔离特定流量,并在隔离后可随时恢复,以满足各种场景下的流量隔离需求。 隔离哪些流量 流量隔离的目的是阻断应用节点的流入流量,首先明确下微服务应用节点流入的流量有哪些。 流入微服务应用节点的流量大致可以分为两大类:服务流量、...
相关文章
文章评论
共有0条评论来说两句吧...
文章二维码
点击排行
推荐阅读
最新文章
- CentOS7编译安装Gcc9.2.0,解决mysql等软件编译问题
- Jdk安装(Linux,MacOS,Windows),包含三大操作系统的最全安装
- SpringBoot2整合Redis,开启缓存,提高访问速度
- SpringBoot2整合MyBatis,连接MySql数据库做增删改查操作
- CentOS8,CentOS7,CentOS6编译安装Redis5.0.7
- MySQL8.0.19开启GTID主从同步CentOS8
- Mario游戏-低调大师作品
- Linux系统CentOS6、CentOS7手动修改IP地址
- Docker安装Oracle12C,快速搭建Oracle学习环境
- CentOS7安装Docker,走上虚拟化容器引擎之路