4

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

该程序执行以下操作:

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

数据库是甲骨文。我使用 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很陌生,所以我可能会遗漏一些基本的东西..


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


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


Oracle JDBC 驱动程序的并发性差说明了与我的类似的问题。


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

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

4

1 回答 1

0

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

即便如此,建立连接应该比这更快。也许在 Oracle 本身中,有一些配置选项可以控制您可以拥有的并发连接数,但我不是 Oracle 专家。

于 2013-07-09T09:12:49.650 回答