שימוש ב-Oracle Direct NFS עם Backup and DR במסוף לניהול מכשירים

כדי להשתמש ב-Oracle Direct NFS ‏ (dNFS) עם מכשיר גיבוי או שחזור, צריך לעמוד בדרישות הבאות:

  • רוחב פס מספיק ברשת בין שרת מסד הנתונים לבין מכשיר הגיבוי או השחזור

  • משתמשים בכל התיקונים הנדרשים או המומלצים של Oracle. חברת Oracle מתחזקת רשימה של תיקונים נדרשים או מומלצים במסמכי התמיכה של Oracle.

הגדרת מסוף הניהול של ה-appliance להגנה על מסדי נתונים וירטואליים של Oracle ולטעינתם באמצעות dNFS

כדי לבצע גיבוי מבוסס dNFS, צריך להגדיר את פורמט הדיסק של מכשיר הגיבוי/השחזור (העדפת הדיסק) ל-NFS.

כדי להגדיר את פורמט הדיסק של סביבת ה-Staging (העדפת הדיסק) ל-NFS, פועלים לפי ההוראות הבאות:

  1. עוברים אל ניהול > מארחים.

  2. לוחצים לחיצה ימנית על המארח ובוחרים באפשרות עריכה.

  3. בפורמט של דיסק ההכנה, בוחרים באפשרות NFS ולוחצים על שמירה.

פעולות שצריך לבצע במארח היעד כדי ש-dNFS יפעל

כדי לוודא ש-dNFS מוגדר בצורה נכונה, מבצעים את הפעולות הבאות:

  1. כדי לוודא ש-dNFS מופעל, מחפשים את ההודעה הבאה בקובץ DB Alert.log:

    Oracle instance running with ODM: Oracle Direct NFS ODM Library Version 3.01.
    

    אם dNFS לא מופעל, צריך להפעיל אותו:

    • חבילות של לקוח NFS צריכות להיות קיימות במארח מסד הנתונים עבור משימות הגנה, ובכל מארח Oracle שבו אתם עשויים לטעון מסד נתונים של Oracle שצולם באמצעות dNFS. לדוגמה, ב-Linux, חבילת nfs-util צריכה להיות קיימת במארח. כדאי לבדוק את הדברים הבאים:

      rpm -qa |grep nfs-util

    • הפעלת dNFS במארח Oracle:

      cd $ORACLE_HOME/rdbms/lib make -f ins_rdbms.mk dnfs_on

    • מפעילים מחדש את מסדי הנתונים שפועלים ב-ORACLE_HOME, ואז בודקים אם ההודעה הבאה מופיעה בקטע DB Alert.log כדי לוודא ש-dNFS מופעל:

      מופע Oracle שפועל עם ODM: Oracle Direct NFS ODM Library Version 3.0

  2. במהלך עבודת הגיבוי, מריצים את השאילתה הבאה כדי לבדוק את השימוש ב-dNFS:

    select * from gv$dnfs_servers;
    

    אפשר לראות את הנתונים הסטטיסטיים של NFS read/write עבור פעולות קלט/פלט שמתבצעות:

    select inst_id, PNUM, NFS_READ, NFS_WRITE, NFS_COMMIT, NFS_MOUNT from
    gv$dnfs_stats where NFS_READ>0 or NFS_WRITE>0 order by inst_id, PNUM;
    

    אנחנו יכולים לראות את פרטי התהליך של ערוץ ה-dnfs.

    select c.inst_id, program, pid,pname, local, path from gv$process p,
    gv$dnfs_channels c where p.inst_id = c.inst_id and c.pnum = p.pid;
    

פתרון בעיות ב-dNFS: בעיות במסד הנתונים

למשל:

יומן ההתראות

השלב הראשון בכל פעולת ניפוי באגים הוא לבדוק את יומן ההתראות לגבי הודעות שקשורות ל-dNFS. בעיה נפוצה שנצפית במסדי נתונים עם dNFS היא הגודל המוגבל של שטח אחסון זמני של שקע. ‫Oracle מנסה להתאים את הגודל, אבל יכול להיות שהמערכת תגביל את זה. במקרה כזה, שגיאה כמו זו שמופיעה כאן נמצאת ביומן ההתראות:

    Direct NFS: Failed to set socket buffer size.wtmax=[1048576]\
    rtmax=[1048576], errno=-1

פריטים נוספים שכדאי לחפש ביומן ההתראות הם אם נעשה שימוש בכרטיסי הרשת הנכונים כדי לתקשר עם ה-filer. אפשר לזהות את זה לפי הודעה שדומה להודעה הבאה:

    Direct NFS: channel id [0] path [192.168.56.3] to filer [192.168.56.3] via local [] is UP

קבצים של פרטי העברה של מסד נתונים

אם מתרחשות בעיות קלט/פלט, אפשר להגדיר את האירועים הבאים במסד הנתונים כדי לתעד מידע נוסף ביומן. מגדירים את האירועים האלה, מחכים שהאירוע יתרחש ואז בודקים את הקבצים כדי לעקוב אחריו.

    ALTER SYSTEM SET MAX_DUMP_FILE_SIZE =UNLIMITED;
    ALTER SYSTEM SET EVENTS '10298 trace name context forever, level 1'; # KSFD I/O tracing
    ALTER SYSTEM SET EVENTS '19392 trace name context forever, level 8'; # kgnfs tracing
    ALTER SYSTEM SET EVENTS '19394 trace name context forever, level 8'; # skgnfs tracing
    ALTER SYSTEM SET EVENTS '19396 trace name context forever, level 6'; # kgodm tracing
    ALTER SYSTEM SET EVENTS '19398 trace name context forever, level 128'; # mount tracing errors

מסד הנתונים לא מגיב

אם מסד נתונים שפועל ב-dNFS לא מגיב, צריך להיכנס בתור SYSDBA באמצעות sqlplus ולבצע hanganalyze או dump:

    ```oradebug
    oradebug setmypid
    oradebug unlimited
    oradebug hanganalyze 3
    oradebug dump systemstate 266
    ```

אם מסד הנתונים הוא מסד נתונים של RAC, צריך להוסיף את האפשרות ‎-g לשתי פקודות ה-oradebug האחרונות.

תצוגות dNFS

לקוח ה-dNFS נמצא בפועל בקרנל של מסד הנתונים. לכן, קיימים כמה תצוגות v$ במסד הנתונים כדי לעקוב אחרי התקינות של dNFS ולבדוק אותה מתוך מסד הנתונים. ‫Oracle מספקת חבילה שאפשר להשתמש בה כדי לעקוב במהירות אחרי הביצועים של dNFS. החבילה הזו נמצאת בחבילת המעקב של Oracle dNFS.

אחרי הפריסה, DBA יכול לבצע את הפעולות הבאות כדי לקבל מידע (פרמטרים: dnfs_monitor(sleep time), dnfs_itermonitor (sleep time,number of times to check), sleep time is in seconds):

    SQL> set serveroutput on
    SQL> set lines 200
    SQL> exec dnfs_monitor(60);
    Started at  01/18/2017 10:09:46 AM
    Finished at 01/18/2017 10:10:46 AM
    READ IOPS:                 2
    WRITE IOPS:                3
    TOTAL IOPS:                5
    READ Throughput:           0 MB/s
    WRITE Throughput:          0 MB/s
    TOTAL Throughput:          0 MB/s
    SQL> exec dnfs_itermonitor(2,10)
    Started at 01/18/2017 10:20:18 AM
    TIMESTAMP              READ IOPS  WRITE IOPS  TOTAL IOPS  READ(MB/s)  WRITE (MB/s) TOTAL (MB/s)

    01/18/2017 10:20:20 AM  15         7          22           0            0           0

    01/18/2017 10:20:22 AM   2         3          5            0            0           0

    01/18/2017 10:20:24 AM   0         3          3            0            0           0

    01/18/2017 10:20:26 AM   2         2          4            0            0           0

    01/18/2017 10:20:28 AM   0         3          3            0            0           0

    01/18/2017 10:20:30 AM   2         3          5            0            0           0

    01/18/2017 10:20:32 AM   4         3          7            0            0           0

    01/18/2017 10:20:34 AM   0         3          3            0            0           0

    01/18/2017 10:20:36 AM   2         3          5            0            0           0

    01/18/2017 10:20:38 AM   2         3          5            0            0           0

    Finished at 01/18/2017 10:20:38 AM

התצוגות של V$:

  • ‫V$DNFS_SERVER: מציג מידע על כל חיבורי שרת NFS (אחד לכל שרת NFS). התצוגה שימושית כדי לוודא את הקישוריות ואת הגדרות שקע ה-TCP.

  • ‫V$DNFS_CHANNELS: מציג מידע על כל נתיבי הרשת שנוצרו לשרתי NFS. כל לקוח dNFS יוצר ערוץ אחד לכל תהליך לכל נתיב ברשת. אם קיימים כמה נתיבים (כמה כרטיסי רשת), לקוח ה-dNFS מבצע איזון עומסים בכל הערוצים. הנתונים משקפים את הפעילות מאז הבחירה האחרונה.

  • ‫V$DNFS_FILES: הצגת קבצים שפתוחים באמצעות לקוח dNFS.

  • ‫V$DNFS_STAT: מדדי ביצועים ללקוח dNFS.

V$DNFS_SERVER
עמודה תיאור
SRVNAME שם שרת NFS
DIRNAME נפח הנתונים שמיוצאים על ידי שרת NFS
MNTPORT יציאת טעינה מקומית
NFSPORT יציאה של שרת NFS
WTMAX גודל הכתיבה המקסימלי לשרת NFS
RTMAX גודל קריאה מקסימלי לשרת NFS
V$DNFS_CHANNELS
עמודה תיאור
PNUM מספר התהליך של Oracle (קישור ל-PID ב-v$process)
SVRNAME השם של שרת ה-NFS
PATH נתיב ברשת לשרת
CH_ID מזהה ערוץ dNFS
SVR_ID מזהה שרת dNFS
SENDS שליחת פעולות בערוץ מאז הבחירה האחרונה.
RECVS קבלת פעולות בערוץ מאז הבחירה האחרונה.
PINGS פעולות פינג בערוץ מאז הבחירה האחרונה.
V$DNFS_FILES
עמודה תיאור
FILENAME שם הקובץ.
FILESIZE גודל הקובץ.
PNUM מזהה תהליך (קישור למזהה התהליך ב-v$process)
SRV_ID מזהה שרת NFS
V$DNFS_STAT
עמודה תיאור
PNUM מספר התהליך של Oracle (קישור ל-PID ב-v$process)
NFS_NULL Null operations
NFS_GETATTR קבלת פעולות של מאפיינים
NFS_SETATTR הגדרת פעולות על מאפיינים
NFS_LOOKUP פעולות חיפוש
NFS_ACCESS פעולות גישה
NFS_READLINK קריאת פעולות קישור
NFS_READ פעולות קריאה
NFS_WRITE פעולות כתיבה
NFS_CREATE יצירת פעולות
NFS_MKDIR ביצוע פעולות בספריות
NFS_MKNOD ביצוע פעולות בצומת
NFS_SYMLINK פעולות של קישורים סמליים
NFS_REMOVE הסרת פעולות
NFS_RMDIR הסרת פעולות בספריות
NFS_RENAME שינוי שמות של פעולות
NFS_LINK פעולות שקשורות לקישורים
NFS_READDIR קריאת פעולות בספרייה
NFS_READDIRPLUS קריאה של פעולות בספרייה
NFS_FSSTAT פעולה של סטטוס מערכת הקבצים
NFS_FSINFO פעולות מידע במערכת הקבצים
NFS_PATHCONF פעולות להגדרת נתיב
NFS_COMMIT ביצוע פעולות
NFS_MOUNT פעולות טעינה

חבילת המעקב Oracle dNFS

    CREATE OR REPLACE PROCEDURE dnfs_monitor
       (sleepSecs IN NUMBER)
    IS
       startTime       DATE;
       startReadIOPS   NUMBER;
       startWriteIOPS  NUMBER;
       startReadBytes  NUMBER;
       startWriteBytes NUMBER;
       endTime         DATE;
       endReadIOPS     NUMBER;
       endWriteIOPS    NUMBER;
       endReadBytes    NUMBER;
       endWriteBytes   NUMBER;
       readThr         NUMBER;
       writeThr        NUMBER;
       readIOPS        NUMBER;
       writeIOPS       NUMBER;
       elapsedTime     NUMBER;
    BEGIN

       SELECT sysdate, SUM(stats.nfs_readbytes), SUM(stats.nfs_writebytes),
    SUM(stats.nfs_read), SUM(stats.nfs_write)
       INTO startTime, startReadBytes, startWriteBytes, startReadIOPS, startWriteIOPS
       FROM dual, v$dnfs_stats stats;

       DBMS_OUTPUT.PUT_LINE('Started at  ' || TO_CHAR(startTime,'MM/DD/YYYY HH:MI:SS AM'));

       DBMS_LOCK.SLEEP(sleepSecs);

       SELECT sysdate, SUM(stats.nfs_readbytes), SUM(stats.nfs_writebytes), SUM(stats.nfs_read), SUM(stats.nfs_write)
       INTO endTime, endReadBytes, endWriteBytes, endReadIOPS, endWriteIOPS
       FROM dual, v$dnfs_stats stats;

       DBMS_OUTPUT.PUT_LINE('Finished at ' || to_char(endTime,'MM/DD/YYYY HH:MI:SS AM'));

       elapsedTime := (endTime - startTime) * 86400;
       readThr := (endReadBytes - startReadBytes)/(1024 * 1024 * elapsedTime);
       writeThr := (endWriteBytes - startWriteBytes)/(1024 * 1024 * elapsedTime);
       readIOPS := (endReadIOPS - startReadIOPS)/elapsedTime;
       writeIOPS := (endWriteIOPS - startWriteIOPS)/elapsedTime;

       DBMS_OUTPUT.PUT_LINE('READ IOPS:        ' || LPAD(TO_CHAR(readIOPS, '999999999'), 10, ' '));
       DBMS_OUTPUT.PUT_LINE('WRITE IOPS:       ' || LPAD(TO_CHAR(writeIOPS,
       '999999999'), 10, ' '));
       DBMS_OUTPUT.PUT_LINE('TOTAL IOPS:       ' || LPAD(TO_CHAR(readIOPS + writeIOPS, '999999999'), 10, ' '));
       DBMS_OUTPUT.PUT_LINE('READ Throughput:  ' || LPAD(TO_CHAR(readThr, '999999999'), 10, ' ') || ' MB/s');
       DBMS_OUTPUT.PUT_LINE('WRITE Throughput: ' || LPAD(TO_CHAR(writeThr,
       '999999999'), 10, ' ') || ' MB/s');
       DBMS_OUTPUT.PUT_LINE('TOTAL Throughput: ' || LPAD(TO_CHAR(readThr + writeThr, '999999999'), 10, ' ') || ' MB/s');
       END;
    /

    CREATE OR REPLACE PROCEDURE dnfs_itermonitor
       (sleepSecs IN NUMBER,
        iter      IN NUMBER)
    IS
       startTime       DATE;
       startReadIOPS   NUMBER;
       startWriteIOPS  NUMBER;
       startReadBytes  NUMBER;
       startWriteBytes NUMBER;
       endTime         DATE;
       endReadIOPS     NUMBER;
       endWriteIOPS    NUMBER;
       endReadBytes    NUMBER;
       endWriteBytes   NUMBER;
       readThr         NUMBER;
       writeThr        NUMBER;
       readIOPS        NUMBER;
       writeIOPS       NUMBER;
       i               NUMBER;
       elapsedTime     NUMBER;
    BEGIN

       DBMS_OUTPUT.PUT_LINE('Started at ' || TO_CHAR(SYSDATE, 'MM/DD/YYYY HH:MI:SS AM'));

       DBMS_OUTPUT.PUT_LINE(
           LPAD('TIMESTAMP', 15, ' ')||
           LPAD('READ IOPS', 33, ' ')||
           LPAD('WRITE IOPS', 15, ' ')||
           LPAD('TOTAL IOPS', 15, ' ')||
           LPAD('READ (MB/s)', 15, ' ')||
           LPAD('WRITE (MB/s)', 15, ' ')||
           LPAD('TOTAL (MB/s)', 15, ' '));

       FOR i IN 1..iter
       LOOP
       SELECT sysdate, SUM(stats.nfs_readbytes), SUM(stats.nfs_writebytes), SUM(stats.nfs_read), SUM(stats.nfs_write)
       INTO startTime, startReadBytes, startWriteBytes, startReadIOPS, startWriteIOPS
       FROM dual, v$dnfs_stats stats;

       DBMS_LOCK.SLEEP(sleepSecs);

       SELECT sysdate, SUM(stats.nfs_readbytes), SUM(stats.nfs_writebytes), SUM(stats.nfs_read), SUM(stats.nfs_write)
       INTO endTime, endReadBytes, endWriteBytes, endReadIOPS, endWriteIOPS
       FROM dual, v$dnfs_stats stats;

       elapsedTime := (endTime - startTime) * 86400;
       readThr := (endReadBytes-startReadBytes)/(1024 * 1024 * elapsedTime);
       writeThr := (endWriteBytes-startWriteBytes)/(1024 * 1024 * elapsedTime);
       readIOPS := (endReadIOPS - startReadIOPS)/elapsedTime;
       writeIOPS := (endWriteIOPS - startWriteIOPS)/elapsedTime;

       DBMS_OUTPUT.PUT_LINE(
           TO_CHAR(endTime, 'MM/DD/YYYY HH:MI:SS AM')||
           LPAD(TO_CHAR(readIOPS, '999999999'), 15, '') ||
           LPAD(TO_CHAR(writeIOPS, '999999999'), 15,' ') ||
           LPAD(TO_CHAR(readIOPS + writeIOPS, '999999999'),15, ' ') ||
           LPAD(TO_CHAR(readThr, '999999999'), 15, '') ||LPAD(TO_CHAR(writeThr, '999999999'), 15, '
    ') ||
    LPAD(TO_CHAR(readThr + writeThr, '999999999'), 15, ' '));
    END LOOP;
    DBMS_OUTPUT.PUT_LINE('Finished at ' || to_char(endTime, 'MM/DD/YYYY HH:MI:SS AM'));

    END;

המדריך למנהלי מסדי נתונים של Oracle