用gptransfer迁移数据

用gptransfer迁移数据

这一主题描述如何使用gptransfer工具在数据库之间传输数据。

gptransfer迁移工具从一个Greenplum数据库把元数据和数据传输到另一个Greenplum数据库,它允许迁移一个数据库的整个内容或者只是选中的表到另一个数据库。源数据库和目标数据库可以在同一个或者不同的集群中。数据会在所有的Segment间并行地传输,使用gpfdist数据装载工具可以得到最高的传输率。

gptransfer处理数据传输的设置和执行。参与的集群必须已经存在,在两个集群的所有主机间必须有网络访问以及证书认证的ssh访问。

接口包括传输一个或者多个完整数据库、一个或者多个数据库表的选项。一次完整数据库传输包括数据库模式、表数据、索引、视图、角色、用户定义函数以及资源队列。配置文件(包括postgres.confpg_hba.conf)必须由管理员手工传输。用gppkg安装在数据库中的扩展(例如MADlib)必须由管理员在目标数据库中安装。

gptransfer工具的完整语法和使用信息请见Greenplum数据库工具指南

先决条件

  • gptransfer工具只能用于Greenplum数据库。不支持将Apache HAWQ作为源或者目标。
  • 源以及目标Greenplum集群必须都是版本4.2或者更高。
  • 至少一个Greenplum实例必须在其发行中包括了gptransfer工具。如果源或者目标都不包括gptransfer,就必须升级一个集群以使用gptransfer
  • gptransfer工具可以从源数据库或者目标数据库所在的集群运行。
  • 目标集群中的Segment数量必须大于等于源集群中的主机数量。目标中的Segment数量可以小于源中的数量,但是数据将会以较低的速率传输。
  • 两个集群中的Segment主机彼此之间必须有网络连接。
  • 两个集群中的每一台主机必须能够用证书认证的SSH连接到每一台其他主机。可以使用gpssh_exkeys工具在两个集群的主机之间交换公钥。

gptransfer会做什么

gptransfer使用可写和可读外部表、Greenplum的gpfdist并行数据装载工具以及命名管道把数据从源数据库传输到目标数据库。源集群上的Segment从源数据库表中选择并且插入到一个可写的外部表。目标集群上的Segment从一个可读外部表中选择并且插入到目标数据库表。可写和可读外部表后面由源集群的Segment主机上的命名管道支持,并且每个命名管道有一个gpfdist进程把管道的输出送给目标Segment上的可读外部表。

gptransfer通过让数据库对象以批次被传送来精心安排其处理。对于每个要被传输的表,它执行下面的任务:
  • 在源数据库中创建一个可写外部表
  • 在目标数据库中创建一个可读外部表
  • 创建命名管道以及源集群中Segment主机上的gpfdist进程
  • 在源数据库中执行一个SELECT INTO语句把源数据插入到可写外部表
  • 在目标数据库中执行一个SELECT INTO语句把数据从可读外部表插入到目标表
  • 通过比较源和目标中行的行数或者MD5哈希来有选择地验证数据
  • 清除外部表、命令管道和gpfdist进程

Fast模式和Slow模式

gptransfer使用gpfdist并行文件服务工具设置数据传输,它会平均地把数据供应给目标Segment。运行更多gpfdist进程会增加并行度和数据传输率。当目标集群比源集群有相同或者更多的Segment,gptransfer会为每个源Segment设置一个命名管道和一个gpfdist进程。这是用于最优数据传输率的配置并且被称为Fast模式。下面的图展示了目标集群拥有至少和源集群同样多的Segment时在一台Segment主机上的设置。

当目标集群的Segment比源集群少时,命名管道的输入端配置有点不同。gptransfer会自动处理这种供替代的设置。配置中的不同意味着传输数据到一个Segment比源集群少的目标集群中的速度不如传输到具有相同或者更多Segment的目标集群中。这被称为Slow模式,因为只有较少的gpfdist进程供应数据给目标集群,然而通过每台Segment主机上的一个gpfdist,传输依然很快。

当目标集群小于源集群时,每台Segment主机上有一个命名管道并且该主机上的所有Segment都通过它发送自己的数据。源主机上的Segment把它们的数据写入到一个连接着命名管道输入端上gpfdist进程的可写外部Web表。这会把表数据联合到一个单一命名管道中。在该命名管道输出上的gpfdist进程会把联合起来的数据供应给目标集群。下图展示了这种配置。

在目标端,gptransfer用源主机上的gpfdist服务器定义一个可读外部表作为输入并且从该可读外部表选择到目标表。数据会被均匀地分布到目标集群中的所有Segment上。

批尺寸和子批尺寸

一次gptransfer执行的并行度决定于两个命令行选项: --batch-size--sub-batch-size--batch-size选项指定一个批次中药传输的表数量。默认的批尺寸是2,意味着任何时刻有两个表的传输在进行。最小批尺寸是1而最大是10。--sub-batch-size参数指定开始做表传输工作的并行子进程的最大数量。默认是25,最大为50。批尺寸和子批尺寸的乘积就是并行量。例如如果设置为默认值,gptransfer能够执行50个并发任务。每个线程是一个Python进程并且会消耗内存,因此将这些值设置得过高可能会导致Python的内存不足错误。由于这个原因,应该为实际的环境调节批尺寸。

为gptransfer准备主机

在安装一个Greenplum数据库集群时,设置所有的Master和Segment主机,以便Greenplum数据库的管理用户(gpadmin)能用SSH从集群中每台主机不用密码连接到其他任一主机。gptransfer工具对源集群和目标集群中的每台主机都要求这样的能力。首先,确保集群彼此之间都有网络连接。然后,准备一个含有两个集群中所有主机列表的主机文件,并且使用gpssh-exkeys工具交换密钥。gpssh-exkeys的参考请见Greenplum数据库工具指南

主机映射文件是一个文本文件,其中列出了源集群中的Segment主机。它被用来启用Greenplum集群中主机之间的通信。该文件可以用--source-map-file=host_map_file命令选项在gptransfer命令行上指定。当使用gptransfer在两个独立Greenplum集群之间拷贝数据时,它是一个必备选项。

该文件包含一个下列格式的列表:
host1_name,host1_ip_addr
host2_name,host2_ipaddr
...
这个文件使用IP地址替代主机名,以避免集群之间名称解析可能造成的任何问题。

限制

gptransfer只从用户数据库传输数据,postgrestemplate0template1数据库不能被传输。管理员必须手工传输配置文件并且用gppkg在目标数据库中安装扩展。

目标集群必须至少有和源集群中Segment主机相同数量的Segment。传输数据到一个较小的集群不如传输到一个较大的集群那么快。

传输小的或者空的表可能会意料之外的慢。在设置外部表和用于Segment之间并行数据装载的通信处理的过程中有显著的固定开销,这种开销不管有没有实际数据传输都会出现。使用其他方法传输方案和较小的表到目标数据库可能会更有效,然后使用带-t选项的gptransfer传输大型表。

完全模式和表模式

在用--full选项运行时,gptransfer把源集群中所有的用户数据库、表、视图、索引、角色、用户定义的函数以及资源队列拷贝到目标集群中。目标系统不能包含任何用户定义的数据库,只能有默认数据库postgres、template0以及template1。如果gptransfer在目标上发现一个数据库,它会失败并且出现类似下面的消息:
[ERROR]:- gptransfer: error: --full option specified but tables exist on destination system
注意: --full选项不能与-t-d-f或者--partition-transfer选项一起制定。
要个别地拷贝表,使用-t命令行选项(每个表一个选项)指定表或者通过使用-f命令行选项来指定一个含有要传输表的列表的文件。表用其完全限定格式database.schema.table指定。表定义、索引和表数据都会被拷贝。该数据库必须已经存在于目标集群上。

默认情况下,如果用户尝试传输一个已经存在于目标数据库中的表,gptransfer会失败:

[INFO]:-Validating transfer table set...
[CRITICAL]:- gptransfer failed. (Reason='Table database.schema.table exists in database database .') exiting...

--skip-existing--truncate或者--drop选项可以覆盖这一行为。

下列表显示在完全模式和表模式下会被拷贝的对象。

对象 完全模式 表模式
数据 Yes Yes
索引 Yes Yes
角色 Yes No
函数 Yes No
资源队列 Yes No
postgresql.conf No No
pg_hba.conf No No
gppkg No No

如果用户想要分阶段(例如在计划好的停机时间或者低活动率时段)拷贝数据库,可以把--full选项和--schema-only选项一起使用。运行gptransfer --full --schema-only ...在目标集群上创建数据库,但是不拷贝数据。然后在计划好的停机时间或者低活动率时段传输表。注意在传输表时包括--truncate或者--drop选项以防止传输因为表已经在目标上存在而失败。

-x选项启用表锁定。如果被请求,一个排他锁将被放置在源表上,直到拷贝和验证完成。

验证

默认情况下,gptransfer不会验证被传输的数据。用户可以使用--validate=type选项请求验证。验证type可以是下列之一:
  • count – 比较源数据库和目标数据库中表的行计数。
  • md5 – 在源和目标上都排序表,然后对已排序行的MD5哈希执行逐行比较。

如果传输期间数据库是可访问的,一定要增加-x选项来锁住表。否则,该表可能在传输期间被修改,进而导致验证失败。

失败的传输

表上的一个失败不会结束gptransfer任务。当一次传输失败时,gptransfer会显示一个错误消息并且把表名加入到一个失败传输文件中。在gptransfer会话结束时,gptransfer会写一个消息告诉用户出现了错误,并且提供失败传输文件的名称。例如:
[WARNING]:-Some tables failed to transfer. A list of these tables
[WARNING]:-has been written to the file failed_transfer_tables_20140808_101813.txt
[WARNING]:-This file can be used with the -f option to continue

失败传输文件的格式是-f选项所要求的格式,因此用户可以使用它来开始一次新的gptransfer会话来重试失败的传输。

最佳做法

小心不要因为用--batch-size--sub-batch-size命令行选项指定太大的并行度而导致超过主机内存。太多子进程可能会耗尽内存,导致一个Python内存不足错误。用一个较小的批尺寸和子批尺寸开始,然后基于经验增加。

分阶段传输数据库。首先,用--schema-only-d database选项运行gptransfer,然后分阶段传输表。在用--schema-only选项运行gptransfer后,一定增加--truncate--drop选项来防止因为表已经存在而失败。

要小心地选择gpfdist和外部表的参数,例如外部表数据的定界符和行最大长度。例如,不要选择可能出现在表数据中的定界符。

如果有很多空表要传输,考虑使用一个DDL脚本而不是gptransfer。为每个表设置传输的gptransfer很显著,因此不是一种传输空表的有效方法。

gptransfer在传输数据之前创建表的索引。这会拖慢数据传输,因为在数据被插入到表中时索引会被同时更新。特别是对于大型的表,考虑在运行gptransfer之前删除索引并且在传输完成后重建索引。