[AWS] Data Pump のダンプファイルをRDS for Oracle インスタンスへ転送する
こんにちは、菊池です。
まずは、こちらをご覧ください。
Oracle Databaseのデータをインポート/エクスポートするツール、Data Pumpを使ったRDS間でデータ移行を紹介しています。マネージドサービスであるRDSでは、DBをホストしているインスタンスのOSレイヤにアクセスする手段がありません。そのためRDSインスタンスへダンプファイルを転送するために、転送元/転送先のDB同士をDBLinkで接続しています。
この方法が可能であれば問題ありませんが、転送元/転送先のDBが直接通信可能である必要がありますので、環境上の制約により難しいケースもあると思います。オンプレミスからの移行では、AWS上のRDSに直接通信が到達できないこともあるでしょう。
そこで今回は、Data Pumpでエクスポートしたダンプファイルを、RDSインスタンスにインポートさせる手法を紹介します。やり方は、以下のホワイトペーパーにて紹介されています。
ファイルとして外部に出力することで、S3を経由する方法や、複数の環境へインポートしたい場合にも取り回しが容易になります。
前提環境
上記のように、EC2に保存されたData PumpのダンプファイルをRDS(Oracle)のインスタンスにインポートします。
- EC2:Amazon Linux 2017.09.1 64bit HVM
- RDS:Oracle Database 12c SE2
ダンプファイルのインポート
ダンプファイルのインポート方法は、前述のホワイトペーパーに記載されています。
- Strategies for Migrating Oracle Databases to AWS
- Data Migration Using Oracle Data Pump
- Next Steps for a Database on Amazon RDS
- Data Migration Using Oracle Data Pump
EC2上で Oracle UTL_FILE パッケージを利用し、DATA_PUMP_DIRディレクトリオブジェクトにコピーするためのPerlスクリプトを実行しています。
大まかな手順は以下の通りです。
- 実行環境の準備
- スクリプトの作成・実行
- 確認
実行環境の準備
まずは前提パッケージをインストールします。
$ sudo yum install -y perl-ExtUtils-MakeMaker perl-DBI gcc
続いて、Oracle Instant ClientのパッケージをOracle公式よりダウンロードし、展開します。以下のパッケージをダウンロードします。
- instantclient-basic-linux.x64-12.2.0.1.0.zip
- instantclient-sqlplus-linux.x64-12.2.0.1.0.zip
- instantclient-tools-linux.x64-12.2.0.1.0.zip
- instantclient-sdk-linux.x64-12.2.0.1.0.zip
以下のように、ホームフォルダ以下に展開します。
$ ls -l ~/oracle/ 合計 70008 -rw-r--r-- 1 ec2-user ec2-user 68965195 2月 28 23:49 instantclient-basic-linux.x64-12.2.0.1.0.zip -rw-r--r-- 1 ec2-user ec2-user 674743 3月 1 00:07 instantclient-sdk-linux.x64-12.2.0.1.0.zip -rw-r--r-- 1 ec2-user ec2-user 904309 2月 28 23:49 instantclient-sqlplus-linux.x64-12.2.0.1.0.zip -rw-r--r-- 1 ec2-user ec2-user 1132671 2月 28 23:50 instantclient-tools-linux.x64-12.2.0.1.0.zip drwxrwxr-x 4 ec2-user ec2-user 4096 3月 1 00:07 instantclient_12_2
展開したディレクトリにパスを通しておきます。
$ export ORACLE_BASE=$HOME/oracle $ export ORACLE_HOME=$ORACLE_BASE/instantclient_12_2 $ export PATH=$ORACLE_HOME:$PATH $ export TNS_ADMIN=$HOME/etc $ export LD_LIBRARY_PATH=$ORACLE_HOME:$LD_LIBRARY_PATH $ mkdir $ORACLE_HOME/log
Oracle DBDモジュールもダウンロードして展開します。
$ wget http://www.cpan.org/authors/id/P/PY/PYTHIAN/DBD-Oracle-1.74.tar.gz $ tar xzf DBD-Oracle-1.74.tar.gz $ cd DBD-Oracle-1.74
DBD::Oracleをインストールします。
$ perl Makefile.PL $ make $ sudo make install
問題なければ、以下のように、DBIのバージョンが確認できます。
$ perl -e 'use DBI; print $DBI::VERSION,"\n";' 1.627
最後に、SQL*Plusで接続して確認するため、tnsnames.oraファイルを作成しておきます。
$ cat $HOME/etc/tnsnames.ora mydb = (DESCRIPTION= (ADDRESS=(PROTOCOL=tcp) (HOST=test.xxxxxxxxxxxxx.ap-northeast-1.rds.amazonaws.com) (PORT=1521)) (CONNECT_DATA=(SERVICE_NAME=ORCL)) )
スクリプトとインポートの実行
インポートを実行するスクリプトを用意します。3行目から6行目の部分を、転送先RDSインスタンスに合わせて編集します。
use DBI; my $RDS_PORT=1521; my $RDS_HOST="test.xxxxxxxxxxx.ap-northeast-1.rds.amazonaws.com"; my $RDS_LOGIN="user/password"; my $RDS_SID="ORCL"; my $dirname = "DATA_PUMP_DIR"; my $fname = $ARGV[0]; my $data = "dummy"; my $chunk = 8192; my $sql_open = "BEGIN perl_global.fh := utl_file.fopen(:dirname,:fname,'wb',:chunk);END;"; my $sql_write = "BEGIN utl_file.put_raw(perl_global.fh,:data,true); END;"; my $sql_close = "BEGIN utl_file.fclose(perl_global.fh); END;"; my $sql_global = "create or replace package perl_global as fh utl_file.file_type; end;"; my $conn = DBI->connect('dbi:Oracle:host='.$RDS_HOST.';sid='.$RDS_SID.';port='.$RDS_PORT, $RDS_LOGIN, '') || die ( $DBI::errstr . "\n") ; my $updated=$conn->do($sql_global); my $stmt = $conn->prepare($sql_open); $stmt->bind_param_inout(":dirname", \$dirname, 12); $stmt->bind_param_inout(":fname", \$fname, 12); $stmt->bind_param_inout(":chunk", \$chunk, 4); $stmt->execute() || die($DBI::errstr . "\n"); open(INF,$fname) || die "\nCan't open $fname for reading: $!\n"; binmode(INF); $stmt = $conn->prepare($sql_write); my %attrib = ('ora_type','24'); my $val=1; while ($val >0) { $val = read(INF, $data, $chunk); $stmt->bind_param(":data", $data, \%attrib); $stmt->execute() || die ($DBI::errstr . "\n"); }; die "Problem copying: $!\n" if $!; close INF || die "Can't close $fname: $!\n"; $stmt = $conn->prepare($sql_close); $stmt->execute() || die ($DBI::errstr . "\n");
準備できたら実行です。引数に、転送したいダンプファイルを指定し、実行します。
$ perl transfer.pl test.dmp
エラーなく完了したら、次の確認を行います。
ダンプファイルの確認
SQL*PlusでRDSに接続します。
$ sqlplus user/password@mydb
DATA_PUMP_DIRを参照してみます。
SQL> select * from table (rdsadmin.rds_file_util.listdir(p_directory => 'DATA_PUMP_DIR')); FILENAME -------------------------------------------------------------------------------- TYPE FILESIZE MTIME ---------- ---------- --------- datapump/ directory 4096 04-MAR-18 test.dmp file 68965195 04-MAR-18 2 rows selected.
test.dmpが転送されていることが確認できました!ここまでできたら、冒頭のブログの記事と同様、DBMS_DATAPUMPパッケージでインポートしましょう。
まとめ
以上です。
OSにアクセスできないRDSでは、インポートにも工夫が必要です。ファイルを直接転送できることで、移行方法の選択肢が広がることでしょう。