در محیطهای Oracle Database، یکی از مواردی که میتواند نشانهای از تغییرات غیرمنتظره در سیستم باشد، افزایش ناگهانی حجم آرشیو لاگها است. این تغییر میتواند به دلیل بار زیاد تراکنشی، تغییرات غیرمجاز، اجرای یک اسکریپت سنگین یا حتی یک حمله امنیتی باشد. در این مقاله، تجربهی عملی بررسی این وضعیت را با استفاده از LogMiner به اشتراک میگذارم و مراحل انجام شده را گامبهگام توضیح میدهم.
با تشکر از استاد عزیزم مهندس تیموری که اولین بار از ایشون این مطلب رو آموختم.
مشاهده افزایش غیرمنتظره تعداد آرشیو لاگ
در هنگام کار با دیتابیس، متوجه شدیم که تعداد آرشیو لاگها بهصورت غیرمنتظرهای افزایش پیدا کرده است. برای بررسی این وضعیت، ابتدا لاگهای تولید شده را لیست کردیم. دقت کنید که اگر این لاگها مربوط به زمان دیگری بود یا به عنوان مثال روی یک thread خاص باشند، می تونیم با استفاده از where در جدول v$archived_log اعمال کنید
SELECT ' DBMS_LOGMNR.ADD_LOGFILE(LogFileName => ''' || NAME ||
''' ,Options => DBMS_LOGMNR.ADDFILE);'
FROM V$ARCHIVED_LOG
WHERE NAME IS NOT NULL
AND DEST_ID = 1
ORDER BY COMPLETION_TIME DESC;
خروجی این دستور به شکل زیر نمایش داده می شود، این خروجی را برای مرحله بعد نیاز داریم:
DBMS_LOGMNR.ADD_LOGFILE(LogFileName => '/u01/app/oracle/product/19c/dbhome/dbs/arch1_64_1184679044.dbf' ,Options => DBMS_LOGMNR.ADDFILE);
DBMS_LOGMNR.ADD_LOGFILE(LogFileName => '/u01/app/oracle/product/19c/dbhome/dbs/arch1_63_1184679044.dbf' ,Options => DBMS_LOGMNR.ADDFILE);
DBMS_LOGMNR.ADD_LOGFILE(LogFileName => '/u01/app/oracle/product/19c/dbhome/dbs/arch1_62_1184679044.dbf' ,Options => DBMS_LOGMNR.ADDFILE);
بررسی تغییرات در آرشیو لاگ با LogMiner
برای بررسی علت این افزایش ناگهانی، تصمیم گرفتیم که از LogMiner استفاده کنیم. ابتدا، لاگهای موردنظر را به LogMiner اضافه کردیم:
BEGIN
DBMS_LOGMNR.ADD_LOGFILE(LogFileName => '/u01/app/oracle/product/19c/dbhome/dbs/arch1_64_1184679044.dbf' ,Options => DBMS_LOGMNR.ADDFILE);
DBMS_LOGMNR.ADD_LOGFILE(LogFileName => '/u01/app/oracle/product/19c/dbhome/dbs/arch1_63_1184679044.dbf' ,Options => DBMS_LOGMNR.ADDFILE);
DBMS_LOGMNR.START_LOGMNR (Options => DBMS_LOGMNR.DICT_FROM_ONLINE_CATALOG);
END;
حالا می توانیم سراغ تحلیل داده های آن برویم. من مثال ساده ای را آماده کردم. می توانید جستجو های خود را بر اساس نیازمندی تغییر دهید:
SELECT username, COUNT(1)
FROM V$LOGMNR_CONTENTS
GROUP BY username
ORDER BY 2 DESC;
خروجی آن بصورت زیر است:
USERNAME COUNT(1)
--------- ---------
UNKNOWN 506146
SYS 305853
چون در محیط تست این کار را شبیه سازی کردم، بجز کاربر sys از کاربر دیگری استفاده نکردم.
تحلیل تغییرات ایجاد شده در جداول
برای بررسی اینکه این تراکنشها چه نوع عملیاتی انجام دادهاند و روی چه جداولی اثر گذاشتهاند، از کوئری زیر استفاده کردیم:
SELECT OS_USERNAME, MACHINE_NAME, TABLE_NAME, COUNT(*)
FROM V$LOGMNR_CONTENTS
WHERE UPPER(TABLE_NAME) LIKE '%TEST%'
GROUP BY OS_USERNAME, MACHINE_NAME, TABLE_NAME;
بررسی حذف ناگهانی دادهها
اگر مقدار زیادی از اطلاعات یک جدول حذف شده باشد، با استفاده از LogMiner میتوان بررسی کرد که چه کسی و چه زمانی این عملیات را انجام داده است:
SELECT username, operation, sql_redo FROM V$LOGMNR_CONTENTS WHERE operation = 'DELETE';
در پایان کار برای بسته شدن پکیج باید دستور زیر را بزنیم:
BEGIN
DBMS_LOGMNR.END_LOGMNR();
END;
فعالسازی Supplemental Logging برای دریافت اطلاعات بیشتر
یکی از مشکلاتی که در لاگها مشاهده کردیم این بود که برخی از تغییرات بدون اطلاعات تکمیلی در LogMiner ثبت شده بودند. بر اساس داکیومنت Doc ID 750198.1 بدون فعالسازی Supplemental Logging، LogMiner نمیتواند اطلاعات مفیدی از آرشیو لاگها استخراج کند. دلیل این موضوع این است که Redo Log فقط شامل تغییرات بر اساس ROWID است، و در حالت عادی، اطلاعات کلیدی مثل نام کاربر یا مقدار فیلدهای تغییر داده شده در لاگها ذخیره نمیشود.
برای فعال کردن suplemental log از دستور زیر استفاده می کنیم:
ALTER DATABASE ADD SUPPLEMENTAL LOG DATA;
در مقایسه ای که در داکیومنتی که گفتم آمده است، خروجی جستجوی زیر
SELECT SQL_REDO , SQL_UNDO FROM V$LOGMNR_CONTENTS WHERE username='SCOTT';
در حالت بدون suplemental log خالی و در حالت با suplemental log حاوی اطلاعات مورد نیاز بود.