mycat分库分表(线上实际案例)

目录

现状分析:

分表方案:

Mycat1.5.1到1.6.7升级方案:

分表规则:

以task_id/task_item_id分表:

以日期分表(实际采用的方案):

csc_task_item表日期分表操作示例

旧数据迁移

mysqldump方式

load data方式(本地导入时不成功)

分表前后性能对比

结论

 


现状分析:

目前平台是基于mycati1.5做的一个垂直分库方案(各个模块有自己的库),mycat的配置如下图所示:

mycat分库分表(线上实际案例)_第1张图片

                                   目前mycati1.5配置片段

 

如果平台目前没有过大并发访问压力,单节点可以支撑,只需要做好数据备份,如上图中的单节点。

以后的扩展,可以加一个读节点,实现读写分离。

 

巡检任务涉及到的表有:

csc_task (巡检任务),csc_task_station(巡检任务站点) csc_task_item(巡检任务测项

csc_task (巡检任务)与csc_task_station为主子表,一对多。

csc_task_station(巡检任务站点)csc_task_item(巡检任务测项为主子表,一对多。

三个表为主子孙表关系,都在csc库里。

 

以格尔木的数据为例:

每天任务数据大概是500条。

每个任务下的站点平均为4个,那么每天的站点数据是2000条。

每个站点下的测项数据是5个,那么每天的站点数据是10000条。

 

一年数据预估:

一天任务数据*400=20

一天站点数据*400=80

一天测项数据*400=400

格尔木线上数据截图:

mycat分库分表(线上实际案例)_第2张图片

mycat分库分表(线上实际案例)_第3张图片

线上实际数据显示,自2018824日起,到现在差不多一年时间,任务数据为20万,站点数据为120万,测项数据为1000万。

上边预估偏小,应调整为:

每天任务数据大概是500条。

每个任务下的站点平均为6个,那么每天的站点数据是3000条。

每个站点下的测项数据是10个,那么每天的站点数据是30000条。

 

一年实际数据:

(一天任务数据)*400=20

(一天站点数据)*400=120

(一天测项数据)*400=1200

 

目前csc_task_item1200万的数据表空间是8G左右,10年后数据为1.2亿,80G

 

结论:任务表和站点表暂不需要分表,测项表需要分表。

 

以上数据取自格尔木项目,对格尔木一个项目来讲,分表即可。

对于平台来讲,情况较为复杂,比如10个租户时,数据应乘以10;那么一年任务数据为200万,一年站点数据为1200万,一年测项数据为1.2亿,10年为12亿,表空间(对于mysql来讲是.idb文件)10年为800G

平台应在垂直分库基础上根据租户id的做水平分库,然后对数据了过于大的表,比如巡检任务测项表再做水平拆分。

 

分表方案:

对任务测项表进行水平拆分

 

由于原来已经做了垂直分库,所以对格尔木项,10年后巡检任务测项数据为1.2亿,80G暂不需要再分库(硬盘容量需要扩容时,第一步可以增加服务器硬盘,目前所有的库都放在一个节点上,以后可以每个库放一个节点,这样对数据容量和并发访问性能都可以明显提升),因此在巡检库hap_csc_gem中对任务测项表csc_task_item进行水平拆分即可。

 

要实现巡检任务表的拆分(水平拆分),需要对mycat升级,目前用的mycat1.5.1Mycat的单库分表1.6版本开始支持,且1.6版本有个bug,需要替换lib下一个jar文件。

参考http://songwie.com/articlelist/202

本地测试1.6.7版本已修复这个bug,也可以升级mycat1.6.7,下载地址:

http://dl.mycat.io/1.6.7.1/。

mycat分库分表(线上实际案例)_第4张图片

Mycat官方说明截图

 

Mycat1.5.1到1.6.7升级方案:

暂无

 

分表规则:

以task_id/task_item_id分表:

任务表的task_id为其主键,站点表和测项表也都有task_id,三个表的task_id为整数类型int,task_id%n,可以作为分表方案之一,n为分表数量。

 

以支撑10年为例,测项表单表数据:

n=50时,1.2亿/50=240万

n=100时,1.2亿/100=120万

n=200时,1.2亿/200=60万

 

Mycat配置文件schema.xml中:

 

该分表规则的限制:n需要确定,这就对数据总量有一个上限的要求,否则在扩容时,n个表的数据都需要迁移;

 

结论:对于格尔木如果支撑10年,以巡检测项表单表数据120万左右为标准,需要分表数最小为100。10年后,如果要继续支撑,需要增加分表数,增加时就需要迁移数据。该方案可行性一般。

 

任务测项表主键的task_item_id,也可以作为分表方案之一,同上。

以日期分表(实际采用的方案):

分片字段的选择,check_time字段有null值,而created_dt没有,应该选择后者。

mycat分库分表(线上实际案例)_第5张图片

mycat分库分表(线上实际案例)_第6张图片

以上为分表规则配置文件rule.xml中的片段

 

 

以上为mycat配置文件schema.xml中分表规则的配置,需要注意的是,已配置的表必须事先创建好,目前创建了自2018年1月起到2020年12年的表,一共36张表,可以支撑业务到2020年结束。

 

说明:

目前格尔木一年的任务测项表数据为1200万,以月为单位,1200万数据分成12个表,单表数量降为100万。

需要用到的表,在mycat中配置即可,比如可以暂时配置3年的表(2018-2020),

2020年之后的表,可以动态添加:

  • 先在配置文件中加上配置,如csc_task_item2021$1-12
  • 然后在数据库创建相应的表
  • 最后需要连上mysql管理端口(默认为9066)执行reload @@config;,让mycat加载最新配置,此过程不需要重启mycat,也不需要重启数据库。

 

该分表规则的限制:数据增长频率需要稳定,否则当变化时(1个月1张表变为10天一张表),也需要迁移数据;

 

结论:对分表数不固定但一定时间内数据量稳定可以预估的的业务比较适合,不需要迁移数据,比较适合目前场景,该方案可行性较好。

csc_task_item表日期分表操作示例

先在数据库建好需要的表:

mycat分库分表(线上实际案例)_第7张图片

 

连上mycat,用explain查看相应sql的数据来自哪些表,以确定无误:

explain select * from csc_task_item;

mycat分库分表(线上实际案例)_第8张图片

在mycat配置文件中增加2021年需要的表:

mycat分库分表(线上实际案例)_第9张图片

 

在在数据库中创建相应的表后,用命令reload @@config;让mycat加载最新配置(注意是连接上9066管理端口,上边的命令都是8066服务端口):

mycat分库分表(线上实际案例)_第10张图片

 

explain查看相应sql的数据来自哪些表,以确定无误:

explain select * from csc_task_item;

mycat分库分表(线上实际案例)_第11张图片

 

SELECT check_time,

       check_value FROM

       csc_task_item

WHERE tenantid =?

AND item_id=?

AND check_time IS NOT NULL

AND date_format(check_time, '%Y-%m-%d') >= ?

AND date_format(check_time, '%Y-%m-%d') <= ? ORDER BY check_time;

 

旧数据迁移

mysqldump方式

导出:

mysqldump -u root -p -t -c -–skip-add-locks hap_csc_gem csc_task_item > d:\\source.sql

-t忽略表结构,-c导出的数据带上列名——这个是必须的,否则mycat会报错,因为导入mycat中需要有分表字段。

 

导入:

mysql -uroot -p -h172.17.xxx.xxx -P8066

切换到指定的数据库:

use databaseName;

导入脚本:

source d:\\source.sql;

load data方式(本地导入时不成功)

以下是参考mycat权威指南写的导出导入sql

 

导出:

select * from csc_task_item into outfile 'd:\\csc_task_item.txt' FIELDS TERMINATED BY '\t' OPTIONALLY ENCLOSED BY '' ESCAPED BY '\\' LINES TERMINATED BY '\n';

 

导入:

load data local infile 'd:\\csc_task_item.txt ' INTO TABLE csc_task_item FIELDS TERMINATED BY '\t' OPTIONALLY ENCLOSED BY  '' ESCAPED BY '\\' LINES TERMINATED BY '\n' (task_item_id, task_station_id, task_id, task_code, task_name, line_id, line_name, station_id, station_name, item_id, item_name, item_type, item_remark, check_obj_type, eq_id, eq_name, unit_id, unit_symbol, item_index_name, org_name, org_id, check_value, standard_value, upper_limit_value, lower_limit_value, ulti_up_limit_value, ulti_low_limit_value, seq, check_result, check_last_value, last_task_id, check_result_last, remark, check_per_id, check_per_name, check_time, upload_time, upload_per_id, upload_per_name, upload_phone, check_gps_x, check_gps_y, created_dt, created_by, updated_by, updated_dt, created_by_name, updated_by_name, tenantid, ver, eq_is_not_work, eq_status, task_item_img, lj_remark, remark_user, remark_time, remark_username);

分表前后性能对比

以下所有测试均为在本地测试(win10,8G,4核,8逻辑处理器)。

测试sql语句为常用sql,以及平台涉及到任务测项表功能点sql(报表统计)。

select count(*)

如下图所示,执行sql为select count(*) from csc_task_item;分表前执行时间2.18秒,分表后1.54秒

mycat分库分表(线上实际案例)_第12张图片

 

order by limit

select * from csc_task_item order by created_dt limit 2\G;

分表前为10.03秒,分表后为7.15秒。

都比较慢,如果有排序字段,最好建立索引,索引提升查询性能是最明显的。

mycat分库分表(线上实际案例)_第13张图片

根据task_id查询

Select * from csc_task_item where task_id = 2000000043148\G;

分表前为24.09秒,分表后为9.35秒

mycat分库分表(线上实际案例)_第14张图片

 

SELECT

       check_time,

       check_value

FROM

       csc_task_item

WHERE

       tenantid =1

AND item_id=2000000023511

AND check_time IS NOT NULL

AND date_format(check_time, '%Y-%m-%d') >= '2019-01-01'

AND date_format(check_time, '%Y-%m-%d') <=  '2020-01-01'

ORDER BY

       check_time;

 

分表前为41.47秒,分表后为0.21秒。

(两个查询执行的情况均在未为加索引csc_task_item (item_id,check_time);下执行)

mycat分库分表(线上实际案例)_第15张图片

 

加完索引后

mycat分库分表(线上实际案例)_第16张图片

 

SELECT task_name,station_name,item_name,check_result,check_value,remark,item_type, eq_is_not_work ,unit_symbol

FROM csc_task_item

WHERE tenantid=1 AND task_id=2000000023622 AND check_result='EXCEPTION'\G;

数据集为空,用时均为0.01秒

mycat分库分表(线上实际案例)_第17张图片

 

SELECT task_name,station_name,item_name,check_result,check_value,item_type,eq_is_not_work,unit_symbol

FROM csc_task_item

WHERE tenantid=1 AND task_id= 2000000043148\G;

时间一样,都执行的这么快,因为有索引

KEY `I_TENANTID_TASKID_TASK_STATION_ID` (`tenantid`,`task_id`,`task_station_id`)

mycat分库分表(线上实际案例)_第18张图片

 

SELECT

       item.task_id,

       item.task_name,

       count(item.check_result) items

FROM

       csc_task_item item

WHERE

       item.tenantid =1

and item.task_id = 2000000148172

GROUP BY

       item.task_id,

       item.task_name\G;

mycat分库分表(线上实际案例)_第19张图片

SELECT

       item.station_id,

       item.station_name,

       item.item_id,

       item.item_name

FROM

       csc_task_item item

WHERE

       item.tenantid =1

and item.task_id = 2000000107904

GROUP BY

       item.station_id,

       item.station_name,

       item.item_id,

       item.item_name

ORDER BY

       item.station_id \G;

 

分表前后几乎一样

mycat分库分表(线上实际案例)_第20张图片

结论

根据本地测试的结果,分表后性能有一定提升。

查询不走索引时,性能提升比较明显。走索引时,分表前后没太大区别。

如果要充分利用分表后的优势,sql语句中最好加分表字段created_dt,这样可以路由到具体的表,而不是由mycat查所有表然后汇总。

 

巡检任务测项表最好添加索引。

CREATE INDEX I_ITEMID_CHECKTIME ON csc_task_item (item_id,check_time);

 

你可能感兴趣的:(mycat)