问题
前段时间,开发同事反应出应用程序在insert数据时出现
[com.eyou.reyun.controller.reyun.ReyunAndroidGameLogController%addGameLoginLog() 161 ] - Could not open JDBC Connection for transaction; nested exception is com.alibaba.druid.pool.GetConnectionTime outException: wait millis 10000, active 56, maxActive 800, creating 1, createElapseMillis 28926
分析
连接数据库异常。 查看当时的客户端接数也达到800+; 这个不正常。初步考虑是不是数据库被入侵;根据监听日志;去查看当天的连接情况。
awk -F"=" '/CONNECT_DATA/{print $10}' log.xml | awk -F')' '{a[$1]++}END{for(i in a)print i,a[i]}'
连接数据库都是应用程序的服务器; 有各个媒体的数据、自有SDK数据、以及服务器本地。 其中自有SDK所在的服务器有大量的连接。超过70%。
初步诊断是连接数不够;导致应用程序大量重复申请连接,数据库支撑不了这么大数据量;
- 单机Oracle数据库(主备模式)、未采用读写分离
- 主库有大量定时任务
- 配置相对比较差。服务器的CPU配置
vendor_id : GenuineIntel cpu family : 6 model : 62 model name : Intel(R) Xeon(R) CPU E5-2620 v2 @ 2.10GHz stepping : 4 cpu MHz : 2100.170 cache size : 15360 KB physical id : 0 siblings : 12 cpu cores : 6 cpuid level : 13
解决
先从数据库分析解决
1、增加连接数
目前Oracle数据库的最大连接数是1000;相对足够大了。因为Oracle是进程数据库;不像mysql那样能支持大量的客服端连接不像mysql那样能支持大量的客服端连接
在这需要吐槽下Oracle;连个连接池的中间件也找不到;是不是缴费了才有这服务。
2、解除限制非活跃回话
为啥应用程序会大量重复连接数据库呢?是限制非活跃回话超过多少分钟就自动断开
alter system set resource_file=FALSE;
3、取消外网监听、以及服务器上网
做了上面3步;上面ConnectionTimeoutException;没有出现;但是出现
socket() failed (24: Too many open files) while connecting to upstream
若单独百度查询;这个可能不管数据库的事;但是连接数还是没有降下来
4、查看哪些应用数据是否可以取消录入
核查后;发现有个游戏登录记录是CP方通过接口传递过来的;游戏登录数据自有SDK也是有的;只是没有角色信息。而推广平台未涉及到角色的层次的统计。
通过以上处理;在写个脚本监控下连接数
#!/bin/sh n=`ps -ef|grep oracleorcl | grep "LOCAL=NO" |wc -l` d=`date` echo "$d:$n" >> /home/oracle/log/oracle_p_num if [ $n -gt 900 ];then echo $n >> /home/oracle/killorcl.log ps -ef|grep oracleorcl | grep "LOCAL=NO" |awk '{system("kill -9 " $2)}' echo "$d" >> /home/oracle/killorcl.log fi
在 oracle_p_num 记录每分钟的统计; 观察下一周数据库连接数趋于平稳100左右;oracle晚上10点会做统计信息收集;最高不超过150的连接数。
拓展
最后:考虑后期公司游戏业务发展/上线;需重新规划下数据库架构;重新挑选下数据库服务器;将Oracle迁移到PostgreSQL12。采用读写分离模式(逻辑复制+hot standby+pgbouncer)
最近通过编写PostgreSQL存储过程有些心得;后期可考虑写一系列的PostgreSQL的存储过程教程。