核心架構理解

連線的本質與操作流程

Oracle的網路連線實際上是三層架構

  1. 客戶端命名解析 → 將服務名稱轉換為具體的伺服器位址
  2. Listener路由 → 負責接收連線請求並分配適當的伺服器程序
  3. 伺服器程序處理 → 執行實際的資料庫操作

實際操作驗證這個流程:

# 1. 測試命名解析
$ tnsping ORCLCDB
# 如果失敗,檢查 sqlnet.ora 的 NAMES.DIRECTORY_PATH 設定
 
# 2. 測試Listener狀態
$ lsnrctl status
$ lsnrctl services  # 查看已註冊的服務
 
# 3. 測試實際連線
$ sqlplus hr/password@ORCLCDB

1. 服務註冊

動態註冊的關鍵參數操作:

-- 檢查動態註冊關鍵參數
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_STATIC

2. 命名解析的完整配置流程

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
 

運作邏輯:

  1. 客戶端會隨機選擇其中一個地址進行連線(因為LOAD_BALANCE = ON
  2. 如果選中的地址連線失敗,Oracle Net會自動嘗試下一個地址
  3. 兩個地址都指向同一台主機(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 statistics

3. 客戶端通過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.log

3. 資料庫層診斷:

-- 檢查資料庫狀態
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

複習與問題

  1. PostgreSQL網路設置的對比實作
  2. sqlnet.ora跟cman.ora的區別
  3. dispatcher跟cman的關係