2017-11-07 48 views
3

두 개의 다른 Redis 클러스터 (Amazon Elasticache)와 대화하는 스프링 부팅 응용 프로그램이 있습니다. 스프링 데이터 redis 1.6.4를 사용하고 있습니다.Spring RedisTemplate에 연결 풀링 문제가 있습니까?

@Service 
RedisService { 

    private final RedisConfig redisConfig; 
    private final ObjectMapper mapper; 

    @Autowired 
    public RedisCache(RedisConfig redisConfig, ObjectMapper mapper) { 
    this.redisConfig = redisConfig; 
     this.mapper = mapper; 
    } 

    @Async 
    public void saveValueInClusterA(String cacheKey, MyObject myObject) { 
      try { 
     String cacheValue = mapper.writeValueAsString(myObject); 
       redisConfig.clusterARedisTemplate().opsForValue().set(cacheKey, cacheValue, 1, TimeUnit.HOURS); 
      } catch (Exception e) { 
       LOGGER.error(...); 
      } 
    } 

    public MyObject getValueFromClusterA(String cacheKey) { 
     MyObject myObject = null; 
     try { 
      String cachedEntry = redisConfig.clusterARedisTemplate().opsForValue().get(cacheKey).toString(); 
      myObject = mapper.readValue(cachedEntry, MyObject.class); 
     } catch (Exception e) { 
      LOGGER.error (...); 
     } 
     return myObject; 
    } 

    @Async 
    public void saveValueInClusterB(String cacheKey, MyObject myObject) { 
      try { 
     String cacheValue = mapper.writeValueAsString(myObject); 
       redisConfig.clusterBRedisTemplate().opsForValue().set(cacheKey, cacheValue, 1, TimeUnit.HOURS); 
      } catch (Exception e) { 
       LOGGER.error(...); 
      } 
    } 

    public MyObject getValueFromClusterB(String cacheKey) { 
     MyObject myObject = null; 
     try { 
      String cachedEntry = redisConfig.clusterBRedisTemplate().opsForValue().get(cacheKey).toString(); 
      myObject = mapper.readValue(cachedEntry, MyObject.class); 
     } catch (Exception e) { 
      LOGGER.error (...); 
     } 
     return myObject; 
    } 

} 

이 정상 부하 상태에서 잘 작동 : 내 코드에서 내가 사용하는 같은 것을 가지고, 다음

@Configuration 
public class RedisConfig { 
    @Bean 
    @Primary 
    public JedisConnectionFactory clusterAJedisConnectionFactory() { 
    JedisConnectionFactory jedisConnectionFactory = new JedisConnectionFactory(); 
    jedisConnectionFactory.setHostName(clusterAUrl); 
    jedisConnectionFactory.setPort(clusterAPort); 
    jedisConnectionFactory.setUsePool(true); 
    return jedisConnectionFactory; 
    } 

    @Bean 
    public JedisConnectionFactory clusterBJedisConnectionFactory() { 
    JedisConnectionFactory jedisConnectionFactory = new JedisConnectionFactory(); 
    jedisConnectionFactory.setHostName(clusterBUrl); 
    jedisConnectionFactory.setPort(clusterBPort); 
    jedisConnectionFactory.setUsePool(true); 
    return jedisConnectionFactory; 
    } 

    @Bean(name="clusterARedisTemplate") 
    public RedisTemplate<String, Object> clusterARedisTemplate() { 
    RedisTemplate<String, Object> redisTemplate = new RedisTemplate<String, Object>(); 

    redisTemplate.setConnectionFactory(clusterAJedisConnectionFactory()); 
    redisTemplate.setKeySerializer(new StringRedisSerializer()); 
    redisTemplate.setHashValueSerializer(new GenericToStringSerializer<Object>(Object.class)); 
    redisTemplate.setValueSerializer(new GenericToStringSerializer<Object>(Object.class)); 

    return redisTemplate; 
    } 

    @Bean(name="clusterBRedisTemplate") 
    public RedisTemplate<String, Object> clusterBRedisTemplate() { 
    RedisTemplate<String, Object> redisTemplate = new RedisTemplate<String, Object>(); 

    redisTemplate.setConnectionFactory(clusterBJedisConnectionFactory()); 
    redisTemplate.setKeySerializer(new StringRedisSerializer()); 
    redisTemplate.setHashValueSerializer(new GenericToStringSerializer<Object>(Object.class)); 
    redisTemplate.setValueSerializer(new GenericToStringSerializer<Object>(Object.class)); 

    return redisTemplate; 
    } 
} 

그리고이 내 다른 레디 스 구성을위한 코드입니다.

"XNIO-2 task-973" #1547 prio=5 os_prio=0 tid=0x00007f472c41d800 nid=0x2d4e waiting on condition [0x00007f4680851000] 
    java.lang.Thread.State: WAITING (parking) 
    at sun.misc.Unsafe.park(Native Method) 
    - parking to wait for <0x00000004ab53fb58> (a java.util.concurrent.locks.AbstractQueuedSynchronizer$ConditionObject) 
    at java.util.concurrent.locks.LockSupport.park(LockSupport.java:175) 
    at java.util.concurrent.locks.AbstractQueuedSynchronizer$ConditionObject.await(AbstractQueuedSynchronizer.java:2039) 
    at org.apache.commons.pool2.impl.LinkedBlockingDeque.takeFirst(LinkedBlockingDeque.java:583) 
    at org.apache.commons.pool2.impl.GenericObjectPool.borrowObject(GenericObjectPool.java:442) 
    at org.apache.commons.pool2.impl.GenericObjectPool.borrowObject(GenericObjectPool.java:363) 
    at redis.clients.util.Pool.getResource(Pool.java:48) 
    at redis.clients.jedis.JedisPool.getResource(JedisPool.java:99) 
    at redis.clients.jedis.JedisPool.getResource(JedisPool.java:12) 
    at org.springframework.data.redis.connection.jedis.JedisConnectionFactory.fetchJedisConnector(JedisConnectionFactory.java:155) 
    at org.springframework.data.redis.connection.jedis.JedisConnectionFactory.getConnection(JedisConnectionFactory.java:251) 
    at org.springframework.data.redis.connection.jedis.JedisConnectionFactory.getConnection(JedisConnectionFactory.java:58) 
    at org.springframework.data.redis.core.RedisConnectionUtils.doGetConnection(RedisConnectionUtils.java:128) 
    at org.springframework.data.redis.core.RedisConnectionUtils.getConnection(RedisConnectionUtils.java:91) 
    at org.springframework.data.redis.core.RedisConnectionUtils.getConnection(RedisConnectionUtils.java:78) 
    at org.springframework.data.redis.core.RedisTemplate.execute(RedisTemplate.java:178) 
    at org.springframework.data.redis.core.RedisTemplate.execute(RedisTemplate.java:153) 
    at org.springframework.data.redis.core.AbstractOperations.execute(AbstractOperations.java:86) 
    at org.springframework.data.redis.core.DefaultValueOperations.set(DefaultValueOperations.java:182) 
    at com.mypkg.services.RedisService.saveValueInClusterA(RedisService.java:97) 
    at com.mypkg.services.RedisService$$FastClassBySpringCGLIB$$aa4c9d31.invoke() 
    at org.springframework.cglib.proxy.MethodProxy.invoke(MethodProxy.java:204) 
    at org.springframework.aop.framework.CglibAopProxy$DynamicAdvisedInterceptor.intercept(CglibAopProxy.java:651) 
    at com.mypkg.services.RedisService$$EnhancerBySpringCGLIB$$a879b180.saveValueInClusterA() 
    at com.mypkg.services.impl.MyImpl.method2(MyImpl.java:745) 
    at com.mypkg.services.impl.MyImpl.method1(MyImpl.java:419) 
    at sun.reflect.GeneratedMethodAccessor487.invoke(Unknown Source) 
    at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43) 
    at java.lang.reflect.Method.invoke(Method.java:498) 
    at org.springframework.aop.support.AopUtils.invokeJoinpointUsingReflection(AopUtils.java:302) 
    at org.springframework.aop.framework.ReflectiveMethodInvocation.invokeJoinpoint(ReflectiveMethodInvocation.java:190) 
    at org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:157) 
    at org.springframework.aop.framework.adapter.MethodBeforeAdviceInterceptor.invoke(MethodBeforeAdviceInterceptor.java:52) 
    at org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:179) 
    at org.springframework.aop.aspectj.AspectJAfterThrowingAdvice.invoke(AspectJAfterThrowingAdvice.java:59) 
    at org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:179) 
    at org.springframework.aop.interceptor.ExposeInvocationInterceptor.invoke(ExposeInvocationInterceptor.java:92) 
    at org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:179) 
    at org.springframework.aop.framework.JdkDynamicAopProxy.invoke(JdkDynamicAopProxy.java:208) 
      ….. 
      ….. 
      ….. 
      ….. 
      ….. 
      ….. 
    at io.undertow.server.handlers.PredicateHandler.handleRequest(PredicateHandler.java:43) 
    at io.undertow.server.handlers.PredicateHandler.handleRequest(PredicateHandler.java:43) 
    at io.undertow.servlet.handlers.ServletInitialHandler.handleFirstRequest(ServletInitialHandler.java:284) 
    at io.undertow.servlet.handlers.ServletInitialHandler.dispatchRequest(ServletInitialHandler.java:263) 
    at io.undertow.servlet.handlers.ServletInitialHandler.access$000(ServletInitialHandler.java:81) 
    at io.undertow.servlet.handlers.ServletInitialHandler$1.handleRequest(ServletInitialHandler.java:174) 
    at io.undertow.server.Connectors.executeRootHandler(Connectors.java:202) 
    at io.undertow.server.HttpServerExchange$1.run(HttpServerExchange.java:793) 
    at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1142) 
    at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:617) 
    at java.lang.Thread.run(Thread.java:745) 
    Locked ownable synchronizers: 
    - <0x00000004b41253a0> (a java.util.concurrent.ThreadPoolExecutor$Worker) 

내가 128으로 최대 풀 크기를 설정, AWS 콘솔가 말한다 비록 : 나는 부하 테스트를하고 스레드 덤프를했다 그러나, 나는 스레드의 대부분이 이런 식으로 뭔가를 기다리고있는 것을 보았다 Redis 클러스터에 최대 35 개의 연결 만 허용됩니다. 여기서 무슨 일이 일어나고있는거야? 내 redis 구성이 잘못 되었습니까? 또는 매번 사용 후에 연결을 해제해야합니까? Redis 템플릿이 모든 것을 내부적으로 처리한다고 생각했습니다. 사실 여러 문제를 일으키는 여러 개의 redis 클러스터에 연결하고 있습니까?

감사합니다.

+0

안녕하세요 drunkenfist, 나는 대기 문제와 관련하여 문제가 발생했습니다. 문제는 redis로 의심됩니다. 근본적인 원인을 찾지 못했습니다. 이 컨텍스트에서 스레드 덤프를 사용하는 접근 방식은 근본 원인을 찾는데 도움이됩니다! 감사 . – Robocide

답변

0

기본 연결 풀은 풀이 모두 사용되면 차단하는 차단 풀입니다. 충분한 동시 요청이 있고 풀 크기가 동시 요청 수보다 작은 경우 쉽게 발생할 수 있습니다.

문제를 해결하려면 풀 크기를 늘리십시오.

: 1.6.4가 오래되어서 Spring Data Redis 버전을 업그레이드하고 싶을 수도 있습니다. 또한 Lettuce 드라이버로 전환 할 때 풀링이 필요하지 않습니다. 코드에는 차단/트랜잭션 Redis 명령이 포함되지 않은 작업이 표시되므로 총 두 개의 연결 (첫 번째 Elasticache에는 하나, 두 번째 Elascticache는 두 번째 연결)로 잘되어야합니다.

+0

최대 풀 크기를 128로 설정하려고 시도했습니다. AWS 콘솔에 언제든지 최대 35 개의 연결 만 있다고하더라도 여전히 오류가 발생합니다. – drunkenfist

+0

String을 키로 사용하여 Lettuce RedisConnection을 만들고 바이트 []로 값을 생성하는 방법에 대한 아이디어가 있습니까? 나는이 질문을 https://stackoverflow.com/questions/47292145/create-lettuce-statefulredisconnection-for-storing-string-as-keys-and-byte-array에 요청했다. – drunkenfist