修改gh-ost源码实现两表在线高速复制

修改gh-ost源码实现两表在线高速复制

一、问题起源

笔者所在的公司的需要对核心业务表tb_doc  进行表分区,目前该表的记录数为190,522,155
由于该表没有分区,新增分区需要创建影子表,然后从原表导入数据,最后修改表名。
二、处理结果
我们在生产环境对tb_doc按照hash算法分区,分区数量1024。操作耗时9小时22分,累计迁移 190,522,155 条数据。
三、方案选型
关键步骤是导入数据的过程,我们经过一番筛选,初步选定kettle、gh-ost两种技术方案。

3.1、测试环境的服务器配置
Dell R720
Intel(R) Xeon(R) CPU E5-2620 v2 @ 2.10GHz ( 24核
内存256G
4块SEAGATE ST3600057SS组成RAID10 磁盘空间1.089 TB

3.2 数据表结构
测试记录数 19,891,000
CREATE TABLE ` tb_doc `(
  `ID` varchar(40) NOT NULL,
  `LASTMODIFIED` datetime DEFAULT NULL,
  `FORMNAME` varchar(40) DEFAULT NULL,
  `OWNER` varchar(40) DEFAULT NULL,
  `PARENT` varchar(40) DEFAULT NULL,
  `LASTMODIFIER` varchar(40) DEFAULT NULL,
  PRIMARY KEY (`ID`),
  KEY `t_document_formname` (`FORMNAME`),
  KEY `idx_t_document_parent` (`PARENT`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8;

CREATE TABLE ` tb_doc _partition` (
  `ID` varchar(40) NOT NULL,
  `LASTMODIFIED` datetime DEFAULT NULL,
  `FORMNAME` varchar(40) DEFAULT NULL,
  `OWNER` varchar(40) DEFAULT NULL,
  `PARENT` varchar(40) DEFAULT NULL,
  `LASTMODIFIER` varchar(40) DEFAULT NULL,
  PRIMARY KEY (`ID`),
  KEY `t_document_formname` (`FORMNAME`),
  KEY `idx_t_document_parent` (`PARENT`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8
PARTITION BY LINEAR KEY( ID)
PARTITIONS 1024;

3.3Kettle测试
执行方式:分成四个任务,每个任务 5 个线程
耗费小时: 10.57
Kettle四个任务的CPU占用分别为87.4%、63.9%,47.4%,42.1%,
MySQL 的CPU占用为256.3%

3.4gh-ost测试
块大小10

耗费小时: 8.57

mysql cpu 11.6%
gh-ost cpu 4.6% 

四、 gh-ost 发现的一些不足
  1. 相比pt-osc缺少–check-interval参数;目前这个值写死是1s;issue地址默认是1s,足够小了,作者认为当前可以;
  2. –conf选项设置的my.cnf文件中不支持设置prompt=[\h]\u@\d\r:\m:\s>;issue地址,作者已经修复;
  3. 缺少增加unique index的时候的检查;如果增加unique index的时候会丢失数据;(pt-osc也存在这个问题);作者认为不需要修复,问题的解决难度也比较大,DBA在使用前需要注意;
  4. 相比pt-osc缺少–check-replication-filters;是否确实对从库是否存在这个表的检查
  5. 相比pt-osc缺少–recursion-method=processlist;需要通过参数进行设置,issue地址

五、修改gh-ost增加两表复制
main.go
       flag.StringVar(&migrationContext.TableDst, "table-dst", "", "MySQL Copy Table Dest - Added By chengqian")
       flag.BoolVar(&migrationContext.AllowTableDataCopy, "allow-table-data-copy", false , "Allow Copy Table From Source to Dest - Added By chengqian")
       flag.BoolVar(&migrationContext.SkipTrigerCheck, "skip-trigger-check", false , "Skip Trigger Check - Added By chengqian ")
       flag.BoolVar(&migrationContext.AllowSharedUniqueKeysLike, "allow-sharedUniqueKey-like", false , "allow sharedUniqueKey like - Added By chengqian")


        if migrationContext.AllowTableDataCopy {
               if migrationContext.TableDst == "" {
                     log.Fatalf("--table-dst Copy Table Dest must not be empty")
              }
       } else {
               if migrationContext.AlterStatement == "" {
                     log.Fatalf("--alter must be provided and statement must not be empty")
              }
       }

migrator.go (5 matches)
 Migrate()函数
       // 跳过Alter参数的检验
        if this.migrationContext. AllowTableDataCopy {
              log.Debugf("Allow Table Data Copy: %s", this.migrationContext.TableDst)
       } else {
               if err := this.parser.ParseAlterStatement(this.migrationContext.AlterStatement); err != nil {
                      return err
              }
              
               //
               if err := this.validateStatement(); err != nil {
                      return err
              }
       }
       ...
       //新增函数 inspectOriginalAndCopyDstTables
        if this.migrationContext. AllowTableDataCopy {
               if err := this.inspector. inspectOriginalAndCopyDstTables (); err != nil {
                      return err
              }
       } else {
               if err := this.inspector.inspectOriginalAndGhostTables(); err != nil {
                      return err
              }
       }

applier.go (4 matches)
func (this *Applier) ApplyIterationInsertQuery() (chunkSize int64 , rowsAffected int64 , duration time.Duration, err error ) {
       startTime := time.Now()
       chunkSize = atomic.LoadInt64(&this.migrationContext.ChunkSize)
       
        if
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值