内容介绍
sqlnet是oracle提供的与网络层面交互的一个工具,比如如何解析客户端发起的连接,如何对客户端发起的连接进行辨别,如何对客户端连接进行阻隔限制,或者启用日志及跟踪(log and trace)功能等等一系列的功能,在以往的几期技术通讯录里面,我们也曾提到过通过sqlnet工具跟踪并分析oracle空闲回话中断的原因,本次我们继续通过sqlnet工具来详细的分析一次通过对tnsping的跟踪结果进行分析,查找为何外部网络无法连接数据库的原因。虽然说从很大程度上说,外部网络无法正常连接到数据库服务器,很大程度上都是因为网络问题造成的原因,无论是端口限制,安全加固等等,如果没有很好的考虑数据库方面的资源,往往会造成各种奇怪的连接问题。
故障说明
本次故障发生在一个客户的RAC环境中,客户的RAC环境一直采用的是只连接一号节点,二号节点一直没有连接,在最近的一次改造过程中,客户决定启用二号节点,于是调整了连接串,却发现客户端无法正常连接开放的二号节点上。应用和数据库处于同一个网段。IP通过主机层面的ping没有问题但是数据库连接却直接报错,tnsping连接串也返回报错信息:TNS-12537: TNS: 连接关闭。
故障分析
由于故障报错信息相对简单:TNS-12537: TNS: 连接关闭,往往这种报错涉及的原因也很多,比如windows下的监听日志达到4G限制,后续连接如果无法写监听日志,就会产生TNS-12537报错,再比如从11g开始Automatic Diagnostic Repository中的 Oracle Net diagnostic在默认的情况下是开启的,当数据库和客户端的连接超过特定时间,就会把这样的信息写入到alert日志中,但这并不是一个致命的问题,往往也不会造成tnsping不通这种结果。首先我们检查了数据库tnsping不通的节点的监听,发现没有问题,可以正常连接。我们检查了客户设置的连接串模式:
ORACLE_63 = (DESCRIPTION = (ADDRESS_LIST = (ADDRESS = (PROTOCOL = TCP)(HOST = 10.20.10.63)(PORT = 1521)) ) (CONNECT_DATA = (SID = xxxx2) ) ) ORACLE_157 = (DESCRIPTION = (ADDRESS_LIST = (ADDRESS = (PROTOCOL = TCP)(HOST = 10.20.10.157)(PORT = 1521)) ) (CONNECT_DATA = (SID = xxxx1) ) ) |
以上的连接串虽然说从连接模式上来说存在着一定的不合理性,没有真正发挥RAC应用的负载均衡的特点,但是从连接串的写法上来看,并没有任何问题。并且在测试环境上,该连接串也没有任何问题。
在检查过程中我们发现,从正常的一节点通过网络服务名连接到二节点不存在任何的问题,而从应用端发起连接就不行。到这一步,我们可以有一个大致的判断,数据库服务器层面不存在问题,两节点之间可以通过网络服务名连通对方。而通过外网交换机的应用网络却无法正常连接到数据库,所以我们有理由相信,问题出现的层面应该在网络层面,或者应用层面,但是应用可以正常的连接到一节点,考虑到二节点之前也没有连接应用,我们怀疑是否是集成商当初做安全加固将二节点的某些网络资源进行了限制,导致虽然IP能够ping通但是数据库却连不上。如果问题出现在网络层面,我们需要和网络人员沟通,至少我们需要可以拿出数据库层面关于网络问题的详细报错信息。既然问题出现在tnsping就已经不通了,那么我们尝试通过对tnsping进行详细的跟踪。
跟踪参数设置:
和连接跟踪一样,默认的tnsping也是关闭的,如果需要开启跟踪也同样是在客户端sqlnet.ora文件中编入参数:(因此你的客户端至少需要是完全安装版本的,简单绿色版的客户端不行)
TNSPING.TRACE_LEVEL=SUPPORT TNSPING.TRACE_DIRECTORY=d:\oracle\trace |
TNSPING.TRACE_LEVEL指的是跟踪的级别,SUPPORT为*别,该参数可选的级别包括:off,user,admin,support 一般来说既然是跟踪错误原因,个人觉得还是将细粒度调整到最大为好,越详细的日志,对于我们分析问题帮助越大。
TNSPING.TRACE_DIRECTORY指的是跟踪产生的trace文件存放的位置
编入以上参数,我们即可执行tnsping过程:
C:\Users\frank-ying>tnsping oracle_157 已使用 TNSNAMES 适配器来解析别名 Attempting to contact (DESCRIPTION = (ADDRESS_LIST = (ADDRESS = (PROTOCOL = TCP) (HOST = 10.20.10.157)(PORT = 1521))) (CONNECT_DATA = (SID = credit1))) TNS-12537: TNS: 连接关闭 |
结果获取后我们可以对文件进行分析,以下部分贴出整个跟踪文件结果集进行详细分析:
详细日志分析过程
########!跟踪文件头信息记录包括客户端信息,版本,跟踪时##################### TNS Ping Utility for 32-bit Windows: Version 10.2.0.1.0 - Production on 17-7月 -2014 08:52:31
Copyright (c) 1997, 2005, Oracle. All rights reserved. #######本次跟踪的信息读取,包括跟踪级别,基本的跟踪参数读取位置############## --- TRACE CONFIGURATION INFORMATION FOLLOWS --- New trace stream is d:\oracle\trace\tnsping.trc New trace level is 16 --- TRACE CONFIGURATION INFORMATION ENDS --- --- PARAMETER SOURCE INFORMATION FOLLOWS --- Attempted load of system pfile source D:\oracle\product\10.2.0\db_1\network\admin\sqlnet.ora Parameter source loaded successfully
-> PARAMETER TABLE LOAD RESULTS FOLLOW Successful parameter table load -> PARAMETER TABLE HAS THE FOLLOWING CONTENTS TNSPING.TRACE_LEVEL = SUPPORT NAMES.DIRECTORY_PATH = (TNSNAMES, EZCONNECT) TNSPING.TRACE_DIRECTORY = d:\oracle\trace SQLNET.AUTHENTICATION_SERVICES = (NTS) --- PARAMETER SOURCE INFORMATION ENDS --- --- LOG CONFIGURATION INFORMATION FOLLOWS --- Log stream will be "standard output" Log stream validation not requested --- LOG CONFIGURATION INFORMATION ENDS --- |
以上是整个跟踪文件的头文件,记录包括客户端信息,版本,跟踪时间,跟踪级别,基本的跟踪参数读取位置等信息。
#########################开始跟踪tnsping过程############################## nlstdipi: entry nlstdipi: exit nnfun2awanm: entry nnfgiinit: entry nncpcin_maybe_init: first request sent to name server will have ID 0 nncpcin_maybe_init: initial retry timeout for all name servers is 1500 csecs nncpcin_maybe_init: max request retries per name server is 1 nngsini_init_streams: initializing stream subsystem, cache size is 10 nngtini_init_msg: initializing PDU subsystem, initial pool size is 2 nncpcin_maybe_init: default name server domain is [root] nnfgiinit: Installing read path nnfgsrsp: entry ####################读取本地tnsnames.ora文件############################## nnfgsrsp: Obtaining path parameter from names.directory_path or native_names.directory_path nnfgsrdp: entry nnfgsrdp: Setting path: nnfgsrdp: checking element TNSNAMES nnfgsrdp: checking element EZCONNECT nnfgsrdp: Path set nnfun2a: entry nlolgobj: entry nnfgrne: entry nnfgrne: Going though read path adapters nnfgrne: Switching to TNSNAMES adapter nnftboot: entry nlpaxini: entry nlpaxini: exit nnftmlf_make_local_addrfile: entry nnftmlf_make_local_addrfile: construction of local names file failed nnftmlf_make_local_addrfile: exit nlpaxini: entry nlpaxini: exit nnftmlf_make_system_addrfile: entry nnftmlf_make_system_addrfile: system names file is D:\oracle\product\10.2.0\db_1\network\admin\tnsnames.ora nnftmlf_make_system_addrfile: exit nnftboot: exit nnftrne: entry ####获取本次需tnsping的连接串名,扫描整个tnsnames.ora文件匹配该连接串名#### nnftrne: Original name: oracle_157 nnfttran: entry nncpdpt_dump_ptable: --- D:\oracle\product\10.2.0\db_1\network\admin\tnsnames.ora TABLE HAS THE FOLLOWING CONTENTS --- nncpdpt_dump_ptable: load_balance = (DESCRIPTION = (ADDRESS = (PROTOCOL = TCP)(HOST = 10.20.10.157)(PORT = 1521)) (ADDRESS = (PROTOCOL = TCP)(HOST = 10.20.10.63)(PORT = 1521)) (LOAD_BALANCE = yes) (CONNECT_DATA = (SERVER = DEDICATED) (SERVICE_NAME = credit_server_taf) (FAILOVER_MODE = (TYPE = SELECT) (METHOD = BASIC) (RETRIES = 180) (DELAY = 5)))) nncpdpt_dump_ptable: balance = (DESCRIPTION = (ADDRESS = (PROTOCOL = TCP)(HOST = 10.20.10.157)(PORT = 1521)) (ADDRESS = (PROTOCOL = TCP)(HOST = 10.20.10.63)(PORT = 1521)) (LOAD_BALANCE = yes) (CONNECT_DATA = (SERVER = DEDICATED) (SERVICE_NAME = creditmanager) (FAILOVER_MODE = (TYPE = SELECT) (METHOD = BASIC) (RETRIES = 180) (DELAY = 5)))) nncpdpt_dump_ptable: --- END D:\oracle\product\10.2.0\db_1\network\admin\tnsnames.ora TABLE --- nnfttran: exit ############################结果正常获取################################## nnftrne: Using tnsnames.ora address (DESCRIPTION = (ADDRESS_LIST = (ADDRESS = (PROTOCOL = TCP)(HOST = 10.20.10.155)(PORT = 1521))) (CONNECT_DATA = (SID = credit1))) for name oracle_157 ######################解析连接串结果并开始跟踪############################ nsmal: 212 bytes at 0xee81d8 nsmal: normal exit nscall: connecting... nladini: entry nladini: exit nladget: entry nladget: exit nsc2addr: entry nsc2addr: (DESCRIPTION=(ADDRESS=(PROTOCOL=TCP)(HOST=10.20.10.155)(PORT=1521))(CONNECT_DATA=(SID=credit1))) nttbnd2addr: entry snlinGetAddrInfo: entry snlinGetAddrInfo: exit nttbnd2addr: using host IP address: 10.20.10.155(此处可以看到,配置的是实际地址,所以不用在去解析DNS或者分析hosts文件) nsmal: normal exit nsbal: normal exit nsiorini: exit (0) nscpxget: entry nscpxget: normal exit nsopenalloc_nsntx: nlhthput on mplx_ht_nsgbu:ctx=f32ef0, nsntx=f331d8 nsopenmplx: normal exit ########################开始创建连接###################################### nsopen: opening transport... nttcon: entry nttcon: toc = 1 nttcnp: entry nttcnp: creating a socket. nttcnp: exit nttcni: entry nttcni: trying to connect to socket 1808. snlinGetNameInfo: entry snlinGetNameInfo: Using numeric form of host's address 10.20.10.131 snlinGetNameInfo: exit nttcni: connected on ipaddr 10.20.10.131(解析本地IP地址) nttcni: exit nttcon: NT layer TCP/IP connection has been established.(TCP/IP协议) nttcon: set TCP_NODELAY on 1808 nttcon: exit ####################以下开始发包过程,发送87字节的包####################### nsdo: cid=0, opcode=67, *bl=29, *what=8, uflgs=0x0, cflgs=0x3 nsdo: rank=64, nsctxrnk=0 nsdo: nsctx: state=14, flg=0x4005, mvd=0 nsdo: gtn=10, gtc=10, ptn=10, ptc=2011 nscon: entry nscon: doing connect handshake... nscon: sending NSPTCN packet nspsend: entry nspsend: plen=87, type=1 nttwr: entry nttwr: socket 1808 had bytes written=87 nttwr: exit nspsend: packet dump nspsend: 00 57 00 00 01 00 00 00 |.W......| nspsend: 01 39 01 2C 00 00 08 00 |.9.,....| nspsend: 7F FF C6 0E 00 00 01 00 |........| nspsend: 00 1D 00 3A 00 00 00 00 |...:....| nspsend: 00 00 00 00 00 00 00 00 |........| nspsend: 00 00 00 00 00 00 00 00 |........| nspsend: 00 00 00 00 00 00 00 00 |........| nspsend: 00 00 28 43 4F 4E 4E 45 |..(CONNE| nspsend: 43 54 5F 44 41 54 41 3D |CT_DATA=| nspsend: 28 43 4F 4D 4D 41 4E 44 |(COMMAND| nspsend: 3D 70 69 6E 67 29 29 |=ping)) | nspsend: 87 bytes to transport(发包成功返回) nspsend: normal exit nscon: exit (0) nsdo: nsctxrnk=0 nsdo: normal exit nsdo: entry nsdo: cid=0, opcode=68, *bl=1024, *what=9, uflgs=0x2000, cflgs=0x3 nsdo: rank=64, nsctxrnk=0 nsdo: nsctx: state=2, flg=0x4005, mvd=0 nsdo: gtn=10, gtc=10, ptn=10, ptc=2011 nscon: entry ############################开始回包过程################################## nscon: recving a packet nsprecv: entry nsprecv: reading from transport... nttrd: entry ntt2err: entry ntt2err: soc 1808 error - operation=5, ntresnt[0]=530, ntresnt[1]=53, ntresnt[2]=0 ntt2err: exit nttrd: exit nsprecv: error exit nserror: entry nserror: nsres: id=0, op=68, ns=12570, ns2=12560; nt[0]=530, nt[1]=53, nt[2]=0; ora[0]=0, ora[1]=0, ora[2]=0 nscon: error exit nsdo: nsctxrnk=0 nsdo: error exit nscall: unexpected response 我们详细分析上面的报错过程,从目前来看,整个的发包过程没有问题,但是在包返回过程中,直接报错,返回错误ntt2err: soc 1808 error - operation=5, ntresnt[0]=530, ntresnt[1]=53, ntresnt[2]=0 从错误的信息看,应该是在网络层面出了问题,据此我们搜索了MOS相关文档: ORA-3113 reported when using NitroSecurity Firewall. (文档 ID 1388804.1) 该文档报错信息一致,原因是NitroSecurity防火墙的阻隔 通过对以上结果的分析,我们有理由确信在中间的网络层面出现了阻隔导致返回包的过程中出现了问题,就此将问题提交网络工程师
|
技术结论
从以上的分析结果看,sqlnet跟踪的分析过程其实并没有我们想像的那么复杂,tnsping通过解析主机及端口号,建立与数据库服务器的连接。通过一次发包及回包的过程来检测网络是否存在问题,本次分析我们更多的是为了分析tnsping的结果而分析,在真正实际环境中,大家可以从跟踪文件的最后开始倒推分析。往往这种连接问题,通过相应的跟踪日志,基本都能大致的分析出问题的成因所在。