REBALANCE与分区
最近更新时间: 2024-10-17 17:10:00
Range/List一级分区表数据重分布
针对range/list表的数据重分布:目前建议通过proxy运行重分布sql的方式完成。
proxy运行rebalance重分布sql
针对range/list一级分区表的重分布语法,支持将range分区或者list枚举范围进行搬迁。共有offline和online两种方式。offline锁表时间较长,使用数据导入导出的方式完成数据重分布。online方式不锁表,但是依赖多源同步组件实现重分布。
注意:
- 重分布不能和添加set(扩容操作)同时进行
- online 方式需要部署kafka,consumer组件,并开启实例的数据订阅开关
- 需要有涉及重分布的数据所占用的空间大小。如果全部分区都参与重分布,则是要有两倍空间
- 仅TXSQL8.0.24内核版本可以使用该rebalance功能。
重分布基本功能
offline重分布分区:
alter table t_range TDSQL_DISTRIBUTED (s1 valuesless than(50), s2 values less than(200)) offline;
online重分布分区:
alter table t_range TDSQL_DISTRIBUTED (s1 values less than(50), s2 values less than(200));
查看正在运行的任务信息:
/*proxy*/show rebalance_task;
查看所有任务信息:
/*proxy*/show all rebalance_task;
Kill任务:
kill rebalance_task 具体任务id;
kill rebalance_task 12;//停止id为12的任务
重分布增加分区示例
注意:
- 至少需要具有3个set的分布式实例才可模拟以下示例
- online 方式需要部署kafka,consumer组件
- 开启实例的数据订阅开关(在实例详情页面可设置),用于支持online方式的rebalance功能,如下图所示:
示例:
--假设test数据库已有分区表t_range和t_list:
create table t_range(a int key, b int) TDSQL_DISTRIBUTED BY RANGE(a) (s1 values less than(100), s2 values less than(200));
create table t_list(a int key, b int) TDSQL_DISTRIBUTED BY LIST(a) (s1 values in('1','10','100'), s2 values in('110','150','200'));
--增加新的range分区s3:
alter table t_range add TDSQL_DISTRIBUTED (s3 values less than (300));
--增加新的list分区s3:
alter table t_list add TDSQL_DISTRIBUTED (s3 values in (40));
--s3增加range分区范围(只能在最后一个set上增加)
alter table t_range add TDSQL_DISTRIBUTED (s3 values less than (600));
--s2增加list分区范围:
alter table t_list add TDSQL_DISTRIBUTED (s2 values in (90));
注意:
- 不支持altertable t_range add TDSQL_DISTRIBUTED (s2 values less than (300),s2 values lessthan (400));会报语法错误。s2重复时不能通过语法解析。
- 支持altertable t_range add TDSQL_DISTRIBUTED (s2 values less than (300),s3 values lessthan (400));一次增加多个分区。
重分布删除分区示例
示例:
--强制删除
alter table t_range force drop TDSQL_DISTRIBUTED s3;
--删除,但是有数据会提示并停止删除操作
alter table t_list drop TDSQL_DISTRIBUTED s3;
--一次性删除多个分区
alter table t_range drop TDSQL_DISTRIBUTED s2,s3;
注意:
- 当全局分区表只剩下一个分区时,会拒绝删除分区的操作。
- 删除分区会清空数据,删除路由,请谨慎操作。
- 当想删除所有分区时,会拒绝:Can'tdelete all partitions。
- force删除一个分区后,会把指定分区上的表清空,但是表结构还在。
- 当有s1<100, s2<200,force drop s1后,s1上数据会清空,路由会转到s2(0-200),此功能同drop partition,往后归属。
Range表支持语法
注意:
- offline和online支持范围一致。下面以offline为例,online方式只需去掉后面的offline标志即可
- 分区表语句中指定的s1、s2、s3…是每个set的别名,基于实现原理,不能自定义,只能按照顺序依次命名为s1、s2、s3…
--重分布后路由:s1:0-100 s2:100-200 s3:200-300 s4:300-500
alter table t_range add TDSQL_DISTRIBUTED (s4 values less than (500));
--重分布后路由:s1:0-100 s2:100-200 s3:200-300 s4:300-400 s5:400-500
alter table t_range add TDSQL_DISTRIBUTED (s5 values less than (500));
--重分布后路由:s1:0-100 s4:100-400
alter table t_range drop TDSQL_DISTRIBUTED s2,s3;
--重分布后路由:s1:0-50 s2:50-200 s3:200-300 s4:300-400
alter table t_range TDSQL_DISTRIBUTED (s1 values less than(50), s2 values less than(200)) offline;
--重分布后路由:s1:0-300 s4:300-400
alter table t_range TDSQL_DISTRIBUTED (s1 values less than(300)) offline;
--重分布后路由:s1:0-100 s2:100-300 s4:300-400
alter table t_range TDSQL_DISTRIBUTED (s1 values less than(100), s2 values less than(300)) offline;
--重分布后路由:s1:0-50 s5:50-100 s2:100-200 s3:200-300 s4:300-400
alter table t_range TDSQL_DISTRIBUTED (s1 values less than(50), s5 values less than(100)) offline;
--重分布后路由:s2:0-50 s1:50-200 s3:200-300 s4:300-400
alter table t_range TDSQL_DISTRIBUTED (s2 values less than(50), s1 values less than(200)) offline;
--重分布后路由:s1:0-100 s2:100-200 s3:200-400
alter table t_range TDSQL_DISTRIBUTED (s1 values less than(100), s2 values less than(200),s3 values less than(400)) offline;
注意:
- alter table t_range TDSQL_DISTRIBUTED (s1 values less than(150)) offline;//不支持,需要写为s1 values less than(150),s2 values less than(200)
- alter table t_range TDSQL_DISTRIBUTED (s1 values less than(100), s2 values less than(300),s4 values less than(400)) offline;和alter table test.t_range TDSQL_DISTRIBUTED (s2 values less than(300),s4 values less than(400)) offline;的区别,前者是表示s2和s3分区重分布,s1不参与重分布;后者是s1,s2,s3重分布到s2上
List表支持语法
示例:
--重分布后路由:s1:1 2 3 11 12 s2:4 5 6 s3:7 8 9
alter table t_list add TDSQL_DISTRIBUTED (s1 values in ('11','12'));
--重分布后路由:s1:1 2 3 s2:4 5 6 s3:7 8 9 s4:11 12
alter table t_list add TDSQL_DISTRIBUTED (s4 values in ('11','12'));
--重分布后路由:s3:7 8 9
alter table t_list drop TDSQL_DISTRIBUTED s1,s2;
--重分布后路由:s1:1 2 6 s2:4 5 3 s3:7 8 9
alter table t_list TDSQL_DISTRIBUTED (s1 values in ('1','2','6'),s2 values in ('4','5','3')) offline;
--重分布后路由:s1:1 2 3 4 5 6 s3:7 8 9
alter table t_list TDSQL_DISTRIBUTED (s1 values in ('1','2','3','4','5','6')) offline;
--重分布后路由:s1:1 2 s2:4 5 6 s3:7 8 9 s4:3
alter table t_list TDSQL_DISTRIBUTED (s1 values in ('1','2'), s4 values in ('3')) offline;
List表不支持语法
--缺少6
alter table t_list TDSQL_DISTRIBUTED (s1 values in ('1','2'),s2 values in ('4','5','3')) offline;
--多出7,写成s1 values in ('1','2''6','7'),s2 values in ('4','5','3'),s3 values in ('8','9')则支持
alter table t_list TDSQL_DISTRIBUTED (s1 values in ('1','2''6','7'),s2 values in ('4','5','3')) offline;
Range表的rebalance示例
--通过proxy连接数据库,创建数据库和range分区表
create database if not exists rebalance;
use rebalance;
CREATE TABLE `sbtest1` (
`id` int NOT NULL,
`k` int NOT NULL DEFAULT '0',
`c` char(120) CHARACTER SET utf8 COLLATE utf8_bin NOT NULL DEFAULT '',
`pad` char(60) CHARACTER SET utf8 COLLATE utf8_bin NOT NULL DEFAULT '',
PRIMARY KEY (`id`),
KEY `k_1` (`k`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb3 COLLATE=utf8_bin TDSQL_DISTRIBUTED BY RANGE(id) (s1 values less than ('50000'),s2 values less than ('100000'));
--给range分区表增加一个分区s3
alter table sbtest1 add TDSQL_DISTRIBUTED (s3 values less than ('150000'));
--执行show create table sbtest1;语句确认range分区表的三个分区范围正确
--往各个分区分别插入数据,查询数据所在分区正确(数据量多少可自行决定,只要不超过分区范围限制)
insert into sbtest1(id,k,c,pad) values (19999,1,'abc','abc');
insert into sbtest1(id,k,c,pad) values (25000,1,'abc','abc');
insert into sbtest1(id,k,c,pad) values (49999,1,'abc','abc');
insert into sbtest1(id,k,c,pad) values (50000,2,'abc','abc');
insert into sbtest1(id,k,c,pad) values (55000,2,'abc','abc');
insert into sbtest1(id,k,c,pad) values (99999,2,'abc','abc');
insert into sbtest1(id,k,c,pad) values (100000,3,'abc','abc');
insert into sbtest1(id,k,c,pad) values (120000,3,'abc','abc');
insert into sbtest1(id,k,c,pad) values (149999,3,'abc','abc');
/*sets:allsets*/select * from sbtest1;
--执行如下sql语句进行offline方式的重分布,将s1分区的[40000,50000)迁到s2分区,s2分区的[70000,100000)迁到s3分区:
alter table sbtest1 TDSQL_DISTRIBUTED (s1 values less than(40000), s2 values less than(70000),s3 values less than(150000)) offline;
--执行show create table sbtest1;语句确认range分区表的三个分区范围重分布正确
--查询offline方式数据重分布结果正确
/*sets:allsets*/select * from sbtest1;
--执行如下sql语句进行online方式的重分布,将s1分区的[20000,40000)迁到s2分区,s3分区的[70000,120000)迁到s2分区:
alter table sbtest1 TDSQL_DISTRIBUTED (s1 values less than(20000), s2 values less than(120000),s3 values less than(150000));
--执行show create table sbtest1;语句确认range分区表的三个分区范围重分布正确
--查询online方式数据重分布结果正确
/*sets:allsets*/select * from sbtest1;
List表的rebalance示例
--通过proxy连接数据库,创建数据库和list分区表
create database if not exists rebalance;
use rebalance;
CREATE TABLE `t_list` (
`a` int NOT NULL,
`b` int DEFAULT NULL,
PRIMARY KEY (`a`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb3 COLLATE=utf8_bin TDSQL_DISTRIBUTED BY LIST(a) (s1 values in ('1','10','100'),s2 values in ('110','150','200'));
--给list分区表增加一个分区s3
alter table t_list add TDSQL_DISTRIBUTED (s3 values in ('40','300','180'));
--执行show create table t_list;语句确认list分区表的三个分区范围正确
--往各个分区分别插入数据,查询数据所在分区正确
insert into t_list(a,b) values(1,1),(10,1),(100,1),(110,2),(150,2),(200,2),(40,3),(300,3),(180,3);
/*sets:allsets*/select * from t_list;
--执行如下sql语句进行offline方式的重分布,将s1分区的100迁到s2分区
alter table t_list TDSQL_DISTRIBUTED (s1 values in('1','10'), s2 values in('100','110','150','200')) offline;
--执行show create table t_list;语句确认list分区表的三个分区范围重分布正确
--查询offline方式数据重分布结果正确
/*sets:allsets*/select * from t_list;
--执行如下sql语句进行online方式的重分布,将s2分区的100,150迁到s3分区:
alter table t_list TDSQL_DISTRIBUTED (s1 values in('1','10'), s2 values in('110','200'), s3 values in('40','300','180','100','150'));
--执行show create table t_list;语句确认list分区表的三个分区范围重分布正确
--查询online方式数据重分布结果正确
/*sets:allsets*/select * from t_list;
其他功能介绍
任务抢占:所有proxy都会执行select任务中未完成且时间戳停止时间超过租约时间(目前设置为120s)的任务,获得时间戳停止时间time1。然后尝试更新这条记录(带where update_time = time1条件)如果更新成功则代表拿到任务,开始写时间戳和自己的proxyid。如果更新失败则代表未拿到任务。
kill任务id:直接写任务表的is_stop=1(重试,300s超时,可配置),然后想应proxy会感知到任务需要停止,执行停止。
任务迁移:当任务时间戳不更新时,时差超过租约则会被任务抢占,抢占到的proxy会重新执行重分布任务。
proxy重启继续执行:因为在租约内,所以不会被抢占,重启后会查找proxyid为自身,is_finish=0且还在租约内的任务写入队列执行。
当前任务执行ctrl+c断开连接,会写入一个stop任务,stop任务执行时,会先从任务列表中查找是否存在该任务,如果存在,则表示当前proxy正在运行该任务,直接执行stop影响状态转换即可回滚。如果不存在,表示当前任务已经停止。
二级分区的自增
功能介绍
针对一级Hash二级Range分区自增的情况。
使用场景
使用二级分区的场景下。
Range表自动化创建分区示例
注意:
- 测试前确保网关参数已经打开,默认是开启的,可以通过赤兔页面查看:
--创建range二级分区表:
DROP DATABASE IF EXISTS test;
CREATE DATABASE test;
CREATE TABLE test.t1 (
id int primary key,
hired varchar(100)
) shardkey=id partition by range (day(hired))
(
PARTITION p0 VALUES LESS THAN (20211020),
PARTITION p2 VALUES LESS THAN (20211021)
);
--查看当前分区:
MySQL [rebalance]> show create table test.t1\G;
*************************** 1. row ***************************
Table: t1
Create Table: CREATE TABLE `t1` (
`id` int NOT NULL,
`hired` varchar(100) COLLATE utf8_bin DEFAULT NULL,
PRIMARY KEY (`id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb3 COLLATE=utf8_bin shardkey=id PARTITION BY RANGE ( day(hired) ) ( PARTITION p0 VALUES LESS THAN (20211020), PARTITION p2 VALUES LESS THAN (20211021))
1 row in set (0.001 sec)
--等待数分钟左右,查看是否自动创建分区:
MySQL [rebalance]> show create table test.t1\G;
*************************** 1. row ***************************
Table: t1
Create Table: CREATE TABLE `t1` (
`id` int NOT NULL,
`hired` varchar(100) COLLATE utf8_bin DEFAULT NULL,
PRIMARY KEY (`id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb3 COLLATE=utf8_bin shardkey=id PARTITION BY RANGE ( day(hired) ) ( PARTITION p0 VALUES LESS THAN (20211020), PARTITION p2 VALUES LESS THAN (20211021), PARTITION p_auto_20211029 VALUES LESS THAN (20211030), PARTITION p_auto_20211030 VALUES LESS THAN (20211031), PARTITION p_auto_20211031 VALUES LESS THAN (20211101), PARTITION p_auto_20211101 VALUES LESS THAN (20211102), PARTITION p_auto_20211102 VALUES LESS THAN (20211103))
1 row in set (0.001 sec)
--在自动化创建的分区插入数据:
INSERT INTO test.t1(id,hired) VALUES(1,'20211027');
SELECT * from test.t1;