搭配備份和災難復原服務使用 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,請按照下列步驟進行:

    • 保護工作必須在資料庫主機上執行,而您可能會使用 dNFS 掛載擷取的 Oracle 資料庫,因此,NFS 用戶端套件也必須存在於任何 Oracle 主機上。舉例來說,如果是 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 Library 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(sleep time)、dnfs_itermonitor (sleep time, number of times to check),sleep time 以秒為單位):

    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 伺服器各一個)。View 可用於驗證連線和 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 指南