2
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

More than 1 year has passed since last update.

[OCI]Autonomous Database:クロスリージョン・リフレッシュ可能クローンの起動→リフレッシュ→停止をPL/SQLで自動化してみた

Last updated at Posted at 2022-12-09

はじめに

Automoous Databaseは、ソースとなるAutomomous Databaseがあるリージョンと異なるリージョンにリフレッシュ可能クローン(クロス・リージョン・リフレッシュ可能クローン)を作成することができます。

Autonomous Databaseのリフレッシュ可能クローンには、以下の特徴があります。
・クローン元(ソース)のAutonomoous Databaseとは異なる数のOCPUを設定することが可能
・リフレッシュ中もソースのAutonomous Databaseは利用可能
・作成後または前回のリフレッシュから1週間以内にリフレッシュ操作が必要
・作成後または前回のリフレッシュから1週間以内の任意のタイミングでリフレッシュ操作が可能
・リフレッシュ時にソースのどの時点までの変更を反映するか(リフレッシュ・ポイント)を指定可能

これらの特徴から、リフレッシュ可能クローンは、ソースのAutonomous Databaseへのアクセスを停止することなく取得できる、特定時点のバックアップとして利用が可能です。

今回は、ソースと異なるリージョンにリフレッシュ可能クローンを作成し、DBMS_SCHEDULERで以下の処理を行うPL/SQLプロシージャを1時間に1回実行することで、リフレッシュ可能クローンをDRを目的としたリモート・バックアップとして使用する環境を構築してみました。

  1. リフレッシュ可能クローンの状態を確認
  2. リフレッシュ可能クローンが停止していたら起動
  3. 起動が完了し、使用可能になるのを待つ
  4. 直前の正時(0分)のタイムスタンプを生成
  5. 直前の正時(0分)のタイムスタンプをリフレッシュ・ポイントに指定してリフレッシュを実行
  6. リフレッシュが完了し、使用可能になる完了を待つ
  7. リフレッシュが完了したら、リフレッシュ可能クローンを停止

なお、こちらで作成するプロシージャでは、以下の2つの記事で作成しているget_adb_stateファンクションとwait_adb_stateプロシージャを使用しています。

1. 異なるリージョンへのリフレッシュ可能クローンの作成

コンソールでクローンのソースとなるAutonomous Databaseの詳細画面にアクセスします。
スクリーンショット 2022-12-07 9.18.21.png
「他のアクション」から「クローンの作成」を選択します。
スクリーンショット 2022-12-07 9.14.47.png
「クローン・タイプの選択」で「リフレッシュ可能クローン」を選択します。
「優先リージョンの選択」でクローンを作成するリージョンを選択します。
ここでは東京リージョンにあるAutonomous Databaseのクローンを大阪リージョンに作成するので「日本中央部(大阪)」を選択します。
作成するコンパートメント、表示名、データベース名を入力します。
スクリーンショット 2022-12-07 9.16.13.png
作成するクローンのOCPUの設定、ネットワーク・アクセスの情報を入力します。
スクリーンショット 2022-12-07 9.16.33.png
ライセンス・タイプを選択し、通知先のメールアドレスを入力します。
入力が完了したら、「Autonomous Databaseのクローンの作成」をクリックします。
スクリーンショット 2022-12-07 9.16.51.png
リフレッシュ可能クローンのプロビジョニングが始まります。
スクリーンショット 2022-12-07 9.17.34.png
しばらく待つとリフレッシュ可能クローンが利用可能になります。
画面上部にリフレッシュの期限が、「一般情報」の「クローン情報」のセクションに
・このAutonomous Databaseがリフレッシュ可能クローンであること
・クローン元(ソース)のAutonomous Database
・リフレッシュ・ポイント(ソースのどの時点のデータが反映されているか)
が表示されます。
スクリーンショット 2022-12-07 9.34.52.png
スクリーンショット 2022-12-07 9.54.30.png
スクリーンショット 2022-12-07 9.54.45.png

2. リフレッシュ可能クローンを起動→リフレッシュ→停止するPL/SQLプロシージャの作成

プロシージャを実行するAutonomous Databaseのリフレッシュ可能クローンのリフレッシュを実行するPL/SQLプロシージャrefresh_remote_cloneを作成します。
以下のような処理の流れになっています。

1.APIをコールして、自身がソースとなっているリフレッシュ可能クローンの情報を取得
2.取得したリフレッシュ可能クローンの情報からリージョンとOCIDを抽出
3.リフレッシュ可能クローンが停止していたら起動し、起動が完了するのを待つ
4.直前の正時(0分)のタイムスタンプを生成
5.直前の正時(0分)のタイムスタンプをリフレッシュ・ポイントに指定してリフレッシュを実行
6.リフレッシュの完了を待つ
7.リフレッシュが完了したら、リフレッシュ完了クローンを停止

refresh_remote_cloneプロシージャ
CREATE OR REPLACE PROCEDURE refresh_remote_clone
IS
  source_adb_region    VARCHAR2(100);
  source_adb_ocid      VARCHAR2(100);
  clone_adb_region     VARCHAR2(100);
  clone_adb_ocid       VARCHAR2(100);
  
  request_uri          VARCHAR2(300);
  resp                 DBMS_CLOUD_TYPES.resp;
  
  response_start       dbms_cloud_oci_db_database_start_autonomous_database_response_t;
  response_stop        dbms_cloud_oci_db_database_stop_autonomous_database_response_t;
  response_refresh     dbms_cloud_oci_db_database_autonomous_database_manual_refresh_response_t;
  refresh_details      dbms_cloud_oci_database_autonomous_database_manual_refresh_details_t := dbms_cloud_oci_database_autonomous_database_manual_refresh_details_t();
  
BEGIN
  -- ソースとなるAutonomous Database(プロシージャを実行しているADB)のOCIDとリージョンをv$pdbsから取得
  SELECT json_value(cloud_identity, '$.REGION'), LOWER(json_value(cloud_identity, '$.DATABASE_OCID'))
    INTO source_adb_region, source_adb_ocid FROM v$pdbs;

  -- リフレッシュ可能クローンの情報を取得するAPIのURIを生成
  request_uri := 'https://database.'||source_adb_region||'.oraclecloud.com/20160918/autonomousDatabases/'||source_adb_ocid||'/refreshableClones';

  -- APIをコールしてリフレッシュ可能クローンの情報を取得
  resp := DBMS_CLOUD.send_request(
            credential_name => 'OCI$RESOURCE_PRINCIPAL',
            uri => request_uri,
            method => DBMS_CLOUD.METHOD_GET);

  -- 取得したリフレッシュ可能クローンの情報からリージョンとOCIDを取得
  clone_adb_region := json_value(DBMS_CLOUD.get_response_text(resp), '$.items.region');
  clone_adb_ocid   := json_value(DBMS_CLOUD.get_response_text(resp), '$.items.id');

  -- クローンの状態を確認し、停止していたら起動
  IF get_adb_state(clone_adb_region, clone_adb_ocid) = 'STOPPED'
  THEN

    DBMS_OUTPUT.PUT_LINE('Starting ADB.'||CHR(10));
    response_start := DBMS_CLOUD_OCI_DB_DATABASE.START_AUTONOMOUS_DATABASE(
                        credential_name => 'OCI$RESOURCE_PRINCIPAL',
                        autonomous_database_id => clone_adb_ocid,
                        region                 => clone_adb_region);

    wait_adb_state(clone_adb_region, clone_adb_ocid, 'AVAILABLE');
    DBMS_OUTPUT.PUT_LINE('ADB is started.'||CHR(10));

  ELSE

    DBMS_OUTPUT.PUT_LINE('ADB is already running.'||CHR(10));

  END IF;

  -- 直前の正時(0分)のタイムスタンプを生成し、リフレッシュのタイムスタンプに設定
  SELECT TO_TIMESTAMP_TZ(TO_CHAR(sysdate,'YYYY-MM-DD HH24')||':00:00 +9:00','YYYY-MM-DD HH24:MI:SS TZH:TZM')
    INTO refresh_details.time_refresh_cutoff FROM dual;

  -- 直前の正時(0分)のタイムスタンプを指定してリフレッシュ可能クローンのリフレッシュを実行
  DBMS_OUTPUT.PUT_LINE('Refreshing ADB.'||CHR(10));
  response_refresh := DBMS_CLOUD_OCI_DB_DATABASE.AUTONOMOUS_DATABASE_MANUAL_REFRESH(
 				        credential_name => 'OCI$RESOURCE_PRINCIPAL',
                        autonomous_database_id => clone_adb_ocid,
 				        region => clone_adb_region,
						autonomous_database_manual_refresh_details => refresh_details);

  -- リフレッシュが終了し、クローンが利用可能になるのを待つ
  wait_adb_state(clone_adb_region, clone_adb_ocid, 'AVAILABLE');
  DBMS_OUTPUT.PUT_LINE('ADB is refreshed.'||CHR(10));

  --クローンを停止する
  DBMS_OUTPUT.PUT_LINE('Stopping ADB.'||CHR(10));
  response_stop := DBMS_CLOUD_OCI_DB_DATABASE.STOP_AUTONOMOUS_DATABASE(
                     credential_name => 'OCI$RESOURCE_PRINCIPAL',
                     autonomous_database_id => clone_adb_ocid,
                     region                 => clone_adb_region);
					 
  wait_adb_state(clone_adb_region, clone_adb_ocid, 'STOPPED');
  DBMS_OUTPUT.PUT_LINE('ADB is stopped.'||CHR(10));

END;
/

ソースのAutonomous DatabaseにSQL*Plusから接続し、実際に作成してみます。

SQL> CREATE OR REPLACE PROCEDURE refresh_remote_clone
  2  IS
  3  
  4    source_adb_region    VARCHAR2(100);
  5    source_adb_ocid	    VARCHAR2(100);
  6    clone_adb_region     VARCHAR2(100);
  7    clone_adb_ocid	    VARCHAR2(100);
  8  
  9    request_uri	    VARCHAR2(300);
 10    resp		    DBMS_CLOUD_TYPES.resp;
 11  
 12    response_start	    dbms_cloud_oci_db_database_start_autonomous_database_response_t;
 13    response_stop	    dbms_cloud_oci_db_database_stop_autonomous_database_response_t;
 14    response_refresh     dbms_cloud_oci_db_database_autonomous_database_manual_refresh_response_t;
 15    refresh_details	    dbms_cloud_oci_database_autonomous_database_manual_refresh_details_t := dbms_cloud_oci_database_autonomous_database_manual_refresh_details_t();
 16  
 17  BEGIN
 18  
 19    SELECT json_value(cloud_identity, '$.REGION'), LOWER(json_value(cloud_identity, '$.DATABASE_OCID'))
 20  	 INTO source_adb_region, source_adb_ocid FROM v$pdbs;
 21  
 22    request_uri := 'https://database.'||source_adb_region||'.oraclecloud.com/20160918/autonomousDatabases/'||source_adb_ocid||'/refreshableClones';
 23  
 24    resp := DBMS_CLOUD.send_request(
 25  		 credential_name => 'OCI$RESOURCE_PRINCIPAL',
 26  		 uri => request_uri,
 27  		 method => DBMS_CLOUD.METHOD_GET);
 28  
 29    clone_adb_region := json_value(DBMS_CLOUD.get_response_text(resp), '$.items.region');
 30    clone_adb_ocid	:= json_value(DBMS_CLOUD.get_response_text(resp), '$.items.id');
 31  
 32    IF get_adb_state(clone_adb_region, clone_adb_ocid) = 'STOPPED'
 33    THEN
 34  	 DBMS_OUTPUT.PUT_LINE('Starting ADB.'||CHR(10));
 35  	 response_start := DBMS_CLOUD_OCI_DB_DATABASE.START_AUTONOMOUS_DATABASE(
 36  			     credential_name => 'OCI$RESOURCE_PRINCIPAL',
 37  			     autonomous_database_id => clone_adb_ocid,
 38  			     region		    => clone_adb_region);
 39  
 40  	 wait_adb_state(clone_adb_region, clone_adb_ocid, 'AVAILABLE');
 41  	 DBMS_OUTPUT.PUT_LINE('ADB is started.'||CHR(10));
 42    ELSE
 43  	 DBMS_OUTPUT.PUT_LINE('ADB is already running.'||CHR(10));
 44    END IF;
 45  
 46    SELECT TO_TIMESTAMP_TZ(TO_CHAR(sysdate,'YYYY-MM-DD HH24')||':00:00 +9:00','YYYY-MM-DD HH24:MI:SS TZH:TZM')
 47  	 INTO refresh_details.time_refresh_cutoff FROM dual;
 48  
 49    DBMS_OUTPUT.PUT_LINE('Refreshing ADB.'||CHR(10));
 50    response_refresh := DBMS_CLOUD_OCI_DB_DATABASE.AUTONOMOUS_DATABASE_MANUAL_REFRESH(
 51  					     credential_name => 'OCI$RESOURCE_PRINCIPAL',
 52  			     autonomous_database_id => clone_adb_ocid,
 53  					     region => clone_adb_region,
 54  						     autonomous_database_manual_refresh_details => refresh_details);
 55  
 56    wait_adb_state(clone_adb_region, clone_adb_ocid, 'AVAILABLE');
 57    DBMS_OUTPUT.PUT_LINE('ADB is refreshed.'||CHR(10));
 58  
 59    DBMS_OUTPUT.PUT_LINE('Stopping ADB.'||CHR(10));
 60    response_stop := DBMS_CLOUD_OCI_DB_DATABASE.STOP_AUTONOMOUS_DATABASE(
 61  			  credential_name => 'OCI$RESOURCE_PRINCIPAL',
 62  			  autonomous_database_id => clone_adb_ocid,
 63  			  region		 => clone_adb_region);
 64  
 65    wait_adb_state(clone_adb_region, clone_adb_ocid, 'STOPPED');
 66    DBMS_OUTPUT.PUT_LINE('ADB is stopped.'||CHR(10));
 67  
 68  END;
 69  /

プロシージャが作成されました。

SQL> 

PL/SQLプロシージャrefresh_remote_cloneが作成できました。

早速実行してみます。

SQL> set serveroutput on
SQL> exec refresh_remote_clone;

PL/SQLプロシージャが正常に完了しました。

SQL>

コンソールでリフレッシュ可能クローンの詳細画面を確認すると、ステータスが「起動中」に変わりました。
スクリーンショット 2022-12-08 10.05.22.png
その後、一瞬「使用可能」になり、すぐに「更新中」になりました。
スクリーンショット 2022-12-08 10.05.51.png
しばらく待つと、また一瞬「使用可能」になり、すぐに「停止中」になりました。
スクリーンショット 2022-12-08 10.09.31.png
少し待つと、「停止済」になりました。
スクリーンショット 2022-12-08 10.09.47.png

作業リクエストを確認すると、起動→リフレッシュ→停止の一連の処理が行われたことが確認できました。
スクリーンショット 2022-12-08 8.58.13.png

リフレッシュ・ポイントを確認してみると、リフレッシュ実行時間の直前の正時(0分)に更新されていることが確認できました。
(リフレッシュの実行が2022/12/7 23:49:49 UTCなので、リフレッシュ・ポイントは直前の正時である2022/12/7 23:00:00 UTC)になっています)
スクリーンショット 2022-12-08 8.58.03.png

3. 自動実行の設定

PL/SQLプロシージャの自動実行にはDBMS_SCHEDULERを使用します。
ここでは、毎時5分にrefresh_remote_cloneプロシージャを実行してリフレッシュを自動実行するジョブrefresh_remote_clone_jobを作成します。
初回実行時間は日本時間の2022/12/8 9:05としました。

BEGIN
   DBMS_SCHEDULER.CREATE_JOB (
        job_name           =>  'REFRESH_REMOTE_CLONE_JOB',
        job_type           =>  'STORED_PROCEDURE',
        job_action         =>  'ADMIN.REFRESH_REMOTE_CLONE', 
        start_date         =>  TO_TIMESTAMP_TZ('2022-12-8 09:05:00 +9:00','YYYY-MM-DD HH24:MI:SS TZH:TZM'),
        repeat_interval    =>  'FREQ=HOURLY;INTERVAL=1',
        auto_drop          =>  FALSE,
        enabled            =>  TRUE
    );
END;
/

SQL*Plusから実際に作成してみます。

SQL> BEGIN
  2  	DBMS_SCHEDULER.CREATE_JOB (
  3  	     job_name	       =>  'REFRESH_REMOTE_CLONE_JOB',
  4  	     job_type		   =>  'STORED_PROCEDURE',
  5  	     job_action 	   =>  'ADMIN.REFRESH_REMOTE_CLONE',
  6  	     start_date 	   =>  TO_TIMESTAMP_TZ('2022-12-8 09:05:00 +9:00','YYYY-MM-DD HH24:MI:SS TZH:TZM'),
  7  	     repeat_interval   =>  'FREQ=HOURLY;INTERVAL=1',
  8  	     auto_drop		   =>  FALSE,
  9  	     enabled		   =>  TRUE
 10  	 );
 11  END;
 12  /

PL/SQLプロシージャが正常に完了しました。

SQL>

ジョブrefresh_remote_clone_jobが作成できました。

ジョブrefresh_remote_clone_jobがログを出力するように設定します。

BEGIN
  DBMS_SCHEDULER.SET_ATTRIBUTE (
   'REFRESH_REMOTE_CLONE_JOB', 'logging_level', DBMS_SCHEDULER.LOGGING_FULL);
END;
/
SQL> BEGIN
  2    DBMS_SCHEDULER.SET_ATTRIBUTE (
  3  	'REFRESH_REMOTE_CLONE_JOB', 'logging_level', DBMS_SCHEDULER.LOGGING_FULL);
  4  END;
  5  /

PL/SQLプロシージャが正常に完了しました。

SQL>

ジョブrefresh_remote_clone_jobの設定内容を確認します。

col job_name for a25
col next_run_date for a35
col logging_level for a15
SELECT job_name, next_run_date, logging_level FROM all_scheduler_jobs
WHERE job_name = 'REFRESH_REMOTE_CLONE_JOB';
SQL> col job_name for a25
SQL> col next_run_date for a35
SQL> col logging_level for a15
SQL> SELECT job_name, NEXT_RUN_DATE, LOGGING_LEVEL FROM all_scheduler_jobs
  2  WHERE job_name = 'REFRESH_REMOTE_CLONE_JOB';

JOB_NAME		          NEXT_RUN_DATE 		              LOGGING_LEVEL
------------------------- ----------------------------------- ---------------
REFRESH_REMOTE_CLONE_JOB  22-12-08 09:05:00.000000 +09:00     FULL

1行が選択されました。

SQL>

しばらく待ってから、以下のSQLでジョブの実行状況を確認します。

col job_name for a25
col log_timestamp for a35
col status for a15
SELECT
job_name,
TO_CHAR(FROM_TZ(sys_extract_utc(log_date), 'UTC') at time zone 'Asia/Tokyo','YYYY/MM/DD HH24:Mi:SS') log_timestamp, 
status
FROM user_scheduler_job_run_details
WHERE job_name = 'REFRESH_REMOTE_CLONE_JOB'
ORDER BY log_date;
SQL> col job_name for a25
SQL> col log_timestamp for a35
SQL> col status for a15
SQL> SELECT
  2  job_name,
  3  FROM_TZ(sys_extract_utc(log_date), 'UTC') at time zone 'Asia/Tokyo' timestamp,
  4  status
  5  FROM user_scheduler_job_run_details
  6  WHERE job_name = 'REFRESH_REMOTE_CLONE_JOB'
  7  ORDER BY log_date;

JOB_NAME		          LOG_TIMESTAMP 		              STATUS
------------------------- ----------------------------------- ---------------
REFRESH_REMOTE_CLONE_JOB  2022/12/08 09:10:15		          SUCCEEDED
REFRESH_REMOTE_CLONE_JOB  2022/12/08 10:09:44		          SUCCEEDED

SQL>

ジョブが問題なく自動実行されていることが確認できました。

リフレッシュ可能クローンの作業リクエストを確認すると、指定した時間にジョブが自動実行されていることがわかります。
スクリーンショット 2022-12-08 10.25.02.png

また、リフレッシュ・ポイントを確認すると、最後にジョブが実行された時刻(2022/12/8 10:05 JST)の直前の正時(2022/12/8 1:00:00 UTC = 2022/12/8 10:00 JST)になっていることがわかります。
スクリーンショット 2022-12-08 10.26.21.png

まとめ

リフレッシュ可能クローンをDR目的の遠隔地バックアップとして利用する場合の起動、リフレッシュ、停止といった一連の処理を、PL/SQLのみで自動化することができました。
リフレッシュ可能クローンは差分のみの更新なので、フルクローンを作成する場合に比べて短時間でリフレッシュでき、ソース側のAutonomous Databaseの負荷も軽減できます。

参考資料

Autonomous Databaseでのリフレッシュ可能クローンについて
API Reference and Endpoints:ListAutonomousDatabaseRefreshableClones
DBMS_CLOUD_OCI_DB_DATABASE.START_AUTONOMOUS_DATABASE
DBMS_CLOUD_OCI_DB_DATABASE.STOP_AUTONOMOUS_DATABASE
BMS_CLOUD_OCI_DB_DATABASE.AUTONOMOUS_DATABASE_MANUAL_REFRESH

2
0
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
2
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?