یکی از اصلیترین کاربردهای اسکریپتنویسی در دنیای Oracle DBA، خودکارسازی کارهای تکراری است.
کارهایی مثل:
- اجرای روزانه RMAN backup
- بررسی هفتگی فضای دیسک
- مانیتورینگ شبانه وضعیت Instanceها
- پاک کردن فایلهای log قدیمی
این کارها را با ابزار cron در لینوکس انجام میدهیم.
cron و crontab چیست؟
cron: یک دیمون (daemon) یا سرویس پسزمینه در لینوکس است که مسئول اجرای زمانبندی شده دستورات است.crontab: فایل تنظیماتی است که لیستی از دستورات زمانبندی شده را برایcronتعریف میکند. هر کاربر میتواندcrontabمخصوص به خود را داشته باشد.
دستورات پایه crontab
crontab -e: ویرایشcrontabکاربر فعلی (این دستور فایل را در ویرایشگر پیشفرض باز میکند).crontab -l: نمایش محتویاتcrontabکاربر فعلی.crontab -r: حذف کاملcrontabکاربر فعلی (با احتیاط استفاده شود!).
ساختار یک خط در crontab
هر خط در crontab شامل ۵ فیلد زمانی و سپس دستور است:
* * * * * command_to_execute
این ۵ فیلد عبارتند از:
- Minute (دقیقه):
0-59 - Hour (ساعت):
0-23 - Day of Month (روز ماه):
1-31 - Month (ماه):
1-12 - Day of Week (روز هفته):
0-7(0 و 7 هر دو یکشنبه هستند)
مثالهای کاربردی
- اجرای اسکریپت backup روزانه ساعت 2 بامداد:
(*/15 یعنی مضربهای 15 دقیقه)
- اجرای اسکریپت پاکسازی log ساعت 3:30 بامداد روز اول هر ماه:
30 3 1 * * /path/to/your/cleanup_script.sh
چالش مهم: محیط (Environment) در cron
اینجاست که خیلی از اسکریپتها، مخصوصاً اسکریپتهای اوراکل، مشکل پیدا میکنند.
وقتی اسکریپتی را مستقیم در ترمینال اجرا میکنید، محیط آن ترمینال (متغیرهای PATH، ORACLE_HOME، LD_LIBRARY_PATH و…) در دسترس اسکریپت قرار میگیرد.
اما cron این محیط را ندارد!
cron یک محیط مینیمال اجرا میکند.
راهحلها برای مشکل محیط:
- تعریف کامل متغیرها در ابتدای اسکریپت Bash:
این بهترین و امنترین روش است. تمام متغیرهای لازم را داخل اسکریپت Bash تعریف کنید.
#!/bin/bash
set -euo pipefail
export ORACLE_HOME=/u01/app/oracle/product/19.0.0/dbhome_1
export PATH=$ORACLE_HOME/bin:$PATH
export LD_LIBRARY_PATH=$ORACLE_HOME/lib:$LD_LIBRARY_PATH
# Rest of your script
sqlplus / as sysdba << EOF
-- your SQL commands
EXIT;
EOF
- تعریف متغیرها در
crontab:
میتوانید متغیرها را مستقیماً در crontab تعریف کنید. این متغیرها فقط برای دستورات همان crontab معتبر خواهند بود.
- اجرای اسکریپت با
source:
اگر یک فایل env.sh دارید که متغیرها را تنظیم میکند، میتوانید اسکریپت اصلی را با source اجرا کنید.
0 2 * * * . /path/to/your/env.sh; /path/to/your/backup_script.sh
یا
# backup_script.sh
source /path/to/your/env.sh
# ... rest of script
مدیریت خروجی cron
cron خروجی دستورات (stdout و stderr) را به ایمیل کاربر مدیر سیستم (root یا کاربری که crontab را اجرا کرده) ارسال میکند.
برای مدیریت این خروجی:
- ارسال به فایل log:
0 2 * * * /path/to/your/backup_script.sh >> /var/log/backup.log 2>&1
این دستور هم stdout و هم stderr را به فایل backup.log هدایت میکند.
- نادیده گرفتن خروجی:
0 2 * * * /path/to/your/backup_script.sh > /dev/null 2>&1
مثال واقعی و عملی: اتوماسیون RMAN Backup با منطق Incremental/Full
در این بخش، یک سناریوی حرفهای را پیادهسازی میکنیم. فرض کنید میخواهیم:
- شنبه تا پنجشنبه: بکاپ Incremental Level 1 گرفته شود.
- جمعه: بکاپ Full (Incremental Level 0) گرفته شود.
- قبل از هر بکاپ، یک PFILE برای احتیاط ساخته شود.
- تمام لاگها، وضعیت سلامت فایلها و پاکسازی فایلهای قدیمی (Obsolete/Expired) مدیریت شود.
گام ۱: ایجاد اسکریپت اصلی Bash (rman_backup_manager.sh)
این اسکریپت ورودی inc یا full را میگیرد و محیط اوراکل را تنظیم میکند.
#!/bin/bash
# rman_backup_manager.sh
set -euo pipefail
# --- تنظیم متغیرهای محیطی (بسیار مهم برای Cron) ---
export ORACLE_HOSTNAME=vahiddb01.rhrac.rh
export ORACLE_UNQNAME=vahiddb
export ORACLE_BASE=/u01/app/oracle
export ORACLE_HOME=$ORACLE_BASE/product/21.3.0/db_1
export ORACLE_SID=vahiddb1
export PATH=$ORACLE_HOME/bin:/usr/sbin:$PATH
export LD_LIBRARY_PATH=$ORACLE_HOME/lib:/lib:/usr/lib
# --- مسیرها و تنظیمات ---
BKP_DIR="/BKP-RMAN-18/vahiddbbackup"
SCRIPT_DIR="/BKP-RMAN-18/scripts"
SQL_DIR="/home/oracle/scripts/rman"
DATE_TAG=$(date +%Y-%m-%d--%H-%M-%S)
# بررسی ورودی اسکریپت
MODE="${1:-}" # گرفتن مقدار inc یا full
if [[ "$MODE" != "inc" && "$MODE" != "full" ]]; then
echo "خطا: لطفا نوع بکاپ را مشخص کنید: {inc|full}"
exit 1
fi
mkdir -p "$BKP_DIR"
# ۱. تهیه PFILE از روی SPFILE (طبق متد مقاله)
echo "Creating PFILE backup..."
sqlplus -s / as sysdba @"$SQL_DIR/createPfileFromSpfile.sql" > /dev/null
# ۲. انتخاب فایل RMAN بر اساس ورودی
if [[ "$MODE" == "full" ]]; then
RMAN_CMD_FILE="$SCRIPT_DIR/rman_full_script.rman"
LOG_FILE="${BKP_DIR}/vahiddb_FULL_${DATE_TAG}.log"
else
RMAN_CMD_FILE="$SCRIPT_DIR/rman_inc_script.rman"
LOG_FILE="${BKP_DIR}/vahiddb_INC_${DATE_TAG}.log"
fi
# ۳. اجرای RMAN
echo "Starting RMAN $MODE backup..."
rman target / cmdfile="$RMAN_CMD_FILE" log="$LOG_FILE"
# بررسی وضعیت نهایی
if [ $? -eq 0 ]; then
echo "بکاپ با موفقیت انجام شد. Log: $LOG_FILE"
else
echo "بکاپ با خطا مواجه شد. Log را بررسی کنید."
exit 1
fi
گام ۲: فایلهای کمکی (SQL و RMAN)
فایل SQL برای PFILE (createPfileFromSpfile.sql):
create pfile='/BKP-RMAN-18/vahiddbbackup/vahiddb_pfile.ora' from spfile;
exit;
فایل RMAN برای Full (جمعهها) (rman_full_script.rman):
در این فایل از incremental level 0 استفاده میکنیم که به عنوان پایه بکاپهای بعدی عمل میکند.
run {
allocate channel c1 device type disk format '/BKP-RMAN-18/vahiddbbackup/full_%T_%U';
allocate channel c2 device type disk format '/BKP-RMAN-18/vahiddbbackup/full_%T_%U';
# ... (تعریف کانالهای بیشتر در صورت نیاز)
crosscheck archivelog all;
delete noprompt obsolete;
delete noprompt expired backup;
delete noprompt expired archivelog all;
backup incremental level 0 cumulative
filesperset 5
as COMPRESSED BACKUPSET
tag 'VAHIDDB_DAILY_FULL'
database;
backup as backupset archivelog all format '/BKP-RMAN-18/vahiddbbackup/arch_%T_%U';
backup current controlfile format '/BKP-RMAN-18/vahiddbbackup/ctrl_%T_%U';
sql 'alter system switch all logfile';
backup as backupset archivelog all not backed up format '/BKP-RMAN-18/vahiddbbackup/arch_%T_%U';
delete force archivelog all backed up 3 times to device type disk;
delete noprompt obsolete;
release channel c1; release channel c2;
}
(نکته: برای فایل rman_inc_script.rman کافیست خط level 0 را به level 1 تغییر دهید).
گام ۳: تنظیم Crontab برای اجرای خودکار
حالا نوبت به زمانبندی میرسد. طبق خواسته ما:
- شنبه تا پنجشنبه (روزهای 0,1,2,3,4,6 در لینوکس): اجرای نسخه
inc - جمعه (روز 5): اجرای نسخه
full
دستور crontab -e را بزنید و این دو خط را اضافه کنید:
# شنبه تا پنجشنبه ساعت ۲۱:۰۰ - بکاپ Incremental
00 21 * * 0-4,6 /BKP-RMAN-18/scripts/rman_backup_manager.sh inc >> /BKP-RMAN-18/vahiddbbackup/cron_inc.log 2>&1
# جمعهها ساعت ۲۱:۰۰ - بکاپ Full (Level 0)
00 21 * * 5 /BKP-RMAN-18/scripts/rman_backup_manager.sh full >> /BKP-RMAN-18/vahiddbbackup/cron_full.log 2>&1
چرا این روش عالی است؟
- جداسازی منطق: اسکریپت Bash وظیفه مدیریت سیستمعامل و ورودیها را دارد و فایل RMAN فقط دستورات دیتابیسی را اجرا میکند.
- پایداری در Cron: تمام متغیرهای محیطی به صورت صریح (Explicit) تعریف شدهاند، پس اسکریپت در محیط محدود Cron از کار نمیافتد.
- امنیت داده: با گرفتن PFILE و سوئیچ لاگ بلافاصله بعد از بکاپ کنترلفایل، خیالتان از بابت داشتن آخرین تغییرات راحت است.
- مدیریت فضا: استفاده از
delete obsoleteوcompressed backupsetباعث میشود فضای دیسک بهینه مصرف شود.
تمرین نهایی:
یک بار اسکریپت را به صورت دستی با دستور ./rman_backup_manager.sh inc تست کنید و سپس در فایل crontab قرار دهید تا از اجرای صحیح آن در زمانبندی مطمئن شوید.