2017-07-17 120 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秒才能檢測到。

但我們已經測試了好幾天,它的功能就像一個魅力。

如果有人有正確的解決方案或更好的主意,請不要猶豫! 謝謝。