Потоки Java, ожидающие соединения Mysql, но Mysql не показывает никаких доказательств этого

0

У нас возникла проблема с prod, которая требует перезапуска наших серверов tomcat для исправления. Мы можем воспроизвести это с помощью теста производительности, но мы не совсем уверены в последовательности событий, необходимых для его воспроизведения. Кажется, что если мы наложим достаточное количество трафика на экземпляр tomcat, у него будет следующая проблема:

Tomcat имеет 200 потоков, но все 200 из них делают это:

"http-nio-8080-exec-1" #41 daemon prio=5 os_prio=0 tid=0x00007f7264a5b800 nid=0xdf9 runnable [0x00007f71e39fd000]
   java.lang.Thread.State: RUNNABLE
    at java.net.SocketInputStream.socketRead0(Native Method)
    at java.net.SocketInputStream.socketRead(SocketInputStream.java:116)
    at java.net.SocketInputStream.read(SocketInputStream.java:171)
    at java.net.SocketInputStream.read(SocketInputStream.java:141)
    at com.mysql.jdbc.util.ReadAheadInputStream.fill(ReadAheadInputStream.java:101)
    at com.mysql.jdbc.util.ReadAheadInputStream.readFromUnderlyingStreamIfNecessary(ReadAheadInputStream.java:144)
    at com.mysql.jdbc.util.ReadAheadInputStream.read(ReadAheadInputStream.java:174)
    - locked <0x000000008b9bbb60> (a com.mysql.jdbc.util.ReadAheadInputStream)
    at com.mysql.jdbc.MysqlIO.readFully(MysqlIO.java:3008)
    at com.mysql.jdbc.MysqlIO.readPacket(MysqlIO.java:567)
    at com.mysql.jdbc.MysqlIO.doHandshake(MysqlIO.java:1016)
    at com.mysql.jdbc.ConnectionImpl.coreConnect(ConnectionImpl.java:2188)
    at com.mysql.jdbc.ConnectionImpl.connectWithRetries(ConnectionImpl.java:2035)
    at com.mysql.jdbc.ConnectionImpl.createNewIO(ConnectionImpl.java:2019)
    - locked <0x000000008b9bbc88> (a com.mysql.jdbc.JDBC4Connection)
    at com.mysql.jdbc.ConnectionImpl.<init>(ConnectionImpl.java:776)
    at com.mysql.jdbc.JDBC4Connection.<init>(JDBC4Connection.java:47)
    at sun.reflect.GeneratedConstructorAccessor69.newInstance(Unknown Source)
    at sun.reflect.DelegatingConstructorAccessorImpl.newInstance(DelegatingConstructorAccessorImpl.java:45)
    at java.lang.reflect.Constructor.newInstance(Constructor.java:423)
    at com.mysql.jdbc.Util.handleNewInstance(Util.java:425)
    at com.mysql.jdbc.ConnectionImpl.getInstance(ConnectionImpl.java:386)
    at com.mysql.jdbc.MultiHostConnectionProxy.createConnectionForHost(MultiHostConnectionProxy.java:346)
    - eliminated <0x000000008b9bc188> (a com.mysql.jdbc.LoadBalancedConnectionProxy)
    at com.mysql.jdbc.LoadBalancedConnectionProxy.createConnectionForHost(LoadBalancedConnectionProxy.java:372)
    - eliminated <0x000000008b9bc188> (a com.mysql.jdbc.LoadBalancedConnectionProxy)
    at com.mysql.jdbc.RandomBalanceStrategy.pickConnection(RandomBalanceStrategy.java:73)
    at com.mysql.jdbc.LoadBalancedConnectionProxy.pickNewConnection(LoadBalancedConnectionProxy.java:317)
    - locked <0x000000008b9bc188> (a com.mysql.jdbc.LoadBalancedConnectionProxy)
    at com.mysql.jdbc.LoadBalancedConnectionProxy.<init>(LoadBalancedConnectionProxy.java:229)
    at com.mysql.jdbc.LoadBalancedConnectionProxy.createProxyInstance(LoadBalancedConnectionProxy.java:105)
    at com.mysql.jdbc.NonRegisteringDriver.connectLoadBalanced(NonRegisteringDriver.java:374)
    at com.mysql.jdbc.NonRegisteringDriver.connect(NonRegisteringDriver.java:314)
    at com.mysql.jdbc.ReplicationConnectionProxy.initializeMasterConnection(ReplicationConnectionProxy.java:415)
    at com.mysql.jdbc.ReplicationConnectionProxy.<init>(ReplicationConnectionProxy.java:182)
    at com.mysql.jdbc.ReplicationConnectionProxy.createProxyInstance(ReplicationConnectionProxy.java:85)
    at com.mysql.jdbc.NonRegisteringDriver.connectReplicationConnection(NonRegisteringDriver.java:459)
    at com.mysql.jdbc.NonRegisteringReplicationDriver.connect(NonRegisteringReplicationDriver.java:46)
    at com.myapp.rest.JSONService.setUpConnection(JSONService.java:1278) ******************************************************************************
    at sun.reflect.GeneratedMethodAccessor120.invoke(Unknown Source)
    at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
    at java.lang.reflect.Method.invoke(Method.java:498)
    at org.glassfish.jersey.server.model.internal.ResourceMethodInvocationHandlerFactory.lambda$static$0(ResourceMethodInvocationHandlerFactory.java:76)
    at org.glassfish.jersey.server.model.internal.ResourceMethodInvocationHandlerFactory$$Lambda$127/439202272.invoke(Unknown Source)
    at org.glassfish.jersey.server.model.internal.AbstractJavaResourceMethodDispatcher$1.run(AbstractJavaResourceMethodDispatcher.java:148)
    at org.glassfish.jersey.server.model.internal.AbstractJavaResourceMethodDispatcher.invoke(AbstractJavaResourceMethodDispatcher.java:191)
    at org.glassfish.jersey.server.model.internal.JavaResourceMethodDispatcherProvider$TypeOutInvoker.doDispatch(JavaResourceMethodDispatcherProvider.java:243)
    at org.glassfish.jersey.server.model.internal.AbstractJavaResourceMethodDispatcher.dispatch(AbstractJavaResourceMethodDispatcher.java:103)
    at org.glassfish.jersey.server.model.ResourceMethodInvoker.invoke(ResourceMethodInvoker.java:493)
    at org.glassfish.jersey.server.model.ResourceMethodInvoker.apply(ResourceMethodInvoker.java:415)
    at org.glassfish.jersey.server.model.ResourceMethodInvoker.apply(ResourceMethodInvoker.java:104)
    at org.glassfish.jersey.server.ServerRuntime$1.run(ServerRuntime.java:277)
    at org.glassfish.jersey.internal.Errors$1.call(Errors.java:272)
    at org.glassfish.jersey.internal.Errors$1.call(Errors.java:268)
    at org.glassfish.jersey.internal.Errors.process(Errors.java:316)
    at org.glassfish.jersey.internal.Errors.process(Errors.java:298)
    at org.glassfish.jersey.internal.Errors.process(Errors.java:268)
    at org.glassfish.jersey.process.internal.RequestScope.runInScope(RequestScope.java:289)
    at org.glassfish.jersey.server.ServerRuntime.process(ServerRuntime.java:256)
    at org.glassfish.jersey.server.ApplicationHandler.handle(ApplicationHandler.java:703)
    at org.glassfish.jersey.servlet.WebComponent.serviceImpl(WebComponent.java:416)
    at org.glassfish.jersey.servlet.WebComponent.service(WebComponent.java:370)
    at org.glassfish.jersey.servlet.ServletContainer.service(ServletContainer.java:389)
    at org.glassfish.jersey.servlet.ServletContainer.service(ServletContainer.java:342)
    at org.glassfish.jersey.servlet.ServletContainer.service(ServletContainer.java:229)
    at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:292)
    at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:207)
    at org.apache.tomcat.websocket.server.WsFilter.doFilter(WsFilter.java:52)
    at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:240)
    at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:207)
    at org.apache.catalina.core.StandardWrapperValve.invoke(StandardWrapperValve.java:212)
    at org.apache.catalina.core.StandardContextValve.invoke(StandardContextValve.java:94)
    at org.apache.catalina.authenticator.AuthenticatorBase.invoke(AuthenticatorBase.java:504)
    at org.apache.catalina.core.StandardHostValve.invoke(StandardHostValve.java:141)
    at org.apache.catalina.valves.ErrorReportValve.invoke(ErrorReportValve.java:79)
    at org.apache.catalina.valves.RemoteIpValve.invoke(RemoteIpValve.java:676)
    at org.apache.catalina.valves.AbstractAccessLogValve.invoke(AbstractAccessLogValve.java:620)
    at org.apache.catalina.core.StandardEngineValve.invoke(StandardEngineValve.java:88)
    at org.apache.catalina.connector.CoyoteAdapter.service(CoyoteAdapter.java:502)
    at org.apache.coyote.http11.AbstractHttp11Processor.process(AbstractHttp11Processor.java:1132)
    at org.apache.coyote.AbstractProtocol$AbstractConnectionHandler.process(AbstractProtocol.java:684)
    at org.apache.tomcat.util.net.NioEndpoint$SocketProcessor.doRun(NioEndpoint.java:1533)
    at org.apache.tomcat.util.net.NioEndpoint$SocketProcessor.run(NioEndpoint.java:1489)
    - locked <0x000000008a974068> (a org.apache.tomcat.util.net.NioChannel)
    at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1142)
    at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:617)
    at org.apache.tomcat.util.threads.TaskThread$WrappingRunnable.run(TaskThread.java:61)
    at java.lang.Thread.run(Thread.java:745)

Я знаю, что большая стена текста, но вы можете найти наш код, ища ****************************************************************************** в этой трассе стека,

Поскольку все доступные потоки ждут, чтобы захватить соединение, tomcat становится невосприимчивым. Когда tomcat блокируется таким образом, на сервере mysql нет связей (хотя я не проверял ведомые устройства). Таким образом, похоже, что Java-код ожидает соединения из базы данных, а в базе данных нет записи о попытке подключения к ней Java.

Эта база данных имеет 7k доступных соединений, и через New Relic мы можем видеть, что сделано не более 3 тысяч. Таким образом, это не проблема с отсутствием связей с БД.

Вот код, используемый для соединения:

    Class.forName("com.mysql.jdbc.ReplicationDriver");
    final String JDBC_CONNECTION_STRING = System.getProperty("JDBC_CONNECTION_STRING");
    final String DB_USER_STRING = System.getProperty("DB_USER_STRING");
    final String DB_PASSWORD_STRING = System.getProperty("DB_PASSWORD_STRING");

    ReplicationDriver driver = new ReplicationDriver();

    Properties props = new Properties();

    // We want this for failover on the slaves
    props.put("autoReconnect", "true");

    // We want to load balance between the slaves
    props.put("roundRobinLoadBalance", "true");

    props.put("user", DB_USER_STRING);
    props.put("password", DB_PASSWORD_STRING);
    props.put("useLocalSessionState", "true");
    props.put("useLocalTransactionState", "true");
    props.put("connectTimeout", System.getProperty("MYSQL_CLIENT_CONNECT_TIMEOUT_MS"));
    props.put("socketTimeout", System.getProperty("MYSQL_CLIENT_SOCKET_TIMEOUT_MS"));

    if(use_utf8)
    {
        props.put("useUnicode", "yes");
        props.put("characterEncoding", "UTF-8");
    }

    connect = driver.connect(JDBC_CONNECTION_STRING, props);  //all threads block on this line
    connect.setReadOnly(false);

В качестве обходного пути мы добавили строки для MYSQL_CLIENT_CONNECT_TIMEOUT_MS и MYSQL_CLIENT_SOCKET_TIMEOUT_MS. Установка этих параметров не позволяет машинам запираться, но мы не решили основной проблемы. Я хотел бы исправить основную проблему: почему Java-код ожидает подключения к базе данных?

Мы используем MySQL в RDS, версия 5.6.10.

Я использую Tomcat 8, JDK 8, Jersey 2.26 и

    <dependency>
        <groupId>mysql</groupId>
        <artifactId>mysql-connector-java</artifactId>
        <version>5.1.45</version>
    </dependency>

Вероятно, стоит отметить, что я подключаюсь к этой базе данных с этим префиксом jdbc url: jdbc:mysql:replication://. Кроме того, это, похоже, происходит только на RDS, а не локально. Разница между двумя средами заключается в том, что RDS имеет мастера и ведомые устройства, а локально это не так.

  • 0
    Какие операции Mysql выполняются под вашим трафиком Tomcat? Только выбрать операции? Возможно ли возникновение тупиковой ситуации, когда ваши параллельные запросы UPDATE / DELETE / SELECT отправляются на сервер Mysql? Если есть тупик, ваши темы будут работать так, как вы описали выше.
  • 0
    @ftb мы делаем все виды операций CRUD. Но я не уверен, согласен ли я с вашим утверждением, потому что трассировка стека всегда показывает его ожидание соединения, а не операции CRUD. Почему он остановился там из-за тупика БД? Имейте в виду, что БД имеет 7 тыс. Соединений, и каждый кот использует только 200.
Показать ещё 9 комментариев
Теги:
tomcat
jdbc
jersey-2.0

1 ответ

2

Если вы используете пул соединений с базой данных, это предполагает, что пул исчерпан, вероятно, потому, что соединения не закрываются и не возвращаются в пул должным образом.

Из вашего сообщения не ясно, как вы разработали свое приложение.

  1. Вы принимали одно соединение для каждого пользователя, сохраняющееся на протяжении всего сеанса?
  2. Вы проверяете, используете, закрываете и возвращаете соединение в самом узком методе?
  3. Вы используете Spring?
  • 0
    1. Мы предполагаем одно соединение на запрос. Соединение закрывается в конце каждого запроса. 2. Я не верю в это. Мы открываем соединение в начале каждого запроса, а затем закрываем его в конце каждого запроса. 3. Нет, мы используем Джерси 2.26. Мы вообще не используем пул соединений.
  • 0
    Я бы рекомендовал использовать пул, настроенный соответствующим образом.
Показать ещё 1 комментарий

Ещё вопросы

Сообщество Overcoder
Наверх
Меню