繁体   English   中英

如何避免并发数据库查询的大延迟?

[英]How to avoid big delays on concurrent database queries?

我正在编写一个小程序,它将通过CGI在Apache Web服务器(而不是Tomcat)上启动,以响应POST请求。

该计划执行以下操作:

  1. 读取xml,通过http发送请求
  2. 使用从xml中提取的数据在数据库中执行存储过程
  3. 返回存储过程的结果作为对POST请求的响应

数据库是Oracle。 我使用jdbc OCI来访问它。

Class.forName("oracle.jdbc.OracleDriver");

String dbCS = "jdbc:oracle:oci:@//ip:port/service"

Connection conn = DriverManager.getConnection(dbCS, dbUserId, dbPwd);
CallableStatement cs = conn.prepareCall("{ call ? := my_pkg.my_sp(?,?,?,?)}");
cs.registerOutParameter(pReturnValue, OracleTypes.NUMBER);
cs.setInt("p1", p1);
cs.setString("p2", p2);
cs.setString("p3", p3);
cs.registerOutParameter("p_out", Types.VARCHAR);
try {
    cs.executeQuery();
    return cs.getString(pReqResponse);
} finally {
    try {
        cs.close();
   } catch (SQLException ex) {
        //....        
   }
}

在执行单个请求时,它工作正常(整个程序在2秒内完成)。 但是,如果我尝试一次发送多个POST请求,我会将所有这些请求停留一段时间,具体取决于请求的数量(对于10个请求,大约为10秒,对于15个请求,为15秒)。 )。

我试着估计,哪部分代码给了延迟。 它似乎是两行:

Connection conn = DriverManager.getConnection(dbConnectionString, dbUserId, dbPwd);
CallableStatement cs = conn.prepareCall("{ call ? := my_pkg.my_sp(?,?,?,?)}");

执行本身几乎立即完成。

为什么会这样?

PS:我在Windows7上进行了相同的实验。 当然,它不是从Web服务器启动的,而是一个简单的控制台进程。 它还必须从硬盘驱动器上的文件中读取xml。 所有并发启动的程序实例都在一起完成。

什么阻止它通过Apache在Linux上快速工作?


根据评论

我试图为我的连接设置池化属性,但都是徒劳的。 我尝试了以下方法:

  1. 在URL中指定UserId和Password

     jdbc:oracle:oci:login/password@//ip:port/service 

    我试图设置连接属性:

      Properties p = new Properties(); p.setProperty("Pooling", "true"); p.setProperty("Min Pool Size", "1"); p.setProperty("Max Pool Size", "10"); p.setProperty("Incr Pool Size", "4"); Connection conn = DriverManager.getConnection(dbConnectionString, p); 
  2. 我试图使用OCI连接池

      OracleOCIConnectionPool cpool = new OracleOCIConnectionPool(); cpool.setUser("user"); cpool.setPassword("pwd"); cpool.setURL(dbConnectionString); Properties p = new Properties(); p.put(OracleOCIConnectionPool.CONNPOOL_MIN_LIMIT, "1"); p.put(OracleOCIConnectionPool.CONNPOOL_MAX_LIMIT, "5"); p.put(OracleOCIConnectionPool.CONNPOOL_INCREMENT, "2"); p.put(OracleOCIConnectionPool.CONNPOOL_TIMEOUT, "10"); p.put(OracleOCIConnectionPool.CONNPOOL_NOWAIT, "true"); cpool.setPoolConfig(p); Connection conn = (OracleOCIConnection) cpool.getConnection(); 
  3. 我尝试使用apache DBCP组件

     basicDataSource = new BasicDataSource(); basicDataSource.setUsername("user"); basicDataSource.setPassword("pwd"); basicDataSource.setDriverClassName("oracle.jdbc.OracleDriver"); basicDataSource.setUrl(dbConnectionString); Connection conn = basicDataSource.getConnection(); 

行为保持不变,即所有并发请求中的getConnection都有很大的延迟。

所有这些尝试似乎都试图解决其他问题,因为在我的情况下,所有连接都是从不同的进程建立的,并且在不同进程之间管理来自一个池的连接看起来并不明显(我在这里错了吗?)。

我有什么选择? 或者我可能做错了什么? 另外我应该说,我对java很新,所以我可能会遗漏一些基本的东西..


这可能是操作系统或Web服务器问题吗? 可能应该在那里设置一些东西,而不是代码......?


我也尝试使用thin而不是oci 然而它更奇怪地工作:第一个请求在一秒钟内完成,而第二个请求延迟了一分钟


Oracle JDBC驱动程序的并发性差表明存在类似于我的问题。


最后,我们发现Apache通过CGI启动的进程占用了所有100%的CPU(以及大部分内存),因此它们根本没有足够的资源。 不幸的是我不知道,为什么一个非常简单和基本的程序(读取一个xml并建立一个与DB的连接来执行存储过程)启动simultanuosly只有20次,吃掉所有资源。

然而,解决方案确实非常明显。 我已经使用servlet将它重构为一个java Web应用程序,我们将它部署在Apache Tomcat和MAGIC上......它开始按预期工作,对资源没有任何明显的影响。

我认为问题在于cgi。 当你发出cgi请求时,它会启动一个新的cpu进程来处理请求。 每个新请求也在新的JVM中,因此连接池不是一个选项。

即使这样,它也应该比获得连接更快。 也许在Oracle本身有配置选项可以控制你可以拥有的并发连接数,但我不是Oracle专家。

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM