mysql高可用方案--切换分区

首先声明一下,我这边说的mysql高可用不是指的mysql集群架构的高可用,而是针对我所面临的特定场景 ---- 表切换的高可用的实现方案。

说说需求的来源,前段时间,由于项目需要做个一个数据模型中台,其主要作用是通过读取大数据给到的数据文件到mysql库,同时提供查询数据api接口的功能。所有功能基本都实现完成了,但是在后期测试的时候发现一个问题,在数据api接口的查询过程中,少数请求五法正常返回数据。后来通过排查定位到问题,发现是由于同步数据任务完成时修改表明造成的一瞬间原表不存在的原因造成。
首先提一下我们实现这个数据模型中台的方案,主要是对阿里开源数据同步工具datax进行了封装,支持定时执行任务以及提供对同步完成数据的查询功能。

因为同步任务的过程中,全量任务执行之前会先清除之前的数据,然后跑入新的数据,但是不管数据量的多少,执行跑数总是有一定的时间间隔,而在这个时间间隔中就回造成 api 接口查询的数据要么不全,要么就是数据不准(因为跑数过程中,旧的数据已经清除,新的数据只跑了一部分)。针对这种情况,之前的实现方案是每个任务会对应两张表,一张普通表一张对应的临时表,每次跑数任务把数据跑到正式表或者是临时表,跑数的过程中 api 查询另一张表,跑数完成以后把临时表表名改为正式表,把正式表表名改为临时表,每次进行切换。类似如下语句:

RENAME TABLE user TO user_bak;
RENAME TABLE user_tmp TO user;
RENAME TABLE user_bak TO user_tmp;

问题也就出在这上面,在这个重命名表的过程中,有一段时间是找不到 user 这个表的(虽然这个时间可能很短),但是依然会造成业务出现异常。

针对这个情况,通过调研,发现了另外一种切换数据的方式可以免除这种一瞬间表不存在的情况,这就是切换分区表。mysql 5.6以下不支持分区表,分区表的相关介绍可以查看 mysql 分区表

下面来看看具体实现方式,假设业务主表如下:

CREATE TABLE user
(
    id   int         NOT NULL PRIMARY KEY AUTO_INCREMENT COMMENT 'id',
    name varchar(10) NULL COMMENT '用户姓名'
) ENGINE = innodb CHARSET = 'utf8mb4' COMMENT '用户信息表';

这时需要建一张和原表结构相同的分区表

CREATE TABLE user_tmp
(
    id   int         NOT NULL PRIMARY KEY AUTO_INCREMENT COMMENT 'id',
    name varchar(10) NULL COMMENT '用户姓名'
) ENGINE = innodb CHARSET = 'utf8mb4' COMMENT '用户信息表' PARTITION BY RANGE (id) (
    PARTITION p0 VALUES LESS THAN MAXVALUE
    );

因为要把分区表的全量数据和原表进行交换,因此只需要一个分区,当然也可以通过先建一张和原表结构相同的表,然后给这个表添加分区信息。

CREATE TABLE user_tmp LIKE user;
ALTER TABLE user_tmp PARTITION BY RANGE COLUMNS (id) (PARTITION p0 VALUES LESS THAN MAXVALUE );

向 user_tmp 表中插入测试数据

INSERT INTO colour.user1_tmp
VALUES (1, '张三');
INSERT INTO colour.user1_tmp
VALUES (2, '李四');
INSERT INTO colour.user1_tmp
VALUES (3, '王五');
INSERT INTO colour.user1_tmp
VALUES (4, '赵六');
INSERT INTO colour.user1_tmp
VALUES (5, '钱七');

查看表中数据

SELECT COUNT(1) FROM user;

count(1)
0

SELECT COUNT(1) FROM user_tmp;

count(1)
5

交换分区

ALTER TABLE user_tmp EXCHANGE PARTITION p0 WITH TABLE user;

再次查看数据,发现 user_tmp 的数据已经交换到 user 表,user_tmp 中已经没有数据。
通过如下语句可以查看表的分区信息:

SELECT partition_name        AS partitionName,
       partition_expression  AS partitionExpression,
       partition_description AS partitionDescription,
       table_rows            AS rowCount
FROM information_schema.partitions
WHERE table_schema = '数据库名'
  AND table_name = '表名';

注意:表有多个分区时,分区可以删除,删除分区后,对应的分区数据会丢失。

使用分区表切换方案以后,之前的表瞬时不存在问题解决了,目前没有遇到其他相关问题。今天的分享就到这里了,有对应需求场景的小伙伴可以考虑使用类似方案来解决表切换问题。由于笔者认知有限,如文中有不妥之处欢迎大家批评、指正。

猜你喜欢

转载自blog.csdn.net/hxj413977035/article/details/121404070