搭配備份和災難復原服務使用 Oracle Direct NFS

如要搭配備份/還原裝置使用 Oracle Direct NFS (dNFS),必須符合下列規定:

  • 資料庫伺服器與備份/復原設備之間的網路頻寬足夠

  • 使用所有 Oracle 必要或建議修補程式。Oracle 會在 Oracle 支援文件中維護必要或建議修補程式的清單。

設定管理主控台,透過 dNFS 保護及掛接虛擬 Oracle 資料庫

如要執行以 dNFS 為基礎的備份作業,您必須將備份/復原設備的暫存磁碟格式 (磁碟偏好設定) 設為 NFS。

請按照下列操作說明,將暫存磁碟格式 (磁碟偏好設定) 設為 NFS:

  1. 依序前往「管理」>「主機」

  2. 在主機上按一下滑鼠右鍵,然後選取「編輯」

  3. 在暫存磁碟格式中選取「NFS」,然後按一下「儲存」

在目標主機上執行的動作,讓 dNFS 正常運作

請執行下列動作,確保 dNFS 設定正確無誤:

  1. 在「DB Alert.log」下方檢查下列訊息,確認 dNFS 已啟用:

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

    如果 dNFS 未啟用,請啟用:

    • 資料庫主機上必須有 NFS 用戶端套件,才能執行保護作業,而且您可能會在任何 Oracle 主機上使用 dNFS 掛接擷取的 Oracle 資料庫,因此這些主機也必須有 NFS 用戶端套件。舉例來說,在 Linux 上,主機應有 nfs-util 套件。請確認下列事項:

      rpm -qa |grep nfs-util

    • 在 Oracle 主機上啟用 dNFS:

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

    • 重新啟動在該 ORACLE_HOME 上執行的資料庫,然後檢查「DB Alert.log」下方是否顯示下列訊息,確認 dNFS 已啟用:

      使用 ODM 執行的 Oracle 執行個體:Oracle Direct NFS ODM 程式庫 3.0 版

  2. 在備份工作期間,執行下列查詢來檢查 dNFS 使用情形:

    select * from gv$dnfs_servers;
    

    您可以查看發生 I/O 的 NFS 讀取/寫入統計資料:

    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

警示記錄中還有其他項目,包括是否使用正確的網路卡與歸檔器通訊。如要判斷是否為這種情況,請查看類似以下的訊息:

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

資料庫追蹤記錄檔

如果發生 I/O 問題,可以在資料庫中設定下列事件,擷取額外的記錄資訊。設定這些事件,等待事件發生,然後查看以追蹤檔案。

    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 上執行的資料庫沒有回應,請使用 sqlplus 以 SYSDBA 身分登入,然後執行「hanganalyze」或傾印:

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

如果資料庫是 RAC 資料庫,請在最後兩個 oradebug 指令中新增 -g 選項。

dNFS 檢視畫面

dNFS 用戶端實際上位於資料庫核心中。因此,資料庫中存在多個 v$ 檢視區塊,可從資料庫內部監控及檢查 dNFS 的健康狀態。Oracle 提供可用於快速監控 dNFS 效能的套件。這個套件位於 Oracle dNFS 監控套件中。

部署完成後,資料庫管理員可以執行下列作業來取得資訊 (參數:dnfs_monitor(睡眠時間)、dnfs_itermonitor(睡眠時間、檢查次數),睡眠時間以秒為單位):

    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 用戶端都會為每個程序和每個網路路徑建立一個通道。如果有多個路徑 (多個 NIC),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 程序編號 (連結至 v$process 中的 PID)
SVRNAME NFS 伺服器名稱
PATH 伺服器的網路路徑
CH_ID dNFS 管道 ID
SVR_ID dNFS 伺服器 ID
SENDS 透過管道傳送自上次選取以來執行的作業
RECVS 接收自上次選取以來,透過管道進行的作業。
PINGS 透過管道 自上次選取以來的 Ping 作業。
V$DNFS_FILES
說明
FILENAME 檔案名稱。
FILESIZE 檔案大小。
PNUM 程序 ID (連結至 v$process 中的 PID)
SRV_ID NFS 伺服器 ID
V$DNFS_STAT
說明
PNUM Oracle 程序編號 (連結至 v$process 中的 PID)
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 DBA 指南