5

ここに環境があります:

  • Java5
  • Windows 上の Tomcat 6.0.18 で実行されている Web アプリケーション (バージョンは不明)
  • データベース: SQL Server 2008 R2
  • JDBC ドライバー: jTDS 1.2.5
  • 接続プール プロバイダー: C3P0 0.9.1.2

クライアントが抱えている問題をデバッグしようとしています。基本的に数週間ごとに、Web アプリケーションがサーバー上でロックアップし、アクセスできなくなります。再起動すると問題が解決します。さらに調査すると、すべてがロックされている理由は、すべてがデータベース接続が戻るのを待っているためであることがわかります。問題は C3P0 ではなく、SQL Server にある可能性が高いと思います。

私が信じているのは、C3P0 の「アイドル チェック クエリ」がハングしていることです。クエリは次のとおりです。

select * from c3p0_connection_test_table

このクエリが実行されているように見えますが、結果は返されません。これが私のスレッドダンプにあるものです。DefaultConnectionTester.activeCheckConnection()アイドルチェックであることに注意してください:

"com.mchange.v2.async.ThreadPoolAsynchronousRunner$PoolThread-#2" daemon prio=6 tid=0x0000000007c32000 nid=0x1250 runnable [0x000000001072f000]
   java.lang.Thread.State: RUNNABLE
    at java.net.SocketInputStream.socketRead0(Native Method)
    at java.net.SocketInputStream.read(SocketInputStream.java:129)
    at java.io.DataInputStream.readFully(DataInputStream.java:178)
    at java.io.DataInputStream.readFully(DataInputStream.java:152)
    at net.sourceforge.jtds.jdbc.SharedSocket.readPacket(SharedSocket.java:841)
    at net.sourceforge.jtds.jdbc.SharedSocket.getNetPacket(SharedSocket.java:722)
    - locked <0x000000016ac03f48> (a java.util.ArrayList)
    at net.sourceforge.jtds.jdbc.ResponseStream.getPacket(ResponseStream.java:466)
    at net.sourceforge.jtds.jdbc.ResponseStream.read(ResponseStream.java:103)
    at net.sourceforge.jtds.jdbc.ResponseStream.peek(ResponseStream.java:88)
    at net.sourceforge.jtds.jdbc.TdsCore.wait(TdsCore.java:3928)
    at net.sourceforge.jtds.jdbc.TdsCore.executeSQL(TdsCore.java:1045)
    - locked <0x000000016d965268> (a net.sourceforge.jtds.jdbc.TdsCore)
    at net.sourceforge.jtds.jdbc.JtdsStatement.executeSQLQuery(JtdsStatement.java:465)
    at net.sourceforge.jtds.jdbc.JtdsStatement.executeQuery(JtdsStatement.java:1301)
    at com.mchange.v2.c3p0.impl.DefaultConnectionTester.activeCheckConnection(DefaultConnectionTester.java:73)
    at com.mchange.v2.c3p0.impl.C3P0PooledConnectionPool$1PooledConnectionResourcePoolManager.testPooledConnection(C3P0PooledConnectionPool.java:374)
    at com.mchange.v2.c3p0.impl.C3P0PooledConnectionPool$1PooledConnectionResourcePoolManager.refurbishIdleResource(C3P0PooledConnectionPool.java:310)
    at com.mchange.v2.resourcepool.BasicResourcePool$AsyncTestIdleResourceTask.run(BasicResourcePool.java:1999)
    at com.mchange.v2.async.ThreadPoolAsynchronousRunner$PoolThread.run(ThreadPoolAsynchronousRunner.java:547)

しかし、このような単純なクエリがソケットからの読み取り時にハングアップする原因は何でしょうか? このテーブルは C3P0 によって完全に管理され、挿入/更新されないため、このテーブルにデータベース ロックが発生するとは考えていません。また、プールから接続を取得しようとして失敗した場合 (これがハングの原因である場合)、スタックトレースがどこかにあると予想されます。代わりに、将来のすべての接続要求がこの「アイドルチェック」が完了するのを待っているため、アプリがロックされているだけです。

「アイドルチェック」が完了するのを待っているスレッドの 1 つを次に示します。

    "http-80-3" daemon prio=6 tid=0x0000000007c33800 nid=0x122c in Object.wait() [0x000000001082d000]
   java.lang.Thread.State: WAITING (on object monitor)
    at java.lang.Object.wait(Native Method)
    at com.mchange.v2.resourcepool.BasicResourcePool.prelimCheckoutResource(BasicResourcePool.java:579)
    - locked <0x0000000167a88a60> (a com.mchange.v2.resourcepool.BasicResourcePool)
    at com.mchange.v2.resourcepool.BasicResourcePool.checkoutResource(BasicResourcePool.java:477)
    at com.mchange.v2.c3p0.impl.C3P0PooledConnectionPool.checkoutPooledConnection(C3P0PooledConnectionPool.java:525)
    at com.mchange.v2.c3p0.impl.AbstractPoolBackedDataSource.getConnection(AbstractPoolBackedDataSource.java:128)
    at org.springframework.orm.hibernate3.LocalDataSourceConnectionProvider.getConnection(LocalDataSourceConnectionProvider.java:81)
    at org.hibernate.jdbc.ConnectionManager.openConnection(ConnectionManager.java:446)
    at org.hibernate.jdbc.ConnectionManager.getConnection(ConnectionManager.java:167)
    at org.hibernate.jdbc.JDBCContext.connection(JDBCContext.java:142)
    at org.hibernate.transaction.JDBCTransaction.begin(JDBCTransaction.java:85)
    at org.hibernate.impl.SessionImpl.beginTransaction(SessionImpl.java:1354)
    at org.springframework.orm.hibernate3.HibernateTransactionManager.doBegin(HibernateTransactionManager.java:555)
    at org.springframework.transaction.support.AbstractPlatformTransactionManager.getTransaction(AbstractPlatformTransactionManager.java:371)
    at sun.reflect.GeneratedMethodAccessor105.invoke(Unknown Source)
    at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:25)
    at java.lang.reflect.Method.invoke(Method.java:597)
    at org.springframework.aop.support.AopUtils.invokeJoinpointUsingReflection(AopUtils.java:309)
    at org.springframework.aop.framework.ReflectiveMethodInvocation.invokeJoinpoint(ReflectiveMethodInvocation.java:183)
    at org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:150)
    at org.springframework.aop.interceptor.ExposeInvocationInterceptor.invoke(ExposeInvocationInterceptor.java:89)
    at org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:172)
    at org.springframework.aop.framework.JdkDynamicAopProxy.invoke(JdkDynamicAopProxy.java:202)
    at $Proxy15.getTransaction(Unknown Source)
    at org.springframework.transaction.interceptor.TransactionAspectSupport.createTransactionIfNecessary(TransactionAspectSupport.java:317)
    at org.springframework.transaction.interceptor.TransactionInterceptor.invoke(TransactionInterceptor.java:105)
    at org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:172)
    at org.springframework.aop.interceptor.ExposeInvocationInterceptor.invoke(ExposeInvocationInterceptor.java:89)
    at org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:172)
    at org.springframework.aop.framework.JdkDynamicAopProxy.invoke(JdkDynamicAopProxy.java:202)
    at $Proxy79.getCrowdProperties(Unknown Source)
    at com.jamasoftware.contour.gateway.crowd.CrowdSsoServices.autoLogin(Unknown Source)
    at com.jamasoftware.contour.security.AutoLoginServicesManager.autoLogin(Unknown Source)
    at org.springframework.security.ui.rememberme.RememberMeProcessingFilter.doFilterHttp(RememberMeProcessingFilter.java:74)
    at org.springframework.security.ui.SpringSecurityFilter.doFilter(SpringSecurityFilter.java:53)
    at org.springframework.security.util.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.java:390)
    at org.springframework.security.ui.AbstractProcessingFilter.doFilterHttp(AbstractProcessingFilter.java:277)
    at org.springframework.security.ui.SpringSecurityFilter.doFilter(SpringSecurityFilter.java:53)
    at org.springframework.security.util.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.java:390)
    at com.jamasoftware.contour.view.filter.CheckSetupFilter.doFilter(Unknown Source)
    at org.springframework.security.util.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.java:390)
    at org.springframework.security.context.HttpSessionContextIntegrationFilter.doFilterHttp(HttpSessionContextIntegrationFilter.java:235)
    at org.springframework.security.ui.SpringSecurityFilter.doFilter(SpringSecurityFilter.java:53)
    at org.springframework.security.util.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.java:390)
    at org.springframework.security.concurrent.ConcurrentSessionFilter.doFilterHttp(ConcurrentSessionFilter.java:99)
    at org.springframework.security.ui.SpringSecurityFilter.doFilter(SpringSecurityFilter.java:53)
    at org.springframework.security.util.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.java:390)
    at org.springframework.web.filter.CharacterEncodingFilter.doFilterInternal(CharacterEncodingFilter.java:88)
    at org.springframework.web.filter.OncePerRequestFilter.doFilter(OncePerRequestFilter.java:76)
    at org.springframework.security.util.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.java:390)
    at com.jamasoftware.contour.view.filter.ExpirationFilter.doFilter(Unknown Source)
    at org.springframework.security.util.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.java:390)
    at com.jamasoftware.contour.view.filter.GzipFilter.doFilter(Unknown Source)
    at org.springframework.security.util.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.java:390)
    at org.springframework.security.util.FilterChainProxy.doFilter(FilterChainProxy.java:175)
    at org.springframework.web.filter.DelegatingFilterProxy.invokeDelegate(DelegatingFilterProxy.java:237)
    at org.springframework.web.filter.DelegatingFilterProxy.doFilter(DelegatingFilterProxy.java:167)
    at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:235)
    at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:206)
    at org.apache.catalina.core.StandardWrapperValve.invoke(StandardWrapperValve.java:233)
    at org.apache.catalina.core.StandardContextValve.invoke(StandardContextValve.java:191)
    at org.apache.catalina.core.StandardHostValve.invoke(StandardHostValve.java:127)
    at org.apache.catalina.valves.ErrorReportValve.invoke(ErrorReportValve.java:102)
    at org.apache.catalina.core.StandardEngineValve.invoke(StandardEngineValve.java:109)
    at org.apache.catalina.connector.CoyoteAdapter.service(CoyoteAdapter.java:298)
    at org.apache.coyote.http11.Http11AprProcessor.process(Http11AprProcessor.java:864)
    at org.apache.coyote.http11.Http11AprProtocol$Http11ConnectionHandler.process(Http11AprProtocol.java:579)
    at org.apache.tomcat.util.net.AprEndpoint$Worker.run(AprEndpoint.java:1665)
    at java.lang.Thread.run(Thread.java:619)

C3P0 のソース コードを見ると、上部の 2 行:

at java.lang.Object.wait(Native Method)
at com.mchange.v2.resourcepool.BasicResourcePool.prelimCheckoutResource(BasicResourcePool.java:579)

...接続が「アイドルチェック」を待っているときにのみ発生します。

残念ながら、これはクライアントであり、ここで環境の正確な詳細を報告することはできません. しかし、次の電話で彼らに提案できることは何でも構いません。

更新

彼らのアプリケーションは今日もロックされました。これまでに試したことは次のとおりです。

  • 最新の jTDS ドライバー (1.2.5) に更新されました。
  • 接続文字列のプロパティを 300 に設定しsocketTimeoutましたが、ドライバーは 5 分後も socketRead0() でスタックしたままです。
  • アクティブ チェック クエリを「select * from c3p0_connection_test_table」から「select 1」に変更しました。
  • unreturnedConnectionTimeoutおよびdebugUnreturnedConnectionStackTracesプロパティを C3P0 に追加しました(ただし、これらは切断された接続をキャッチしません)。

設定したすべての C3P0 接続プロパティは次のとおりです。

    <property name="minPoolSize" value="1"/>
    <property name="maxPoolSize" value="30"/>
    <property name="acquireIncrement" value="3"/>
    <property name="automaticTestTable" value="c3p0_connection_test_table"/>
    <property name="idleConnectionTestPeriod" value="30"/>
    <property name="testConnectionOnCheckin" value="true"/>
    <property name="testConnectionOnCheckout" value="true"/>

アプリケーションがロックされている間に、アプリケーション ユーザーで SQL Server Management Studio にログインしようとしたところ、ログインできませんでした (通常のタイムアウト エラーだったと思います)。データベースは起動され、ポート 1433 でリッスンされていました (で確認済みtelnet)。これは、データベースへの接続の最大数に達したことを意味すると思います。ただし、それがこの問題の原因を特定するのに役立つかどうかはわかりません。

成功しなかったリード:

  • この人は、オペレーティング システムに問題があり、サーバー上の NIC カードの数に問題がある可能性があります。
  • 以下の回答者は、ここで jTDS の古いバージョンのバグを指摘しました

役立つ回答は、クライアントのマシンで何かを確認するように依頼するか、考えられる根本原因を指摘することができます。これを追跡するのに役立つ回答があれば、賞金を獲得できます。

4

4 に答える 4

2

最初のアイデア: 最新の jTDS バージョンを使用していることと、SQL Server にパッチが適用され、最新の SP に更新されていることを確認してください。

jTDS バグ追跡でこの種の動作に関する報告がいくつかありますが、最も顕著なのはこれです。どうやら SQL Server は接続を閉じようとしていますが、jTDS は気づきません。

jTDS の新しいバージョンにはsocketTimeout プロパティ(デフォルト = 0) があり、おそらくこれが役立ちます。

別の JDBC ドライバーをテストすることもできます。

于 2011-08-08T20:03:45.243 に答える
1

SQL サーバーで、プロパティ - 接続 - 「クエリ ガバナーを使用して実行時間の長いクエリを防止する」が無効になっていることを確認します。

于 2011-09-21T10:06:28.260 に答える
0

接続のテスト中に接続を閉じる別のスレッドもありましたか? c3p0-0.9.2-pre3 で C3P0 がこれを修正したようです:

-- PooledConnection.close() が接続テストと一致する場合に時折発生するデッドロックを防ぐために、これらの PooledConnections に関連付けられたロックを所有する PooledConnections の必須テスト。この問題に注意を喚起してくれた匿名の SourceForge ユーザーに感謝します。

から: https://github.com/swaldman/c3p0/blob/master/src/dist-static/CHANGELOG

于 2015-02-09T07:45:59.673 に答える
0

jtdsを使用してSQLサーバーに接続するときに、c3p0(0.9.1)がハングするという同様の問題に遭遇しました。

c3p0を使用せず、DriverManagerを使用して必要なときに接続を開くだけで解決しました。パフォーマンスはそれほど高くないと思いますが、機能します。

于 2011-09-06T15:16:39.860 に答える