私は、POST 要求に応答して CGI を介して Apache Web サーバー (Tomcat ではない) で起動される小さなプログラムを作成しています。
プログラムは次のことを行います。
- リクエストで http 経由で送信された xml を読み取ります
- 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 秒です)。 )。
コードのどの部分が遅延したかを推定しようとしました。次の 2 行のように見えました。
Connection conn = DriverManager.getConnection(dbConnectionString, dbUserId, dbPwd);
CallableStatement cs = conn.prepareCall("{ call ? := my_pkg.my_sp(?,?,?,?)}");
実行自体はほぼ即座に終了しました。
これはなぜですか?
PS: Windows7 でも同じことを試しました。もちろん、これは Web サーバーから起動されたのではなく、単純なコンソール プロセスとして起動されました。また、ハード ドライブ上のファイルから xml を読み取る必要があります。プログラムの同時に起動されたすべてのインスタンスは、すべて一緒に 1 秒で終了しました。
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 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 コンポーネントを使用しようとしました:
basicDataSource = new BasicDataSource(); basicDataSource.setUsername("user"); basicDataSource.setPassword("pwd"); basicDataSource.setDriverClassName("oracle.jdbc.OracleDriver"); basicDataSource.setUrl(dbConnectionString); Connection conn = basicDataSource.getConnection();
getConnection
動作は同じままでした。つまり、すべての同時リクエストで大きな遅延が発生しました。
私の場合、すべての接続が別々のプロセスから確立されており、異なるプロセス間で 1 つのプールから接続を管理することは自明ではないように見えます (ここで間違っていますか??)。
どのようなオプションがありますか? または、おそらく私は何か悪いことをしましたか?また、私は一般的にJavaにまったく慣れていないので、いくつかの基本的なことが欠けている可能性があります..
これは OS または Web サーバーの問題でしょうか? おそらく、コードではなく、そこに何かを設定する必要があります...?
またthin
、代わりに clientを使用しようとしましたoci
。ただし、それはさらに奇妙に機能しました。最初のリクエストは 1 秒で完了し、2 番目のリクエストは 1分間遅延しました。
Oracle JDBC ドライバーとの並行性が低いと、私と同様の問題が発生します。
最終的に、CGI を介して Apache によって起動されたプロセスが CPU の 100% (およびメモリの大部分のシェア) をすべて占有していたため、十分なリソースがないことがわかりました。残念ながら、非常に単純で基本的なプログラム (xml を読み取り、DB への 1 つの接続を確立してストアド プロシージャを実行する) が同時に 20 回しか起動されず、すべてのリソースを消費する理由はわかりません。
しかし、解決策は確かに非常に明白であるように見えました。サーブレットを使用して Java Web アプリケーションにリファクタリングし、Apache Tomcat と MAGIC にデプロイしました。リソースに目に見える影響を与えることなく、期待どおりに動作し始めました。