シェル-RACコールドバックアップ
対応バージョン
Oracle Database 10.2 - 11.2
2015-06-01記事公開
よく使用する便利ツールの公開です。
※ カスタマイズなどのご要望がございましたら、お見積りいたしますので、弊社までお問い合わせください。
シェル概要
RAC環境にて指定したデータベースのコールドバックアップを取得します。
シングルインスタンス環境では動作しません。
テスト環境
OS: Oracle Linux 6
Database: Oracle Database 11cR2 Real Application Cluseter
Database: Oracle Database 11cR2 Real Application Cluseter
使用方法
rootユーザにて以下のように実行します。(rootユーザ又はsudoにて実行)
$ rac_backup_rmancold.sh [引数1:バックアップ対象DB]
実行例
# su - # chmod 755 /tmp/rac_backup_rmancold.sh # /tmp/rac_backup_rmancold.sh orcl
シェル内容
以下に rac_backup_rmancold.sh シェルの内容を示します。
#!/bin/bash
# Copyright 2015 SIX SQUARE JAPAN.co.,ltd. All Rights Reserved.
# 本著作物は例を示したサンプルであり、資料の内容を利用した場合について、
# 弊社が一切の責任を負うものではありません。
# Version:
# Ver 1.0 - 2015/06/01 - 新規作成
# Description:
# 引数に与えられたOracle RAC データベースのコールドバックアップを取得する。
# データベースの起動・停止を行う。
# 実行はrootユーザまたはsudoにて実行を行う。
# Usage:
# parameter1: バックアップ対象DBの DB_NAME
###############################################################################
# SYSDBA権限のグループをもつOSユーザ
SYSDBA_OSUSER=oracle
# レポートファイルの出力先定義
BACKUP_DIRECOTRY=/mnt/dbbackup/oraclerman
# バックアップ世代数(手動管理)
BACKUP_RETENTION=1
# RMAN実行チャネルの数(パラレル度)
NUM_PARALLEL=16
ORACLE_BASE=""
ORACLE_HOME=""
NORMAL_CODE=0
ERROR_CODE=1
# バックアップオプション [ON/OFF]
BACKUP_SET_OPTION_COMPRESS=ON
BACKUP_SET_OPTION_ENCRYPTION=ON
# SYSDBA_OSUSER に設定したユーザの.bash_profile読み込み
L_ORACLE_BASH_PROFILE=`eval ls -1 ~${SYSDBA_OSUSER}/.bash_profile`
if [ -f ${L_ORACLE_BASH_PROFILE} ]; then
source ${L_ORACLE_BASH_PROFILE}
fi
export LANG=C
export NLS_LANG=American_America.AL32UTF8
# ORACLE_BASEが空の場合、.bash_profileから取得
if [ -z "${ORACLE_BASE}" ]; then
ORACLE_BASE=`grep "ORACLE_BASE=" ${L_ORACLE_BASH_PROFILE} | grep -v "^[ ]*#" \
| cut -d'=' -f2- | sed -e 's@#.*$@@'`
# ORACLE_BASEが取得できない場合は必須でないためそのまま実行
if [ -z "${ORACLE_BASE}" ]; then
echo "`date '+%Y/%m/%d %H:%M:%S'` Warning: ORACLE_BASE is NULL"
fi
fi
# ORACLE_HOMEが空の場合、.bash_profileから取得
if [ -z "${ORACLE_HOME}" ]; then
ORACLE_HOME=`grep "ORACLE_HOME=" ${L_ORACLE_BASH_PROFILE} | grep -v "^[ ]*#" \
| cut -d'=' -f2- | sed -e 's@#.*$@@'`
if [ -z "${ORACLE_HOME}" ]; then
# ORACLE_HOMEが取得できない場合は異常終了
echo "ORACLE_HOME of environment variable Not found."
exit ${ERROR_CODE}
fi
fi
export ORACLE_BASE ORACLE_HOME
PATH=${ORACLE_HOME}/bin:${PATH}:/usr/bin:/usr/sbin:/bin:/sbin
export PATH
echo "`date '+%Y/%m/%d %H:%M:%S'` Started shell[`basename $0`]"
# ユーザの確認
case "${USER}" in
"root" )
echo "`date '+%Y/%m/%d %H:%M:%S'` User is ${USER}. [Pass]"
;;
* )
echo "`date '+%Y/%m/%d %H:%M:%S'` User is ${USER}. Switch user to [root]."
exit ${ERROR_CODE}
;;
esac
# 引数の数のチェック
if [ $# -ne 1 ]; then
echo "Usage: $0 [Backup DB Name]"
echo " ex: $0 orcl"
exit ${ERROR_CODE}
fi
# 第一引数に指定された値をバックアップ対象のDBとして設定
BKDB=$1
# RMANファイルのバックアップディレクトリ設定
L_BACKUP_DIRECOTRY_RMANFILE=${BACKUP_DIRECOTRY}/${BKDB}_cold
# Gridが動作しているORACLE_HOMEを特定
GRID_OCSSDBIN=`ps -ef | awk '{print $8}' | grep "/ocssd.bin$" | head -1`
export PATH=`dirname ${GRID_OCSSDBIN}`:${PATH}
# シェル実行ノードのデータベースのステータスを取得
L_DB_STATUS=`srvctl status database -d ${BKDB} | grep " \`uname -n | cut -d'.' -f1\`$"`
if [ "${L_DB_STATUS}" = "" ]; then
# シェル実行ノードで稼働しているインスタンスが取得できなかった場合
echo "`date '+%Y/%m/%d %H:%M:%S'` Instance was not exists. [${BKDB} on `uname -n | cut -d'.' -f1`]"
exit ${ERROR_CODE}
fi
# インスタンス名を取得
L_TGT_INSTANCE=`echo "${L_DB_STATUS}" | awk '{print $2}'`
# 古いバックアップの削除
if [ -d ${L_BACKUP_DIRECOTRY_RMANFILE} ]; then
# バックアップディレクトリ付与番号最大値の取得
L_NUM_DIRECTORY_MAX=`expr ${BACKUP_RETENTION} - 1`
for L_NUM_DIRECTORY in `ls -1d ${L_BACKUP_DIRECOTRY_RMANFILE}.[0-9]* 2>/dev/null \
| sed -e "s@${L_BACKUP_DIRECOTRY_RMANFILE}.@@" | sort -r`
do
# 取得したディレクトリ番号の数値チェック
echo "${L_NUM_DIRECTORY}" | grep -q "[0-9]*[0-9]"
if [ $? -ne 0 ]; then
# 取得したディレクトリ番号が数値以外の場合
echo "[${L_NUM_DIRECTORY}] is not numeric data."
else
# 決められたフォーマットのものはローテーションを行う
if [ ${L_NUM_DIRECTORY} -ge ${L_NUM_DIRECTORY_MAX} ]; then
# 取得したディレクトリ番号が世代最大値より大きいか等しい場合
echo "`date '+%Y/%m/%d %H:%M:%S'` Remove [${L_BACKUP_DIRECOTRY_RMANFILE}.${L_NUM_DIRECTORY}]"
rm -rf ${L_BACKUP_DIRECOTRY_RMANFILE}.${L_NUM_DIRECTORY}
else
# 取得したディレクトリ番号が世代最大値より小さい場合
L_NUM_DIRECTORY_MOVE=`expr ${L_NUM_DIRECTORY} + 1`
echo -n "`date '+%Y/%m/%d %H:%M:%S'` Move [${L_BACKUP_DIRECOTRY_RMANFILE}.${L_NUM_DIRECTORY}] to"
echo " [${L_BACKUP_DIRECOTRY_RMANFILE}.${L_NUM_DIRECTORY_MOVE}]"
mv -f ${L_BACKUP_DIRECOTRY_RMANFILE}.${L_NUM_DIRECTORY} ${L_BACKUP_DIRECOTRY_RMANFILE}.${L_NUM_DIRECTORY_MOVE}
fi
# ローテーション対象のディレクトリが残存していた場合
if [ -d ${L_BACKUP_DIRECOTRY_RMANFILE}.${L_NUM_DIRECTORY} ]; then
echo "`date '+%Y/%m/%d %H:%M:%S'` Remove directory failed. [${L_BACKUP_DIRECOTRY_RMANFILE}.${L_NUM_DIRECTORY}]"
exit ${ERROR_CODE}
fi
fi
done
# 前回バックアップの処理
if [ ${L_NUM_DIRECTORY_MAX} -ge 1 ]; then
# 最大ローテーション番号が1より大きい場合(二世代以上)は、前回バックアップを .1 に変更
echo "`date '+%Y/%m/%d %H:%M:%S'` Move [${L_BACKUP_DIRECOTRY_RMANFILE}] to [${L_BACKUP_DIRECOTRY_RMANFILE}.1]"
mv -f ${L_BACKUP_DIRECOTRY_RMANFILE} ${L_BACKUP_DIRECOTRY_RMANFILE}.1
else
# 1世代保存の場合、前回のバックアップを削除
echo "`date '+%Y/%m/%d %H:%M:%S'` Remove [${L_BACKUP_DIRECOTRY_RMANFILE}]"
rm -rf ${L_BACKUP_DIRECOTRY_RMANFILE}
fi
# ローテーション処理のチェック
if [ -d ${L_BACKUP_DIRECOTRY_RMANFILE} ]; then
echo "`date '+%Y/%m/%d %H:%M:%S'` Remove directory failed. [${L_BACKUP_DIRECOTRY_RMANFILE}]"
exit ${ERROR_CODE}
fi
fi
# データベースをマウントモードへ変更
echo "`date '+%Y/%m/%d %H:%M:%S'` Stop database [${BKDB}]"
L_DB_STATUS=`su - ${SYSDBA_OSUSER} -c "export ORACLE_HOME=${ORACLE_HOME}; ${ORACLE_HOME}/bin/srvctl stop database -d ${BKDB}"`
echo "`date '+%Y/%m/%d %H:%M:%S'` Mount database [${BKDB}]"
L_DB_STATUS=`su - ${SYSDBA_OSUSER} -c "export ORACLE_HOME=${ORACLE_HOME}; \
${ORACLE_HOME}/bin/srvctl start instance -d ${BKDB} -i ${L_TGT_INSTANCE} -o mount"`
# データベースのオープン状態を取得
L_MNTSTATUS=`su - ${SYSDBA_OSUSER} -c "export LANG=C; export NLS_LANG=American_America.AL32UTF8; \
export ORACLE_HOME=${ORACLE_HOME}; export ORACLE_SID=${L_TGT_INSTANCE}; \
${ORACLE_HOME}/bin/sqlplus -s -L / as sysdba << SQL_EOF
whenever sqlerror exit 2
whenever oserror exit 2
set pages 0 line 1200 trim on trims on feed off heading off timing off verify off
select OPEN_MODE from v\\\\\\\$database;
exit
SQL_EOF"`
echo "`date '+%Y/%m/%d %H:%M:%S'` The status of database:${BKDB} is [${L_MNTSTATUS}]"
# データベースのオープン状態がコールドバックアップの前提であるマウントモードになっていることの確認
if [ "${L_MNTSTATUS}" != "MOUNTED" ]; then
echo "`date '+%Y/%m/%d %H:%M:%S'` Status of database[${BKDB}] is not MOUNTED. Change status was failed."
exit ${ERROR_CODE}
fi
# バックアップディレクトリの作成
mkdir -m777 ${L_BACKUP_DIRECOTRY_RMANFILE}
if [ ! -d ${L_BACKUP_DIRECOTRY_RMANFILE} ]; then
echo "`date '+%Y/%m/%d %H:%M:%S'` mkdir failed.[${L_BACKUP_DIRECOTRY_RMANFILE}]"
exit ${ERROR_CODE}
fi
# 指定されたパラレル度に応じて、チャネル宣言の生成
for L_NUM_CH in `seq 1 ${NUM_PARALLEL}`
do
L_ALLOCATE_CHANNEL=" ALLOCATE CHANNEL ch${L_NUM_CH} DEVICE TYPE DISK FORMAT '${L_BACKUP_DIRECOTRY_RMANFILE}/DATA_%d_DBID%I_%U';"
L_ALLOCATE_CHANNELS=`printf "%s\n%s" "${L_ALLOCATE_CHANNELS}" "${L_ALLOCATE_CHANNEL}"`
done
# 圧縮オプションがONの場合は圧縮処理を付与
if [ "${BACKUP_SET_OPTION_COMPRESS}" == "ON" ]; then
L_BACKUP_SET_OPTION=`printf "%s\n%s" "${L_BACKUP_SET_OPTION}" "SET COMPRESSION ALGORITHM 'LOW';"`
L_BACKUP_FTYPE="AS COMPRESSED BACKUPSET"
else
L_BACKUP_FTYPE="AS BACKUPSET"
fi
# 暗号化オプションがONの場合は暗号化処理を付与
if [ "${BACKUP_SET_OPTION_ENCRYPTION}" == "ON" ]; then
L_BACKUP_SET_OPTION=`printf "%s\n%s" "${L_BACKUP_SET_OPTION}" "SET ENCRYPTION ALGORITHM 'AES128' ON;"`
fi
# RMAN コマンドファイル生成
L_RMANCMDFILE=${L_BACKUP_DIRECOTRY_RMANFILE}/rman_`date '+%Y%m%d%H%M%S'`.cmd
echo "CROSSCHECK BACKUP;" >> ${L_RMANCMDFILE}
echo "DELETE NOPROMPT EXPIRED BACKUP;" >> ${L_RMANCMDFILE}
echo "${L_BACKUP_SET_OPTION}" >> ${L_RMANCMDFILE}
echo "run {" >> ${L_RMANCMDFILE}
echo " ${L_ALLOCATE_CHANNELS}" >> ${L_RMANCMDFILE}
echo " backup ${L_BACKUP_FTYPE} database SECTION SIZE 50G;" >> ${L_RMANCMDFILE}
echo "}" >> ${L_RMANCMDFILE}
echo -n "backup AS BACKUPSET DEVICE TYPE DISK FORMAT " >> ${L_RMANCMDFILE}
echo "'${L_BACKUP_DIRECOTRY_RMANFILE}/SPFL_%d_DBID%I_%U' spfile;" >> ${L_RMANCMDFILE}
echo -n "backup AS BACKUPSET DEVICE TYPE DISK FORMAT " >> ${L_RMANCMDFILE}
echo "'${L_BACKUP_DIRECOTRY_RMANFILE}/CTRL_%d_DBID%I_%U' current controlfile;" >> ${L_RMANCMDFILE}
echo "exit" >> ${L_RMANCMDFILE}
chmod 666 ${L_RMANCMDFILE}
# RMAN コマンドファイルの作成確認
if [ ! -f "${L_RMANCMDFILE}" ]; then
echo "`date '+%Y/%m/%d %H:%M:%S'` Create rman command file failed.[${L_RMANCMDFILE}]"
exit ${ERROR_CODE}
fi
# RMAN コールドバックアップの実行
su - ${SYSDBA_OSUSER} -c "export NLS_DATE_FORMAT='YYYY/MM/DD HH24:MI:SS'; export ORACLE_HOME=${ORACLE_HOME}; \
export ORACLE_SID=${L_TGT_INSTANCE}; \
${ORACLE_HOME}/bin/rman target / nocatalog @'${L_RMANCMDFILE}'" \
| tee -a ${L_BACKUP_DIRECOTRY_RMANFILE}/rman_`date '+%Y%m%d%H%M%S'`.log
echo "`date '+%Y/%m/%d %H:%M:%S'` Ended backup database[${BKDB}]"
# バックアップ後データベースの再起動
echo "`date '+%Y/%m/%d %H:%M:%S'` Stop database [${BKDB}]"
L_DB_STATUS=`su - ${SYSDBA_OSUSER} -c "export ORACLE_HOME=${ORACLE_HOME}; ${ORACLE_HOME}/bin/srvctl stop database -d ${BKDB}"`
echo "`date '+%Y/%m/%d %H:%M:%S'` Start database [${BKDB}]"
L_DB_STATUS=`su - ${SYSDBA_OSUSER} -c "export ORACLE_HOME=${ORACLE_HOME}; ${ORACLE_HOME}/bin/srvctl start database -d ${BKDB}"`
# データベース再起動後のステータス確認
srvctl status database -d ${BKDB} 2>&1 | grep -qv "is running on node"
L_DBSTATUS=$?
if [ ${L_DBSTATUS} -ne 1 ]; then
echo "`date '+%Y/%m/%d %H:%M:%S'` Status of database was wrong.[${BKDB}]"
srvctl status database -d ${BKDB}
exit ${ERROR_CODE}
fi
exit ${NORMAL_CODE}