Oracle :JDBC TNS URL 连接不会故障转移,因为侦听器仍在响应

Oracle : JDBC TNS URL Connection won't failover because listener still responding

我遇到了一个愚蠢的问题,但经过一段时间的在线搜索和试验后,我开始失去希望。
感谢 Dataguard,我有两个配置为副本的 Oracle 数据库。

我正在使用 JDBC TNS URL 连接到我的数据库,例如:

jdbc:oracle:thin:@
  (DESCRIPTION_LIST=
    (FAILOVER=on)
    (LOAD_BALANCE=off)
    (DESCRIPTION=
      (ADDRESS=
        (PROTOCOL=TCP)
        (HOST=DB1) primary
        (PORT=1521))
        (CONNECT_DATA=
          (SERVER=DEDICATED)
          (SID=MySID))
        )
    (DESCRIPTION=
      (ADDRESS=
        (PROTOCOL=TCP)
        (HOST=DB2) secondary
        (PORT=1521))
        (CONNECT_DATA=
          (SERVER=DEDICATED)
          (SID=MySID))
        )
    )

当我执行切换时,角色互换:DB1 成为次要的,DB2 成为主要的。 DB1 处于挂载状态。
到目前为止,还不错。

但是通过我的连接 URL,我希望从 DB2 获得一个连接,它成为主要连接,但由于 DB1 侦听器仍在运行,它表现得好像一切正​​常,我最终得到尝试在 DB1 上建立连接,这会导致以下错误:

ORA-01033: ORACLE initialization or shutdown in progress

如果我终止侦听器,则故障转移会起作用,并且我会从 DB2 获得连接。

但是 dataguard 的全部意义在于执行自动故障转移。
但是如果我被迫杀死监听器:

  1. 这不是我所期待的:)
  2. 切回可能不起作用,因为它使用侦听器来做到这一点

如果有人知道正确配置的线索,我很感兴趣!

提前致谢。

经过长时间的尝试找到合适的解决方案,我很确定这种机制强烈依赖于监听器:故障转移机制只有在监听器停止时才能正常工作 .
知道这一点后,我最终决定在不接触应用程序代码的情况下实现自己的解决方案。

由于我无法使用原始侦听器,因为 Dataguard 使用它们来执行其操作,所以我复制了所有侦听器。 例如,对于端口 1521 上的 LISTENER_DB1,我在端口 1531 上创建了 LISTENER_DB1_FO(FO 代表故障转移)。

从应用程序的角度来看,我的配置变为:

jdbc:oracle:thin:@
  (DESCRIPTION_LIST=
    (FAILOVER=on)
    (LOAD_BALANCE=off)
    (DESCRIPTION=
      (ADDRESS=
        (PROTOCOL=TCP)
        (HOST=DB1) primary
        (PORT=1531))
        (CONNECT_DATA=
          (SERVER=DEDICATED)
          (SID=MySID))
        )
    (DESCRIPTION=
      (ADDRESS=
        (PROTOCOL=TCP)
        (HOST=DB2) secondary
        (PORT=1531))
        (CONNECT_DATA=
          (SERVER=DEDICATED)
          (SID=MySID))
        )
    )

感谢在这方面帮了我一点忙的同事,我写了一个脚本来检查数据库角色是否为主(即使数据库处于挂载状态也能正常工作)。根据该答案,我的脚本将启动或停止关联的侦听器。

#! /bin/bash 导出 ORACLE_HOME=<YOUR_HOME> 导出 ORACLE_BIN=$ORACLE_HOME/bin/ DATABASE_ROLE() { 导出 ORACLE_SID=$1 请求='SELECT DATABASE_ROLE FROM V$DATABASE' 结果=`$ORACLE_BIN/sqlplus -静默/作为 sysdba << EOF 关闭第 0 页反馈<br> ${请求}; 出口 EOF` 回显${结果} } 对于 DB1 DB2 DB3 中的 DBNAME 做 $ORACLE_BIN/lsnrctl 状态 LISTENER_${DBNAME}_FO > /dev/null return_status=$? 如果 [ "$(DATABASE_ROLE ${DBNAME})" != 'PRIMARY' ];然后 回声 "DB ${DBNAME} is secondary" 如果 [ $return_status -eq 0 ]; 那么 $ORACLE_BIN/lsnrctl 停止 LISTENER_${DBNAME}_FO 菲 别的 回声 "DB ${DBNAME} is primary" 如果 [ $return_status -eq 1 ]; 那么 $ORACLE_BIN/lsnrctl 启动 LISTENER_${DBNAME}_FO 菲 菲 完毕

然后我创建了那个脚本。唯一的 "drawback" 是两次 cron 执行之间的最小间隔是一分钟。如果您不走运,您的故障转移检测可能需要 59 秒才能检测到。

但我们已经对其进行了几天的测试,它的效果非常好。

如果有人有正确的解决方案或更好的主意,请不要犹豫! 谢谢

可以在主备服务器上创建同名服务。可以使用服务名称修改连接。仅在当前主服务器上保持服务。