2011-12-16 33 views
21

Tôi đã có một ứng dụng Spring mà tôi tin rằng sử dụng kết nối gộp nhóm DBCP để kết nối với cơ sở dữ liệu MySql. Tôi nói tin bởi vì đây không phải là khu vực tôi rất mạnh mẽ và tôi không tích cực nếu mọi thứ được thiết lập chính xác. Tôi không có vấn đề gì khi chạy ứng dụng và mọi thứ đều hoạt động tốt. Vấn đề xảy ra qua đêm. Các ứng dụng không được sử dụng nhiều và qua đêm nó dường như mất kết nối với MySql. Tôi nhìn vào nó và phát hiện ra MySql có một cửa sổ 8 giờ và sau đó nó ngắt kết nối hoặc bất cứ điều gì. Tôi ổn với điều này, nhưng khi người dùng cố đăng nhập vào buổi sáng, họ sẽ gặp lỗi như sau:Ứng dụng Spring mất kết nối với MySql sau 8 giờ. Cách cấu hình đúng cách?

Lỗi liên kết truyền thông. Gói tin cuối cùng đã nhận được thành công 60.000.000 từ trước. Gói cuối cùng đã được thiết lập thành công 15ms trước.

Đây là vấn đề. Tôi cần họ để có thể kết nối lại vào buổi sáng mà không gặp phải vấn đề này. Cách duy nhất tôi dường như có thể sửa chữa nó là bằng cách nảy máy chủ Tomcat. Từ việc nhìn vào nó, có vẻ như việc gộp nhóm DBCP sẽ có thể ngăn chặn điều này bằng cách nào đó nhưng tôi không thể tìm thấy một nguồn thông tin đáng tin cậy về cách cấu hình nó. Tôi hy vọng một người nào đó ở đây có thể cung cấp cho tôi một số thông tin chi tiết. Dưới đây là cấu hình hiện tại của tôi, tất cả được thực hiện trong một tập tin mùa xuân xml:

app-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> 

Tôi không chắc chắn những gì thuộc tính cụ thể tôi cần phải thêm vào để cho phép các ứng dụng để kết nối lại với cơ sở dữ liệu. Tôi không nhớ nếu nó đóng kết nối sau một số giờ nhưng nó sẽ tự động kết nối lại và không ném lỗi như thế này. Tôi thậm chí không tích cực nó thực sự được thiết lập để sử dụng kết nối tổng hợp. Vì vậy, bất kỳ trợ giúp sẽ được rất nhiều đánh giá cao, cảm ơn bạn.

CẬP NHẬT

tôi thấy this page và tôi nghĩ rằng tất cả những gì cần làm là thêm ValidationQuery tài sản. Bất cứ ai có thể xác minh nếu điều này sẽ có ảnh hưởng mong muốn trong khi để lại tất cả mọi thứ khác theo mặc định? Tôi tin rằng sau đó sẽ sử dụng phương thức testOnBorrow của DBCP. Tôi không hoàn toàn hiểu những gì lời giải thích nói testOnBorrow không, nhưng tôi nghĩ rằng điều này sẽ làm những gì tôi muốn. Có ai xác nhận không? Cảm ơn.

+1

Một ý nghĩ sẽ là có một kịch bản đơn giản truy cập dịch vụ để giữ cho nó "ấm" mỗi giờ hoặc lâu hơn. Nếu vấn đề là các dịch vụ cư trú đang được thực hiện off-line do không hoạt động, điều này sẽ giữ cho điều đó xảy ra. – cdeszaq

+0

Cảm ơn nhưng tôi biết DBCP có thể kết nối lại mà không có vấn đề này hoặc có một thiết lập để ngăn chặn điều này và đó là cách tôi muốn giải quyết nó. – cardician

+0

Tôi đồng ý, đó là lý do tôi đăng nhận xét đó chứ không phải là câu trả lời. Đề nghị của tôi là không có gì hơn là một công việc xung quanh, nhưng nó loại bỏ các triệu chứng cho người dùng của bạn cho đến khi bạn tìm thấy một giải pháp cho vấn đề :) – cdeszaq

Trả lời

4

Câu trả lời ngắn gọn là đủ. DBCP hỗ trợ kiểm tra kết nối khi mượn từ nhóm kết nối (mặc định), nhưng cũng hỗ trợ kiểm tra khi trả về và kiểm tra khi không hoạt động.

Cũng rất đáng hiểu điều gì có thể xảy ra ở đây. Có vẻ như một cái gì đó giữa máy chủ Tomcat của bạn và cơ sở dữ liệu đang bỏ kết nối nhàn rỗi sau một khoảng thời gian chờ (chẳng hạn như bộ định tuyến hoặc tường lửa). Vấn đề với điều này là Tomcat nghĩ rằng nó vẫn có một kết nối hợp lệ, cố gắng thực hiện một số công việc với kết nối và không thành công, nhưng giữ cho kết nối còn sống và trả về kết nối đó với nhóm. Bây giờ bất kỳ nỗ lực hơn nữa để nói chuyện với cơ sở dữ liệu sẽ thất bại nếu nó được đưa ra cùng một kết nối bị hỏng từ hồ bơi.

Tôi nghĩ đó là bản phát hành tuyệt vời của Michael Nygard 'Phát hành!' cuốn sách mô tả kịch bản này trong một trong những câu chuyện của anh ta từ những chiến hào.

Bạn cũng sẽ muốn xem xét cách MySQL dọn dẹp các kết nối chết như khi Tomcat mất kết nối sau 8 giờ, DB cũng sẽ không biết kết nối bị lỗi.

Điểm cuối cùng, nếu bạn đang sử dụng Tomcat 7 chuyển sang connection pool mới vì nó cung cấp hiệu suất tốt hơn DBCP.

+0

Bạn có nói rằng tôi nên sử dụng một trong các bài kiểm tra khác? Quay lại hoặc không hoạt động? Tôi biết họ được mặc định là sai nên tôi sẽ cần bật chúng lên. Tôi là trò chơi để sử dụng bất cứ điều gì là giải pháp tốt nhất, nhưng như tôi đã nói tôi không hiểu đầy đủ những gì giải thích trên trang DBCP đang nói rằng ba phương pháp đó làm. – cardician

+2

Cài đặt máy chủ mysql 'wait_timeout' được mặc định là 8 giờ. Các kết nối không hoạt động được giảm xuống sau 8 giờ, một trình điều khiển JDBC không phát hiện ra điều đó cho đến khi bạn đưa ra một truy vấn trên kết nối đó và bạn nhận được stacktrace ở trên. (bạn dễ dàng nhận được 8 giờ thời gian rảnh cho các ứng dụng chỉ được sử dụng trong giờ làm việc). Thường đặt DBCP testWhileIdle, validationQuery và timeBetweenEvictionRunsMillis có thể trợ giúp với các vấn đề như vậy, vì nó sẽ ping kết nối và giữ cho nó luôn hoạt động. Bạn chỉ có thể đặt truy vấn xác thực thành "chọn 1" – nos

+0

Ok, cảm ơn rất nhiều. Và cảm ơn cho câu lệnh Select 1. Tốt hơn nhiều so với những gì tôi đang sử dụng. Tôi sẽ xem các bản sửa lỗi này có hoạt động vào ngày làm việc tiếp theo hay không. Rất nhiều đánh giá cao. – cardician

1

Bạn của tôi, DBCP thực hiện lời hứa mà anh ấy không thể giữ. Hehe. Tôi đã tìm thấy bản thân mình với vấn đề này và nó đã xuống đến một số tường lửa mới được đặt gần đây trong các kết nối nhàn rỗi giữa nhàn rỗi với thời gian nhàn rỗi dài hơn X giờ. Vì vậy, các Db không thể thông báo cho khách hàng của tôi (và ổ cắm của nó) rằng conn đã đi xuống và ổ cắm được giữ mở, do đó hồ bơi không thể biết rằng conn không có sẵn. Kết quả: nỗ lực truy vấn đầu tiên vào buổi sáng không thành công với thời gian chờ trong khi lần thứ hai hoạt động như mong đợi. Ngay cả với validationQuery, DBCP đã không kiểm tra một conn hợp lệ (không hỏi tôi tại sao, tôi chỉ phát hiện ra)

Giải pháp 1? Do thực tế rằng nó là một môi trường sản xuất (vâng, rất nhiều mồ hôi), con ngựa nhanh là tạo ra một sợi riêng biệt gửi một truy vấn chắc chắn đến DB bằng cách sử dụng hồ bơi mỗi ... X/4 giờ. Nó giữ tường lửa mới/WAF từ cắt conn ổ cắm của tôi!

Giải pháp 2? Kiểm tra cơ sở hạ tầng. Kiểm tra tính liên tục. Kiểm tra tính mạch lạc trong tốc độ và phương thức của các giao diện mạng (ví dụ: full duplex, 100M). Kiểm tra cài đặt máy chủ Db (không có năng lượng tiết kiệm thẻ hehe). Và có thể giữ đầu dò trong dung dịch 1 hoạt động.

EDIT. testOnBorrow và validationQuery sẽ hoạt động trong các trường hợp bình thường. Hình ảnh các hồ bơi với các kênh hợp lý và một máy khách btw vật lý và máy chủ. testOnBorrow kiểm tra xem kênh có hợp lệ hay không trước khi đưa ra yêu cầu của bạn. Nó sử dụng validationQuery để làm điều đó.

+0

Cảm ơn. Vì điều này không xảy ra cho đến sau một khoảng thời gian không hoạt động 8 giờ, tôi sẽ không thể biết chắc chắn nếu ading the validationQuery đã giải quyết được vấn đề của tôi hay nếu có nhiều vấn đề hơn. Tôi đánh giá cao thông tin mặc dù. – cardician

+0

Có lẽ hình ảnh tôi mô tả không đủ rõ ràng để nhấn mạnh điều socket-conn. testOnBorrow CÓ THỂ xác nhận một conn BUT nó không kiểm tra một SOCKET. Do đó, các đối tượng được tạo ra bằng cách sử dụng trình điều khiển trả về một số ngoại lệ lẻ mà không được quản lý đúng cách bởi các hồ bơi, do đó, validationQuery của bạn trở nên vô dụng ... và tôi biết nó như thế nào.Tôi phải đến khách hàng trong một tuần, sáng sớm để kiểm tra xem vấn đề đã biến mất chưa hehehe. Nhưng dù sao đi nữa, hãy cho chúng tôi biết nó như thế nào! – Alfabravo

+0

Xin lỗi, không có gì trong số này là thứ tôi quá mạnh. Vì vậy, bạn đang nói rằng lỗi của tôi sẽ không được cố định bằng cách sử dụng ValidationQuery vì vấn đề thực sự là một cái gì đó khác giết chết kết nối và không cho phép nó được thiết lập lại? Có cách nào để có DBCP buộc kết nối vẫn mở không? Có lẽ bằng cách sử dụng timeBetweenEvictionRunsMillis mà mặc định tắt tôi tin? Sự khác biệt duy nhất tôi thấy trong các tình huống của chúng tôi là không có truy vấn nào hoạt động khi điều này xảy ra với tôi. Thứ nhất, thứ hai, không. – cardician

Các vấn đề liên quan