携程:从MySQL迁移OceanBase的数据库发布系统实践

本文主要是介绍携程:从MySQL迁移OceanBase的数据库发布系统实践,希望对大家解决编程问题提供一定的参考价值,需要的开发者们随着小编来一起学习吧!

作者简介:杨晓军 现就职于携程的数据库团队,主要负责携程数据库的研发与管理,专注于提升数据库的稳定性。

自分布式关系型数据库OceanBase开源以来,携程已经在线上环境中进行了广泛的应用,取代了原先以MySQL为主力的业务数据库系统。在转型过程中,确保与MySQL的高度兼容性成为了我们选型的关键考量。为此,我们自主研发了一套数据库发布系统,旨在通过该系统,DBA、业务专家及运维团队能够迅速识别并理解MySQL与OceanBase在DDL语句执行上的差异,从而加速对OceanBase数据库的掌握与适应,最终提升整体应用系统的稳定性。

本文从以下三个方面介绍携程自研数据库发布系统的实践。

  • 数据库发布系统研发的四个步骤
  • MySQL 与 OceanBase 的兼容性与差异性
  • MySQL 数据同步 OceanBase 过程中 DDL 遇到的问题

一、数据库发布系统研发的四个步骤

MySQL 作为全球最受开发者欢迎的数据库,被广泛应用于各类场景中。其中,MySQL 5.7 版本正是携程在大规模使用的数据库。但在 MySQL 系统中,并不是所有的 DDL 操作都是线上实时进行的,导致了主从复制延迟的问题,即使是 MySQL 8.0 版本也不能避免这个问题的发生。随着表中数据规模越来越大,DDL 的危险系数就越来越高,我们自研的数据库发布系统通过第三方工具 gh-ost 不断监听从节点的复制延迟,解决了长时间执行 DDL 时导致的延迟问题,确保了 MySQL 的高可用。

数据库发布系统的研发共分为四个步骤:设计系统、生成 SQL 语句和发布计划、发布测试环境、发布生产环境。

第一步,设计系统。

设计系统的分工可能在每个公司略有差异,就携程而言,由于系统中的库、表太多,DBA 不参与表结构评审,表结构的设计及变更都由研发人员进行。如下图,研发人员可以通过界面或通过导入 SQL 来完成表结构的变更操作。

第二步,生成 SQL 语句和计划发布。

所有的表结构变更提交后就进入第二步:生成 SQL 语句和发布计划。生成 SQL 语句比较好理解,基于设计系统中的修改生成代码,比如,在界面上添加一个字段 testindex,并在新加的字段上创建索引,就会生成如下 SQL 语句,包括添加的 testindex 在哪个前置字段的后面、是否为空及默认值信息等,最重要的是找到对应数据库所在的 MySQL 实例:

alter table `testyxj_part` add `testindex` varchar(10) not null default ‘’  comment ‘test’ after `datachange_lasttime`;
alter table `testyxj_part` add key test(testindex);

前面说到的系统设计对应的是开发环境,而此处的 SQL 语句其实是对比开发环境和测试环境的表结构差异生成的。在携程,数据库部署环境分为开发环境、测试环境和生产环境,我们会根据配置表来生成数据库最终在哪个环境以及要去哪些集群上执行。从下图的数据库配置信息中可以看到,在每个环境中数据库的类型是不固定的,比如,在设计系统中是 MySQL,在测试环境也可以是 OceanBase。除拉数据库和 OceanBase 的集群关系外,我们还会将数据库和租户的对应关系的元数据放置在这个配置表中。

第三步:发布测试环境。

因为我们会定期检查表数据量,可以保证单表大小基本不会超过 10GB,所以测试环境的发布直接使用了原生的 MySQL DDL 命令。发布测试环境时,没有对同一个发布单下的同一张表做 DDL 合并,比如,同一张表添加2个字段,发布系统会按照字段顺序进行两次拷贝整表的过程。因此,测试环境可以兼容 OceanBase 的表结构变更,只需在连接数据库的时候带上租户即可。

第四步:发布生产环境。

生产环境的表容量大小不一,大则上百 GB,小则几 MB,为了保证 MySQL 大表做表结构变更时主从复制延迟低,我们使用了开源工具 gh-ost。在发布生产环境时,将 DDL 任务放到一个 gh-ost 队列中,进入队列后会进行待发布数据库的检测,比如,待发布数据库所在的集群主从复制是否正常、剩余磁盘空间是否可以支撑一次全量拷贝并在发布完成后磁盘剩余空间是否仍在90%以下,等等。同一个数据库的同一个表会将 DDL 操作合并发布。例如,一个发布要加2个字段,而在 gh-ost 处理时实际只会做一次全量拷贝的动作。其他的 DDL 可以使用 in-place 方法的 DDL 操作判断,如下图,将 varchar10 改为 varchar20,没有跨越 255 字节这个边界,此外,创建表删除、表索引等没有压力的 DDL 都使用原生 DDL 加速发布。

二、MySQL 与 OceanBase 在系统中的兼容性与差异性

1、MySQL 与 OceanBase 在系统中的兼容性。

携程开始使用 OceanBase 数据库后,需要和原来的 MySQL 系统兼容。有两种兼容方案,一是在 OceanBase 数据库上线后,进行表结构变更并发布,开发环境、测试环境、生产环境都采用 OceanBase;二是在迁移过程中进行兼容部署,比如,测试环境是 OceanBase,生产环境使用 MySQL。如下图,在设计系统加入 OceanBase,初期,我们把开发环境的 OceanBase 放在 MySQL 实例上,因为大部分研发人员要做的表结构变更如添加字段、索引都是常规动作,而 hash 分区、key 分区都还刚起步,这部分对于设计表结构的研发人员可能比较陌生,所以暂时将OceanBase数据库部署在 MySQL 实例上用于兼容设计系统。

将 OceanBase DB 和租户、集群的关系加入发布的配置表,这样才能正常生成发布计划,并且代码根据对应的租户连接到数据库之后执行 DDL,如下图。

得益于 OceanBase LSM Tree 的存储引擎,几乎所有 DDL 操作都是真正的 “Online DDL”,因此,OceanBase 数据库发布时我们直接采用了原生 DDL 进行发布(下图为代码判断逻辑)

2、MySQL 与 OceanBase 在系统中的差异性。

在开发环境中,携程将 MySQL 和 OceanBase 做了分离,在 OceanBase 设计时可能会使用分区、特殊压缩等与 MySQL 语法不兼容的功能,这部分在 MySQL 上无法实现,同时前端也会对这些差异功能提供默认值选项,比如,OceanBase 的索引功能可以选 local 索引和 global 索引,在携程,默认使用 global 索引。

但是,Range 分区类型的 Oceanbase 表发布索引自动转换成 local 类型。我们有一张 MySQL 的表,表上索引如下图所示:

研发人员为了实现 MySQL 业务迁移到 Oceanbase 的同时能自动完成数据清理,可能会将原先 MySQL 的普通表在 Oceanbase 中改成 range 分区表,由于分区键必须包含在主键和唯一索引中,并且唯一索引只能创建为 global 类型,因此表结构迁移到 OceanBase 之后演变成下图所示:

从 MySQL 迁移到 OceanBase 时有数据实时同步任务,某一天我们发现使用这个唯一索引查询数据出现了重复数据,如下图所示:

我们在排查时发现,原来是唯一索引失效了,如下图 show index from 的结果显示为 index error,最终,我们判断可能是 drop partition 这个分区清理的动作超时导致了索引失效。

因此,我们放弃了 range 分区,仍然保持了 MySQL 的结构,也就是对原有的表结构进行迁移。经过这次的“踩坑”,我们在发布系统中增加了一个判断,当 OceanBase 的表是 range 类型的分区表时,不能创建唯一索引,并且在生成的发布 SQL 中我们会自动将 global 的索引转换成 local 索引,以保证索引不会失效引发性能问题或其他问题,效果如下图。

三、MySQL 数据同步 OceanBase 时 DDL 遇到的问题

场景一:添加字段。

  • OceanBase 添加不允许为空有默认值的字段,增量同步正常;MySQL 添加相同字段,发布期间写入数据,增量同步 OceanBase 正常。
  • OceanBase 添加不允许为空无默认值的字段,增量同步报错;MySQL 添加相同字段,无法添加,非空字段需要设置默认值。
  • OceanBase 添加允许有默认值的字段,增量同步正常;MySQL 添加相同字段,增量同步正常。
  • OceanBase 添加允许为空无默认值的字段,增量同步正常;MySQL侧 添加相同字段,增量同步正常。

场景二:删除字段。

  • MySQL 删除字段,增量同步正常; OceanBase 删除相同字段,增量同步正常。

场景三:清空表。

  • MySQL 清空表 DDL 的命令无法同步至 OceanBase。
truncate table hjjtesttable;

  • OceanBase 清空表后可以继续同步。
truncate table hjjtesttable;

场景四:修改字段。

  • OceanBase 修改 allow null 字段为 not null 并设置默认值,需要先处理 MySQL 历史空数据,更新 MySQL 数据后未同步至 OceanBase。
alter table `hjjtesttable` modify `testyxj8` varchar(10) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci  not null  default '888' comment 'test';
ERROR 1138 (22004): Invalid use of NULL value
update hjjtesttable set testyxj8 ='888' where testyxj8 is null;

  • OceanBase 修改 not null 字段为 allow null,并且没有默认值,更新 MySQL 数据后未同步至 OceanBase。
OB:alter table `hjjtesttable` modify `testyxj8` varchar(10) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci null  comment 'test';
MYSQL:update hjjtesttable set testyxj8='8888' where id =1;
OB:select * from hjjtesttable where id =1 and testyxj8='8888';
Empty set (0.00 sec)

  • OceanBase 不允许修改非字符类型和修改列定义,仅支持增加特定字符数据类型(VARCHAR、VARBINARY、CHAR等)的长度。
alter table hjjtesttable modify testyxj7 bigint COMMENT 'test';
ERROR 1235 (0A000): Alter non string type not supported

场景五:创建索引。

  • OceanBase 创建索引,增量同步正常;MySQL 创建索引,增量同步正常。

场景六:删除索引。

  • MySQL创建索引,增量同步正常;OceanBase 创建索引,增量同步正常。
  • 类似上述六个场景中的情况还有很多,因此,在 MySQL 向 OceanBase 迁移的过程中,我们将 MySQL 的发布环境全部冻结了,不允许执行任何 DDL 语句。

以上就是携程通过自研数据库发布系统提高应用稳定性的实践经验,希望我们的经验分享能够帮助到你。另外,在携程与 OceanBase 合作期间,携程的各项测试表明,OceanBase 原生分布式数据库的各方面性能都可以满足携程的业务需求。因此,我们非常感谢 OceanBase 的所有技术支持人员,相信在后续的合作中,OceanBase 能发挥更优越的表现。

这篇关于携程:从MySQL迁移OceanBase的数据库发布系统实践的文章就介绍到这儿,希望我们推荐的文章对编程师们有所帮助!



http://www.chinasem.cn/article/1118009

相关文章

Spring Security简介、使用与最佳实践

《SpringSecurity简介、使用与最佳实践》SpringSecurity是一个能够为基于Spring的企业应用系统提供声明式的安全访问控制解决方案的安全框架,本文给大家介绍SpringSec... 目录一、如何理解 Spring Security?—— 核心思想二、如何在 Java 项目中使用?——

MySQL的JDBC编程详解

《MySQL的JDBC编程详解》:本文主要介绍MySQL的JDBC编程,具有很好的参考价值,希望对大家有所帮助,如有错误或未考虑完全的地方,望不吝赐教... 目录前言一、前置知识1. 引入依赖2. 认识 url二、JDBC 操作流程1. JDBC 的写操作2. JDBC 的读操作总结前言本文介绍了mysq

java.sql.SQLTransientConnectionException连接超时异常原因及解决方案

《java.sql.SQLTransientConnectionException连接超时异常原因及解决方案》:本文主要介绍java.sql.SQLTransientConnectionExcep... 目录一、引言二、异常信息分析三、可能的原因3.1 连接池配置不合理3.2 数据库负载过高3.3 连接泄漏

防止Linux rm命令误操作的多场景防护方案与实践

《防止Linuxrm命令误操作的多场景防护方案与实践》在Linux系统中,rm命令是删除文件和目录的高效工具,但一旦误操作,如执行rm-rf/或rm-rf/*,极易导致系统数据灾难,本文针对不同场景... 目录引言理解 rm 命令及误操作风险rm 命令基础常见误操作案例防护方案使用 rm编程 别名及安全删除

Linux下MySQL数据库定时备份脚本与Crontab配置教学

《Linux下MySQL数据库定时备份脚本与Crontab配置教学》在生产环境中,数据库是核心资产之一,定期备份数据库可以有效防止意外数据丢失,本文将分享一份MySQL定时备份脚本,并讲解如何通过cr... 目录备份脚本详解脚本功能说明授权与可执行权限使用 Crontab 定时执行编辑 Crontab添加定

C++统计函数执行时间的最佳实践

《C++统计函数执行时间的最佳实践》在软件开发过程中,性能分析是优化程序的重要环节,了解函数的执行时间分布对于识别性能瓶颈至关重要,本文将分享一个C++函数执行时间统计工具,希望对大家有所帮助... 目录前言工具特性核心设计1. 数据结构设计2. 单例模式管理器3. RAII自动计时使用方法基本用法高级用法

PHP应用中处理限流和API节流的最佳实践

《PHP应用中处理限流和API节流的最佳实践》限流和API节流对于确保Web应用程序的可靠性、安全性和可扩展性至关重要,本文将详细介绍PHP应用中处理限流和API节流的最佳实践,下面就来和小编一起学习... 目录限流的重要性在 php 中实施限流的最佳实践使用集中式存储进行状态管理(如 Redis)采用滑动

ShardingProxy读写分离之原理、配置与实践过程

《ShardingProxy读写分离之原理、配置与实践过程》ShardingProxy是ApacheShardingSphere的数据库中间件,通过三层架构实现读写分离,解决高并发场景下数据库性能瓶... 目录一、ShardingProxy技术定位与读写分离核心价值1.1 技术定位1.2 读写分离核心价值二

深入浅出Spring中的@Autowired自动注入的工作原理及实践应用

《深入浅出Spring中的@Autowired自动注入的工作原理及实践应用》在Spring框架的学习旅程中,@Autowired无疑是一个高频出现却又让初学者头疼的注解,它看似简单,却蕴含着Sprin... 目录深入浅出Spring中的@Autowired:自动注入的奥秘什么是依赖注入?@Autowired

如何通过try-catch判断数据库唯一键字段是否重复

《如何通过try-catch判断数据库唯一键字段是否重复》在MyBatis+MySQL中,通过try-catch捕获唯一约束异常可避免重复数据查询,优点是减少数据库交互、提升并发安全,缺点是异常处理开... 目录1、原理2、怎么理解“异常走的是数据库错误路径,开销比普通逻辑分支稍高”?1. 普通逻辑分支 v