一次webservice连接数据库超时问题排查经历

      一、服务器环境:suse操作系统,IBM WebSphere,oracle数据库。平台有一个短信发布系统。平台内外网隔离,数据通过网闸同步。该webService用来提供其他系统短信发送以及查询短信状态使用。

        二、最初设计:其他系统调用接口-->插入短信管理表-->触发器生成短信发送表-->网闸同步到外网-->外网短信发送程序发送短信-->网闸将发送状态同步到内网短信发送表,再将短信发送管理表和短信发送表用视图关联将合适的数据返回给其他系统。

     补充:由于内外网隔离,采用第三方网闸软件,内网数据变动(增删改)时会同步到外网,外网有变动时也是同步到内网。

     三、历程

     开始测试时,当短信发送了20多条的时候开始出现没有收到短信,有的要大约30分钟才能收到。到数据库查看发现没有插入数据库。查看was日志发现有线程挂起,赶紧重启应用,was节点。后来多次观察发现有时候挂起的线程会释放,不过还是危险性太高,将整个平台弄瘫就不合算了。

     这块是自写了一个数据库连接池,代码如下:


private static DataSource setupDataSource() {

BasicDataSource bds = new BasicDataSource();
bds.setDriverClassName(DBDRIVER);
bds.setUrl(DBURL);
bds.setUsername(DBUSER);
bds.setPassword(DBPWD);
bds.setInitialSize(10);
bds.setMaxActive(30);
return bds;
}
       和同事讨论了一下,怀疑是吧数据库连接池用光了,但是还能用pl/sql连上数据库,那数据库连接应该是能用光。但是上面代码中红色部分总归是问题,每调用setupDataSource一次就就会产生一个新的连接池。因此将代码改为:

private static BasicDataSource bds = new BasicDataSource();

       static{

              bds.setDriverClassName(DBDRIVER);
              bds.setUrl(DBURL);
              bds.setUsername(DBUSER);
              bds.setPassword(DBPWD);
              bds.setInitialSize(10);
              bds.setMaxActive(30); 
       }
       
       public static DataSource setupDataSource() {
              return bds;
       }
问题依然存在,又看保存方法中connection为静态类成员变量又怕没有及时关掉或者并发太多时会串掉 ,又将connection改为方法变量,预料中问题依然存在,后来又改为was数据库连接池,修改为was连接池的时候又遇到一些问题,就是jndi的名字,本来配置的时候就没有jdbc/开头或者jndi/开头,又自作聪明的加上了,结果又报错没有找到was数据库连接池 。但是问题依然存在。

      此时感觉到可能是数据库方面的问题。又仔细看了日志,报

java.net.SocketInputStream.socketRead0

java.net.SocketInputStream.read

      网上有查了一下,晕,原来是数据库有死锁。结果仔细观察发现是网闸会时不时的放出一个锁,在更新时最为频繁,而且在其他系统新增后接着查询状态100%会报错,然后先将查询注释,虽然少了但是依然存在。一想查询的是视图,也就2个表关联,也不应该会这样。

      既然锁会对频繁操作有影响,而网闸又不可能又修改。只能牺牲短信的实时性,增加定时器,删除触发器。每2分钟从短信业务表中取数据插入短信发送表。总算没事了


       但是,半天之后又发现被锁死了。没办法只好又加入判断,如果有锁,则不做任何操作。虽然有时候要20min短信才发出去,但是至少线程挂起是没有了,而且短信都是通知类型的,延时也不影响。


      经过这次经历发现:

     1、看日志时一定要细心,如果第一次就发现数据库有锁, 就不会浪费大约3天时间(不是全天候,中途还有其他事处理)时间。

     2、对数据量连接池配置有了更深的了解

     3、最重要的是在系统设计初期,一定要弄清楚需求,考虑要长远。不能来一个需求加一个功能。这样会死人的。


     附加:

java连接was连接池代码:

public Static Connection getConn(){

    Connection con = null;

    DataSource ds = null;

    try{

         if(null==ctx){//ctx为类变量,定义 略

             try{

                  ctx=new InitialContext();

             }catch(NamingException e){e.preintStackTrace();}

         }

         try{

             ds=(DataSource)ctx.lookup("wasDateDB");

        }catch(NamingException e){e.preintStackTrace();}

        con=ds.getConnection();

   }catch(SQLException e){shutdownDataSource(ds);e.preintStackTrace();}

   return con

}

oracle查看锁

select  t2.username,t2.sid,t2.serial#,t2.logon_time 
 
from  v$locked_object t1,v$session t2 
where  t1.session_id = t2.sid  order   by  t2.logon_time;

杀锁:

alter system kill session 'sid,serial#';

如果大家有遇到过类似的问题请告知。谢谢!

猜你喜欢

转载自zhans52.iteye.com/blog/1064043