如要搭配備份/復原機器使用 Oracle Direct NFS (dNFS),必須符合下列規定:
資料庫伺服器與備份/復原設備之間的網路頻寬充足
使用所有 Oracle 必要或建議的修補程式。Oracle 會在 Oracle 支援文件中維護必要或建議修補程式的清單。
設定管理主控台,透過 dNFS 保護及掛載 Oracle 虛擬資料庫
如要執行以 dNFS 為基礎的備份作業,您必須將備份/復原裝置測試磁碟格式 (磁碟偏好設定) 設為 NFS。
請按照下列操作說明,將暫存磁碟格式 (磁碟偏好設定) 設為 NFS:
依序前往「管理」>「主機」。
在主機上按一下滑鼠右鍵,然後選取「編輯」。
在暫存磁碟格式中,選取「NFS」,然後按一下「儲存」。
在目標主機上執行的動作,以便 dNFS 運作
請執行下列操作,確保 dNFS 設定正確無誤:
請查看 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 版
在備份工作期間,執行下列查詢,檢查 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 用戶端的效能指標。
欄 | 說明 |
---|---|
SRVNAME
|
NFS 伺服器名稱 |
DIRNAME
|
由 NFS 伺服器匯出的磁碟區 |
MNTPORT
|
本機掛載埠 |
NFSPORT
|
NFS 伺服器通訊埠 |
WTMAX
|
NFS 伺服器的最大寫入大小 |
RTMAX
|
NFS 伺服器的最大讀取大小 |
欄 | 說明 |
---|---|
PNUM
|
Oracle 程序編號 (連結至 v$process 中的 PID) |
SVRNAME
|
NFS 伺服器名稱 |
PATH
|
前往伺服器的網路路徑 |
CH_ID
|
dNFS 管道 ID |
SVR_ID
|
dNFS 伺服器 ID |
SENDS
|
透過管道傳送「自上次選取後」的作業。 |
RECVS
|
透過管道接收自上次選取後的作業。 |
PINGS
|
自上次選取後,透過管道執行的 Ping 作業。 |
欄 | 說明 |
---|---|
FILENAME
|
檔案名稱。 |
FILESIZE
|
檔案大小。 |
PNUM
|
程序 ID (連結至 v$process 中的 PID) |
SRV_ID
|
NFS 伺服器 ID |
欄 | 說明 |
---|---|
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;