大家都知道,ORACLE实例在启动时,或使用命令ALTER SYSTEM REGISTER 或每隔一分钟,实例的PMON会向监听进行注册,告知监听,实例的服务名,实例名等信息。
不同的平台有不同的行为,本文所描述的是在LINUX下的行为。ORACLE版本为10.2.0.1。
讲到动态注册,跟监听密切相关,下面先看看监听的行为:
监听在启动时,会从$ORACLE_HOME/network/admin/listener.ora读取监听配置,如果该文件不存在,则监听会在主机名对应的IP和1521端口上进行监听。如果主机名在/etc/hosts里没有配置(或不能通过DNS解析---这是我的猜想,没有验证),则在等待较长一段时间后,将在所有的地址上(0.0.0.0:1521)进行监听,但此时实例并不会进行动态注册,客户端可通过主机的任意IP地址连接,但均会报ORA-12514错误。除非设置LOCAL_LISTENER参数,将本地LISTENER地址指向本机的任意一IP。
如果存在listener.ora文件,则监听会根据该文件配置内容进行启动。如果主机名在/etc/hosts没有条目,监听 启动比较慢(可能是监听起来后,在根据主机名作什么操作),因此必须要保证主机名要在/etc/hosts中有记录。
同一个网络接口(网卡)上,如果绑定了两个或以上的IP地址,则监听这样的网络接口时,最多只能使用一个主机名,比如:
[oracle@xty ~]$ cat /etc/hosts
# Do not remove the following line, or various programs
# that require network functionality will fail.
127.0.0.1 localhost.localdomain localhost
192.168.0.114 xty
192.168.0.115 xty_vip
192.168.0.116 xty_vip2
这里xty和xty_vip对应的IP绑定在同一网卡上
cat listener.ora
# Generated by Oracle configuration tools.
SID_LIST_LISTENER =
(SID_LIST =
(SID_DESC =
(SID_NAME = PLSExtProc)
(ORACLE_HOME = /u01/app/oracle/oracle/product/10.2.0/db_1)
(PROGRAM = extproc)
)
)
LISTENER =
(DESCRIPTION_LIST =
(DESCRIPTION =
(ADDRESS = (PROTOCOL = TCP)(HOST = xty_vip )(PORT = 1521))
(ADDRESS = (PROTOCOL = TCP)(HOST = xty )(PORT = 1521))
(ADDRESS = (PROTOCOL = TCP)(HOST = xty_vip2 )(PORT = 1521))
(ADDRESS = (PROTOCOL = IPC)(KEY = EXTPROC0))
)
)
启动监听时,报下面的错误:
TNSLSNR for Linux: Version 10.2.0.1.0 - Production
System parameter file is /u01/app/oracle/oracle/product/10.2.0/db_1/network/admi
n/listener.ora
Log messages written to /u01/app/oracle/oracle/product/10.2.0/db_1/network/log/l
istener.log
Listening on: (DESCRIPTION=(ADDRESS=(PROTOCOL=tcp)(HOST=192.168.0.115)(PORT=1521
)))
Error listening on: (DESCRIPTION=(ADDRESS=(PROTOCOL=TCP)(HOST=xty)(PORT=1521)))
TNS-12542: TNS:address already in use
TNS-12560: TNS:protocol adapter error
TNS-00512: Address already in use
Linux Error: 98: Address already in use
Listener failed to start. See the error message(s) above...
将listener.ora中的(ADDRESS = (PROTOCOL = TCP)(HOST = xty )(PORT = 1521))行,改为(ADDRESS = (PROTOCOL = TCP)(HOST = 192.168.0.114 )(PORT = 1521)),则监听能够正常启动
下面再来看一下PMON向监听注册实例的行为:
在缺省情况下(也就是没有LOCAL_LISTENER参数配置的情况下),PMON会根据主机名(hostname),查找其IP地址,通常是在/etc/hosts中找对应的条目,如果没有找到hostname的IP地址,则PMON不会注册,同时,必须是本机的IP地址,PMON才能注册。比如在/etc/hosts中将hostname对应的IP地址改为其他非本机的IP地址,PMON也不会进行注册。PMON根据hostname找到IP后,同时判断这个是本机IP,则会通过这个IP连接至监听进行注册。如果listener没有监听这个IP,则PMON也不会注册,因为通过这个IP连接不上监听。
举一个简单的例子,现有两台IBM小机,作双机热备,双机采用HACMP。在监听设置中,只监听了HA的服务IP地址,而hostname对应的IP地址为服务IP绑定的网卡上的另一个地址。在这种情况下,PMON不能进行动态注册,在客户端连接这个ORACLE服务器时,将会报ORA-12514错误。
解决上面提到的这个问题的办法,除了静态注册(本文主要讨论动态注册),还有两种办法,第一种我个人认为最好的一种,是在LISTENER上监听两个IP地址,类似于下面这样:
LISTENER =
(DESCRIPTION_LIST =
(DESCRIPTION =
(ADDRESS = (PROTOCOL = TCP)(HOST = xty_vip )(PORT = 1521))
(ADDRESS = (PROTOCOL = TCP)(HOST = 192.168.0.114 )(PORT = 1521))
(ADDRESS = (PROTOCOL = IPC)(KEY = EXTPROC0))
)
)
另一个办法就是设置LOCAL_LISTENER参数,假如LISTENER只监听了xty_vip(192.168.0.115)这个地址,则通过下面的命令设置LOCAL_LISTENER:
ALTER SYSTEM SET LOCAL_LISTENER=' (ADDRESS = (PROTOCOL = TCP)(HOST = 192.168.0.115 )(PORT = 1521))'
这里建议使用IP地址,特别是对RAC,后文细述。
LOCAL_LISTENER使PMON改变用hostname连接LISTENER进行注册的默认行为。改而用LOCAL_LISTENER参数指定的地址连接LISTENER进行注册。当然LOCAL_LISTENER指定的IP地址必须是本机的IP地址。如果是非本机IP,则会忽略此参数,但是会从前一个已注册的监听中取消注册。
与LOCAL_LISTENER对应的参数有REMOTE_LISTENER参数。REMOTE_LISTENER使PMON在远程(即非本机)监听上进行注册,这个参数在RAC中经常使用(用于负载均衡)。
下面来作一个测试:
主机1,LINUX AS4
主机2,Windows 2003,IP地址:192.168.0.100
,在主机2上启动监听:
D:\oracle\product\10.2.0\db_1\BIN>lsnrctl start
LSNRCTL for 32-bit Windows: Version 10.2.0.1.0 - Production on 02-2月 -2008 09:5
6:44
Copyright (c) 1991, 2005, Oracle. All rights reserved.
启动tnslsnr: 请稍候...
TNSLSNR for 32-bit Windows: Version 10.2.0.1.0 - Production
写入d:\oracle\product\10.2.0\db_1\network\log\listener.log的日志信息
监听: (DESCRIPTION=(ADDRESS=(PROTOCOL=tcp)(HOST=dreamf)(PORT=1521)))
正在连接到 (ADDRESS=(PROTOCOL=tcp)(HOST=)(PORT=1521))
LISTENER 的 STATUS
------------------------
别名 LISTENER
版本 TNSLSNR for 32-bit Windows: Version 10.2.0.1.0 - Produ
ction
启动日期 02-2月 -2008 09:56:47
正常运行时间 0 天 0 小时 0 分 3 秒
跟踪级别 off
安全性 ON: Local OS Authentication
SNMP OFF
监听程序日志文件 d:\oracle\product\10.2.0\db_1\network\log\listener
监听端点概要...
(DESCRIPTION=(ADDRESS=(PROTOCOL=tcp)(HOST=dreamf)(PORT=1521)))
监听程序不支持服务
命令执行成功
在主机1上启动监听:
[oracle@xty ~]$ lsnrctl start
LSNRCTL for Linux: Version 10.2.0.1.0 - Production on 01-FEB-2008 17:28:57
Copyright (c) 1991, 2005, Oracle. All rights reserved.
Starting /u01/app/oracle/oracle/product/10.2.0/db_1/bin/tnslsnr: please wait...
TNSLSNR for Linux: Version 10.2.0.1.0 - Production
System parameter file is /u01/app/oracle/oracle/product/10.2.0/db_1/network/admi
n/listener.ora
Log messages written to /u01/app/oracle/oracle/product/10.2.0/db_1/network/log/l
istener.log
Listening on: (DESCRIPTION=(ADDRESS=(PROTOCOL=tcp)(HOST=192.168.0.115)(PORT=1521
)))
Listening on: (DESCRIPTION=(ADDRESS=(PROTOCOL=tcp)(HOST=192.168.0.114)(PORT=1521
)))
Listening on: (DESCRIPTION=(ADDRESS=(PROTOCOL=ipc)(KEY=EXTPROC0)))
Connecting to (DESCRIPTION=(ADDRESS=(PROTOCOL=TCP)(HOST=xty_vip)(PORT=1521)))
STATUS of the LISTENER
------------------------
Alias LISTENER
Version TNSLSNR for Linux: Version 10.2.0.1.0 - Production
Start Date 01-FEB-2008 17:28:57
Uptime 0 days 0 hr. 0 min. 0 sec
Trace Level off
Security ON: Local OS Authentication
SNMP OFF
Listener Parameter File /u01/app/oracle/oracle/product/10.2.0/db_1/network/adm
in/listener.ora
Listener Log File /u01/app/oracle/oracle/product/10.2.0/db_1/network/log
/listener.log
Listening Endpoints Summary...
(DESCRIPTION=(ADDRESS=(PROTOCOL=tcp)(HOST=192.168.0.115)(PORT=1521)))
(DESCRIPTION=(ADDRESS=(PROTOCOL=tcp)(HOST=192.168.0.114)(PORT=1521)))
(DESCRIPTION=(ADDRESS=(PROTOCOL=ipc)(KEY=EXTPROC0)))
Services Summary...
Service "PLSExtProc" has 1 instance(s).
Instance "PLSExtProc", status UNKNOWN, has 1 handler(s) for this service...
The command completed successfully
[oracle@xty ~]$
然后在主机1上启动数据库。输入命令:
alter system set remote_listener='(ADDRESS=(PROTOCOL=tcp)(HOST=192.168.0.100)(PORT=1521))';
在主机2上查看LISTENER的状态
正在连接到 (ADDRESS=(PROTOCOL=tcp)(HOST=)(PORT=1521))
LISTENER 的 STATUS
------------------------
别名 LISTENER
版本 TNSLSNR for 32-bit Windows: Version 10.2.0.1.0 - Produ
ction
启动日期 02-2月 -2008 09:56:47
正常运行时间 0 天 0 小时 16 分 54 秒
跟踪级别 off
安全性 ON: Local OS Authentication
SNMP OFF
监听程序日志文件 d:\oracle\product\10.2.0\db_1\network\log\listener.log
监听端点概要...
(DESCRIPTION=(ADDRESS=(PROTOCOL=tcp)(HOST=dreamf)(PORT=1521)))
服务摘要..
服务 "XTY" 包含 1 个例程。
例程 "XTY1", 状态 READY, 包含此服务的 1 个处理程序...
服务 "XTY1XDB" 包含 1 个例程。
例程 "XTY1", 状态 READY, 包含此服务的 1 个处理程序...
服务 "XTY_XPT" 包含 1 个例程。
例程 "XTY1", 状态 READY, 包含此服务的 1 个处理程序...
命令执行成功
在主机2上再执行lsnrctl service命令:
D:\oracle\product\10.2.0\db_1\BIN>lsnrctl service
LSNRCTL for 32-bit Windows: Version 10.2.0.1.0 - Production on 02-2月 -2008 10:
5:21
Copyright (c) 1991, 2005, Oracle. All rights reserved.
正在连接到 (ADDRESS=(PROTOCOL=tcp)(HOST=)(PORT=1521))
服务摘要..
服务 "XTY" 包含 1 个例程。
例程 "XTY1", 状态 READY, 包含此服务的 1 个处理程序...
处理程序:
"DEDICATED" 已建立:0 已拒绝:0 状态:ready
REMOTE SERVER
(ADDRESS=(PROTOCOL=TCP)(HOST=xty)(PORT=1521))
服务 "XTY1XDB" 包含 1 个例程。
例程 "XTY1", 状态 READY, 包含此服务的 1 个处理程序...
处理程序:
"D000" 已建立:0 已被拒绝:0 当前: 0 最大: 1022 状态: ready
DISPATCHER <machine: xty, pid: 2996>
(ADDRESS=(PROTOCOL=tcp)(HOST=xty)(PORT=32801))
服务 "XTY_XPT" 包含 1 个例程。
例程 "XTY1", 状态 READY, 包含此服务的 1 个处理程序...
处理程序:
"DEDICATED" 已建立:0 已拒绝:0 状态:ready
REMOTE SERVER
(ADDRESS=(PROTOCOL=TCP)(HOST=xty)(PORT=1521))
命令执行成功
主机1上的实例已经成功注册到主机2上的监听
在主机2上的TNSNAMES.ORA中有:
XTY_R =
(DESCRIPTION =
(ADDRESS_LIST =
(ADDRESS = (PROTOCOL = TCP)(HOST = 192.168.0.100)(PORT = 1521))
)
(CONNECT_DATA =
(SERVICE_NAME = xty)
)
)
在主机2上连接XTY_R(这个实例实际运行在主机1上)
D:\oracle\admin\XJ\bdump>sqlplus test/test@xty_r
SQL*Plus: Release 9.2.0.1.0 - Production on 星期六 2月 2 10:19:41 2008
Copyright (c) 1982, 2002, Oracle Corporation. All rights reserved.
ERROR:
ORA-12535: TNS: 操作超时
请输入用户名:
报了ORA-12536错误。
从上面的lsnrctl service命令可以查看到REMOTE SERVER的地址为:
(ADDRESS=(PROTOCOL=TCP)(HOST=xty)(PORT=1521))
因此客户端连接时,LISTENER判断这是个远程SERVER,会将这个地址返回给客户,客户端再去连接这个地址。但这里HOST=xty,客户端不能解析这个地址,所以就报超时错误。
但如果在主机1上的数据库中执行下面的命令:
alter system set local_listener='(ADDRESS=(PROTOCOL=tcp)(HOST=192.168.0.115)(PORT=1521))';
我们再看看主机2上的LISTENER SERVICE:
正在连接到 (ADDRESS=(PROTOCOL=tcp)(HOST=)(PORT=1521))
服务摘要..
服务 "XTY" 包含 1 个例程。
例程 "XTY1", 状态 READY, 包含此服务的 1 个处理程序...
处理程序:
"DEDICATED" 已建立:0 已拒绝:0 状态:ready
REMOTE SERVER
(ADDRESS=(PROTOCOL=tcp)(HOST=192.168.0.115)(PORT=1521))
服务 "XTY1XDB" 包含 1 个例程。
例程 "XTY1", 状态 READY, 包含此服务的 1 个处理程序...
处理程序:
"D000" 已建立:0 已被拒绝:0 当前: 0 最大: 1022 状态: ready
DISPATCHER <machine: xty, pid: 2996>
(ADDRESS=(PROTOCOL=tcp)(HOST=xty)(PORT=32801))
服务 "XTY_XPT" 包含 1 个例程。
例程 "XTY1", 状态 READY, 包含此服务的 1 个处理程序...
处理程序:
"DEDICATED" 已建立:0 已拒绝:0 状态:ready
REMOTE SERVER
(ADDRESS=(PROTOCOL=tcp)(HOST=192.168.0.115)(PORT=1521))
命令执行成功
注意看到上面REMOTE SERVER已经变成了 (ADDRESS=(PROTOCOL=tcp)(HOST=192.168.0.115)(PORT=1521))
这个时候再次连接,由成功连接到ORACLE服务器上:
D:\oracle\admin\XJ\bdump>sqlplus test/test@xty_r
SQL*Plus: Release 9.2.0.1.0 - Production on 星期六 2月 2 10:39:25 2008
Copyright (c) 1982, 2002, Oracle Corporation. All rights reserved.
连接到:
Oracle Database 10g Enterprise Edition Release 10.2.0.1.0 - Production
With the Partitioning, OLAP and Data Mining options
SQL>
在RAC中,服务器开启了负载均衡,则客户端有时连接时会出现ORA-12514错误,这里需要设置LOCAL_LISTENER参数,以解决该问题。
注意:在通过REMOTE_LISTENER参数向远程监听注册时,本地的LISTENER也需要处于启动状态,否则监听中服务的状态为BLOCKED状态:
正在连接到 (ADDRESS=(PROTOCOL=tcp)(HOST=)(PORT=1521))
服务摘要..
服务 "XTY" 包含 1 个例程。
例程 "XTY1", 状态 READY, 包含此服务的 1 个处理程序...
处理程序:
"DEDICATED" 已建立:1 已拒绝:0 状态:blocked
REMOTE SERVER
(ADDRESS=(PROTOCOL=tcp)(HOST=192.168.0.115)(PORT=1521))
服务 "XTY1XDB" 包含 1 个例程。
例程 "XTY1", 状态 READY, 包含此服务的 1 个处理程序...
处理程序:
"D000" 已建立:0 已被拒绝:0 当前: 0 最大: 1022 状态: ready
DISPATCHER <machine: xty, pid: 2996>
(ADDRESS=(PROTOCOL=tcp)(HOST=xty)(PORT=32801))
服务 "XTY_XPT" 包含 1 个例程。
例程 "XTY1", 状态 READY, 包含此服务的 1 个处理程序...
处理程序:
"DEDICATED" 已建立:1 已拒绝:0 状态:blocked
REMOTE SERVER
(ADDRESS=(PROTOCOL=tcp)(HOST=192.168.0.115)(PORT=1521))
命令执行成功
而这个时候客户端连接报ORA-12516错误
另外,数据库实例版本必须与LISTENER版本兼容,否则不能进行动态注册。
本文主要是通过实验和分析网络包,然后进行总结的结果,没有参考相关的理论文档。有所错误在所难免,欢迎讨论。
listener