如需将 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,请启用它: - 数据库主机上必须存在 NFS 客户端软件包,才能运行保护作业;任何 Oracle 主机上必须存在 NFS 客户端软件包,才能使用 dNFS 装载捕获的 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 库版本 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 [休眠时间]、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 客户端的性能指标。 
| 列 | 说明 | 
|---|---|
| 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;
Oracle DBA 指南
- 适用于 Oracle 数据库的 Backup and DR
- 保护 Oracle 数据库的前提条件
- Oracle 补丁和已知问题
- 准备 Oracle 数据库以进行保护
- 发现并保护 Oracle 数据库
- Oracle 数据库的详细信息和设置
- 将 dNFS 与 Backup and DR 搭配使用
- 保护发现的 Oracle 数据库
- 将 Oracle 数据库装载为标准装载
- 创建 Oracle 数据库的即时虚拟副本
- 恢复和还原 Oracle 数据库
- 使用装载和迁移功能即时恢复 Oracle 数据库
- 通过 Backup and DR 工作流预配环境