2017-07-17 119 views
0

我面临一个愚蠢的问题,但经过一段时间在线搜索和试验后,我开始失去希望。
感谢Dataguard,我有两个配置为副本的Oracle DB。
Oracle:JDBC TNS URL连接不会故障转移,因为侦听器仍然响应

我使用JDBC URL TNS连接到我的DB,如:

 
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. 转回可能无法正常工作,因为它使用的听众这样做

如果有人对于正确的配置有一个线索,我很感兴趣!

在此先感谢。

+0

你可以通过编程实现它,这很容易 - 捕捉一个异常并尝试另一个sid,这是一个想法。 –

+0

感谢您的建议。我宁愿避免编写代码,因为我在应用程序服务器中,并且正在使用连接池机制。编码意味着超载他们的代码,并可能失去支持。我没有试图做一些完全疯狂的事情,我很惊讶没有简单的方法来实现目前的工具。 – mbutton77

回答

0

经过长时间的努力找到一个合适的解决方案,我敢肯定这种机制强烈依赖于侦听器:只有侦听器停止,故障转移机制才能正常工作。
知道了,我终于决定实现我自己的解决方案,而无需触及应用程序代码。

由于我无法与原始听众一起玩,因为Dataguard使用它们来执行其操作,所以我复制了所有听众。 例如,对于在端口1521 LISTENER_DB1,我在端口创建LISTENER_DB1_FO(FO代表故障转移,你可能已经猜到了)1531

从应用的角度看我的配置就变成了:

 
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 export ORACLE_HOME=<YOUR_HOME> export ORACLE_BIN=$ORACLE_HOME/bin/ DATABASE_ROLE() { export ORACLE_SID=$1 request='SELECT DATABASE_ROLE FROM V$DATABASE' result=`$ORACLE_BIN/sqlplus -silent/as sysdba << EOF set pages 0 feedback off
${request}; exit EOF` echo ${result} } for DBNAME in DB1 DB2 DB3 do $ORACLE_BIN/lsnrctl status LISTENER_${DBNAME}_FO > /dev/null return_status=$? if [ "$(DATABASE_ROLE ${DBNAME})" != 'PRIMARY' ];then echo "DB ${DBNAME} is secondary" if [ $return_status -eq 0 ];then $ORACLE_BIN/lsnrctl stop LISTENER_${DBNAME}_FO fi else echo "DB ${DBNAME} is primary" if [ $return_status -eq 1 ];then $ORACLE_BIN/lsnrctl start LISTENER_${DBNAME}_FO fi fi done

然后我cronned该脚本。唯一的“缺点”是两个cron执行之间的最小间隔是一分钟。如果您不幸运,您的FailOver检测可能需要59秒才能检测到。

但我们已经测试了好几天,它的功能就像一个魅力。

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