从 Greenplum 迁移数据到 YMatrix 6

此部分文档主要介绍从 Greenplum 迁移数据到 YMatrix 6 的最佳实践。

1 环境准备

一旦你决定进行一项重要操作,就要做好充分的准备再开始,不管是实际的条件准备还是心理准备(因为可能时刻会遇到问题)。心理准备每个人有自己的方式,条件准备我们会为你列出相对完整的方案,其中有可选的步骤,如下:

序号 准备步骤 说明 可选
1 备份源集群数据 数据迁移对源集群数据只有读操作,没有写操作,因此不涉及因迁移而带来的数据损坏风险
2 安装并部署目标数据库软件 否,必要步骤
3 为目标集群部署监控 视需求而定
4 禁止业务端所有 DDL 操作 此步是重要步骤,会给迁移执行带来风险,请务必重视 否,必要步骤
5 中断所有业务连接 否,必要步骤
6 收集源集群及目标集群信息 软硬件配置信息、源集群拓扑信息、目标集群拓扑信息等 否,必要步骤
7 备份源集群源信息 DDL、模式名、用户信息等 否,必要步骤
8 修正或优化 DDL 修正是为适配 Greenplum 与 YMatrix 间的 DDL 语句,解决兼容性问题(如果是从 YMatrix 4/5 迁移数据到 YMatrix 6 则不用修正),优化是尽可能从初始阶段就启用数据库最佳性能 是,目前 mxshift 已支持自动迁移 DDL,详见mxshift
9 生成修改表字段的 SQL 文件 是,目前 mxshift 已支持自动迁移索引,详见mxshift
10 为源集群的 Master 添加白名单 否,必要步骤
11 为目标集群创建用户 否,必要步骤
12 恢复表结构 是,目前 mxshift 已支持自动迁移索引,详见mxshift
13 为目标集群创建 DDL 在 YMatrix 中,在执行完迁移操作后再重新创建索引效率更高,因此在迁移前为目标集群创建 DDL 时,推荐不带有索引创建语句 是,目前 mxshift 已支持自动迁移 DDL,详见mxshift
14 修改表为 C 排序字符集

根据上表,我们给出具体的示例。

1.1 备份源集群数据(可选)

数据迁移对源集群数据只有读操作,没有写操作,因此不涉及因迁移而带来的数据损坏风险。但如果你还是不放心,或者有其他需要用到数据的业务需求,那么可以使用 mxbackup 工具来实现集群并行备份。

1.2 安装并部署目标数据库软件

注意!
我们推荐你在部署集群时不部署镜像节点(Mirror),在迁移执行完成后再添加,以提高迁移效率。

注意!
目标集群主机名与源集群不可重复!

请参考标准集群部署文档:

1.3 为目标集群部署监控(可选)

请参考监控报警文档:

1.4 禁止业务端所有 DDL 操作

注意!
在正式停止业务端所有业务前,源 Greenplum 集群业务端不允许执行任何 DDL,包括创建对象,修改对象、添加字段,删除字段,禁止执行 CREATEALTERTRUNCATEDROP 语句。

1.5 中断所有业务连接

在源 Greenplum 集群 Master 上修改 pg_hba.conf 文件。

$ vim  pg_hba.conf

以如下格式添加业务客户端地址,以禁用远程访问。

host all all <客户端 IP 地址>/<子网掩码位数> reject

随后重新加载配置,让修改后的配置文件生效

$ gpstop -u

1.6 收集源集群及目标集群信息

收集源集群及目标集群信息,包含物理机数量、操作系统、CPU、内存、磁盘类型、磁盘用量、网卡信息、源集群拓扑、目标集群拓扑、数据库许可证、资源组配置等,视具体场景加以使用调整,以做好全面的迁移执行准备。可能会用到以下命令:

序号 命令 用途
1 free -g 查看操作系统内存信息
2 lscpu 查看 CPU 数量
3 cat /etc/system-release 查看操作系统版本信息
4 uname -a 以如下次序输出所有内核信息(其中若 -p 和 -i 的探测结果不可知则被省略):内核名称;网络节点上的主机名;内核发行号;内核版本;主机的硬件架构名称;处理器类型(不可移植);硬件平台或(不可移植);操作系统名称
5 tail -11 /proc/cpuinfo 查看 CPU 信息
6 gpcheckperf 网络性能、带宽、磁盘 I/O 性能检测

1.7 备份源集群源信息

在 gpadmin 用户下,使用 pg_dump 工具备份源 Greenplum 集群 DDL、模式名、用户信息等。

# 备份全局用户对象
pg_dumpall -g -f global_user.sql

# 备份表结构
pg_dump <源数据库名> -s -f orig.sql          

# 复制一份备用
cp orig.sql copy.sql                        

生成创建索引的 SQL 文件。

$ cat get_index.sql 
WITH soi (oid, toid, SIZE, tschema, tname) AS
  ( SELECT soioid,
           soitableoid,
           soisize,
           soitableschemaname,
           soitablename
   FROM gp_toolkit.gp_size_of_index ),
     childrel (oid, coid)AS
  ( SELECT pp.parrelid,
           ppr.parchildrelid
   FROM pg_partition pp
   INNER JOIN pg_partition_rule ppr ON pp.oid = ppr.paroid ),
     irn (oid, toid, SIZE, tschema, tname, rn) AS
  ( SELECT *,
           row_number() OVER (
            ORDER BY dt.ssize DESC) rn
   FROM
     ( SELECT soi.oid,
              soi.toid ,
              sum(coalesce(dt2.SIZE, soi.SIZE)) ssize ,
                                                soi.tschema,
                                                soi.tname
      FROM soi
      LEFT JOIN
        ( SELECT childrel.oid,
                 soi.SIZE
         FROM soi
         INNER JOIN childrel ON soi.toid = childrel.coid ) dt2 ON soi.toid = dt2.oid
      GROUP BY 1,
               2,
               4,
               5 ) dt )
SELECT SQL || ';'
FROM
  ( SELECT pg_get_indexdef(oid) AS SQL ,
           (rn % 12 + (rn / 12)::int) % 12 AS orderkey
   FROM irn
   WHERE toid NOT IN
       (SELECT coid
        FROM childrel) ) dt
WHERE SQL NOT LIKE 'CREATE UNIQUE INDEX%'
ORDER BY dt.orderkey ;

通过 psql 执行上述 SQL。

psql -d <源数据库名> -U <源数据库超级用户名> -t -f get_index.sql > index.sql

1.8 修正或优化 DDL(可选)

mxshift 现已支持自动迁移 DDL,具体用法请见“2 迁移执行”。如需手动迁移 DDL,则参考此部分内容。

修正是为适配 Greenplum 与 YMatrix 的 DDL 语句,解决兼容性问题(如果是 从 YMatrix 迁移数据到 YMatrix 则不用修正),优化是尽可能从初始阶段就启用数据库最佳性能。以下是手动修正或优化命令示例,在源 Greenplum 集群环境下执行:

# 修改压缩算法
sed -i 's/quicklz/zstd/g' orig.sql   

# 修改 plpython 版本
sed -i 's/plpythonu/plpython3u/g' orig.sql     

# 增加创建插件语法
sed -i '1s/^/create language plpython3u;/' orig.sql  ####

# 删除建索引的语句
sed -i -e '/CREATE INDEX.*;/d' -e '/CREATE INDEX/,/;/d' orig.sql  

# 优化压缩算法
sed -i 's/compresstype=zlib/compresstype=zstd/g' orig.sql  

# 修改压缩级别
sed -i 's/compresslevel=5/compresslevel=1/g' orig.sql        

针对以上修正或优化,给出如下具体说明:

  • 修改压缩算法。YMatrix 不支持 quicklz 压缩算法类型。
  • 修改 plpython 版本。YMatrix 支持 plpython3 依赖。
  • 增加创建插件语法。在 YMatrix 中需要创建一些扩展插件。
  • 删除建索引的语句。如果带着索引在目标数据库创建 DDL,则会因增加扫描数据的次数而大幅降低迁移效率。我们推荐先删除索引语句创建新表,在迁移完成后重新创建索引。
  • 优化压缩算法。在 YMatrix 中使用 zstd 压缩算法类型更优。
  • 修改压缩级别。在 YMatrix 中使用 1 压缩级别更优。

1.9 生成修改表字段的 SQL 文件(可选)

建表后对建索引的字段需要指定为 C 字符集,以便高效添加索引,压缩迁移时间。

$ cat collate.sql
SELECT 'alter table '||quote_ident(b.schemaname)||'.'||quote_ident(b.tablename)||' alter column '||quote_ident(b.colname)||' type '||d.coltype||' COLLATE "pg_catalog"."C";'
FROM
  (SELECT DISTINCT a.schemaname,
                   a.tablename,
                   regexp_split_to_table(replace(a.keyindex,' ',''),',') AS colname
   FROM
     (SELECT schemaname,
             tablename,
             rtrim(split_part(indexdef,'(',2),')') AS keyindex,
             indexdef
      FROM pg_indexes
      WHERE schemaname NOT IN ('pg_catalog')
        AND indexname NOT LIKE '%pkey'
        AND indexdef LIKE 'CREATE INDEX%') a) b
INNER JOIN
  (SELECT c.oid,
          n.nspname,
          c.relname
   FROM pg_catalog.pg_class c
   LEFT JOIN pg_catalog.pg_namespace n ON n.oid = c.relnamespace) c ON b.schemaname=c.nspname
AND c.relname=b.tablename
INNER JOIN
  (SELECT e.attrelid,a.attname, pg_catalog.format_type(a.atttypid, a.atttypmod) AS coltype,
     (SELECT substring(pg_catalog.pg_get_expr(d.adbin, d.adrelid)
                       FOR 128)
      FROM pg_catalog.pg_attrdef d
      WHERE d.adrelid = a.attrelid
        AND d.adnum = a.attnum
        AND a.atthasdef), a.attnotnull,
                          a.attnum
   FROM pg_catalog.pg_attribute a
   LEFT OUTER JOIN pg_catalog.pg_attribute_encoding e ON e.attrelid = a .attrelid
   AND e.attnum = a.attnum
   WHERE a.attnum >0) d ON d.attrelid=c.oid
AND d.attname=b.colname;

1.10 为源集群的 Master 添加白名单

注意!
如果源集群与目标集群在同一台服务器上运行,略过此步骤即可。

在源集群的 Master,将目标集群 Master 的主机 IP 地址增加到 pg_hba.conf 文件中,示例如下,IP 地址为 172.16.100.2:

host    all    all    172.16.100.2    md5

在目标集群的 Master 执行以下命令,增加源集群 Master 节点的主机 IP 地址和主机名到 /etc/hosts 文件中,示例中主机 IP 地址为 172.16.100.195,主机名为 sdw1。

$ cat  add_hosts.sh 
#!/bin/bash
for line  in `psql -Atc "select distinct  hostname from gp_segment_configuration order by datadir desc"`
do
    gpssh -h $hostname -v -e "echo 172.16.100.195 sdw1 >> /etc/hosts"

done

随后重新加载配置,让修改后的配置文件生效。 Greenplum 执行 gpstop 命令。

$ gpstop -u

YMatrix 5 执行 mxstop 命令。

$ mxstop -u

1.11 为目标集群创建用户

在 YMatrix 集群环境下执行以下命令。

$ psql -h <YMatrix 服务器 IP 地址> -p  <目标集群端口号> -d <目标数据库> -U <目标数据库超级用户名> -f global_user.sql

1.12 为目标集群创建 DDL(可选)

在 YMatrix 集群环境下执行以下命令。

$ psql -h <YMatrix 服务器 IP 地址> -p  <目标集群端口号> -d <目标数据库> -U <目标数据库超级用户名> -f orig.sql 

1.13 恢复表结构(可选)

使用备份好的 orig.sql 文件在目标集群 YMatrix 恢复表结构。

$ time psql -d <目标数据库名> -f orig.sql > restoreddl.log  2>&1 &   

1.14 修改表为 C 排序字符集(可选)

$ time psql -d <目标数据库名> -f collate.sql  

2 迁移执行

注意!
mxshift 详细参数介绍请见 mxshift

首先编写配置文件 config_path.toml。示例如下

[database]
        [database.source]
        ## Name of database
        db-database= "testdb"
        ## Hostname of database master
        db-host="sdw3"
        ## password of database
        db-password="xxxx"
        ## Port of database master
        db-port=54322
        ## user name of database
        db-user="gpadmin"
        ## Version of database(Please use the result of 'SELECT version();' as value). Required only when
        ##       1. Source database is un-reachable, and 'ddl.only-ddl' is enabled and 'ddl.mode' is 'input'
        ##       2. Target database is un-reachable, and 'ddl.mode' is 'output' */
         # db-version="PostgreSQL 12 (MatrixDB 5.2.0-enterprise) (Greenplum Database 7.0.0+dev.17410.gedbdb5ef84 build dev) on arm-apple-darwin21.5.0, compiled by Apple clang version 13.0.0 (clang-1300.0.27.3), 64-bit compiled on Jun  5 2023 15:45:24"
         ## The installation directory of matrixdb
         install-dir="/usr/local/greenplum-db-6.7.1"
         [[database.source.hostname-to-ip]]
             ## The content within <> should be replaced with actual information and <> should be removed
             node-hostname="<mdw>" 
             node-ip="<127.0.0.1>"
         [[database.source.hostname-to-ip]]
             node-hostname="<sdw1>"
             node-ip="<127.0.0.2>"
         [[database.source.hostname-to-ip]]
             node-hostname="<sdw2>"
             node-ip="<127.0.0.3>"

        [database.target]
        ## Name of database
        db-database="destdb"
        ## Hostname of database master
        db-host="172.16.100.32"
        ## password of database
        db-password="yyyy"
        ## Port of database master
        db-port=5432
        ## user name of database
        db-user="mxadmin"
        ## Version of database(Please use the result of 'SELECT version();' as value). Required only when
        ##       1. Source database is un-reachable, and 'ddl.only-ddl' is enabled and 'ddl.mode' is 'input'
        ##       2. Target database is un-reachable, and 'ddl.mode' is 'output' */
         # db-version="PostgreSQL 12 (MatrixDB 5.2.0-enterprise) (Greenplum Database 7.0.0+dev.17410.gedbdb5ef84 build dev) on arm-apple-darwin21.5.0, compiled by Apple clang version 13.0.0 (clang-1300.0.27.3), 64-bit compiled on Jun  5 2023 15:45:24"

[scope]
## The compress method for transferring data, methods restricted to 0/gzip/lz4/zstd        
compress-method="lz4"
## mode for transferring data from source to target database, and value restricted to normal/dryrun/fetch/motion.
##dryrun for only executing ddl, not transferring data
##fetch for fetching data from source and abandon
##motion for fetching data from source, redistributing and finally abandon
mode="normal"
## Sql for select segment information from source database        
# select-source-segment-sql="SELECT dbid, content, port, hostname FROM gp_segment_configuration WHERE status = 'u' AND role = 'p' ORDER BY CONTENT;"
## Sql for select segment information from target database
# select-target-segment-sql="SELECT dbid, content, port, hostname FROM gp_segment_configuration WHERE status = 'u' AND role = 'p' ORDER BY CONTENT;"
        [[scope.table-list]]
                schema="test_schema_1"
                name="table_001"
        [[scope.table-list]]
                schema="test_schema_2"
                name="table_002"
        [[scope.exclude-table-list]]
                schema="test_schema_3"
                name="table_003"
schema-list=["test_schema_1", "test_schema_2"]
exclude-schema-list=["test_schema_5", "test_schema_8"]
## Whether to disable data incremental migration, by default, it is true.
# disable-data-increment=true

[log]
## The log level, value restricted to: debug/verbose/info.
log-level="info"
## Print log without color.
# no-color=false

[controller]
## By default, transfer work will start from the largest table. If set 'bothway' it will start from both the largest and the smallest table
both-way=true
## The number of table transferred at the same time
concurrency=3

[transfer]
## Verity the number of record of every table
verify=true
with-index=true

[ddl]
enabled=true
# file-path="/tmp/mxshift.sql"
# mode="output"
only-ddl=false
## During the DDL transfer, whether to skip the transfer of resource queue or group, by default, it is true.
# skip-resource-queue-and-group=true
## During the DDL transfer, whether to skip the transfer of tablespace, by default, it is true.
# skip-table-space=true
        [[ddl.replace]]
        ## Only applicable for the case of migration from Greenplum to YMatrix
                category="role"
                [[ddl.replace.pairs]]
                        old="gpadmin"
                        new="mxadmin"
## Whether to disable ddl incremental migration, by default, it is true.
# disable-ddl-increment=true   

然后在目标 YMatrix 集群上执行数据迁移。

$ mxshift -c config_path.toml

3 后续任务

3.1 执行创建索引(可选)

在目标集群 YMatrix 上执行创建索引。

psql -h localhost -p  <目标集群端口号> -d <目标数据库名> -U mxadmin -f index.sql >>idx.out 2>&1 &

3.2 执行 analyzedb 命令

在目标集群 YMatrix 上更新全库统计信息。

export PGPORT=<目标集群端口号>
time analyzedb -d <目标数据库名> -p 10 -a 

3.3 添加镜像节点(Mirror)

在目标集群 YMatrix 上添加 Mirror 。步骤示例如下:

# 首先,查看当前集群实例信息
postgres=# SELECT * from gp_segment_configuration order by 1;
 dbid | content | role | preferred_role | mode | status | port | hostname | address |                   datadir
------+---------+------+----------------+------+--------+------+----------+---------+---------------------------------------------
    1 |      -1 | p    | p              | n    | u      | 5432 | mdw      | mdw     | /home/mxdata_20220925154450/master/mxseg-1
    2 |       0 | p    | p              | n    | u      | 6000 | sdw2     | sdw2    | /home/mxdata_20220925154450/primary/mxseg0
    3 |       1 | p    | p              | n    | u      | 6001 | sdw2     | sdw2    | /home/mxdata_20220925154450/primary/mxseg1
    4 |       2 | p    | p              | n    | u      | 6000 | sdw3     | sdw3    | /home/mxdata_20220925154450/primary/mxseg2
    5 |       3 | p    | p              | n    | u      | 6001 | sdw3     | sdw3    | /home/mxdata_20220925154450/primary/mxseg3
    6 |      -1 | m    | m              | s    | u      | 5432 | sdw1     | sdw1    | /home/mxdata_20220925154450/standby/mxseg-1
(6 rows)

# 创建一个包含所有主机名(hostname)的文件
$ cat /home/mxadmin/seg_hosts 
sdw1
sdw2
sdw3
sdw4

# 通过 gpssh 命令批量增加 Mirror 目录
$ gpssh -f /home/mxadmin/seg_hosts -e 'mkdir -p /home/mxdata_20220925154450/mirror'

# 生成 Mirror 模板文件
$ mxaddmirrors -o ./addmirror

# 查看 Mirror 模板文件
$ cat addmirror

# 执行增加 Mirror 操作
$ mxaddmirrors -i addmirror

# 最后,再次查看集群实例
postgres=# SELECT * from gp_segment_configuration order by 1;
 dbid | content | role | preferred_role | mode | status | port | hostname | address |                   datadir
------+---------+------+----------------+------+--------+------+----------+---------+---------------------------------------------
    1 |      -1 | p    | p              | n    | u      | 5432 | mdw      | mdw     | /home/mxdata_20220925154450/master/mxseg-1
    2 |       0 | p    | p              | n    | u      | 6000 | sdw2     | sdw2    | /home/mxdata_20220925154450/primary/mxseg0
    3 |       1 | p    | p              | s    | u      | 6001 | sdw2     | sdw2    | /home/mxdata_20220925154450/primary/mxseg1
    4 |       2 | p    | p              | s    | u      | 6000 | sdw3     | sdw3    | /home/mxdata_20220925154450/primary/mxseg2
    5 |       3 | p    | p              | s    | u      | 6001 | sdw3     | sdw3    | /home/mxdata_20220925154450/primary/mxseg3
    6 |      -1 | m    | m              | s    | u      | 5432 | sdw1     | sdw1    | /home/mxdata_20220925154450/standby/mxseg-1
    7 |       0 | m    | m              | n    | d      | 7000 | sdw3     | sdw3    | /home/mxdata_20220925154450/mirror/mxseg0
    8 |       1 | m    | m              | s    | u      | 7001 | sdw3     | sdw3    | /home/mxdata_20220925154450/mirror/mxseg1
    9 |       2 | m    | m              | s    | u      | 7000 | sdw2     | sdw2    | /home/mxdata_20220925154450/mirror/mxseg2
   10 |       3 | m    | m              | s    | u      | 7001 | sdw2     | sdw2    | /home/mxdata_20220925154450/mirror/mxseg3
(10 rows)

完成以上步骤后,恢复业务访问并观察业务运行情况,持续跟踪一段时间(具体时间据具体时序场景而定),如稳定运行则恭喜数据迁移成功完成!