怎样将数据从Oracle迁移到TiDB

2021-02-19 15:51:54 浏览数 (1)

**导读**

> 作者:杨漆

> 16年关系型数据库管理,从oracle 9i 、10g、11g、12c到Mysql5.5、5.6、5.7、8.0 到TiDB获得3个OCP、2个OCM;运维路上不平坦,跌过不少坑、熬过许多夜。把工作笔记整理出来分享给大伙儿,希望帮到大家少走弯路、少熬夜。

Best Practice for Data migration from Oracleto Tidb

为何要选择TiDB ?

随着业务的高速发展、数据的爆发式增长,很多使用关系型数据库的公司为保障业务的有效进行不得不面临一轮数据库的垂直拆分和水平拆分。但拆分后对代码的侵入性较大,后续的不断扩容让 DBA 的管理成本上升(时间成本、运维成本、管理复杂度等等)。所以急需一种既能支持关系型数据库 RDBMS 和非关系型数据库 NoSQL 分布式的存储计算引擎。

市场上有没有这种兼二者之长的Database ?

有!

TiDB 分布式数据库结合了传统的 RDBMS 和NoSQL 的最佳特性。首先,高度兼容 MySQL 协议,大多数情况代码可以直接迁移到 TiDB 分布式数据库,已分库分表的实例可以在 TiDB 中进行聚合;同时,TiDB 分布式数据库支持水平弹性扩展,通过简单地增加新节点即可实现 TiDB 分布式数据库的水平扩展,按需扩展计算节点或存储节点,轻松应对高并发、海量数据场景。

下面介绍怎样将Oracle中的数据同步到 TiDB 分布式数据库:

OGG 是一个综合软件包,用于在异构环境中进行实时数据集成和复制。高可用性解决方案、实时数据集成、事务更改数据捕获、数据复制、转换、操作和分析企业间的系统验证。

    三个步骤:

1. DDL的转换(使用Navicat或其它工具),注意字段类型和一些不兼容的转换

2. 全量数据迁移(使用ogg Initial Load)

3. 增量数据迁移(使用ogg)

增量同步需要在初始化同步之前,先开启日志抽取。由于异构平台,无法基于统一时间点完成数据初始导入操作,所以在完成初始化导入操作之后需要完整应用开始 initial load 同步之后的所有 log,此时会存在重复执行的问题,OGG 中通过 handlecolisions参数处理冲突的场景,保证最终数据的一致性(根据主键或唯一键进行重复的操作可以保证最终数据一致,在缺少主键的场景可能会导致数据重复)。

源端 Oracle 要求

• 开启归档模式

• 开启Force logging

• 设置ENABLE_GOLDENGATE_REPLICATION 参数为 true (11.2.0.4)

• 开启最小补全日志(根据同步数据范围选择)

o    表级别

o    Schema级别

o    数据库级

• 用户权限

o    DBA角色

目标端TiDB分布式数据库要求

• set tidb_constraint_check_in_place = 1;

该参数将TiDB分布式数据库中乐观锁模式下的主键冲突检查由 commit 时检查提升为 insert 时检查,在遇到主键冲突时可配置为忽略冲突,否则在遇到主键冲突时无法忽略,复制进程会 abend。仅需在 OGG 复制进程 session 级别设置,通过配置在复制进程参数中实现,无需全局修改。

• lower-case-table-names = 1

OGG 复制进程需要该参数设置为 1,tidb 中修改此参数并未产生实际效果变化,仅为实现兼容。

OGG 同步要求

DDL 建表语句需提前转换,并在目标端执行。

增量抽取:

OGG Architecture

1. OGG一定要使用以上版本(经过原厂迁移实践Product DB : Oracle 11G)

2. 要注意表名的大小写(tidb中的表名大小写 与ogg中一定要严格统一,否则会报错)

A.OGG 安装 - Oracle 端

解压安装包:unzip V975837-01.zip

静默安装方式:vi./fbo_ggs_Linux_x64_shiphome/Disk1/response/oggcore.rsp

修改以下几处关键点就好:

oracle.install.responseFileVersion=/oracle/install/rspfmt_ogginstall_response_schema_v12_1_2

##默认无需修改

INSTALL_OPTION=ORA11g

##此处为 Oracle 数据库版本,本文档使用11.2.0.4,此处填写 ORA11G,如果是 12c 版本则填写 ORA12c

SOFTWARE_LOCATION=/home/oracle/ogg12.3

##此处为安装路径

START_MANAGER=false

##安装完成不启动 mgr 进程,设为 false

安装ogg:

$./fbo_ggs_Linux_x64_shiphome/Disk1/runInstaller -silent -responseFile/home/oracle/oggsoft/fbo_ggs_Linux_x64_shiphome/Disk1/response/oggcore.rsp

#此处 response 文件不支持相对路径

Vi  ~/ .bash_profile

exportLD_LIBRARY_PATH=$ORACLE_HOME/lib

ogg初始化(创建目录):

$ ./ggsci

GGSCI ( hostname ) 1> create subdirs

B.OGG 安装 - TiDB 分布式数据库端

解压安装包: $ unzip V978711-01.zip

$tar xvf ./ggs_Linux_x64_MySQL_64bit.tar -C /home/tidb/ogg12.3

ogg初始化(创建目录):

$ ./ggsci

GGSCI ( hostname ) 1> create subdirs

C.TiDB 分布式数据库端数据库环境准备

(1) 设置 lower-case-table-names 参数为 1

$grep lower-case-table-names tidb.toml

lower-case-table-names  = 1

(2) 检查参数是否正确

(3) 创建用于同步的用户并赋权

create user 'tidb' identified by 'tidb';

GRANT ALL PRIVILEGES ON scott.* to oggadmin ;

(4) 创建对应表结构

D.Oracle 端数据库环境准备

 (1).开启归档模式:

shutdown immediate;

startup mount;

alter database archivelog;

alter database open;

## 若DB已为归档模式以上步骤省略

(2).开启数据级别的增量日志

ALTER DATABASE FORCE LOGGING;

##开启强同步,会记录所有的事务日志以及数据导入的日志,即使用户设置了 nolog 也会记录。

ALTER DATABASE ADD SUPPLEMENTAL LOG DATA;

ALTER SYSTEM SWITCH LOGFILE;

selectlog_mode,supplemental_log_data_min,force_logging from v$database;

##  查询是否开启增量日志

(3) 数据库中允许启动 OGG

alter system set enable_goldengate_replication=true;

(4)创建 goldengate 用户,并赋予相关权限

SQL> create tablespace goldengate datafile'/data/goldengate.dbf' size 10G autoextend on next 1G maxsize unlimited;

SQL> create user goldengate identified by goldengate default tablespace goldengate;

SQL> grant dba to goldengate;

(5) ggsci中创建免密登录秘钥

./ggsci

create subdirs

add credentialstore

alter credentialstore add user goldengate,passwordgoldengate

(6) 直接执行下面命令即可在ogg中登录到goldengate用户

dblogin useridalias goldengate

(7) 开启schema 级别的附加日志,能够确保schema 下新表的附加日志也会被自动捕获。

若数据库版本低于11.2.0.2,则需要打Oracle Patch 13794550

若以前的oracle数据库版本没有打上面的补丁,开启schema 级别附加日志会报如下错误:

ERROR OGG-06522 Cannot verify existence of table function that is required to ADD schema level supplemental logging, failed.

a. GGSCI 登录有两种方式

1) dblogin userid goldengate, password goldengate

2) dblogin useridalias goldengate

b. 为指定 schema 开启日志捕获

ADD SCHEMATRANDATA schema ALLCOLS

c. 当没有启动 schema 级别的附加日志时,可以使用基于表级别的附加日志

1) GGSCI 登录: dblogin userid goldengate, password goldengate

2)为指定 schema 开启日志捕获: ADD TRANDATA schema.tablename NOKEY 

E. MGR 进程配置

Manager 进程是 OGG 的控制进程,用于管理Extract、Pump、Replicat 等进程,在Extract、Pump、Replicat 进程启动之前,Manager 进程必须先要在源端和目标端启动。

F. Extract 进程配置

Extract 进程运行在数据库源端上,它是 OGG 的捕获进程,可以配置 Extract 进程来初始数据装载和同步变化捕获。

G. Pump 进程配置

Pump 进程是配置在源端辅助Extract 进程,Pump进程将Extract进程写好的本地 Trail 文件通过网络发送到目标端的 Trail 文件中。

H. 配置应用端

I. Replicat 进程配置

Replicat 进程是运行在目标端系统的一个进程,负责读取 Extract 进程提取到的数据(变更的事务或 DDL 变化)并应用到目标数据库。

J.配置全量抽取

K. 配置全量应用

进程启动顺序:

测试性能数据:

四个分组,每组25个线程并发度控制。

1. 单表30列时,每秒可加载10万行数据。

2. 单表200列时,每秒可加载2万行数据。

OGG运行中常见故障:

1. OGG-01201 Error reported by MGR : Access denied

原因:

This is due to a new security restriction in GoldenGate 12.2. In order to allow access from a remote system the ACCESSRULE parameter must be put into the manager parameter file on the target in order to allow access from the source.

处理方法:需要在源端 mgr 增加允许访问目标端 ip的规则

(1) 编辑 mgr 参数文件

edit params mgr

(2) 增加以下内容:

ACCESSRULE, PROG *, IPADDR *, ALLOW

2. replicat 端报 invalid time format

问题原因:

之前把 Oracle 的 date 类型改为了 TIDB timestmap类型,但是 Oracle 里面部分时间类型数据超过了TIDB timestamp 的范围。(TIDB 范围为 1970-01-01 00:00:01.000000 到 2038-01-19 03:14:07.999999,Oracle 部分时间数据超过 2038 年,应该是原先遗留的测试数据)。

处理方法:

将 TIDB 的 timestamp 改为支持更大的 datetime 类型;同时在 OGG replicat 端增加异常数据不abended 而是记录 discard 的方式,具体参数为:REPERROR (default,discard),防止 OGG 因为异常数据终止。

3. extract 报 ORA-01801: date format is too long for internal buffer

问题原因:Oracle 端有时间类型数据通过 OCI 接口入库时,Oracle 不做时间校验,但是查询的时候就会校验时间格式,正常 Oracle select * 都会报错,属于 Oracle 端数据问题。

处理方法:

用 to_char(date,’yyyy-mm-dd hh24:mi:ss’)处理错误日期后,Oracle 可以正常查出来,但是显示的时间为 ‘0000-00-00 00:00:00’ 的样式,可以通过类似以下的语句查出错误数据,在源端处理掉错误数据:

(1)备份错误数据

create table t_bak as select * from t whereto_char(date1,’yyyy-mm-dd hh24:mi:ss’)= ‘0000-00-00 00:00:00’;

(2)删除原表错误数据:

delete from t where id in (select id from t_bak);

commit;

0 人点赞