一,情况
1,发现问题
今天日常登录内部ERP系统,发现系统不能登录。
具体表现为:输入用户名和密码后,点击登录,系统没有响应。
2,系统表现
开始认为是ERP系统的程序出了问题,但登录应用服务器10.7之后发现,tomcat服务正常,ERP服务器进程运行正常,但日志不断出现新的报错信息。
查看日志,发现提示的都是数据库查询错误,因此判断是数据库问题。
- 本机使用PL/SQL工具连接数据库,进程进入假死状态,长期没有响应。
- 连接数据库服务器10.8,使用sqlplus登录数据库,可以正常登录。
- 本机使用PL/SQL工具,连接数据库,仍然出现程序假死的情况,没有响应。
- 由于昨天我在服务器上修改了memory_max_target和memory_target参数的值,从30G修改为20G,为了稳妥起见,先将服务器上的参数值再次改为了30G。
- 另外,由于10.8有一张网卡始终显示为 “正在识别 ”,因此将该网卡禁用了。
然而以上方式均没有起任何作用,还没有找到真正的问题。
百度发现可以使用tnsping命令测试服务器是否能够连接。
- 于是使用TNSPING,但没有结果,一直在等待。
C:\Users\Administrator>tnsping 192.168.10.8 orcl
TNS Ping Utility for 64-bit Windows: Version 11.2.0.1.0 - Production on 03-11月-2017 16:25:15
Copyright (c) 1997, 2010, Oracle. All rights reserved.
已使用的参数文件:
D:\app\Administrator\product\11.2.0\dbhome_1\network\admin\sqlnet.ora
已使用 EZCONNECT 适配器来解析别名
尝试连接 (DESCRIPTION=(CONNECT_DATA=(SERVICE_NAME=))(ADDRESS=(PROTOCOL=TCP)(HOST=192.168.10.8)(PORT=1521)))
tnsping常用格式
tnsping IP:PORT/SID tnsping IP SID
举例
tnsping 192.168.1.123:1521/oracle11g tnsping 192.168.1.123 oracle11g
tnsping:
如果能够ping通,则说明客户端能解析listener的机器名,而且lister也已经启动,但是并不能说明数据库已经打开。
但是如果不能用tnsping通,则肯定连接不到数据库。
注意:tsnping的过程与真正客户端连接的过程并不一致。
- 通过Windows服务管理器,重启所有Oracle相关服务,但仍然无法连接。
这时注意到,当重启监听器服务时,PL/SQL程序立即出现了报错信息,提示没有监听器错误。
联想到之前的表现,初步能够确定是Oracle监听器出了问题,但重启监听器服务,甚至直接重启服务器,但均没有能够解决这个问题。
3,结果
再次百度,发现有人提到监听器由于日志满了而无法工作,联想到以前黄老师讲过,Oracle系统日志满了会导致数据库服务无法启动的情况,意识到服务器10.8很可能也是这种情况。
登录10.8,找到监听器日志文件夹,打开发现,日志文件大小已经达到4G。
将文件剪切到其他地方,重启服务器,系统可以正常连接。
二,反思
4,事后诸葛亮
- 心态:保持冷静,小心操作
- 当问题出现时,一定要保持冷静,分析问题,在确定问题的原因之前,应当尽量避免对数据库的修改。
- 如果条件允许,应先对所有的数据文件、日志文件做好备份。
- 做任何操作之前,先想好该操作应如何回滚或对冲操作。
目的:避免数据库的小问题变成大问题。
- 排查:注重逻辑,思路明确
- 根据问题的外在表现、Oracle运行原理等,初步确定问题范围
- 不断缩小问题范围,最终定位问题
- 确定问题原因
以本次问题为例,问题表现为
1, 在数据库服务器上通过sqlplus可以连接数据库,并且查到数据库为正常运行状态
2, 无论是服务器,还是客户端,使用PL/SQL软件不能连接,表现为软件发起连接数据库后,一直没有响应
3, 在服务器上sqlplus的@orcl连接方式无法连接数据库
4,想要通过expdp方式导出数据库,但命令长期无响应,此时是使用username/password@SID的方式连接数据库的
5,改为username/password方式,可以导出数据
综上可以判断,是监听器出现了问题。
知识点
在数据库服务器上有4种方式运行sqlplus,需要不同的监听器和服务器状态1> sqlplus / as sysdba
1,不通过监听器,也不需要数据库处于运行状态
2> sqlplus username/password
2,不通过监听器,但需要数据库处于运行状态
3> sqlplus username/password@SID 4> sqlplus username/password@//host:port/sid 4(举例)> sqlplus userA/123@//192.168.100.100:1521/ORCL
3&4均通过网络连接,这时需要数据库服务器的listener处于监听状态,服务器需要处于运行状态。
此时建立一个连接的大致步骤如下
a. 查询sqlnet.ora,看看名称的解析方式,默认是TNSNAME
b. 查询tnsnames.ora文件,从里边找SID的记录,并且找到数据库服务器的主机名或者IP,端口和service_name
c. 如果服务器listener进程没有问题的话,建立与listener进程的连接。
d. 根据不同的服务器模式如专用服务器模式或者共享服务器模式,listener采取接下去的动作。默认是专用服务器模式,没有问题的话客户端就连接上了数据库的server process。
e. 这时连接已经建立,可以操作数据库了。而PL/SQL软件通常都是通过第4种方式连接服务器,需要监听器处于监听状态,数据库处于运行状态,才能连接数据库。
经百度,发现在Windows环境下,Oracle的日志如果达到4G大小,Oracle就会无法继续写日志,从而导致Oracle及其服务不能正常工作。
自身需要增加知识储备
- 对Oracle数据库的架构、运行机制有一定了解(监听器,数据库例程,客户端 / 服务器通话机制,后台进程工作原理等)
- 掌握查找问题的服务器状态指标、查找方法(命令、脚本等)
- Oracle日志的作用、位置,通过日志定位问题的方法
- 解决:解决问题,并尽可能避免再次发生
解决问题
- 通过oerr命令查看错误提示(Linux系统自带,Windows需要自己下载)
- 查看Oracle的相关技术文档(Oracle网站或下载到本地的文档)
- 通过搜索引擎,查找解决办法
避免问题再次发生
- 系统设置方面的错误,改为正确设置,定期检查
- 需要定期处理的问题(例如日志等),可以通过定时任务,按照规则对日志做处理(例如,定期复制到其他位置并按规则命名,原地重建空日志文件)
- 硬件问题(如磁盘空间不够等),需要定期检查或者自动报警等方式监控(如Nagios等),提前准备硬件设备。
5,Oracle监听器日志知识相关博客
博客作者:潇湘隐者(他的博客)
博客摘录:
要对监听日志文件(listener.log)进行定期清理,如果不定期清理,会遇到下面一些麻烦:
1:监听日志文件(listener.log)变得越来越大,占用额外的存储空间。(当然现在存储白菜价,不差那几G的空间。但是我们还是要本着工匠情怀,精益求精)
2:监听日志文件(listener.log)变得太大会带来一些问题:LISTENER.LOG日志大小不能超过2GB,超过会导致LISTENER监听器无法处理新的连接。
3:监听日志文件(listener.log)变得太大,给后续日志写入带来一些性能问题和麻烦。
4:在一个很大的监听日志文件(listener.log)中查找某一天或某一个错误,这个也会带来一些性能问题,查找起来也相当麻烦。所以应该定期对监听日志文件(listener.log)进行清理,另外一种说法叫截断日志文件。
关于截断监听日志,要注意一些问题。初学ORACLE的时候遇到一个错误的截断监听日志的,演示如下
[oracle@DB-Server log]$ mv listener.log listener.log.20150114 [oracle@DB-Server log]$ cp /dev/null listener.log [oracle@DB-Server log]$ more listener.log
这样截断监听日志(listener.log)后,监听服务进程(tnslsnr)并不会将新的监听信息写入listener.log,而是继续写入listener.log.20150114
规范正确的流程应该这么处理:
Step 1:首先停止监听服务进程(tnslsnr)记录日志。
[oracle@DB-Server log]$ lsnrctl set log_status off;
Step 2:将监听日志文件(listener.log)复制一份,以listener.log.yyyymmdd格式命名
[oracle@DB-Server log]$ cp listener.log listener.log.20150114
Step 3:将监听日志文件(listener.log)清空。清空文件的方法有很多
3.1 echo “” > filename 3.2 cp /dev/null 或 echo /dev/null > filename
Step 4:开启监听服务进程(tnslsnr)记录日志
[oracle@DB-Server log]$ lsnrctl set log_status on;
当然也可以直接移走监听日志文件(listener.log),数据库实例会自动创建一个listener.log文件。
% lsnrctl set log_status off % mv listener.log listener.yyyymmdd % lsnrctl set log_status on
这些操作应该通过shell脚本来处理,然后结合crontab作业定期清理、截断监听日志文件。例如网上的一个清理、截断监听日志文件的shell脚本。
rq=` date +"%d" ` cp $ORACLE_HOME/network/log/listener.log $ORACLE_BACKUP/network/log/listener_$rq.log su - oracle -c "lsnrctl set log_status off" cp /dev/null $ORACLE_HOME/network/log/listener.log su - oracle -c "lsnrctl set log_status on"
但这样的脚本还没有解决一个问题,就是截断的监听日志文件保留多久的问题。
比如我只想保留这些截断的监听日志一个月时间,我希望作业自动维护。不需要我去手工操作。
有这样一个脚本cls_oracle.sh可以完全做到这个,当然它还会归档、清理其它日志文件,例如告警文件(alert_sid.log)等等。功能非常强大。