经过长时间的尝试寻找合适的解决方案,我很确定这种机制强烈依赖于侦听器:故障转移机制只有在侦听器停止时才能正常工作。
知道了这一点,我最终决定实现自己的解决方案,而不涉及应用程序代码。
由于我无法使用原始侦听器,因为 Dataguard 使用它们来执行其操作,所以我复制了所有侦听器。例如,对于端口 1521 上的 LISTENER_DB1,我在端口 1531 上创建了 LISTENER_DB1_FO(FO 代表您可能已经猜到的故障转移)。
从应用程序的角度来看,我的配置变为:
jdbc:甲骨文:瘦:@
(DESCRIPTION_LIST=
(故障转移=开启)
(负载平衡=关闭)
(描述=
(地址=
(协议=TCP)
(HOST=DB1) 主
(端口= 1531 ))
(连接数据=
(服务器=专用)
(SID=我的SID))
)
(描述=
(地址=
(协议=TCP)
(HOST=DB2) 辅助
(端口= 1531 ))
(连接数据=
(服务器=专用)
(SID=我的SID))
)
)
感谢一位帮助我的同事,我编写了一个脚本来检查数据库角色是否是主要的(即使数据库处于挂载状态也可以工作)。从那个答案,我的脚本将启动或停止相关的侦听器。
#! /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 执行之间的最小间隔是一分钟。如果您不走运,您的故障转移检测可能需要 59 秒才能被检测到。
但我们已经对其进行了几天的测试,它就像一个魅力。
如果有人有正确的解决方案或更好的主意,请不要犹豫!谢谢。