SCTとDMSを使用してオンプレミスにあるOracleをAWSのRDSへ移行してみる。
- [AWS Schema Conversion Toolとは](https://docs.aws.amazon.com/ja_jp/SchemaConversionTool/latest/userguide/CHAP_Welcome.html)
- [AWS Database Migration Serviceとは](https://docs.aws.amazon.com/ja_jp/dms/latest/userguide/Welcome.html)
## 典型的な構成イメージ
```
[オンプレ Oracle DB(:1521)]
│
(VPN / Direct Connect)
│
[AWS VPC内 EC2(SCTインストール)]
│ │
│(VPN / Direct Connect経由)
│ │
│ └── JDBC接続 → オンプレミス側ルータ → Oracle(:1521)
│
(VPC経由)
│
└── JDBC接続 → AWS VPC内 MySQL(:3306)
[AWS VPC内 DMS Replication Instance]
│ │
│(VPN / Direct Connect経由)
│ │
│ └── 接続 → オンプレミス側ルータ → Oracle(:1521)
│
(VPC経由)
│
└── 接続 → AWS VPC内 MySQL(:3306)
```
> 必要な穴あけ
> - SCT用EC2のセキュリティグループ
> - アウトバウンド:ソースDB(オンプレ Oracle)とターゲットDB(RDS for MySQL)への JDBC ポート(通常 1521 や 3306)を許可
> - インバウンド:必要に応じて SSH(22)などを制限付きで許可
> - DMSレプリケーションインスタンスのセキュリティグループ
> - アウトバウンド:ソースDB(オンプレ Oracle)とターゲットDB(RDS for MySQL)へのTCPポート(1521 や 3306)を許可
> - インバウンド:不要(DMSはアウトバウンド接続)
> - ターゲットDB(RDS for MySQL)のセキュリティグループ
> - インバウンド:SCT用EC2 と DMSインスタンスのセキュリティグループからの接続を許可。ポートは DBエンジンに応じて(例:MySQLなら 3306)
> - オンプレ側のファイアウォール設定
> - SCTとDMSからの接続元IP(またはVPN経由のCIDR)を許可
> - Oracleリスナーのポート(1521)を開放
>
## 代替の構成イメージ(仮想オンプレミス)
ここでは仮想オンプレミスとしてデータセンターの代わりに自宅からAWSへ接続します。
また、SCTは自宅LAN側のPC内に配置します。
```
[自宅 LAN内 Oracle DB(:1521)]
│
[自宅 LAN内 PC(SCTインストール)]
│ │
│(LAN経由)
│ │
│ └── JDBC接続 → 自宅 LAN内 Oracle(:1521)
│
(インターネット経由)
│
└── JDBC接続 → 自宅ルータ(GIP:65533) → AWS VPC内 MySQL(:3306)
[AWS VPC内 AWS DMS Replication Instance]
│ │
│(インターネット経由)
│ │
│ └── 接続 → 自宅ルータ(GIP:65533) → 自宅LAN内 Oracle(LocalIP:1521)
│
(VPC経由)
│
└──── 接続 → AWS VPC内 MySQL(:3306)
```
## 構築の主な流れ
1. ソースDB(Oracle)を作成
2. ターゲットDB(MySQL)を作成
3. スキーマの移行
4. データの移行
## 1. ソースDB(Oracle)を作成
まず、自宅LAN内のPCにVirtualBoxで仮想マシン(Windows)を作成し、ソースDBにあたるOracleデータベース環境を構築する。
### 1.1 Virtualboxで仮想マシン(Windows)を作成
以下、主な設定履歴
```
- システム
- CPU: 1→2
- メモリ: 2048MB→4096MB
- ストレージを設定
- OS用: 20GB
- Oracle用: HDD(15GB)を追加
- ネットワークを設定
- ブリッジアダプター(ルーターから直接ポート転送するため)
- OSユーザ
- testuser/P@ssw0rd
```
### 1.2 仮想マシンのWindowsにOracle XEをインストール
以下、主な設定履歴
```
- tnsname.oraを設定
- ブリッジアダプターのインターフェース(192.168.xx.xx)で起動するように設定
- 以下を追記
XEPDB1 =
(DESCRIPTION =
(ADDRESS = (PROTOCOL = TCP)(HOST = 192.168.xx.xx)(PORT = 1521))
(CONNECT_DATA =
(SERVER = DEDICATED)
(SERVICE_NAME = XEPDB1)
)
)
```
```
- listener.ora
- sqlnet.oraがデフォルトで以下のためlistener.oraは未使用(EZCONNECTは簡易接続ネーミング)
NAMES.DIRECTORY_PATH = (TNSNAMES, EZCONNECT)
```
### 1.3 ユーザ作成、権限付与
Oracleはスキーマ名が基本的にユーザー名と同じになる。
ユーザー名 testuser を作成すると、スキーマ名は TESTUSER (大文字) となる。
以下、主な設定履歴
```
# ユーザ作成と権限付与
sqlplus / as sysdba
show con_name
show pdbs
alter session set container=XEPDB1
create user testuser identified by testuser;
grant connect, resource, dba to testuser;
# PDBにはリスナー経由でログインする
sqlplus testuser/testuser@XEPDB1
```
### 1.4 移行データの作成
#### テーブル
```
CREATE TABLE departments (
department_id NUMBER PRIMARY KEY,
department_name VARCHAR2(100) NOT NULL
);
CREATE TABLE employees (
employee_id NUMBER PRIMARY KEY,
first_name VARCHAR2(50),
last_name VARCHAR2(50) NOT NULL,
hire_date DATE DEFAULT SYSDATE,
salary NUMBER(8,2),
department_id NUMBER,
CONSTRAINT fk_department FOREIGN KEY (department_id) REFERENCES departments(department_id)
);
```
```
INSERT INTO departments (department_id, department_name) VALUES (10, 'Sales');
INSERT INTO departments (department_id, department_name) VALUES (20, 'Engineering');
INSERT INTO departments (department_id, department_name) VALUES (30, 'Human Resources');
INSERT INTO departments (department_id, department_name) VALUES (40, 'Finance');
INSERT INTO employees (first_name, last_name, hire_date, salary, department_id)
VALUES ('Taro', 'Yamada', TO_DATE('2022-04-01', 'YYYY-MM-DD'), 5500.00, 10);
INSERT INTO employees (first_name, last_name, hire_date, salary, department_id)
VALUES ('Hanako', 'Suzuki', TO_DATE('2023-01-15', 'YYYY-MM-DD'), 6200.00, 20);
INSERT INTO employees (first_name, last_name, hire_date, salary, department_id)
VALUES ('John', 'Smith', TO_DATE('2021-07-20', 'YYYY-MM-DD'), 4800.00, NULL);
INSERT INTO employees (first_name, last_name, hire_date, salary, department_id)
VALUES ('Alice', 'Tanaka', TO_DATE('2021-07-20', 'YYYY-MM-DD'), 7000.00, 30);
INSERT INTO employees (first_name, last_name, hire_date, salary, department_id)
VALUES ('Bob', 'Lee', TO_DATE('2020-12-31', 'YYYY-MM-DD'), 5100.00, 40);
```
#### シーケンス
```
CREATE SEQUENCE emp_seq
START WITH 1000
INCREMENT BY 1
NOCACHE
NOCYCLE;
```
#### ユーザ定義関数
```
CREATE OR REPLACE FUNCTION get_employee_salary_fn (
p_emp_id IN NUMBER
) RETURN NUMBER IS
v_salary NUMBER;
BEGIN
SELECT salary INTO v_salary FROM employees WHERE employee_id = p_emp_id;
RETURN v_salary;
END;
/
```
#### ストアドプロシージャ
```
CREATE OR REPLACE PROCEDURE get_employee_salary (
p_emp_id IN NUMBER,
p_salary OUT NUMBER
) AS
BEGIN
SELECT salary INTO p_salary FROM employees WHERE employee_id = p_emp_id;
END;
/
```
#### トリガー
```
CREATE OR REPLACE TRIGGER trg_before_insert_emp
BEFORE INSERT ON employees
FOR EACH ROW
BEGIN
:NEW.employee_id := emp_seq.NEXTVAL;
END;
/
```
#### ビュー
```
CREATE VIEW emp_summary AS
SELECT employee_id, first_name || ' ' || last_name AS full_name, salary
FROM employees
WHERE salary > 5000;
```
### 1.5 LAN上のPCからDB接続確認
1. 必要な穴あけ
- 仮想マシンのWindowsファイアーウォール(wf.msc)
- インバウンド:任意のIPアドレスからのTCP1521を許可
2. DBクライアントツールで接続を確認
URL: jdbc:oracle:thin:@//192.168.xx.xx:1521/xepdb1
### 1.6 DMSで変更データキャプチャ(CDC)を利用する場合に必要な設定
1. サプリメンタルログの有効化
2. アーカイブログモードの有効化
#### 1.6.1 サプリメンタルログの有効化
サプリメンタル・ロギング(Supplemental Logging)は、OracleデータベースでCDCを行う際に必要な設定。どの種類のサプリメンタル・ログを有効にするかは選択可能。
```
# データベースレベルでの補足ログ設定
ALTER DATABASE ADD SUPPLEMENTAL LOG DATA;
# すべての列の補足ログを有効化
ALTER DATABASE ADD SUPPLEMENTAL LOG DATA (ALL) COLUMNS;
# テーブル単位で補足ログの有効化
ALTER TABLE TESTUSER.DEPARTMENTS ADD SUPPLEMENTAL LOG DATA (ALL) COLUMNS;
ALTER TABLE TESTUSER.EMPLOYEES ADD SUPPLEMENTAL LOG DATA (ALL) COLUMNS;
```
#### 1.6.2 アーカイブログモードの有効化
アーカイブログが未設定の場合、以下のエラーが出た。
```
# アーカイブログが無効な場合
E: To use CDC, the Oracle database must be configured to archived Redo logs [1022313]
# アーカイブログが取得できない場合(パスエラーや権限不足など)
E: Cannot retrieve Oracle archived Redo log destination ids [1020401]
```
```
sqlplus / as sysdba
# 確認
ARCHIVE LOG LIST;
# データベースをマウント状態に切り替え(オープン状態では変更不可)
SHUTDOWN IMMEDIATE;
STARTUP MOUNT;
# ARCHIVE LOGモードを有効にする
ALTER DATABASE ARCHIVELOG;
# データベースをオープンに戻す
ALTER DATABASE OPEN;
# ログモードを確認
ARCHIVE LOG LIST;
# ここではアーカイブログの保存先を「E:/oracle_db/archivelogs」とする。
# Oracleサービスの実行ユーザーを確認し、アーカイブログ保存先へ書き込み権限を与えること。
# アーカイブログの保存先を定義
ALTER SYSTEM SET LOG_ARCHIVE_DEST_1='LOCATION=E:/oracle_db/archivelogs' SCOPE=SPFILE;
# 変更後の再起動
SHUTDOWN IMMEDIATE;
STARTUP;
```
## 2. ターゲットDB(MySQL)を作成
AWSにRDS for MySQLをセットアップする。
自宅からDBクライアントツールで接続したいため、今回はパブリックサブネットに直置き。
以下、主な設定履歴
```
# MySQL接続
mysql -h xxx.yyy.zzz.rds.amazonaws.com -u admin -ppassword
# DB確認
SHOW DATABASES;
# データベースを作成
CREATE DATABASE testuser;
# ユーザ作成
CREATE USER 'testuser'@'%' IDENTIFIED BY 'testuser';
# ユーザ権限付与
GRANT SELECT, SHOW VIEW, CREATE, ALTER, DROP, INDEX, REFERENCES, CREATE VIEW, TRIGGER, CREATE ROUTINE, ALTER ROUTINE, EXECUTE ON *.* TO 'testuser'@'%';
# LinuxのMySQLは大文字小文字が区別される。「testuser.*」と「TESTUSER.*」は別物
GRANT ALL PRIVILEGES ON testuser.* TO 'testuser'@'%';
# Oracle特有の構造をターゲット側で再現するために SCT が生成したりする。※MySqlはSEQUENCEに非対応など
GRANT ALL PRIVILEGES ON aws_oracle_ext_data.* TO 'testuser'@'%';
GRANT ALL PRIVILEGES ON aws_oracle_ext.* TO 'testuser'@'%';
# 権限を適用
FLUSH PRIVILEGES;
# 権限確認
SHOW GRANTS FOR 'testuser'@'%';
```
## 3. スキーマの移行
### 3.1 SCTを設定
ユーザーガイドを参照してSCTを設定する。
1. SCTのインストール
[AWS Schema Conversion Toolのインストール](https://docs.aws.amazon.com/ja_jp/SchemaConversionTool/latest/userguide/CHAP_Installing.Procedure.html)
2. JDBCドライバーのダウンロード
[AWS Schema Conversion Tool用の JDBC ドライバーのインストール](https://docs.aws.amazon.com/ja_jp/SchemaConversionTool/latest/userguide/CHAP_Installing.JDBCDrivers.html)
> ソースデータベースエンジンとターゲットデータベースエンジンの JDBC ドライバーをダウンロードします。
- [Oracle](https://www.oracle.com/database/technologies/appdev/jdbc-downloads.html)
- [MySQL](https://downloads.mysql.com/archives/c-j/)
#### 3.2 database migration project
[AWS SCTのユーザーインターフェイスの操作 ](https://docs.aws.amazon.com/ja_jp/SchemaConversionTool/latest/userguide/CHAP_UserInterface.html)
新規プロジェクトウィザードを使用して以下の流れで設定していく。
1. Choose a source
1. Connect to the source database
1. Choose a schema
1. Run the database migration assessment
1. Choose a target
#### 3.3 スキーマの変換
**1. Migration rules(変換ルールがあれば作成。Number型をDecimalでなく、BIGING UNSIGNEDとするなど)**
設定例
```
> - For: Column
> - Action: Change Data Type
> - From: NUMBER
> - To: BIGINT UNSIGNED
- NUMBER の定義が曖昧(精度・スケール未指定)の場合、実データの確認が必須。小数が含まれていると BIGINT ではデータ損失となる。
- SCTの評価レポートで「精度損失の可能性」などの警告が出る場合は、NUMERIC や DECIMAL の方が安全。
```

**2. Convert schema**
> この操作により、すべてのソーススキーマのメタデータが AWS SCT プロジェクトにロードされます。
以下のエラーが出たが、ログを確認して問題なければ続行。
```
Metadata loading was interrupted because of data fetching issues. For details, see the log.
```
SCTのログ出力先
```
C:\Users\<ユーザー名>\AWS Schema Conversion Tool\Log
```
**3. Apply to database**
> 変換されたスキーマがターゲット DB インスタンスに適用されます。
## 4. データの移行
### 4.1 レプリケーションインスタンスを作成
1. 必要なロール
```
- dms-vpc-role
- dms-cloudwatch-logs-role
```
2. レプリケーションインスタンスを作成
```
- 事前にサブネットグループを作成しておく
今回インターネット経由でソースデータベースへアクセスするために以下を指定。
- ✔ パブリックアクセス可能
- インスタンス作成に10分程度がかかる
```

### 4.2 ソースエンドポイントを作成
ソースDBの情報を指定する。
以下、設定履歴
```
- エンドポイントタイプ: ソースエンドポイント
- ソースエンジン: Oracle
- サーバー名: 自宅のGIP
- ポート: 65533
- ユーザー名: xxxx
- パスワード: xxxx
- SID/サービス名: xepdb1
# 以下を追加
- 追加の接続属性: useLogMinerReader=N;useBfile=Y;
```
エンドポイント接続属性を指定する前の接続テストでは、以下のエラーが出た。
```
Test Endpoint failed: Application-Status: 1020912, Application-Message: Log Miner is not supported in Oracle PDB environment Endpoint initialization failed.
```
> AWS DMS が Oracle の PDB(Pluggable Database)環境では LogMiner を使用できないことを示しています。つまり、現在の構成では LogMinerベースのCDC(変更データキャプチャ)方式が使えないということです。
> AWS DMS では、PDB 環境で Oracle をソースにする場合、LogMiner の代わりに Binary Reader を使用する必要があります。
対処)DMS ソースエンドポイントの「追加接続属性」に以下を指定
```
useLogMinerReader=N;useBfile=Y;
```
補足)
Binary Reader を使うには以下の権限が必要(testuserが「V\$LOG」などのV_\$ビューを参照できていればOK)
```
GRANT SELECT ON V_$LOG TO testuser;
GRANT SELECT ON V_$LOGFILE TO testuser;
GRANT SELECT ON V_$ARCHIVED_LOG TO testuser;
GRANT SELECT ON V_$DATABASE TO testuser;
GRANT SELECT ON V_$THREAD TO testuser;
GRANT SELECT ON V_$PARAMETER TO testuser;
GRANT SELECT ON V_$NLS_PARAMETERS TO testuser;
GRANT SELECT ON V_$TIMEZONE_NAMES TO testuser;
```
#### 4.3 ターゲットエンドポイントを作成
ターゲットDBの情報を指定する。
以下、設定履歴
```
- エンドポイントタイプ: ターゲットエンドポイント
- RDSインスタンス: test-migrate-rds
- ターゲットエンジン: MySQL
- サーバー名: xxxxxxxxxx.us-east-1.rds.amazonaws.com
- ポート: 3306
- ユーザー名: xxxx
- パスワード: xxxx
- 追加の接続属性: なし
```

#### 4.4 データベース移行タスクを作成
移行タスクの情報を指定する。
以下、設定履歴
```
- レプリケーションインスタンス: 上で作成したインスタンス
- ソースデータベースエンドポイント: 上で作成したソースエンドポイント
- ターゲットデータベースエンドポイント: 上で作成したターゲットエンドポイント
- 移行タイプ:
- フルロードのみ
- ✔ フルロード+CDC
- CDCのみ
- レプリケーション期間: 一定期間
- タスク設定
- カスタムCDC停止モード: 無効
- ターゲットテーブル準備モード:
- ✔ 何もしない
- ターゲット上のテーブルを削除
- 切り捨て
- フルロード完了後にタスクを停止: 停止しない
- LOB列設定:
- LOB列を含めない
- ✔ 完全LOBモード
- 制限付きLOBモード
- データ検証: オフ
- タスクログ: CloudWatchログを有効化
- テーブルマッピング: 以下を指定
```
- テーブルマッピング
移行対象のテーブルを指定する。(対象スキーマの全テーブル(%)を指定)
```
{
"rules": [
{
"rule-type": "selection",
"rule-id": "1",
"rule-name": "include-all",
"object-locator": {
"schema-name": "TESTUSER",
"table-name": "%"
},
"rule-action": "include"
},
{
"rule-type": "selection",
"rule-id": "2",
"rule-name": "exclude-aws-oracle-ext",
"object-locator": {
"schema-name": "aws_oracle_ext_data",
"table-name": "%"
},
"rule-action": "include"
}
]
}
```
aws_oracle_extスキーマはOracle特有の構造をターゲット側で再現するためにSCTが生成したもの。
今回はSCTがOracleのシーケンスをMySQLで模倣したもの。(移行対象とせずにautoincrementへテーブル定義を手直しするかのどちらか。)
LinuxのMySQLはデフォルトで大文字小文字を区別するので、lower_case_table_namesを指定してない場合は、大文字と小文字のマッピングが必要な場合もある。
以下、指定例
```
{
"rules": [
{
"rule-type": "selection",
"rule-id": "1",
"rule-name": "include-all",
"object-locator": {
"schema-name": "TESTUSER",
"table-name": "%"
},
"rule-action": "include"
},
{
"rule-type": "transformation",
"rule-id": "2",
"rule-name": "map-schema",
"rule-action": "rename",
"rule-target": "schema",
"object-locator": {
"schema-name": "TESTUSER"
},
"value": "testuser"
},
{
"rule-type": "transformation",
"rule-id": "3",
"rule-name": "rename-table",
"rule-action": "rename",
"rule-target": "table",
"object-locator": {
"schema-name": "TESTUSER",
"table-name": "DEPARTMENTS"
},
"value": "departments"
},
{
"rule-type": "transformation",
"rule-id": "4",
"rule-name": "rename-table",
"rule-action": "rename",
"rule-target": "table",
"object-locator": {
"schema-name": "TESTUSER",
"table-name": "EMPLOYEES"
},
"value": "employees"
}
]
}
```

移行タスクの実行後は、CloudWatch Logsでログをモニタリングする。
## 5. 変更データキャプチャ(CDC)の確認
レプリケーション中にソースDBへデータ追加してCDCの動作を確認する。
```
INSERT INTO employees (first_name, last_name, hire_date, salary, department_id)
VALUES ('Add1', 'xxx', TO_DATE('2020-12-31', 'YYYY-MM-DD'), 7000.00, 40);
INSERT INTO employees (first_name, last_name, hire_date, salary, department_id)
VALUES ('Add2', 'xxx', TO_DATE('2020-12-31', 'YYYY-MM-DD'), 4000.00, 40);
INSERT INTO employees (first_name, last_name, hire_date, salary, department_id)
VALUES ('Add3', 'xxx', TO_DATE('2020-12-31', 'YYYY-MM-DD'), 5500.00, 40);
```
## 関連記事
[AWS DMS と AWS Snowball を使用して大規模なデータベース移行を可能にする](https://aws.amazon.com/jp/blogs/news/enable-large-scale-database-migrations-with-aws-dms-and-aws-snowball)
0 件のコメント:
コメントを投稿