2011-11-18 12 views
5

Mam aplikację Java EE uruchomioną na Glassfish i łączącą się z MSSQL Server 2008 poprzez jTDS. Z nieznanego powodu połączenie z bazą danych zostaje nieoczekiwanie zamknięte podczas żądań. Aplikacja jest ogromna, ale tutaj znajduje się podsumowanie tego, jak wystąpił błąd:Połączenie z bazą danych nieoczekiwanie zamknęło się przez Glassfish, jTDS i SQL Server 2008

Podczas konfiguracji Glassfish, z utworzeniem puli połączeń z asadmin create-jdbc-connection-pool i asadmin create-jdbc-resource. Klasa źródła danych to net.sourceforge.jtds.jdbcx.JtdsDataSource.

Kiedy Glassfish idzie w górę, wywołuje naszą implementację ServletContextListener.contextInitialized(), gdzie pobieramy źródło danych z JNDI. Źródło danych jest przechowywane na zmiennej statycznej.

Przez chwilę wszystko idzie dobrze. Wszystkie żądania są obsługiwane, a żadne połączenie nie jest zamykane. Nasza aplikacja wykonuje przetwarzanie przy użyciu modułów EJB Timera i MDB (Message Driven Bean).

To jest przykład onMessage() realizacja:

public void onMessage(Message message) { 
    this.message = message; 
    this.connection = dataSource.getConnection(userName, password); 
    try { 
    doQuery1(); 
    doTransaction1(); 
    doTransaction2(); 
    doQuery2(); 
    doQuery3(); 
    } finally { 
    this.connection.close(); 
    this.connection = null; 
    } 
} 

końcu zaczynamy się następujący wyjątek (zdarza się około 100 razy w ciągu jednej godziny):

java.sql.SQLException: Invalid state, the Connection object is closed. 
    at net.sourceforge.jtds.jdbc.ConnectionJDBC2.checkOpen(ConnectionJDBC2.java) 
    at net.sourceforge.jtds.jdbc.ConnectionJDBC2.prepareStatement(ConnectionJDBC2.java) 
    at net.sourceforge.jtds.jdbc.ConnectionJDBC2.prepareStatement(ConnectionJDBC2.java) 
    at com.sun.gjc.spi.base.ConnectionHolder.prepareStatement(ConnectionHolder.java:475) 
    at com.acme.myejbs.MyMDB.doQuery2(MyMDB.java:123) 
    at com.acme.myejbs.MyMDB.onMessage(MyMDB.java:614) 
    at sun.reflect.GeneratedMethodAccessor115.invoke(Unknown Source) 
    at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java) 
    at java.lang.reflect.Method.invoke(Method.java) 
    at com.sun.enterprise.security.application.EJBSecurityManager.runMethod(EJBSecurityManager.java:1011) 
    ... 
    at $Proxy92.onMessage(Unknown Source) 
    at com.sun.messaging.jms.ra.OnMessageRunner.run(OnMessageRunner.java) 
    at com.sun.enterprise.connectors.work.OneWork.doWork(OneWork.java:77) 
    at com.sun.corba.ee.impl.orbutil.threadpool.ThreadPoolImpl$WorkerThread.run(ThreadPoolImpl.java:555) 

Wyjątkiem dzieje się losowo JDBC połączenia. Czasami jest podczas iteracji ResultSet, innym razem podczas wykonywania kwerendy.

w bardzo rzadkich przypadkach (7 razy w ciągu godziny) otrzymujemy ten wyjątek:

java.sql.SQLException: Error in allocating a connection. Cause: This Managed Connection is not valid as the phyiscal connection is not usable 
    at com.sun.gjc.spi.base.DataSource.getConnection(DataSource.java:136) 
    at com.acme.myejbs.MyMDB.onMessage(MyMDB.java:614) 
    at sun.reflect.GeneratedMethodAccessor115.invoke(Unknown Source) 
    at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java) 
    at java.lang.reflect.Method.invoke(Method.java) 
    at com.sun.enterprise.security.application.EJBSecurityManager.runMethod(EJBSecurityManager.java:1011) 
    ... 
    at $Proxy92.onMessage(Unknown Source) 
    at com.sun.messaging.jms.ra.OnMessageRunner.run(OnMessageRunner.java) 
    at com.sun.enterprise.connectors.work.OneWork.doWork(OneWork.java:77) 
    at com.sun.corba.ee.impl.orbutil.threadpool.ThreadPoolImpl$WorkerThread.run(ThreadPoolImpl.java:555) 

również w bardzo rzadkich przypadkach (5 razy w ciągu godziny) otrzymujemy ten wyjątek:

java.sql.SQLException: I/O Error: Connection reset by peer: socket write error 
    at net.sourceforge.jtds.jdbc.TdsCore.executeSQL(TdsCore.java) 
    at net.sourceforge.jtds.jdbc.JtdsStatement.executeSQLQuery(JtdsStatement.java) 
    at net.sourceforge.jtds.jdbc.JtdsPreparedStatement.executeQuery(JtdsPreparedStatement.java) 
    at com.acme.myejbs.MyMDB.doQuery2(MyMDB.java:126) 
    at com.acme.myejbs.MyMDB.onMessage(MyMDB.java:614) 
    ... 
Caused by: java.net.SocketException: Connection reset by peer: socket write error 
    at java.net.SocketOutputStream.socketWrite0(Native Method) 
    at java.net.SocketOutputStream.socketWrite(SocketOutputStream.java) 
    at java.net.SocketOutputStream.write(SocketOutputStream.java) 
    at java.io.DataOutputStream.write(DataOutputStream.java) 
    at net.sourceforge.jtds.jdbc.SharedSocket.sendNetPacket(SharedSocket.java) 
    at net.sourceforge.jtds.jdbc.RequestStream.putPacket(RequestStream.java) 
    at net.sourceforge.jtds.jdbc.RequestStream.flush(RequestStream.java) 
    ... 44 more 

W rzadkich przypadkach możemy uzyskać ten straszny wyjątek (NPE wewnątrz jTDS):

java.lang.NullPointerException 
    at net.sourceforge.jtds.jdbc.JtdsPreparedStatement.executeQuery(JtdsPreparedStatement.java) 
    at com.acme.myejbs.MyMDB.doQuery2(MyMDB.java:126) 
    at com.acme.myejbs.MyMDB.onMessage(MyMDB.java:614) 
    ... 

nie możemy odnaleźć dlaczego tak się dzieje. Używane połączenia nigdy nie stają się bezczynne przez ponad sekundę podczas żądania. Nie wiemy, kto zrzuca połączenie. Może to być niestabilność sieci, ale w takim razie jTDS powinien generować tylko wyjątki związane z siecią, prawda?

Inną opcją jest polityka lub konfiguracja puli połączeń Glassfish (może Glassfish przedwcześnie zamyka fizyczne połączenia), ale jak możemy to śledzić?

Wreszcie, MS SQL Server 2008 może zdalnie zrzucać połączenia, ale jak możemy monitorować stronę serwera, aby dowiedzieć się, czy tak się dzieje?

+0

nie występują również problemy podczas używania sterownika JDBC Microsoftu? – extraneon

+0

@extraneon Nie testowaliśmy sterownika Microsoft JDBC. Istnieje cała warstwa trwałości oparta na jTDS, a przejście na MS zajmie kilka dni. – fernacolo

+0

Czy Twój kod łapie/ignoruje SQLExceptions? Czy używasz podstawowego DataSource lub connectionpool? –

Odpowiedz

2

Miałem aplikację, która otrzymała tego rodzaju wyjątki prawie dokładnie. Wszystkie moje maszyny były nowymi serwerami, a wszystkie karty sieciowe zostały ustawione tak, aby automatycznie wykrywać prędkość sieci. Wszystkie były podłączone do starego przełącznika, który był dupleksem HALF 100MB/s.

Ustawienie wszystkich urządzeń na tym przełączniku, aby jawnie używać ustawienia połączenia dupleksowego o wartości 100MB/sekundę, zamiast automatycznego wykrywania, było tym, co zadziałało po wykonaniu niezliczonych godzin poszukiwania rozwiązania. Musisz dowiedzieć się, jakie powinny być Twoje ustawienia łączności lub poeksperymentować (będzie oczywiste, że wybierzesz niewłaściwy, ponieważ nie będziesz w stanie połączyć się z pudłem na pulpicie zdalnym, więc upewnij się, że możesz uzyskać dostęp do maszyna fizyczna).

To dość nisko wiszące owoce, żeby to przetestować. Ustawiłem okno poleceń za pomocą komendy ping z jednego z komputerów roboczych pingujących serwer bazy danych i mogłem okresowo obserwować utratę pakietów. Po zmianie ustawień NIC i poprawieniu go, problem zniknął całkowicie. W Internecie jest kilka artykułów omawiających ten problem. Trudno go wyśledzić, ponieważ jest: 1) okresowy i 2) wygląda jakby coś było nie tak z obiektami połączeń itp.

Powiązane problemy