2016-12-19 11 views
3

私は少しのShow-Case-Applicationで問題を単純化しようとしていました。
スレッドが終了するまでConnectionが閉じられないようです。 Check this outSpringデータベースのロードテスト:接続を解放する方法

依存関係情報:

サーブレットエンジン:Apache Tomcatの/ 8.5.5
JPAプロバイダ:休止

私のpom.xml:

<?xml version="1.0" encoding="UTF-8"?> 
<project xmlns="http://maven.apache.org/POM/4.0.0" 
     xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" 
     xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd"> 
    <modelVersion>4.0.0</modelVersion> 

    <groupId>...</groupId> 
    <artifactId>***-service</artifactId> 
    <version>0.0.1</version> 
    <packaging>jar</packaging> 

    <name>...</name> 
    <description>...</description> 

    <parent> 
     <groupId>org.springframework.boot</groupId> 
     <artifactId>spring-boot-starter</artifactId> 
     <version>1.4.1.RELEASE</version> 
    </parent> 

    <properties> 
     <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding> 
     <project.reporting.outputEncoding>UTF-8</project.reporting.outputEncoding> 
     <java.version>1.8</java.version> 
     <spring.cloud.release.version>Brixton.SR2</spring.cloud.release.version> 
    </properties> 

    <dependencies> 

     <dependency> 
      <groupId>org.springframework.boot</groupId> 
      <artifactId>spring-boot-starter-thymeleaf</artifactId> 
     </dependency> 
     <dependency> 
      <groupId>org.springframework.boot</groupId> 
      <artifactId>spring-boot-starter-actuator</artifactId> 
     </dependency> 
     <dependency> 
      <groupId>org.springframework.boot</groupId> 
      <artifactId>spring-boot-starter-data-jpa</artifactId> 
     </dependency> 
     <dependency> 
      <groupId>org.springframework.boot</groupId> 
      <artifactId>spring-boot-starter-data-rest</artifactId> 
     </dependency> 
     <dependency> 
      <groupId>org.springframework.boot</groupId> 
      <artifactId>spring-boot-starter-web</artifactId> 
     </dependency> 

     <!-- eureka discovery client --> 
     <dependency> 
      <groupId>org.springframework.cloud</groupId> 
      <artifactId>spring-cloud-starter-eureka</artifactId> 
     </dependency> 

     <dependency> 
      <groupId>mysql</groupId> 
      <artifactId>mysql-connector-java</artifactId> 
      <scope>runtime</scope> 
     </dependency> 

     <!-- for unit tests --> 
     <dependency> 
      <groupId>org.springframework.boot</groupId> 
      <artifactId>spring-boot-starter-test</artifactId> 
      <scope>test</scope> 
     </dependency> 

     <!-- for rest documentation --> 
     <dependency> 
      <groupId>org.springframework.restdocs</groupId> 
      <artifactId>spring-restdocs-mockmvc</artifactId> 
      <scope>test</scope> 
     </dependency> 

     <!-- for (un)marshalling of json/xml --> 
     <dependency> 
      <groupId>com.fasterxml.jackson.core</groupId> 
      <artifactId>jackson-databind</artifactId> 
     </dependency> 
     <dependency> 
      <groupId>com.fasterxml.jackson.dataformat</groupId> 
      <artifactId>jackson-dataformat-xml</artifactId> 
     </dependency> 

     <dependency> 
      <!-- jsoup HTML parser library @ http://jsoup.org/ --> 
      <groupId>org.jsoup</groupId> 
      <artifactId>jsoup</artifactId> 
      <version>1.9.2</version> 
     </dependency> 

    </dependencies> 

    <dependencyManagement> 
     <dependencies> 
      <!-- also needed for eureka discovery --> 
      <dependency> 
       <groupId>org.springframework.cloud</groupId> 
       <artifactId>spring-cloud-dependencies</artifactId> 
       <version>${spring.cloud.release.version}</version> 
       <type>pom</type> 
       <scope>import</scope> 
      </dependency> 
     </dependencies> 
    </dependencyManagement> 

    <build> 
     <finalName>${artifactId}</finalName> 
     <plugins> 
      <plugin> 
       <groupId>org.springframework.boot</groupId> 
       <artifactId>spring-boot-maven-plugin</artifactId> 
       <configuration> 
        <executable>true</executable> 
        <outputDirectory>${dir}</outputDirectory> 
       </configuration> 
      </plugin> 
     </plugins> 
    </build> 
</project> 

I DBとしてMYSQLを持つSpringブートサーバーを持っています。私は100以上のスレッド/ユーザーで負荷テスト(JMeterは)だとき、私はこの例外を取得:

org.apache.tomcat.jdbc.pool.PoolExhaustedException:[HTTP-NIO-8015-EXEC-195 ]タイムアウト:プールが空です。 60秒で接続を取得できません。使用できません[サイズ:50;ビジー:50;アイドル:0; lastwait:60000]。

マイデータソース設定:

spring.datasource.tomcat.minIdle = 0 
spring.datasource.tomcat.maxIdle = 10 
spring.datasource.tomcat.maxActive = 50 
spring.datasource.tomcat.maxWait = 60000 
spring.datasource.tomcat.testOnBorrow = true 
spring.datasource.tomcat.timeBetweenEvictionRunsMillis = 1800000 // Updated 
spring.datasource.tomcat.numTestsPerEvictionRun = 50 // Updated 
spring.datasource.tomcat.minEvictableIdleTimeMillis = 10 
spring.datasource.tomcat.validationQuery = SELECT 1 
spring.datasource.tomcat.testWhileIdle = true 

データベース上の唯一のクエリは、単純なSELECT * FROM TABLE WHERE deletedat IS NULLです。これは、約4000秒のエントリを約0.01秒で返します(mysql CLI経由)。
MYSQLをプロファイルするNeor Profile SQLをインストールしました。すべてのプロセスをチェックすると、私のスキーマのプロセスはすべてスリープ状態になります。私の設定がそれらの接続を解放しないようです。

私はCrudRepositoryから延びているシンプルなインタフェース使用しています:私は何をしないのです

public interface MyRepository extends CrudRepository<MyModel, String> { 
    @Query("SELECT m from MyModel m WHERE m.deletedAt IS NULL") 
    List<MyModel> findWhereDeletedAtIsNull(); 
} 

をし、それを

List<MyModel> myModelList = myRepository.findWhereDeletedAtIsNull(); 

を使うのか?
接続を解放するために、設定またはコードのいずれかを調整する必要があるようです。

休止状態設定:

spring.jpa.properties.hibernate.dialect = org.hibernate.dialect.MySQL5Dialect 
+1

あなたはtimeBetweenEvictionRunsMillisとminEvictableIdleTimeMillisのために設定した値が低すぎる、それはミリ秒です... Tomcatのドキュメントは「値が1秒で設定すべきではない」と言う、すなわち1000、さらには検証クエリを実行することがあまりにも多いようです...これらの値を調整することが役立つかどうかを確認してください... – MattR

+0

投稿にTomcatやブートバージョンなどの依存関係情報を追加したり、ログ内に何かがあるかどうかを調べる – Veeram

+0

接続プールのパラメータはどこにありますか? –

答えて

3

jpa設定では、要求の処理全体に対してJPA EntityManagerをワーカースレッドにバインドするOpenEntityManagerInViewInterceptorが登録されます。したがって、サービスメソッド(com.example.api.UserService.getAllUser())の終了後に、データベース接続が閉じられている(またはプールに戻っています)。

これにより、DB接続を長時間開いたままにして、ロード中に接続プールが使い果たされてしまいます。

あなたの問題を解決するには、あなたのapplication.propertiesに

=中 - ビュー - spring.jpa.open偽

このプロパティをbelow propertyを追加することにより、OpenEntityManagerInViewInterceptorフィルタの自動登録を無効にすることができますデフォルトではtrueです。

関連の問題を参照してください: 1. Consider not registering OpenEntityManagerInViewInterceptor by default

+0

これを試してみるべきですが、それは問題のようです。私はそれが今動作することを確認した後、私はあなたの答えを受け入れるだろう –

1

重要である何が、ここでは、logAbandonedを有効にすることです。そうすれば、TomcatのJDBCプールはを返します。が返されていない接続が割り当てられています。現時点では、あなたは単にに問題を解決することによってを回復しようとしています。プールが強制的に返されなかった接続を解放するように強制します。

java.sql.SQLException: Connection has already been closedは、完了までに50秒以上かかるクエリがありますが、自分のコードで適切にクリーンアップされているために発生しています。そのため、50秒後にプールが接続を終了し(コードが放棄されたため)、コードが制御を取り戻すと接続も閉じられます。放棄された接続のタイムアウトを上げることを検討してください。

+0

それは文字通り問題を要約していますかなり良い。私はショーケースプロジェクトを追加しました。スレッドが終了するまで接続が解放されないようです。もはや私が接続を使用しない場合でも。手動で接続を閉じるにはどうしたらいいですか? –

+0

申し訳ありません...休止状態は私の渋滞ではありません。神が意図したとおり、JDBCを手で書きます。 '@ Transactional'アノテーションは接続の利用範囲を拡大しますか?おそらくその注釈は、そのリクエスト中に実行されたクエリはすべて単一のトランザクションでグループ化されなければならないことを意味します。そのJDBCコードの一部を手書きで書くことを検討したいかもしれません。それはより多くの作業ですが、より効率的になり、あなたがしたいことを正確に実行します。 –

+0

https://github.com/bastiankemmer/Spring-Hibernate-Problem このプロジェクトをチェックしてください。 '@ Transactional'は単一のdbトランザクションのスコープを定義しますが、私の問題の一部ではありません。 –

関連する問題