2017-03-28 10 views
1

スプリングブートプロジェクトでredisを使用します。一定期間実行した後、redis操作で破損パイプエラーが発生することがありますが、いつか成功します。サービスを再起動するとこの問題は解決しますが、それは良い考えではありません。スプリングブートredis操作スレーブパイプエラーのエラー

なぜそれが起こるのかわかりません。プール内の一部の赤いつながりは使用できないようですが、プールから閉じて取り除かれることはありません。

私の質問は以下のとおりです。

  • 可能な理由は、壊れたパイプのエラーの原因?
  • 長期間redisation操作がない場合、プール内のアイドル状態の接続は使用できなくなりますか?
  • 壊れたパイプエラーが発生した場合、接続は閉じられ、プールから削除されますか?

のpom.xml:

<dependency> 
    <groupId>org.springframework.boot</groupId> 
    <artifactId>spring-boot-starter-data-redis</artifactId> 
</dependency> 

application.yml:

spring: 
    redis: 
    database: 0 
    host: ${REDIS_HOST:127.0.0.1} 
    password: ${REDIS_PASSWORD:password} 
    port: ${REDIS_PORT:6379} 
    timeout: ${REDIS_TIMEOUT:1000} 
    pool: 
     max-active: ${REDIS_MAX_ACTIVE:100} 
     max-wait: ${REDIS_MAX_WAIT:500} 
     max-idle: ${REDIS_MAX_IDLE:20} 
     min-idle: ${REDIS_MIN_IDLE:5} 

エラーメッセージ:

org.springframework.data.redis.RedisConnectionFailureException: java.net.SocketException: Broken pipe (Write failed); nested exception is redis.clients.jedis.exceptions.JedisConnectionException: java.net.SocketException: Broken pipe (Write failed) 
    at org.springframework.data.redis.connection.jedis.JedisExceptionConverter.convert(JedisExceptionConverter.java:67) ~[spring-data-redis-1.7.6.RELEASE.jar!/:na] 
    at org.springframework.data.redis.connection.jedis.JedisExceptionConverter.convert(JedisExceptionConverter.java:41) ~[spring-data-redis-1.7.6.RELEASE.jar!/:na] 
    at org.springframework.data.redis.PassThroughExceptionTranslationStrategy.translate(PassThroughExceptionTranslationStrategy.java:37) ~[spring-data-redis-1.7.6.RELEASE.jar!/:na] 
    at org.springframework.data.redis.FallbackExceptionTranslationStrategy.translate(FallbackExceptionTranslationStrategy.java:37) ~[spring-data-redis-1.7.6.RELEASE.jar!/:na] 
    at org.springframework.data.redis.connection.jedis.JedisConnection.convertJedisAccessException(JedisConnection.java:212) ~[spring-data-redis-1.7.6.RELEASE.jar!/:na] 
    at org.springframework.data.redis.connection.jedis.JedisConnection.hSet(JedisConnection.java:2810) ~[spring-data-redis-1.7.6.RELEASE.jar!/:na] 
    at org.springframework.data.redis.core.DefaultHashOperations$9.doInRedis(DefaultHashOperations.java:173) ~[spring-data-redis-1.7.6.RELEASE.jar!/:na] 
    at org.springframework.data.redis.core.RedisTemplate.execute(RedisTemplate.java:204) ~[spring-data-redis-1.7.6.RELEASE.jar!/:na] 
    at org.springframework.data.redis.core.RedisTemplate.execute(RedisTemplate.java:166) ~[spring-data-redis-1.7.6.RELEASE.jar!/:na] 
    at org.springframework.data.redis.core.AbstractOperations.execute(AbstractOperations.java:88) ~[spring-data-redis-1.7.6.RELEASE.jar!/:na] 
    at org.springframework.data.redis.core.DefaultHashOperations.put(DefaultHashOperations.java:170) ~[spring-data-redis-1.7.6.RELEASE.jar!/:na] 
Caused by: redis.clients.jedis.exceptions.JedisConnectionException: java.net.SocketException: Broken pipe (Write failed) 
    at redis.clients.jedis.Connection.flush(Connection.java:291) ~[jedis-2.8.2.jar!/:na] 
    at redis.clients.jedis.Connection.getIntegerReply(Connection.java:220) ~[jedis-2.8.2.jar!/:na] 
    at redis.clients.jedis.BinaryJedis.hset(BinaryJedis.java:749) ~[jedis-2.8.2.jar!/:na] 
    at org.springframework.data.redis.connection.jedis.JedisConnection.hSet(JedisConnection.java:2808) ~[spring-data-redis-1.7.6.RELEASE.jar!/:na] 
    ... 115 common frames omitted 
Caused by: java.net.SocketException: Broken pipe (Write failed) 
    at java.net.SocketOutputStream.socketWrite0(Native Method) ~[na:1.8.0_111] 
    at java.net.SocketOutputStream.socketWrite(SocketOutputStream.java:109) ~[na:1.8.0_111] 
    at java.net.SocketOutputStream.write(SocketOutputStream.java:153) ~[na:1.8.0_111] 
    at redis.clients.util.RedisOutputStream.flushBuffer(RedisOutputStream.java:52) ~[jedis-2.8.2.jar!/:na] 
    at redis.clients.util.RedisOutputStream.flush(RedisOutputStream.java:216) ~[jedis-2.8.2.jar!/:na] 
    at redis.clients.jedis.Connection.flush(Connection.java:288) ~[jedis-2.8.2.jar!/:na] 
    ... 118 common frames omitted 

答えて

1

これが理由のn個の数、それらのいずれかの発生する可能性が長寿命の接続を使用している場合があります(たとえば、アプリケーションスタジアムでRedisに接続しますrtを使用して、接続を何度も使用します)。

行うことができることのいくつかは
1.接続が切断された場合は再接続(エラーは、アプリケーション・ロジックに伝播されることを防ぐために、いくつかのtry/catchの魔法を必要とする) 以上だったのは、
を使用することです TestOnBorrow - リソースを要求するときにPING要求を送信します。
TestOnReturn - リソースをプールに返すときにPINGを送信します。
TestWhileIdle - プール内のアイドル状態のリソースから定期的なPINGを送信します。
2.接続を必要とし、長い期間のRedisの操作がない場合に
については後で

を抜いた瞬間に接続するには、プール内のアイドル接続が使用できなくなるのだろうか?

maxidleは、システムが「maxIdle」接続を多数アイドル状態にすることを常に許可することを意味し、残りは常にチェックされ、閉じられ、プールに戻されます。 アイドル状態の接続を使用できない理由がわかりません。とにかくこれは、上記の方法を使用して取り除くことができます。

+0

スプリング@ConfigurationPropertiesのRedisPropertiesでTestOnBorrow設定がない、それはそれは、顧客のJedisConnectionFactoryを作成し、JedisPoolConfigでTestOnBorrowを追加する必要がありますを意味していますか? –

0

私の質問に答えて:

壊れたパイプエラーが発生する理由は何ですか?

TransactionSynchronizationManagerは、スレッドでRedisConnectionを保持し、それを閉じたり、プールに戻したりしません.RedisTemplate.javaおよびRedisConnectionUtils.javaを参照してください。Redisサーバを再起動した後、スレッド内の保持されたRedisConnection上で操作すると、パイプエラーが発生します。

解決方法を教えてください。

すべてのredis操作にtry/catchを追加します。エラーが発生した場合はスレッドからバインドを解除し、プールから新しい接続を取得してredis操作を再度実行できます。

private static final ExceptionTranslationStrategy EXCEPTION_TRANSLATION = 
     new FallbackExceptionTranslationStrategy(JedisConverters.exceptionConverter()); 

public Object req(RedisRequest req) { 
    try { 
     return req.request(); 
    } catch (Exception ex) { 
     if (ex instanceof NullPointerException) { 
      throw ex; 
     } 
     DataAccessException exception = EXCEPTION_TRANSLATION.translate(ex); 
     if (exception instanceof RedisConnectionFailureException) { 
      RedisConnectionUtils.unbindConnection(factory); 
      /** retry again */ 
      return req.request(); 
     } else { 
      throw ex; 
     } 
    } 
} 
関連する問題