当前位置: 首页 > 科技观察

GitHub开源MySQL在线schema更改工具

时间:2023-03-13 21:42:24 科技观察

MySQL有很多在线schema更改工具,比如Percona的pt-online-schema-change、Facebook的OSC和LHM等,但是这些都是基于触发器(Trigger)的,今天gh-ost我们介绍过号称是一款无需触发器(Triggerless)支持的在线更改表结构的工具。原文地址:gh-ost:GitHub的MySQL在线schema迁移工具本文首先介绍了业界已有的这些工具的使用场景和原理,然后详细介绍了gh-ost的工作原理和特点。今天我们开源了一个不需要触发器支持的MySQL在线表结构更改工具gh-ost,GitHub使用的。gh-ost的开发是为了应对GitHub在生产环境中面临的不断变化的在线表结构变化。要求。gh-ost通过提供低影响、可控、可审计和操作友好的解决方案,改变了现有在线迁移表工具的工作模型。MySQL表迁移和结构更改操作是业界众所周知的问题。自2009年以来,在线(不间断服务)更改工具已经能够解决它们。快速增长和快速迭代的产品往往需要频繁更改数据库结构。添加/更改/删除/字段和索引等,这些操作在MySQL中默认会锁表,影响在线服务。我们每天多次面对这个数据库结构级别的变化。当然,该操作不应影响用户的正常服务。在开始介绍gh-ost工具之前,我们先了解一下目前这些工具的解决方案。在线修改表结构,已有场景现在,在线修改表结构可以通过以下三种方式:hasbeenchanged设置主库使用MySQLInnoDB存储引擎提供的在线DDL特性,使用在线修改表结构的工具。现在最流行的是pt-online-schema-change和Facebook的OSC;当然还有LHM和相对原始的oak-online-alter-table工具。其他包括Galera集群的Schema滚动更新,以及其他一些非InnoDB存储引擎。在GitHub,我们使用通用的主从架构和InnoDB存储引擎。为什么我们决定开始一个新的解决方案而不是使用上面提到的那些?每个现有的解决方案都有其局限性。下面将简要说明这些方法的常见问题,但不会对基于触发器的在线更改工具的问题进行详细描述。基于主从复制的迁移方式需要大量的前置工作,例如:主机数量多、传输时间长、管理复杂等。变更操作需要在指定的从库上或者在基于子树的主从结构中进行。还有很多情况需要,比如:主机宕机,主机从之前的备份中恢复数据,新主机加入集群等等,这些都可能影响我们的操作。最可怕的是,这些操作可能一天要进行很多次。如果采用这种方式,我们算子的日常效率是非常高的(译者注:现在很少有人用这种方式)MySQLforInnodb存储引擎在线DDL操作需要一个短期的独占锁(exclusive)来准备之前的环境starting,所以alter命令发出后,会先等待对表的其他操作完成,alter命令后的请求会出现waitingmetadatalock。同样在ddl结束之前,需要等待alter期间的所有事务完成,同时也会出现短时间的阻塞,对于繁忙的数据库业务来说是一个非常高的风险因素。此外,DDL操作不能被中断。如果中途被杀死,会造成长时间的事务回滚,并可能造成元数据损坏。不太好操作,不能限速,不能暂停,重负载环境下甚至会影响正常业务。我们已经使用pt-online-schema-change工具很多年了。但是随着我们的业务和流量越来越大,我们遇到了很多问题,我们不得不考虑在操作中有哪些危险的操作(译者注:pt工具集的文档中经常会有一些危险的提示)。某些操作必须在高峰时段执行,否则MySQL可能会挂起。现有的在线表结构修改工具都是使用MySQL触发器执行的,存在一些隐患。基于触发器的在线修改有哪些问题?所有在线表结构修改工具的操作方式都差不多:创建一个与原表结构一致的临时表。临时表已经是按要求修改的表结构,慢慢递增从原表复制数据,记录原表的变化(所有INSERT、DELETE、UPDATE操作)并应用到临时表。当工具确认表数据已经同步后,会进行替换工作,将临时表重命名为原表。pt-online-schema-change、LHM和oak-online-alter-table等工具都使用同步方法。当原表有变更操作时,利用一些事务的间隙时间,将这些变更同步到临时表中。Facebook的工具使用异步的方式将变更写入到changelog表中,然后将changelog表中的变更反复应用到临时表中。所有这些工具都使用触发器来识别对原始表的更改。当表中的每一行数据都有INSERT、DELETE、UPDATE操作时调用存储触发器。触发器可能包含事务空间中的一系列查询操作。这样就会导致一个原子操作不仅要在原表上执行,还要调用对应的触发器执行多个操作。在基于触发器的迁移实践中,遇到了以下问题:触发器以解释代码的形式保存。MySQL不预编译这些代码。将在每个事务空间中调用,它们被添加到分析和解释器之前对正在操作的表进行每个查询的操作。锁表:触发器在原表查询中共享同一个事务空间,这些查询会在这个表中有竞争锁,而触发器在另一个表中会排他性地竞争锁。在这种极端情况下,同步模式下的锁争用直接关系到主库的并发写性能。根据我们的经验,在生产环境中,当争用锁临近或结束时,数据库可能会因为争用锁而阻塞。触发锁的另一个方面是创建或销毁时所需的元数据锁。我们在busytable中遇到过,当表结构修改完成后,deletetrigger可能需要几秒到几分钟。不可靠:当主库负载增加时,我们想减慢或暂停操作,但基于触发器的操作无法做到这一点。虽然它可以暂停行复制操作,但不能暂停触发器。如果触发器被删除,可能会导致数据丢失,所以触发器需要在整个操作过程中一直存在。在我们比较繁忙的服务器中,曾经遇到过因为trigger占用CPU资源导致主库被拖死的例子。ConcurrentMigration:我们或者其他人可能更关心同时修改表结构(不同表)的多个场景。鉴于上述触发器的开销,我们对同时对多个表进行实时修改操作不感兴趣,我们不确定是否有人在生产中这样做过。测试:我们可能只是为了测试而修改表结构,或者评估它的负载开销。基于触发器的表结构修改操作只能通过基于语句的复制来模拟,离真正的主库操作还有一定差距,不能真实反映实际情况。gh-ostgh-ostGitHub的在线Schema修改工具,工作原理图如下:gh-ost具有以下特点:无触发器LightweightPause动态控制AuditabletestTrustworthyNotriggersgh-ost不使用触发器设备。它通过分析binlog日志来监控表中的数据变化。因此,它的工作模式是异步的,只有当原表的变更commit时,变更才会同步到临时表(ghost表)gh-ost要求binlog为RBR格式(row-basedreplication);但是,这并不意味着您不能基于SBR(基于语句的复制)日志格式对主库执行在线更改操作。其实可以。gh-ost可以将库中的SBR日志转换为RBR日志,只需要重新配置即可。轻量级不使用触发器,因此运行过程中对主库的影响极小。当然,在运行过程中不用担心并发和锁的问题。更改操作以流的形式顺序写入binlog文件,gh-ost只是读取它们并应用到gh-ost表中。事实上,gh-ost是通过读取binlog写入事件来执行顺序行复制操作的。因此,主库将只有一个连接顺序向临时表(ghost表)写入数据。这与ETL操作有很大不同。暂停所有写操作由gh-ost控制,异步读取binlog。当限速时,gh-ost可以暂停向主库写入数据。限速是指不会在主库中复制库,也没有行更新。在限速时,gh-ost会创建一个内部跟踪表,并以最小的系统开销将心跳事件写入该表。gh-ost支持多种限速方式:Load:熟悉pt-online-schema-change工具的用户提供了类似的功能,可以在MySQL中设置状态阈值,比如Threads_running=30Replicationdelay:gh-ost内置了心跳机制,可以指定不同的从库,从而延迟对主从复制进行监控,如果达到设定的延迟阈值,程序自动进入限速模式。查询:用户可以设置一个限流SQL,比如SELECTHOUR(NOW())BETWEEN8and17这样就可以动态设置限流时间。标志文件:可以通过创建标志文件来限制程序的运行速度,删除文件后可以恢复正常运行。用户命令:可以动态连接gh-ost(后文提到),通过网络连接实现限速。当前工具可以被动态控制。当操作执行过程中负载增加时,DBA不得不终止操作,重新配置chunk-size等参数,然后重新执行操作命令。我们发现这种方法效率很低。gh-ost可以通过unixsocket文件或者TCP端口(可配置)监听请求,操作者可以在命令运行后更改相应的参数。参考以下示例:echothrottle|socat-/tmp/gh-ost.袜子打开速率限制。同样,可以使用no-throttle来关闭速率限制。更改执行参数:chunk-size=1500,max-lag-millis=2000,max-load=Thread_running=30这些参数可以在运行时更改。Auditable同理,gh-ost的状态也可以通过上面提到的程序接口获取。gh-ost可以报告当前进度,主要参数的配置和当前服务器标志等,这些信息都可以通过网络接口获取,比传统的taillog方式灵活多了。可以测试,因为日志文件与主库的负载关系不大,所以在从库上修改表结构的操作更能真实反映这些操作锁的实际影响。(虽然不是很理想,但我们以后会做优化工作)。gh-ost内置了对测试功能的支持,使用--test-on-replica参数指定:它可以对从库进行更改操作,操作结束时gh-ost会停止复制,swap表,并反向交换表,保留2个表并保持同步,停止复制。您可以在空闲时测试和比较两个表的数据。这是我们在GitHub生产环境中的测试:我们生产环境中有多个从库;有些从库不为用户提供服务,而是用来对所有表进行持续覆盖迁移测试。我们生产环境的表,小的可能没有数据,大的可能达到几百GB。我们只是做个标记,不会修改表结构(engine=innodb)。当每次迁移完成后,复制就会停止,我们会对原表和临时表中的数据进行完整的校验,保证它们的数据一致性。然后我们将恢复复制并转到下一张表。我们生产环境的从库通过gh-ost成功操作了很多表。值得信赖。上面说了这么多是为了提高大家对gh-ost的信任度。毕竟它在行业中仍然是新事物,并且类似的工具已经存在多年。首次试用前,建议用户在从库上进行测试,验证数据的一致性。我们已经成功地对奴隶进行了数千次迁移。如果在主库上使用gh-ost,可以实时观察主库的负载情况。如果发现负载变化较大,可以通过上述各种形式进行限速,直到负载恢复正常,再通过命令参数进行微调,动态控制运行风险。如果迁移操作开始,预计完成时间(ETA)显示要到晚上2点才能完成,最后需要换表,要不要留下看?您可以通过标记文件来告诉gh-ost推迟切换操作。gh-ost会完成行复制,但不会切换表,它会继续同步原表的数据更新操作到临时表。第二天你来办公室,删除标记文件或者通过接口echounpostpone告诉gh-ost开始切换表。我们不希望我们的软件束缚用户,它应该为我们做这件事。说到ETA,您可能会喜欢--exact-rowcount参数。相对于长长的SELECTCOUNT(*)语句,gh-ost会预估迁移操作所需的时间,并会根据当前的迁移状态更新预估时间。尽管ETA时间随时变化,但进度百分比的显示是准确的。gh-ost运行方式gh-ost可以同时连接多个服务器。为了获取二进制数据流,它会充当从库,将数据从一个库复制到另一个库。它有多种操作模式,具体取决于您的设置、配置和运行迁移的环境。A。连接从库,在主库上做迁移。这是gh-ost默认的工作方式。gh-ost会检查从库的状态,在集群结构中找到并连接到主库,然后执行迁移操作:在主库上读写行数据读取从库的二进制日志,并在从库中将变化应用到主库,从库收集表格式、字段&索引、行数等信息,并从从库中读取内部变化事件(如心跳事件)。在主库中切换表。如果你的主库日志格式是SBR,该工具也可以正常使用。但是从库必须开启二级日志(log_bin、log_slave_updates)并设置binlog_format=ROW(gh-ost是从库读取的二级文件)。如果直接在主库上操作,当然还需要二进制日志格式为RBR。b.连接主库如果没有从库,或者不想使用从库,可以直接在主库上操作。gh-ost将直接在主存储库上执行所有操作。您需要留意复制滞后问题。您的主库的二进制日志必须是RBR格式。在此模式下,您必须指定--allow-on-master参数c。此模式将在从库迁移/测试期间执行从库的迁移操作。gh-ost将简单地连接到主库,然后所有操作将从该库执行,而不会对主库进行任何更改。在整个运行过程中,gh-ost会控制速度,保证从库能够及时同步数据--migrate-on-replica是指gh-ost会直接对从库进行迁移操作。即使在复制操作期间也可以执行表切换操作。--test-on-replica表示迁移操作只是为了测试复制会在切换之前停止,然后执行切换操作,然后切换回来,你的原始表最终还是原始表。保留两个表并停止复制操作。您可以对这两张表进行一致性检查等测试操作。GitHub上的gh-ost我们一直在使用gh-ost进行所有在线数据库操作,我们每天都需要使用它,可能一天使用多次,具体取决于我们的数据库修改需求。凭借其审计和控制功能,我们已将其集成到ChatOps流程中。我们的工程师可以清楚地了解迁移操作的进度,并可以灵活地控制其行为。开源gh-ost在MIT许可证下发布到开源社区。虽然gh-ost在使用中非常稳定,但是我们也在不断的完善和完善它。我们将其开源,欢迎各界朋友参与贡献。稍后我们将发布一个页面以供贡献和建议。我们会积极维护gh-ost项目,希望广大用户能够试用和测试这个工具。我们付出了巨大的努力,让它更值得信赖。译者注gh-ost是MySQL业界在线表结构修改工具中的一个新秀。通常,我们使用Percona的pt-online-schema-change工具来完成这项工作。gh-ost的出现给我们带来了一种全新的方式。本文是对gh-ost介绍的翻译,我还没有试用过这个工具。欢迎喜欢尝鲜的网友说说自己的经历。