Приложение Spring теряет соединение с MySql через 8 часов.Как правильно настроить? - PullRequest
22 голосов
/ 16 декабря 2011

У меня есть приложение Spring, которое, как мне кажется, использует пул соединений DBCP для подключения к базе данных MySql. Я говорю: верь, потому что это не та область, в которой я очень силен, и я не уверен, что все настроено правильно. У меня нет проблем с запуском приложения, и все работает нормально. Проблема возникает в одночасье. Приложение не сильно используется, и в одночасье оно, очевидно, теряет связь с MySql. Я посмотрел в него и обнаружил, что MySql имеет 8-часовое окно, а затем он отключается или что-то еще. Я в порядке с этим, но когда пользователь пытается войти в систему утром, он получает сообщение об ошибке вроде:

Ошибка линии связи. Последний пакет успешно получен 60 000 000 мс назад. Последний пакет успешно установлен 15 мс назад.

Это проблема. Мне нужно, чтобы они могли восстановить соединение утром, не сталкиваясь с этой проблемой. Единственный способ, которым я могу это исправить, - это отскок сервера Tomcat. Из этого видно, что пул DBCP должен каким-то образом предотвратить это, но я не могу найти надежного источника информации о том, как его настроить. Я надеюсь, что кто-то здесь может дать мне некоторое представление. Вот моя текущая конфигурация, все сделано в XML-файле Spring:

Приложение-data.xml

<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns:aop="http://www.springframework.org/schema/aop"
xmlns:tx="http://www.springframework.org/schema/tx"
xmlns:context="http://www.springframework.org/schema/context"
xsi:schemaLocation="
    http://www.springframework.org/schema/beans 
    http://www.springframework.org/schema/beans/spring-beans-3.0.xsd
    http://www.springframework.org/schema/tx 
    http://www.springframework.org/schema/tx/spring-tx-3.0.xsd
    http://www.springframework.org/schema/aop 
    http://www.springframework.org/schema/aop/spring-aop-3.0.xsd
    http://www.springframework.org/schema/context
    http://www.springframework.org/schema/context/spring-context-3.0.xsd">

<context:annotation-config />
<context:component-scan base-package="com.vz.sts.domain" />
<context:component-scan base-package="com.vz.sts.persistence" />
<context:component-scan base-package="com.vz.sts.service" />

<bean class="org.springframework.orm.jpa.support.PersistenceAnnotationBeanPostProcessor" />

<bean id="entityManagerFactory" class="org.springframework.orm.jpa.LocalContainerEntityManagerFactoryBean">
    <property name="dataSource" ref="dataSource" />
    <property name="jpaVendorAdapter">
        <bean class="org.springframework.orm.jpa.vendor.HibernateJpaVendorAdapter">
            <property name="database" value="MYSQL" />
            <property name="showSql" value="true" />
        </bean>
    </property>
</bean>

<bean id="dataSource" class="org.apache.commons.dbcp.BasicDataSource">
    <property name="driverClassName" value="com.mysql.jdbc.Driver" />
    <property name="url" value="jdbc:mysql://localhost:3306/app" />
    <property name="username" value="root" />
    <property name="password" value="admin" />
    <property name="initialSize" value="5" />
</bean>

<bean id="transactionManager" class="org.springframework.orm.jpa.JpaTransactionManager">
    <property name="entityManagerFactory" ref="entityManagerFactory" />
</bean>

<bean id="jdbcUserService" class="org.springframework.security.provisioning.JdbcUserDetailsManager">
    <property name="dataSource" ref="dataSource"/>
    <property name="authenticationManager" ref="authenticationManager"/>
</bean>

<bean id="saltSource" class="org.springframework.security.authentication.dao.ReflectionSaltSource">
    <property name="userPropertyToUse" value="username" />
</bean>

<tx:annotation-driven />
</beans>

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

UPDATE

Я нашел эту страницу и думаю, что все, что мне нужно сделать, это добавить свойство ValidationQuery . Может кто-нибудь проверить, повлияет ли это на желание, оставив все остальное по умолчанию? Я полагаю, что тогда будет использоваться аспект testOnBorrow DBCP. Я не совсем понимаю, что в объяснении говорится, что testOnBorrow делает, но я думаю, что это будет делать то, что я хочу. Кто-нибудь подтвердит? Спасибо.

Ответы [ 2 ]

4 голосов
/ 16 декабря 2011

Краткий ответ: этого должно быть достаточно. DBCP поддерживает тестирование соединения при заимствовании из пула соединений (по умолчанию), но также поддерживает тестирование при возврате и тестирование в режиме ожидания.

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

Я думаю, что это был отличный 'Release It!' Майкла Найгарда. книга, описывающая этот сценарий в одной из его историй из окопов.

Вы также захотите посмотреть, как MySQL удаляет мертвые соединения, например, когда Tomcat теряет соединение через 8 часов, БД также не будет знать о сбое соединения.

И последнее замечание: если вы используете Tomcat 7, переключитесь на их новый пул соединений , поскольку он обеспечивает лучшую производительность, чем DBCP.

1 голос
/ 16 декабря 2011

Мой друг, DBCP дает обещание, которое он не может сдержать. Хехе. Я обнаружил, что столкнулся с этой проблемой, и дело дошло до того, что недавно недавно установленный межсетевой экран вставил в середину прерывание бездействующих соединений с временем простоя, превышающим X часов. Таким образом, Db не смог уведомить моего клиента (и его сокет) о том, что соединение отключилось, и сокет оставался открытым, поэтому пул не мог знать, что соединение не было доступно. Результат: первая попытка запроса утром не удалась с таймаутом, в то время как вторая работала как ожидалось. Даже с помощью validationQuery, DBCP не проверял уже действующее соединение (не спрашивайте меня, почему, я только что узнал)

Решение 1? Из-за того, что это была производственная среда (да, много пота), быстрый конь должен был создать отдельный поток, отправляющий достоверный запрос в БД, используя пул каждые ... X / 4 часа. Это защитило совершенно новый брандмауэр / WAF от прерывания моей розетки!

Решение 2? Проверьте инфраструктуру. Проверьте непрерывность. Проверьте согласованность скорости и режима сетевых интерфейсов (например, полный дуплекс, 100M). Проверьте настройки сервера Db (нет сетевой карты, экономя энергию хе-хе). И, возможно, поддержание работы зонда в растворе 1.

EDIT . testOnBorrow и validationQuery должны работать в обычных условиях. Отображение пула с логическими каналами и физическим сокетом между клиентом и сервером. testOnBorrow проверяет, является ли канал действительным, прежде чем выдать его по вашему запросу. Для этого используется validationQuery.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...