我正在编写一个小程序,它将通过 CGI 在 Apache Web 服务器(不是 Tomcat)上启动以响应 POST 请求。
该程序执行以下操作:
- 读取 xml,在请求中通过 http 发送
- 使用从 xml 中提取的数据在数据库中执行存储过程
- 返回存储过程的结果作为对 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 上快速运行?
根据评论
我试图为我的连接设置池属性,但都是徒劳的。我尝试了以下方法:
在 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);
我尝试使用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();
我尝试使用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 ......它开始按预期工作,对资源没有任何明显的影响。