我正在编写一个小程序,它将通过CGI在Apache Web服务器(而不是Tomcat)上启动,以响应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(?,?,?,?)}");
执行本身几乎立即完成。
为什么会这样?
P.S。:我在Windows7上进行了相同的实验。当然,它不是从Web服务器启动的,而是一个简单的控制台进程。它还必须从硬盘驱动器上的文件中读取xml。所有并发启动的程序实例都在一起完成。
是什么阻止它通过Apache在Linux上快速运行?
基于评论
我尝试为我的连接设置泳池属性,但都是徒劳的。我尝试了以下方法:
在网址
中指定UserId和密码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 Connection Pooling:
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 component:
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
。然而它更奇怪地工作:第一个请求在一秒钟内完成,而第二个请求延迟了分钟。
Poor concurrency with Oracle JDBC drivers陈述了与我类似的问题。
最后,我们发现Apache通过CGI启动的进程占用了所有100%的CPU(以及大部分内存),因此他们根本没有足够的资源。不幸的是,我不知道,为什么一个非常简单和基本的程序(读取xml并建立一个与DB的连接以执行存储过程)仅启动了20次,只吃了所有资源。
然而,解决方案确实非常明显。我已经使用servlet将它重构为一个java web应用程序,我们将它部署在Apache Tomcat和MAGIC上......它开始按预期工作,对资源没有任何明显的影响。
答案 0 :(得分:0)
我认为问题出在cgi上。当你发出cgi请求时,它会启动一个新的cpu进程来处理请求。每个新请求也在新的JVM中,因此连接池不是一个选项。
即便如此,获得连接也应该比这更快。也许在Oracle本身有配置选项可以控制你可以拥有的并发连接数,但我不是Oracle专家。