問題背景:
????????用戶在客戶端服務器通過sqlplus通過scan ip登陸訪問數據庫時,偶爾會出現連接報錯ORA-12545: Connect failed because target host or object does not exist的情況。
?
問題分析:
????????首先,登陸到連接有問題的客戶端數據庫上,通過sqlplus進行多次連接測試,的確會出現用戶所說的ORA-12545: Connect failed because target host or object does not exist報錯現象,此外,還發現登陸成功的節點顯示的實例都是節點一實例servicedb1
?
????????檢查數據庫的listener_scan監聽配置,服務servicedb下動態注冊了(ready)兩個實例servicedb1以及servicedb2,沒有其他的配置實例
?
????????接下來,獲取客戶端連接報錯的具體trace信息,需要在客戶端的服務器的sqlnet.ora里面配置跟蹤參數,對客戶端的連接過程進行跟蹤
TRACE_LEVEL_CLIENT=16
TRACE_DIRECTORY_CLIENT=/tmp
TRACE_UNIQUE_CLIENT=ON
DIAG_ADR_ENABLED =OFF
????????配置完跟蹤參數之后,再一次通過sqlplus連接scan ip訪問數據庫,每一次登陸都會在/tmp目錄下面生成登陸的跟蹤trc文件cli_xxxx.trc ,打開發生ORA-12545:報錯時的trc文件
????????從trc文件里面,我們看到了發生解析主機錯誤(hostname lookup failure!)的主機連接地址nsc2addr: (ADDRESS=(PROTOCOL=TCP)(HOST=servicedb2)(PORT=1521))
????????該地址是客戶端在連接scan監聽之后,返回給客戶端的本地監聽服務連接地址,因為scan 監聽上的服務是數據庫通過遠程注冊進去的(remote?listener),客戶端在連接scan監聽上的服務之后,scan監聽會再把負載較小節點所在的本地監聽(local listener)地址返回給客戶端,客戶端再訪問這個監聽地址去連接數據庫
????????從這個返回報錯地址nsc2addr我們可以看到里面的地址信息host返回的是主機名而不是實際的IP地址,查看客戶端的/etc/hosts配置,可以看到只配置了節點一的主機名IP地址解析,并沒有配置節點二的主機名IP地址解析,也沒有配置dns去解析這個主機名,從而導致一旦scan 監聽分配到節點二給客戶端時就會出現了ORA-12545: Connect failed because target host or object does not exist的報錯,而分配到節點一客戶端可以連接成功,因為hosts里面有節點一的主機名IP地址解析
接下來繼續分析scan監聽返回的地址信息host為主機名的原因,查看數據庫的scan監聽的服務配置信息lsnrctl services listener_scan1
可以看到scan監聽下的服務servicedb注冊的實例servicedb1,servicedb2的遠程服務(remote server)地址的連接信息都是直接的服務器主機名(host=servicedb1)以及(host=servicedb2),不是實際的IP地址信息,這也是為什么客戶端接收到的地址nsc2addr里面不是IP地址信息的原因,因為數據庫注冊到scan監聽服務的連接信息是主機名形式
?
show parameter查看數據庫的動態注冊配置參數local listener,該參數表示實例節點所注冊的本地監聽地址,數據庫遠程注冊到scan監聽的服務會指向這個地址,我們可以看到由于參數local_listener的配置為空,因此數據庫注冊到scan監聽服務的連接信息host就是默認的服務器主機名
?
問題解決:
????????1 臨時解決方案,客戶端的/etc/hosts里面配置數據庫節點二主機的IP解析條目,需要注意的是,這個方式只是解決了該客戶端的訪問數據庫的問題,如果其他客戶端沒有配置hosts或者dns去解析數據庫服務器的主機名,依然會出現ORA-12545: Connect failed because target host or object does not exist的情況
????????2 完整解決方案,數據庫兩個節點動態注冊參數local_listener配置為兩個節點的VIP連接信息
節點一:(ADDRESS = (PROTOCOL=TCP)(HOST=xxx.xxx.xxx.13)(PORT=1521)),
節點二:(ADDRESS = (PROTOCOL=TCP)(HOST=xxx.xxx.xxx.74)(PORT=1521))
這樣返回給客戶端的是IP的形式而非主機名,全部客戶端就可以不用配置hosts或者dns去解析數據庫服務器的主機名
?
?
?