核心架構理解
連線的本質與操作流程
Oracle的網路連線實際上是三層架構:
- 客戶端命名解析 → 將服務名稱轉換為具體的伺服器位址
- Listener路由 → 負責接收連線請求並分配適當的伺服器程序
- 伺服器程序處理 → 執行實際的資料庫操作
實際操作驗證這個流程:
# 1. 測試命名解析
$ tnsping ORCLCDB
# 如果失敗,檢查 sqlnet.ora 的 NAMES.DIRECTORY_PATH 設定
# 2. 測試Listener狀態
$ lsnrctl status
$ lsnrctl services # 查看已註冊的服務
# 3. 測試實際連線
$ sqlplus hr/password@ORCLCDB1. 服務註冊
動態註冊的關鍵參數操作:
-- 檢查動態註冊關鍵參數
SQL> SHOW PARAMETER instance_name
SQL> SHOW PARAMETER service_names
SQL> SHOW PARAMETER local_listener
-- 檢查LREG程序運作
SQL> SELECT name, description FROM v$bgprocess WHERE name = 'LREG';
-- 手動觸發服務註冊
SQL> ALTER SYSTEM REGISTER;靜態註冊的實作範例:
# 編輯 listener.ora
$ vi $ORACLE_HOME/network/admin/listener.ora
# 添加靜態註冊設定
LISTENER_STATIC =
(DESCRIPTION_LIST =
(DESCRIPTION =
(ADDRESS = (PROTOCOL = TCP)(HOST = hostname)(PORT = 1561))
)
)
SID_LIST_LISTENER_STATIC =
(SID_LIST =
(SID_DESC =
(GLOBAL_DBNAME = PDB1.example.com)
(SID_NAME = ORCLCDB)
(ORACLE_HOME = /u01/app/oracle/product/19.3.0/dbhome_1)
)
)
# 重新載入listener設定
$ lsnrctl reload LISTENER_STATIC2. 命名解析的完整配置流程
1. Easy Connect 的實際使用:
# 基本語法
$ sqlplus username/password@hostname:1521/service_name
# 實際範例
$ sqlplus hr/hr@edvmr1p0.us.oracle.com:1521/ORCLCDB
# 檢查是否啟用Easy Connect
$ cat $ORACLE_HOME/network/admin/sqlnet.ora
NAMES.DIRECTORY_PATH= (TNSNAMES, EZCONNECT)2. Local Naming (tnsnames.ora) 的標準配置:
# 備份現有設定
$ cd $ORACLE_HOME/network/admin
$ cp tnsnames.ora tnsnames.ora.backup
# 使用Oracle Net Manager建立新服務
$ netmgr
# 或手動編輯
$ vi tnsnames.ora
# 標準的tnsnames.ora條目
TESTORCL =
(DESCRIPTION =
(ADDRESS_LIST =
(ADDRESS = (PROTOCOL = TCP)(HOST = edvmr1p0.us.oracle.com)(PORT = 1521))
)
(CONNECT_DATA =
(SERVER = DEDICATED)
(SERVICE_NAME = CDBTEST)
)
)
# 測試設定
$ tnsping TESTORCL
$ sqlplus hr/password@TESTORCL高可用性配置範例:
# 具備故障轉移的tnsnames.ora
PROD_HA =
(DESCRIPTION =
(ADDRESS_LIST =
(ADDRESS = (PROTOCOL = TCP)(HOST = server1)(PORT = 1521))
(ADDRESS = (PROTOCOL = TCP)(HOST = server2)(PORT = 1521))
)
(CONNECT_DATA =
(SERVICE_NAME = PRODDB)
(FAILOVER_MODE =
(TYPE = SELECT)
(METHOD = BASIC)
(RETRIES = 180)
(DELAY = 5)
)
)
)多Listener環境的實務管理
建立第二個Listener的完整流程:
# 1. 修改tnsnames.ora添加新listener別名
LISTENER2 =
(ADDRESS = (PROTOCOL = TCP)(HOST = edvmr1p0.us.oracle.com)(PORT = 1561))
# 2. 修改初始化參數
SQL> ALTER SYSTEM SET local_listener="LISTENER_ORCLCDB,LISTENER2";
# 3. 使用Oracle Net Manager配置listener.ora
$ netmgr
# 或手動編輯listener.ora
# 4. 啟動新listener
$ lsnrctl start LISTENER2
# 5. 驗證服務註冊
$ lsnrctl services LISTENER2
# 6. 測試負載分散
$ sqlplus hr/password@service_using_listener2附載平衡配置
DESCRIPTION =
ADDRESS_LIST =
ADDRESS 1: lnka2:1522 (COMMUNITY = tcp.world)
ADDRESS 2: lnka2:1521 (COMMUNITY = tcp.world)
LOAD_BALANCE = ON
CONNECT_DATA = SID = lnka2
運作邏輯:
- 客戶端會隨機選擇其中一個地址進行連線(因為
LOAD_BALANCE = ON) - 如果選中的地址連線失敗,Oracle Net會自動嘗試下一個地址
- 兩個地址都指向同一台主機(lnka2),只是埠號不同(1522和1521)
效能最佳化的具體實作
共享伺服器的完整配置
1. 資料庫端配置:
-- 檢查現有設定
SQL> SHOW PARAMETER shared_servers
SQL> SHOW PARAMETER dispatchers
-- 啟用共享伺服器
SQL> ALTER SYSTEM SET shared_servers = 3;
SQL> ALTER SYSTEM SET dispatchers = "(PROTOCOL=TCP)";
-- 驗證dispatcher啟動
SQL> SELECT name, status FROM v$dispatcher;
SQL> SELECT servers_started, servers_terminated FROM v$shared_server;2. 客戶端配置:
# 在tnsnames.ora中配置共享伺服器連線
TEST_SS =
(DESCRIPTION=
(ADDRESS_LIST =
(ADDRESS=(PROTOCOL=tcp)(HOST=edvmr1p0.us.oracle.com)(PORT=1521))
)
(CONNECT_DATA=
(SERVICE_NAME=ORCLCDB)
(SERVER=shared)
)
)
# 測試共享伺服器連線
$ sqlplus system/password@TEST_SS
# 驗證使用共享伺服器
SQL> SELECT username, server FROM v$session WHERE username = 'SYSTEM';3. 效能監控:
-- 監控共享伺服器效能
SQL> SELECT * FROM v$queue WHERE type = 'DISPATCHER';
SQL> SELECT * FROM v$shared_server_monitor;
-- 調整共享伺服器數量
SQL> ALTER SYSTEM SET shared_servers = 5;Connection Manager的企業級部署
cman.ora的實戰配置
1. 建立完整的cman.ora:
# 建立必要目錄
$ mkdir -p /u01/app/oracle/cman/log
$ mkdir -p /u01/app/oracle/cman/trace
# 配置cman.ora
$ vi $ORACLE_HOME/network/admin/cman.ora
cman_localhost =
(configuration=
(address=(protocol=tcp)(host=localhost)(port=1522))
(rule_list=
(rule=(src=*)(dst=localhost)(srv=*)(act=accept))
)
(parameter_list=
(log_directory=/u01/app/oracle/cman/log)
(trace_directory=/u01/app/oracle/cman/trace)
(log_level=2)
(max_gateway_processes=8)
(min_gateway_processes=3)
)
)2. Connection Manager的操作管理:
# 啟動Connection Manager
$ cmctl start cman_localhost
# 檢查狀態
$ cmctl show status
$ cmctl show address
# 停止特定程序
$ cmctl stop cm # 只停止gateway程序
$ cmctl stop adm # 只停止admin程序
# 檢視連線統計
$ cmctl show statistics3. 客戶端通過Connection Manager連線:
# tnsnames.ora設定
FINANCE_CMAN =
(DESCRIPTION=
(ADDRESS=(PROTOCOL=tcp)(HOST=localhost)(PORT=1522))
(CONNECT_DATA=(SERVICE_NAME=ORCLCDB))
)
# 測試連線
$ sqlplus hr/password@FINANCE_CMAN故障診斷的系統化方法
分層診斷的具體步驟
1. 網路層診斷:
# 基礎連通性測試
$ ping hostname
$ telnet hostname 1521
# 檢查埠號使用情況
$ netstat -tulpn | grep 1521
$ lsof -i :1521 # Linux系統2. Oracle層診斷:
# 檢查Oracle環境變數
$ echo $ORACLE_HOME
$ echo $TNS_ADMIN
$ . oraenv # 確保環境設定正確
# 命名解析測試
$ tnsping service_name
# Listener診斷
$ lsnrctl status LISTENER
$ lsnrctl services LISTENER
# 查看Listener日誌
$ tail -f $ORACLE_BASE/diag/tnslsnr/hostname/listener/trace/listener.log3. 資料庫層診斷:
-- 檢查資料庫狀態
SQL> SELECT status FROM v$instance;
SQL> SELECT name, open_mode FROM v$database;
-- 檢查會話和程序
SQL> SELECT count(*) FROM v$session;
SQL> SELECT count(*) FROM v$process;
SQL> SHOW PARAMETER processes;
-- 檢查服務註冊
SQL> SELECT name, value FROM v$parameter
WHERE name IN ('service_names', 'local_listener');4. 常見錯誤的具體解決方案:
# TNS-12154: 無法解析指定的連線ID
# 解決步驟:
$ cat $ORACLE_HOME/network/admin/sqlnet.ora # 檢查NAMES.DIRECTORY_PATH
$ cat $ORACLE_HOME/network/admin/tnsnames.ora # 檢查服務名稱是否存在
$ tnsping service_name # 測試解析
# TNS-12541: TNS沒有監聽器
# 解決步驟:
$ lsnrctl status # 檢查listener是否啟動
$ ps -ef | grep tnslsnr # 檢查listener程序
$ lsnrctl start LISTENER # 啟動listener
# ORA-12520: TNS監聽器找不到可用的處理程序
# 解決步驟:
SQL> SHOW PARAMETER processes;
SQL> SELECT count(*) FROM v$process;
SQL> ALTER SYSTEM SET processes = 300 SCOPE=SPFILE; -- 需要重啟
-- 或考慮使用共享伺服器監控與維護的自動化腳本
Oracle網路監控腳本範例
Listener狀態檢查腳本:
#!/bin/bash
# listener_check.sh
ORACLE_HOME=/u01/app/oracle/product/19.3.0/dbhome_1
export ORACLE_HOME
export PATH=$ORACLE_HOME/bin:$PATH
LISTENER_NAME=${1:-LISTENER}
# 檢查listener狀態
lsnrctl status $LISTENER_NAME > /tmp/listener_status.txt 2>&1
if grep -q "no listener" /tmp/listener_status.txt; then
echo "$(date): Listener $LISTENER_NAME is down, attempting to start..."
lsnrctl start $LISTENER_NAME
if [ $? -eq 0 ]; then
echo "$(date): Listener $LISTENER_NAME started successfully"
else
echo "$(date): Failed to start listener $LISTENER_NAME"
exit 1
fi
else
echo "$(date): Listener $LISTENER_NAME is running"
fi
# 檢查註冊的服務數量
SERVICES=$(lsnrctl services $LISTENER_NAME | grep "Service" | wc -l)
echo "$(date): $LISTENER_NAME has $SERVICES registered services"連線測試腳本:
#!/bin/bash
# connection_test.sh
SERVICES="ORCLCDB ORCLPDB1 ORCLPDB2"
USERNAME="system"
PASSWORD="password"
for SERVICE in $SERVICES; do
echo "Testing connection to $SERVICE..."
sqlplus -s $USERNAME/$PASSWORD@$SERVICE <<EOF > /dev/null 2>&1
SELECT 1 FROM dual;
EXIT;
EOF
if [ $? -eq 0 ]; then
echo "$(date): Connection to $SERVICE successful"
else
echo "$(date): Connection to $SERVICE failed"
fi
done