【OCI クラウド移行ガイド】 NoSQL Database MigratorでAmazon keyspaces を Oracle NoSQL Database Cloud Serviceへ移行してみた

# OCIクラウド移行ガイドとは

オンプレミスやAWSなど、複数のプラットフォームからOracle Cloud Infrastructureへの移行プロジェクトに取り組んでいるクラウドエンジニア（@araidon,@kazunishi,@yama6）による、OCI移行手順をまとめたシリーズ記事です。
各回、サンプルワークロードから対象サービスを取り上げ、移行手順をガイドいたします。

# 移行したいサンプルワークロード

日々の業務でよく目にするサービスを中心に、サンプルワークロードとしてまとめてみました。このシリーズでは、主にAWSからの移行を取り上げます。
このワークロードは、ユーザがログインして、Web上で写真を共有するWebサービスをイメージしています。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2325706/86ace69d-7aef-5440-7436-1df3b0e3e69f.png)

# 移行するサービス：Amazon keyspaces

今回、移行対象とするのはAmazon keyspacesです。
上記のAWS構成図では、key-value型DBとしてDynamoDBが記載されていますが、今回はこれがAmazon keyspacesのケースで移行をガイドします。

https://aws.amazon.com/jp/keyspaces/

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2325706/72fa3250-d04d-bf2c-e9bd-3c8f6bfb3454.png)

# NoSQL Database Migratorとは

OCIにもOracle NoSQL Database Cloud ServiceというNoSQL Databaseサービスがあり、Amazon DynamoDBやMongoDB等のkey-value型DBからの移行をサポートするNoSQL Database Migratorというツールが用意されてます。

>Oracle NoSQL Database Migratorを使用して、NoSQL表をあるデータ・ソースから別のデータ・ソース(オンプレミスまたはクラウドのOracle NoSQL Databaseなど)または単純なJSONファイルに移動できます。MongoDB形式のJSON入力ファイル、DynamoDB形式のJSON入力ファイル(AWS S3ソースまたはファイルから格納)またはCSVファイルをオンプレミスまたはクラウドのNoSQLデータベースにコピーすることもできます。

https://docs.public.oneportal.content.oci.oraclecloud.com/ja-jp/iaas/nosql-database/doc/overview.html

# 移行方式

NoSQL Database Migratorでは、移行元を"ソース"、移行先を"シンク"と表現します。
今回は、下記を移行元、移行先とした場合のガイドをご案内します。

|移行元（ソース） |移行先（シンク）
|---|---
|csv|Oracle NoSQL Database Cloud Service

NoSQL Database MigratorがインストールされているEC2のストレージに格納されたcsvファイルをソースとして、Oracle NoSQL Database Cloud Serviceへデータを移行します。
データの移行だけではなく、ツールの実行過程で移行先（シンク）であるOracle NoSQL Database Cloud Serviceも構築することができます。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2325706/49a308e4-6d46-9c6c-36d5-8ffa8ce94741.png)

# 前提条件

本記事のガイドに沿って移行を実施する前提条件は、２つです。
1. 下記記事でAmazon EC2にOracle NoSQL Database Migratorがインストールされ、実行できる状態であること。

https://qiita.com/yama6/items/346bea6e7f06d3f19116

2. Oracle NoSQL Database MigratorがインストールされているEC2に紐づけられたIAM RoleへAmazon keyspacesを操作するためのIAM Policyが付与されていること。
※追加方法は下記記事を参考にしてください。

https://docs.aws.amazon.com/ja_jp/IAM/latest/UserGuide/id_credentials_access-keys.html#Using_CreateAccessKey

# 移行手順
1. Amazon keyspaces作成
2. cqlでcsvエクスポート
3. NoSQLDatabase用のDDL文作成
4. NoSQL Database Migrator実行
5. 実行結果の確認

# 1. Amazon keyspaces作成
下記記事を参考に、移行元のソースとなるAmazon keyspacesを作成していきます。

https://docs.aws.amazon.com/ja_jp/keyspaces/latest/devguide/getting-started.html

# 1-1. キースペースとテーブルの作成
チュートリアルステップ 1でキースペースとテーブルを作成します。
「キースペースの作成」にて、「▶コンソールを使用する場合」から、"myGSGKeyspace"というキースペースを作成します。
次に、「テーブルの作成」にて、「▶コンソールを使用する場合」から、"employees_tbl"というテーブルを作成します。
移行元であるkeyspacesの構成において、パーティションキーに"ID"、ソートキーに""を指定しています。
|パーティションキー |ソートキー
|---|---
|ID|division

これは後に、DDL文を作成するときに考慮が必要になります。

# 1-2. サンプルデータの挿入
ステップ2のテーブルへのデータの挿入とロードで、作成したテーブルにサンプルデータを挿入します。
今回はcqlshを使用して、サンプルデータファイル (employees.csv)からデータを挿入します。

# 1-2-1. サンプルデータの準備
サンプルデータを下記からダウンロードしてローカルで解凍します。

https://docs.aws.amazon.com/ja_jp/keyspaces/latest/devguide/samples/sampledata.zip

Cloud Shellへアップロードし、下記コマンドでcloudshellからEC2へファイルを転送します。

```
$scp -i pemキー名 employees.csv ec2-user@EC2のパブリックIPアドレス:/home/ec2-user
```

# 1-2-2. cqlshのインストール
cqlshをインストールするために、まずはAmazon EC2へpython3をインストールします。
```
$sudo dnf install python3.11
```
python3-pipをインストールします。
```
$sudo dnf install python3-pip
```
cqlsh-expansionをインストールします。
```
$python3 -m pip install --user cqlsh-expansion
$pip3 install --user cqlsh-expansion
```
バージョンを確認します。
```
$cqlsh-expansion --version
cqlsh 6.1.0
```
バージョンが出力されたらインストール完了です。

# 1-2-3. cqlsh からAmazon KeySpacesへの接続

AWS CLIでデフォルトリージョンを設定します。
```
$aws configure
…
Default region name [None]: ap-northeast-1
```
cqlshでAmazon keyspacesにSSL接続します。
```
$ cqlsh-expansion cassandra.ap-northeast-1.amazonaws.com 9142 --ssl
Connected to Amazon Keyspaces at cassandra.ap-northeast-1.amazonaws.com:9142
[cqlsh 6.1.0 | Cassandra 3.11.2 | CQL spec 3.4.4 | Native protocol v4]
Use HELP for help.
cqlsh current consistency level is ONE.
cqlsh> 
```
接続が確認できると、cqlsh プロンプトが表示されるので、ここから操作していきます。
キースペースを指定してます。

```
cqlsh> USE "myGSGKeyspace" ;
cqlsh:myGSGKeyspace> 
```
書き込みの整合性レベルを設定します。
```
cqlsh> CONSISTENCY LOCAL_QUORUM;
Consistency level set to LOCAL_QUORUM.
```
# 1-2-4. サンプルデータのインサート
サンプルデータをkeyspacesにインサートします。
```
COPY employees_tbl (id,name,project,region,division,role,pay_scale,vacation_hrs,manager_id) 
FROM 'path-to-the-csv-file/employees.csv' WITH delimiter=',' AND header=TRUE ;
```
次のクエリを実行して、7行のデータがテーブルに追加されていることを確認します。
```
cqlsh> SELECT * FROM employees_tbl ;

 id          | division    | manager_id  | name    | pay_scale | project     | region | role    | vacation_hrs
-------------+-------------+-------------+---------+-----------+-------------+--------+---------+--------------
 789-01-2345 |   Executive |        None | Roberta |        15 |         All |     US |     CEO |          184
 567-89-0123 |   Marketing | 678-90-1234 |   Ahmed |         4 | NightFlight |     US |      IC |           88
 234-56-7890 | Engineering | 789-01-2345 |     Bob |         6 | NightFlight |     US | Manager |           72
 456-78-9012 | Engineering | 234-56-7890 |    Beth |         7 | NightFlight |     US |      IC |        100.5
 123-45-6789 | Engineering | 234-56-7890 |     Bob |         1 | NightFlight |     US |  Intern |            0
 678-90-1234 |   Marketing | 789-01-2345 |    Alan |         3 |       Storm |     US | Manager |         18.4
 345-67-8901 | Engineering | 234-56-7890 |   Sarah |         4 |       Storm |     US |      IC |          108
```
AWSのコンソール画面からデータを見ると、このように表示されます。
CQLエディタから、同様のCQL文を実行します。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2325706/5be40042-853d-c9b9-398d-3063e09ba0f3.png)


# 2. cqlでcsvエクスポート
NoSQL Databaseに移行するため、いまインサートしたデータをcsv形式でエクスポートします。

```
cqlsh:myGSGKeyspace> COPY employees_tbl (id,name,project,region,division,role,pay_scale,vacation_hrs,manager_id) 
                 ... TO '/home/ec2-user/nosqlMigrator/nosql-migrator-1.5.0/expemployees.csv' WITH delimiter=',' AND header=TRUE AND QUOTE='"' ;
cqlsh current consistency level is LOCAL_QUORUM.
Reading options from /home/ec2-user/.cassandra/cqlshrc:[copy]: {'numprocesses': '16', 'maxattempts': '1000'}
Reading options from the command line: {'delimiter': ',', 'header': 'TRUE', 'quote': '"'}
Using 16 child processes

Starting copy of myGSGKeyspace.employees_tbl with columns [id, name, project, region, division, role, pay_scale, vacation_hrs, manager_id].
Processed: 7 rows; Rate:     145 rows/s; Avg. rate:      22 rows/s
7 rows exported to 1 files in 0.370 seconds.
```
catコマンドで確認すると、ヘッダーありの7行のデータが確認できます。
```
$ cat expemployees.csv 
id,name,project,region,division,role,pay_scale,vacation_hrs,manager_id
234-56-7890,Bob,NightFlight,US,Engineering,Manager,6,72,789-01-2345
567-89-0123,Ahmed,NightFlight,US,Marketing,IC,4,88,678-90-1234
789-01-2345,Roberta,All,US,Executive,CEO,15,184,None
345-67-8901,Sarah,Storm,US,Engineering,IC,4,108,234-56-7890
678-90-1234,Alan,Storm,US,Marketing,Manager,3,18.4,789-01-2345
456-78-9012,Beth,NightFlight,US,Engineering,IC,7,100.5,234-56-7890
123-45-6789,Bob,NightFlight,US,Engineering,Intern,1,0,234-56-7890
```
エクスポート後、exitでcqlshを抜けて、EC2に戻ります。

# 3. NoSQLDatabase用のDDL文作成

nosql-migrator-1.5.0 ディレクトリに移動し、"mytable_schema.ddl"という名前のddlファイルを作成します。
```
$ cd /nosqlMigrator/nosql-migrator-1.5.0
$ touch mytable_schema.ddl
```
viコマンドで、下記内容のDDL文を記載します。
```
create table employees (id STRING, name STRING, project STRING, region STRING, division STRING, role STRING, pay_scale INTEGER, vacation_hrs FLOAT, manager_id STRING, PRIMARY KEY(SHARD(id),division));
```
ポイントは、1-1. キースペースとテーブルの作成でお話しした、パーティションキーをid、ソートキーをdivisionとして指定している点です。

ここまでで、データソースとする"expexpemployees.csv"、NoSQL Databaseのテーブル構成情報となる"mytable_schema.ddl"が用意できました。
この２点をインプットとして、次の手順でMigratorを実行し、テーブルの移行を行います。

# 4. NoSQL Database Migrator実行

DynamoDBから移行したときと同様、runMigratorコマンドを実行します。
```
$ ./runMigrator
```
コマンド実行後、ツールから質問の回答を求められ、：以降にパラメータを入力し、Enterを押下していきます。
[]で囲われた中の文字は:を空欄で回答した場合のデフォルト回答になっています。
これらのパラメータを基にして、NoSQL Database Migratorは、"migrator-config.json"という設定ファイルを生成します。これが移行の設定ファイルとなります。

下記より、今回の条件における入力パラメータを画面表示される区切りことに記載しました。
コメントを参考にして入力してください。

# 4-1. 設定の作成開始
```
Configuration file is not provided. Do you want to generate
configuration? (y/n) [n]: y
```
yであれば次に進みます。nであれば元のコンソールに戻ります。

# 4-2. 移行設定ファイルの名前指定
```
Enter a location for your config [./migrator-config.json]: 
```
特に理由がなければ、デフォルトのまま"./migrator-config.json"でよいかと思います。
同名で被っている場合には、このあと上書きしてもよいか聞かれます。

# 4-3. ソースの選択
```
Select the source: 
1) nosqldb
2) nosqldb_cloud
3) file
4) object_storage_oci
5) aws_s3
#? 
3
```
3のfileを選択します。今回のソースファイルはローカルディレクトリのcsvファイルであるからです。

# 4-4. ソースのパラメータ設定
```
Configuration for source type=file
Select the source file format: 
1) json
2) mongodb_json
3) dynamodb_json
4) csv
#? 4
Enter path to a file or directory containing csv data: ./expemployees.csv
Does the CSV file contain a headerLine? (y/n) [n]: y
Do you want to reorder the column names of NoSQL table with respect to
CSV file columns? (y/n) [n]: n
Provide the CSV file encoding. The supported encodings are:
UTF-8,UTF-16,US-ASCII,ISO-8859-1. [UTF-8]: UTF-8
Do you want to trim leading and trailing blanks? (y/n) [n]: n
```
4のcsvを選択します。
次に、データファイルの場所を聞かれるので、# 2. cqlでcsvエクスポートで作った"expemployees.csv"を指定します。
csvを出力する際に、header=TRUEパラメータを使用し、ヘッダーありの状態で出力したのでヘッダーを含めていると回答します。
あとはデフォルト値でOKです。

# 4-5. シンクの選択
```
Select the sink: 
1) nosqldb
2) nosqldb_cloud
#? 2
```
2のOracle NoSQL Database Cloud Serviceを選択します。


# 4-6. シンクの選択
```
Configuration for sink type=nosqldb_cloud
Enter endpoint URL or region ID of the Oracle NoSQL Database Cloud: ap-tokyo-1
Would you like to use instance principal authentication?
Use this if you're running migrator within a OCI compute instance and
configured instance principal authentication on it. If you select no you will be
asked to enter OCI credentials file details. (y/n) [n]: n
Enter path to the file containing OCI credentials [/home/ec2-user/.oci/config]: 
Enter the profile name in OCI credentials file [DEFAULT]: 
Enter the compartment name or id of the table []: <コンパートメント名>
Enter table name: employees
Include TTL data? If you select 'yes' TTL value provided by the
source will be set on imported rows. (y/n) [n]: 
Would you like to create table as part of migration process?
Use this option if you want to create table through the migration tool.
If you select yes, you will be asked to provide a file that contains
table DDL or to use schema provided by the source or default schema.
(y/n) [n]: y
Enter path to a file containing table DDL: ./mytable_schema.ddl 
Would you like to use on demand read and write units? (y/n) [n]: y
Enter storage size in GB of new table: 10
Enter percentage of table write units to be used for migration operation. 
(1-100) [90]: 
would you like to overwrite records which are already present?
If you select 'no' records with same primary key will be skipped [y/n] [y]: y
Enter store operation timeout in milliseconds. [5000]: 
Would you like to add transformations to source data? (y/n) [n]: 
Would you like to continue migration if any data fails to be migrated?
 (y/n) [n]: n
```
設定項目が多いため、デフォルト値以外で注意が必要なパラメータのみ表記します。

Enter endpoint URL or region ID of the Oracle NoSQL Database Cloud: ap-tokyo-1
→Oracle NoSQL Database Cloud Serviceは東京リージョンに作成するので、ap-tokyo-1を指定します。

Enter the compartment name or id of the table []: <コンパートメント名>
→OCI側でOracle NoSQL Database Cloudを作成するコンパートメントを選択してください。

Enter table name: employees
→テーブル名を記載してください。3. NoSQLDatabase用のDDL文作成 で書いたDDL文の中のテーブル名と表記を合わせます。

Would you like to create table as part of migration process?
→今回、データ移行と併せてテーブルも作成するので、yを入力してください。

Enter path to a file containing table DDL: ./mytable_schema.ddl 
→3. NoSQLDatabase用のDDL文作成 で作成したmytable_schema.ddl を指定します。

Would you like to use on demand read and write units? (y/n) [n]: y
→オンデマンドでもキャパシティでも問題ないのですが、今回はオンデマンドを指定しました。
後に続く、"Enter storage size in GB of new table" では 10GBを指定しています。

# 4-7. 移行の設定ファイル確認
```
Generated configuration is:
{
  "source" : {
    "type" : "file",
    "format" : "csv",
    "dataPath" : "./expemployees.csv",
    "hasHeader" : true,
    "csvOptions" : {
      "encoding" : "UTF-8",
      "trim" : false
    }
  },
  "sink" : {
    "type" : "nosqldb_cloud",
    "endpoint" : "ap-tokyo-1",
    "table" : "employees",
    "compartment" : "<コンパートメント名>",
    "includeTTL" : false,
    "schemaInfo" : {
      "onDemandThroughput" : true,
      "storageSize" : 10,
      "schemaPath" : "./mytable_schema.ddl"
    },
    "credentials" : "/home/ec2-user/.oci/config",
    "credentialsProfile" : "DEFAULT",
    "writeUnitsPercent" : 90,
    "overwrite" : true,
    "requestTimeoutMs" : 5000
  },
  "abortOnError" : true,
  "migratorVersion" : "1.5.0"
}
Would you like to run the migration with above configuration?
If you select no, you can use the generated configuration file to
run the migration using:
./runMigrator --config ./migrator-config.json
(y/n) [y]: y
```
4-6まで入力すると、入力したパラメータに準じて移行の設定ファイルをjson形式で生成してくれます。
問題なければ、yを入力します。

# 4-8. 移行の実行
```
2023-10-29 15:13:49.975 [INFO] creating source from given configuration:
2023-10-29 15:13:50.126 [INFO] source creation completed
2023-10-29 15:13:50.137 [INFO] creating sink from given configuration:
2023-10-29 15:13:52.311 [INFO] sink creation completed
2023-10-29 15:13:52.312 [INFO] creating migrator pipeline
2023-10-29 15:13:52.312 [INFO] migration started
2023-10-29 15:13:52.312 [INFO] [cloud sink] : start loading DDLs
2023-10-29 15:13:52.334 [INFO] [cloud sink] : executing DDL: create table employees (id STRING, name STRING, project STRING, region STRING, division STRING, role STRING, pay_scale INTEGER, vacation_hrs FLOAT, manager_id STRING, PRIMARY KEY(SHARD(id),division)),limits: [0, 0, 10]
2023-10-29 15:13:57.424 [INFO] [cloud sink] : completed loading DDLs
2023-10-29 15:13:57.595 [INFO] [cloud sink] : start loading records
2023-10-29 15:13:57.608 [INFO] [csv file source] : start parsing CSV records from file: expemployees.csv
2023-10-29 15:13:57.836 [INFO] migration completed.
Records provided by source=7, Records written to sink=7, Records failed=0, Records skipped=0.
Elapsed time: 0min 5sec 514ms
Migration completed.
```
実行ログの"Records provided by source=7, Records written to sink=7, Records failed=0, Records skipped=0."から、7行のデータがソースからシンクへ書き込まれたことが分かります。
次の手順で、OCI側のOracle NoSQL Database Cloud Serviceを確認してデータが正しく反映されているか確認します。

# 5. 実行結果の確認

画面左上のハンバーガーメニューから、データベース>Oracle NoSQL Databaseに遷移します。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2325706/77b24732-407b-24e8-1efc-c2daf98491dc.png)

テーブル名のラベルをクリックすると表の詳細が確認できます。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2325706/63ac7242-5233-470b-9320-d14be6d57fbf.png)

データの探索フィールドで、「実行ボタン」を押下します。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2325706/e2d1abe4-f140-f8b4-c7c4-6166157ca74f.png)

1-2-4. サンプルデータのインサートでインサートしたデータと同じデータが格納されていることが確認できました！

また、リソースの列を選択すると、idとdivisionがそれぞれ主キーに設定されていることが分かります。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2325706/4df01589-e9d4-188c-bb72-4a04c7706538.png)

「表DDLの表示」を押下すると、3. NoSQLDatabase用のDDL文作成 で作成したDDL文と同様のものが表示されていることがわかります。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2325706/fbe643a8-c4ee-d098-779e-1478b9516f62.png)

idがPRIMARY KEYおよびSHARD KEY、divisionがPRIMARY KEYとして設定されていることがわかります。
Oracle NoSQL Database Cloud Serviceでは、下記のようにキーが対応する形となっています。

|Amazon keyspaces |Oracle NoSQL Database Cloud Service
|---|---
|パーティション・キー  |PRIMARY KEYおよびSHARD KEY
|ソート・キー  |PRIMARY KEY

https://docs.oracle.com/cd/F82307_01/admin/mapping-dynamodb-types-oracle-nosql-types.html#GUID-8E500CF0-4DD8-4B78-9AA8-C592A21F2313

# まとめ
前回のDynamoDBに続き、今回はApache CassandraベースのAmazon keyspacesからOracle NoSQL Database Cloud Serviceへ移行してみました。
前回は、jsonデータファイルおよび移行設定ファイルをインプットとしてツールでDDL文を作成しましたが、今回はcsvデータファイルおよびDDL文をインプットとして、ツールで移行設定ファイルを生成することで移行を行いました。
DynamoDBの場合は、ソースをS3上のDynamoDB jsonでしたが、Amazon keyspacesの場合は、ソースをローカルディレクトリのcsv fileに設定しています。
NoSQL Database Migratorでは、移行元のサービスに合わせて、ソースファイルのタイプを選択することができるので、移行元⇔移行先の対応を考えながら使い分けられることは大きなメリットですね。
次回は、Amazon Document DBからOracle NoSQL Database Cloud Serviceへの移行を試してみたいと思います。

# 参考

https://docs.aws.amazon.com/ja_jp/keyspaces/latest/devguide/getting-started.html

https://docs.aws.amazon.com/ja_jp/keyspaces/latest/devguide/programmatic.cqlsh.html#using_cqlsh

https://yohei-a.hatenablog.jp/entry/20230926/1695691923

https://docs.datastax.com/ja/dse/5.1/cql/cql/cql_reference/cqlsh_commands/cqlshCopy.html

https://docs.public.oneportal.content.oci.oraclecloud.com/ja-jp/iaas/nosql-database/doc/oracle-ndcs-reference1.html

https://docs.oracle.com/cd/F82307_01/admin/mapping-dynamodb-types-oracle-nosql-types.html#GUID-8E500CF0-4DD8-4B78-9AA8-C592A21F2313