使用MySQL/InnoDB重新平衡表分片

Arn*_*anc 8 mysql innodb sharding rebalancing

我有一个巨大的InnoDB表(> 1TB,> 1B行),我想要分片:我想从那个大表中创建多个较小的独立表.

怎么做 ?

我已经尝试过的:

  • 通过从原始表中选择行来将行移动到分区,并将它们插入分区.这需要很长时间,并且在操作期间保持行同步是很困难的(但是对于触发器似乎是可行的,只要分区在同一服务器上).我还没有找到一个可以使用的工具来做到这一点.
  • 复制整个表,然后删除不属于该分区的行.仍然很慢,特别是考虑到桌子的大小.这显然是MySQL Fabric所做的.

随机疯狂的想法:

  • .idb文件脱机并将其导入服务器,但我不知道是否存在能够执行此操作的工具.

显示创建表:

CREATE TABLE `Huge` (
  `account_id` int(11) NOT NULL,
  `id` bigint(20) NOT NULL AUTO_INCREMENT,
  `foo` varchar(255) NOT NULL,
  `bar` int(11) NOT NULL,
  `baz` char(2) NOT NULL,
  PRIMARY KEY (`account_id`,`id`),
  UNIQUE KEY `id` (`id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8 ROW_FORMAT=COMPRESSED;
Run Code Online (Sandbox Code Playgroud)

分片键是account_id.当前的主键是(account_id,id)使行聚集account_id.

是否有任何工具可以自动执行此任务?有没有更好的方法呢?

Ric*_*mes 8

"Sharding"是跨多个服务器分割数据(通常是一个表)."分区"是将表拆分为同一服务器上的多个子表.你在做什么?Fabric进行分片.您对.ibd的评论暗示您正在考虑分区.

假设你想要PARTITION一张大桌子,我首先要问为什么.这是一个严肃的问题,因为大多数人(我的意思是大多数)人们认为分区会神奇地产生一些好处,而实际上却不会.我相信只有4个分区用例.你的情况是否属于他们中的任何一个?

另一方面,如果您想要Sharding,请提供SHOW CREATE TABLE并讨论您要对哪个列进行分片.

编辑(在明确目标后)

我希望你没有明确的FOREIGN KEYs; 它们不适用于分区或分片.

`id` bigint(20) NOT NULL AUTO_INCREMENT,
UNIQUE KEY `id` (`id`)
Run Code Online (Sandbox Code Playgroud)

是两个方面的问题.

  • 没有必要id UNIQUE; 对a的唯一要求AUTO_INCREMENT是它是某个索引中的第一列.这样可以降低系统负担:

    INDEX(ID)

  • 一个AUTO_INCREMENT适用于PARTITIONed表,但它不适用于分片表.您需要评估目的id.它可以只在一个碎片中唯一,然后没有真正的问题.如果id需要在所有分片中都是唯一的,那就更难了.可能唯一的解决方案是使用从某个中央服务器获取id的技术.但是,这会导致单点故障和瓶颈.如果你需要走这个方向,我可以建议如何避免这些缺点.

如何迁移到最终的分片系统?

我不建议任何偏离PARTITIONing,从长远来看,它不会真正有用.并且成本REORGANIZE PARTITION很高 - 复制所有行,提取的行和剩余的行. 编辑:如果您确实使用分区,请使用pt-online-schema-change最小停机时间进行拆分.

相反,我建议完善一种工具,将account_id一个碎片从一个碎片迁移到另一个碎片.这必须是自定义代码,因为可能会通过将帐户移动到其他服务器来影响其他表(以及表之间的引用).从长远来看,这对于负载平衡,硬件升级,软件升级甚至架构更改都很有用.当您需要更改某些内容时,请使用新的OS /版本/架构/任何内容创建新的分片,并将用户迁移到该分片.

这个工具的简单方法是

  1. "阻止"为该一个帐户写入
  2. 将记录复制到新分片
  3. 更改网守以了解该帐户现在位于新分片上
  4. 取消阻止写入
  5. 最终(并逐渐)DELETE旧碎片上的行

如果帐户"很小",这不是什么大问题.但如果您需要最少的停机时间(写入被阻止),那么我们可以讨论更复杂的方法.

(如果您没有猜到,我已经'去过那里,做过那个'.)