Oracle Database を使う機会があり、バックアップとリストアの方法を調べました。その時の手順のメモです。

環境

Oracle は Rocky Linux への Oracle Database インストール方法 に記載された方法でインストールされている前提です。

※説明を単純にするため Non-CDB 構成でインストールした Oracle Database を使用しています。

初めに – Oracle でのバックアップの考え方について

本題に入る前に、自分が Oracle のバックアップを調べた時に感じたことを書いておきます。

自分のように他の RDBMS を触ってた人が Oracle のバックアップ方法を調べると、”やりたいことが載ってない” と感じることが多いのではと思います。例えば “バックアップを取っておき、サーバーが壊れたら別のマシンにサーバーをインストールしてバックアップからデータを復元する” ということを Oracle でやろうとすると少し面倒です。

MySQL や PostgreSQL のバックアップでは、ベースバックアップを取った後、トランザクションログ (binlog や WAL) を別の場所に継続的にコピーするという方法で行われます。そしてリストアする時は新しいマシンに DB をインストールした後、ベースバックアップとトランザクションログをそのまま流し込めば DB が復元できます。

これが Oracle では基本的な考え方が異なり、Oracle では “同じサーバーインスタンスを使い続ける” ということが前提にあり、”別のマシンに復元する” というのは例外的な考え方のように感じました。

例えば Oracle のバックアップとリストアは RMAN (Recovery Manager) というツールを使う方法が一般的で、RMAN を使うと簡単なコマンドでバックアップとリストアができます。しかし RMAN では過去に行ったバックアップが RMAN リポジトリ という場所に記録されており、そのリポジトリが無いと RMAN でのリストアができません。またバックアップには DBID 等そのサーバーインスタンス固有の ID が含まれており、ID が一致しないサーバーには復元できないといった制限もあります。

この考え方の背景には、おそらく無料の OSS と ライセンス料を取る商用製品との違いがあるのかなと思います。無料の OSS ではマシンが壊れたら別のマシンに乗せ換える、ということが簡単にできますが、ライセンス管理されている製品ではマシン構成が変わればライセンス料も変わる可能性があるため、導入する時にハードウェア構成の設計からしっかりと行われ、故障時は壊れた部品だけを交換してマシン自体は長く使い続ける、という運用が一般的です。Oracle もそのように設計されているように感じました (これは例えば Oracle の冗長化機能にも見られて、Oracle では様々なファイルを冗長化 (同じファイルを複数の場所に保存する) できるようになっているので、1つの Disk が壊れても別の Disk に保存してあるファイルを使ってサーバーを止めずに運用できるようになっています)。

Oracle を勉強する時は、このような考え方の違いを意識しておくと理解しやすいと思います。

バックアップとリストアの概要

Oracle Database はとても多機能で、様々なユースケースに対応できるようになっています。バックアップとリストアも例に漏れず色々な方法を選択できます。この記事では全ての機能に踏み込むことはしませんが、基本的な概要をここで説明します。

物理バックアップと論理バックアップ

まずバックアップには物理バックアップと論理バックアップがあります。物理バックアップはデータファイルをそのままバックアップする方法で、論理バックアップは SQL 文などの形でデータをバックアップする方法です。Oracle で “バックアップ” というと、通常は物理バックアップを意味します。この記事でも物理バックアップの手順を紹介します。

なお 論理バックアップと復元は Data Pump (expdp と Impdp) というツールで実行できます。

物理バックアップには、RMAN というツールを使う方法と、Flashback 機能を使う方法があります。RMAN を使う方法が一般的で、この記事でも RMAN を使用します。

Flashback は Oracle の機能の1つで、UNDO ログを使ってデータベースを過去のある時点まで巻き戻すことができる機能です。例えば誤ったデータ操作をやり直すという時に便利です。他の RDBMS で誤ったデータ操作をやり直したい場合、バックアップを使って操作直前のデータまで復元するという方法で行いますので、Flashback も DB 復元機能の一つと見られています。

なお データを特定の時点まで復元することを PITR (Point-in-time Recovery) と呼びます。

REDOログとアーカイブログ

Oracle では各トランザクションの記録が REDO ログというファイルに記録されます。これは MySQL の binlog、PostgreSQL の WAL と同じようなものです。

REDO ログおよびアーカイブログの概要は REDO ログと アーカイブログ を参照してください。

Oracle では 2つ以上の REDO ログファイルが順番にローテーションして使われます。ログファイルをを切り替える操作を “ログスイッチ” と呼び、ログスイッチのタイミングで REDO ログファイルがコピー (アーカイブ) され、このコピーをアーカイブログと呼びます。

ログスイッチのタイミングはあらかじめ設定されているログファイルの容量がいっぱいになる他、一定の時間間隔で定期的に実行するよう構成することもできます。

各 REDO ログファイルには ログ順序番号 (LSN) が割り当てられ、ログスイッチが行われる度にインクリメントされます。

REDO ログファイルに含まれる各トランザクションのエントリーには システム変更番号 (SCN) が割り当てられます。バックアップからデータを復元する時、どの SCN までデータを復元するかを指定することで PITR を実行できます。

リストアとリカバリ

Oracle で “リストア” とは物理ファイルをバックアップからコピーして復元すること、”リカバリ” は REDOログファイルからバックアップ取得後のデータ変更を復元することを意味します。この記事ではそこまで厳密な用語の使い分けはせず、”リストア” は一般的な意味でのデータの復元を指すこともありますのでご注意ください。

フルバックアップと差分バックアップ

Oracle ではフルバックアップを取る方法と、一度フルバックアップを取った後は前回のバックアップからの差分のみを継続的にバックアップする方法があります。どちらもデータファイルの物理バックアップですが、差分バックアップではファイルサイズが小さくなるという利点がある反面、ベースバックアップが無いと復元できないという条件もあります。

この記事ではフルバックアップを取得した後、アーカイブログを使ってその後のデータ変更を復元するという方法を紹介します。差分バックアップは扱いません。

今回のシナリオ

今回は MySQL や PostgreSQL で一般的に使用される、以下のシナリオを想定します。

バックアップとリストア手順

1. 事前準備 – 初期データ登録

まずバックアップ元のデータベースでテスト用のテーブルを作って、テストデータを登録します。データベースのインストール方法は Rocky Linux への Oracle Database インストール方法 を参照してください。

バックアップ元サーバー

$ sudo su oracle
$ sqlplus / as sysdba

SQL> create user vagrant identified by vagrant default tablespace USERS temporary tablespace TEMP;
SQL> grant all privileges to vagrant;

SQL> create table vagrant.test1 (id number, value nvarchar2(255));
SQL> insert into vagrant.test1 (id, value) select level, concat('value ', level) from dual connect by level <= 10;
10 rows created.
SQL> commit;
Commit complete.

SQL> exit

$ exit  # exit from oracle user

2. フルバックアップ取得

次にフルバックアップを取得します。

バックアップ元サーバー

# バックアップ用ディレクトリの作成
$ sudo mkdir /backup
$ sudo chown oracle:oinstall /backup
$ sudo chmod 775 /backup
$ sudo su oracle

$ rman target /

RMAN> backup database format '/backup/data_%d_%T_%U.bak' spfile format '/backup/spfile_%d_%T_%U.bak' current controlfile format '/backup/controlfile_%d_%T_%U.bak' plus archivelog delete all input format '/backup/archivelog_%d_%T_%U.bak';

Starting backup at 29-OCT-22
current log archived
using target database control file instead of recovery catalog
allocated channel: ORA_DISK_1
...
Finished backup at 29-OCT-22

ここでは、データベース、パラメータファイル (SPFILE)、制御ファイル (Control file)、アーカイブログの 4つのバックアップを取得しています。どれも他のサーバーインスタンスにデータベースを復元する時に必要となります。バックアップ出力先のファイル名は “format” で指定できます。詳細は Oracle のドキュメントを参照してください。

バックアップを取得すると、リカバリ カタログにバックアップされたファイルの情報が保存されます。リカバリ カタログの情報は BACKUP LIST コマンドで確認できます。

バックアップ元サーバー

# アーカイブログの SCN を確認
RMAN> backup list;
List of Backup Sets
===================
BS Key  Size       Device Type Elapsed Time Completion Time
------- ---------- ----------- ------------ ---------------
1       89.72M     DISK        00:00:00     29-OCT-22      
        BP Key: 1   Status: AVAILABLE  Compressed: NO  Tag: TAG20221029T150344
        Piece Name: /backup/archivelog_ORCLCDB_20221029_011bgb2g_1_1.bak

  List of Archived Logs in backup set 1
  Thrd Seq     Low SCN    Low Time  Next SCN   Next Time
  ---- ------- ---------- --------- ---------- ---------
  1    6       2134639    09-OCT-22 2270924    29-OCT-22
  1    7       2270924    29-OCT-22 2273760    29-OCT-22
...
BS Key  Size       Device Type Elapsed Time Completion Time
------- ---------- ----------- ------------ ---------------
5       24.00K     DISK        00:00:00     29-OCT-22      
        BP Key: 5   Status: AVAILABLE  Compressed: NO  Tag: TAG20221029T150414
        Piece Name: /backup/archivelog_ORCLCDB_20221029_051bgb3e_1_1.bak

  List of Archived Logs in backup set 5
  Thrd Seq     Low SCN    Low Time  Next SCN   Next Time
  ---- ------- ---------- --------- ---------- ---------
  1    8       2273760    29-OCT-22 2273848    29-OCT-22  # <-- ①
...

上記は BACKUP LIST の出力の一部で、アーカイブログの部分を抜粋しています。今回のバックアップでは 3つのアーカイブログファイル (LSN 6, 7, 8 のファイル) がバックアップされており、圧縮されて 2つのバックアップファイルに保存されたことがわかります。(LSN は “Seq” カラムに書かれていて、2つのバックアップファイル archivelog_ORCLCDB_20221029_011bgb2g_1_1.bakarchivelog_ORCLCDB_20221029_051bgb3e_1_1.bak に保存されています)

また、ここで取得したバックアップは同じ DBID を持つデータベースにしか復元できません (DBID は Oracle をインストールする度に固有の値が設定されます)。別サーバーに新しいデータベースをインストールして復元する場合、DBID を同じ値に変更しておく必要があるため、ここでバックアップ元データベースの DBID もメモしておきます。

バックアップ元サーバー

RMAN> SELECT DBID FROM V$DATABASE;
      DBID
----------
2888638050

RMAN> exit

この時点で、/backup フォルダに5個のバックアップファイルが保存されています。

バックアップ元サーバー

$ ls -al /backup
archivelog_ORCLCDB_20221029_011bgb2g_1_1.bak
archivelog_ORCLCDB_20221029_051bgb3e_1_1.bak
controlfile_ORCLCDB_20221029_031bgb3b_1_1.bak
data_ORCLCDB_20221029_021bgb2h_1_1.bak
spfile_ORCLCDB_20221029_041bgb3d_1_1.bak

3. フルバックアップ取得後の追加データ登録

ここで、フルバックアップを取った後に新たにデータを登録します。このデータはフルバックアップからではなく、アーカイブログから復元されます。今回は時間を短縮するため、データ登録後にログスイッチを強制的に行ってアーカイブログを出力します。

バックアップ元サーバー

$ sudo su oracle
$ sqlplus / as sysdba

SQL> insert into vagrant.test1 (id, value) select level, concat('value ', level) from dual connect by level <= 20;
20 rows created.

# ログスイッチを強制的に行う
SQL> alter system switch logfile;

SQL> exit

アーカイブログは、デフォルトで /opt/oracle/product/19c/dbhome_1/dbs フォルダに保存されます。ファイル名は arch1_9_1234567890.dbf のような名前です。このファイルも /backup フォルダにコピーしておきます。自分の環境では最終的に 6個のファイルが /backup フォルダに保存されました。

バックアップ元サーバー

# アーカイブログを /backup フォルダにコピー
$ cp /opt/oracle/product/19c/dbhome_1/dbs/arch* /backup

$ ls /backup
arch1_9_1117576676.dbf
archivelog_ORCLCDB_20221029_011bgb2g_1_1.bak
archivelog_ORCLCDB_20221029_051bgb3e_1_1.bak
controlfile_ORCLCDB_20221029_031bgb3b_1_1.bak
data_ORCLCDB_20221029_021bgb2h_1_1.bak
spfile_ORCLCDB_20221029_041bgb3d_1_1.bak

これらのファイルは、この後のリストア手順で使うためリストア先のサーバーにコピーしておきます。

4. リストア手順

今回は新しいサーバーに新しく Oracle をインストールした状態で、バックアップデータを復元するシナリオを想定しています。そのためバックアップ元とは別の新しいサーバーに、新たに Oracle をインストールします。インストール方法は同じように Rocky Linux への Oracle Database インストール方法 を参照してください。

バックアップしたファイルは、リストア先サーバーの /backup フォルダに配置したものとします。

リストア先サーバー

$ sudo mkdir /backup
$ sudo cp <バックアップファイルの置き場所>/* /backup

$ sudo chown -R oracle:oinstall /backup
$ sudo chmod -R 775 /backup
$ ls /backup
arch1_9_1117576676.dbf
archivelog_ORCLCDB_20221029_011bgb2g_1_1.bak
archivelog_ORCLCDB_20221029_051bgb3e_1_1.bak
controlfile_ORCLCDB_20221029_031bgb3b_1_1.bak
data_ORCLCDB_20221029_021bgb2h_1_1.bak
spfile_ORCLCDB_20221029_041bgb3d_1_1.bak

4-1 パラメータファイルの復元

初めにパラメータファイルを復元します。既存のパラメータファイルがあると復元が面倒なので、事前に別の場所に移動しておきます。同様に REDO ログファイルも後でリセットするためここで別の場所に移動してしまいます。

リストア先サーバー

$ sudo su oracle
$ mkdir ~/oracle-backup-data && cd ~/oracle-backup-data

# 既存のパラメータファイルを移動
$ mv /opt/oracle/product/19c/dbhome_1/dbs/spfileORCLCDB.ora .

# 既存の REDO ログファイルを移動
$ mv /opt/oracle/oradata/ORCLCDB/redo* .

これで準備ができたので、パラメータファイルをリストアします。パラメータファイルを復元する前に、バックアップ元と同じ DBID に設定しておく必要があるので注意してください。

リストア先サーバー

$ rman target /

# まずデータベースをシャットダウンする
RMAN> shutdown immediate;

# DBID を設定
RMAN> set dbid 2888638050;
executing command: SET DBID

# NOMOUNT 状態でデータベースを起動。エラーは無視して大丈夫です。
$ startup nomount;
startup failed: ORA-01078: failure in processing system parameters
LRM-00109: could not open parameter file '/opt/oracle/product/19c/dbhome_1/dbs/initORCLCDB.ora'

starting Oracle instance without parameter file for retrieval of spfile
Oracle instance started

# パラメータファイルをリストア
$ restore spfile from '/backup/spfile_ORCLCDB_20221029_041bgb3d_1_1.bak';
Starting restore at 29-OCT-22
using channel ORA_DISK_1

channel ORA_DISK_1: restoring control file
channel ORA_DISK_1: restore complete, elapsed time: 00:00:01
output file name=/opt/oracle/product/19c/dbhome_1/dbs/cntrlORCLCDB.dbf
Finished restore at 29-OCT-22

# この段階で SPFILE が復元されているのを確認できます
RMAN> exit
$ ls /opt/oracle/product/19c/dbhome_1/dbs
...
spfileORCLCDB.ora

4-2. 制御ファイルの復元

次に制御ファイルを復元します。制御ファイルを復元する前に一度データベースをシャットダウンする必要があるので注意してください。

リストア先サーバー

$ rman target /

# 一度データベースをシャットダウン
RMAN> shutdown immediate;

RMAN> startup nomount;
connected to target database (not started)
Oracle instance started
...

RMAN> restore controlfile from '/backup/controlfile_ORCLCDB_20221029_031bgb3b_1_1.bak';
Starting restore at 29-OCT-22
allocated channel: ORA_DISK_1
channel ORA_DISK_1: SID=38 device type=DISK

channel ORA_DISK_1: restoring control file
channel ORA_DISK_1: restore complete, elapsed time: 00:00:01
output file name=/opt/oracle/oradata/ORCLCDB/control01.ctl
output file name=/opt/oracle/oradata/ORCLCDB/control02.ctl
Finished restore at 29-OCT-22

4-3. データベースの復元

これでフルバックアップからデータベースを復元できます。データベースをリストアするには、まずバックアップファイルを RMAN のリカバリ カタログに登録する必要があります。登録したら RESTORE コマンドでデータベースの復元を実行します。

リストア先サーバー

# データベースをマウント
RMAN> alter database mount
released channel: ORA_DISK_1
Statement processed

# RMAN のカタログにバックアップファイルを追加。
# '/backup/' は最後にスラッシュを付ける必要があるため注意。
RMAN> catalog start with '/backup/' noprompt;
searching for all files that match the pattern /backup/

List of Files Unknown to the Database
=====================================
File Name: /backup/arch1_9_1117576676.dbf
File Name: /backup/archivelog_ORCLCDB_20221029_051bgb3e_1_1.bak
File Name: /backup/controlfile_ORCLCDB_20221029_031bgb3b_1_1.bak
File Name: /backup/spfile_ORCLCDB_20221029_041bgb3d_1_1.bak
cataloging files...
cataloging done

List of Cataloged Files
=======================
File Name: /backup/arch1_9_1117576676.dbf
File Name: /backup/archivelog_ORCLCDB_20221029_051bgb3e_1_1.bak
File Name: /backup/controlfile_ORCLCDB_20221029_031bgb3b_1_1.bak
File Name: /backup/spfile_ORCLCDB_20221029_041bgb3d_1_1.bak


# バックアップファイルがカタログに登録されたのを確認
RMAN> list backup;

List of Backup Sets
===================
BS Key  Size       Device Type Elapsed Time Completion Time
------- ---------- ----------- ------------ ---------------
1       89.72M     DISK        00:00:00     29-OCT-22      
        BP Key: 1   Status: AVAILABLE  Compressed: NO  Tag: TAG20221029T150344
        Piece Name: /backup/archivelog_ORCLCDB_20221029_011bgb2g_1_1.bak
...

# リストア実行
RMAN> restore database;
Starting restore at 29-OCT-22
allocated channel: ORA_DISK_1
channel ORA_DISK_1: SID=45 device type=DISK

channel ORA_DISK_1: starting datafile backup set restore
channel ORA_DISK_1: specifying datafile(s) to restore from backup set
channel ORA_DISK_1: restoring datafile 00001 to /opt/oracle/oradata/ORCLCDB/system01.dbf
channel ORA_DISK_1: restoring datafile 00003 to /opt/oracle/oradata/ORCLCDB/sysaux01.dbf
channel ORA_DISK_1: restoring datafile 00004 to /opt/oracle/oradata/ORCLCDB/undotbs01.dbf
channel ORA_DISK_1: restoring datafile 00007 to /opt/oracle/oradata/ORCLCDB/users01.dbf
channel ORA_DISK_1: reading from backup piece /backup/data_ORCLCDB_20221029_021bgb2h_1_1.bak
channel ORA_DISK_1: piece handle=/backup/data_ORCLCDB_20221029_021bgb2h_1_1.bak tag=TAG20221029T150345
channel ORA_DISK_1: restored backup piece 1
channel ORA_DISK_1: restore complete, elapsed time: 00:00:25
Finished restore at 29-OCT-22

4-4. アーカイブログからのデータ復元

最後に、フルバックアップ取得後に登録されたデータをアーカイブログから復元します。今回は一番新しいアーカイブログの名前が arch1_9_1117576676.dbf であることから、最新のログファイルの LSN は 9 となります。

※アーカイブログファイルの名前のデフォルトのフォーマットは %t_%s_%r.dbf となっていて、2つ目の数値が LSN となります。アーカイブログのファイル名のフォーマットは LOG_ARCHIVE_FORMAT パラメータで確認でき、フォーマットの意味は Oracle のドキュメントで確認できます。

“どの LSN まで復元するか” は RECOVER コマンドの UNTIL SEQUENCE 句を使って指定できます (他に特定の SCN や時間まで復元するためのオプションもあります)。UNTIL SEQUENCE 句を使う場合、指定した値 “未満” のログまで復元されますので注意してください。今回は LSN 9 まで復元したいので、UNTIL SEQUENCE 10 と指定します。

リストア先サーバー

RMAN> recover database until sequence 10;
Starting recover at 29-OCT-22
using channel ORA_DISK_1

starting media recovery

archived log for thread 1 with sequence 9 is already on disk as file /backup/arch1_9_1117576676.dbf
channel ORA_DISK_1: starting archived log restore to default destination
channel ORA_DISK_1: restoring archived log
archived log thread=1 sequence=8
channel ORA_DISK_1: reading from backup piece /backup/archivelog_ORCLCDB_20221029_051bgb3e_1_1.bak
channel ORA_DISK_1: piece handle=/backup/archivelog_ORCLCDB_20221029_051bgb3e_1_1.bak tag=TAG20221029T150414
channel ORA_DISK_1: restored backup piece 1
channel ORA_DISK_1: restore complete, elapsed time: 00:00:01
archived log file name=/opt/oracle/product/19c/dbhome_1/dbs/arch1_8_1117576676.dbf thread=1 sequence=8
archived log file name=/backup/arch1_9_1117576676.dbf thread=1 sequence=9
media recovery complete, elapsed time: 00:00:01
Finished recover at 29-OCT-22

これでデータの復元は完了です。最後にデータベースを OPEN 状態にするとき、RESETLOGS を指定することで既存の REDO ログをリセットします。

リストア先サーバー

RMAN> alter database open resetlogs;
Statement processed

RMAN> exit;

最後に結果確認です。フルバックアップ後に登録したデータが確認できれば OK です。

リストア先サーバー

$ sqlplus / as sysdba
SQL> select * from vagrant.test1;
...
30 rows selected.