[REDIS] 레디 스 연결은 어떻게 해제 레디 스 캐싱에 대한 런타임에 실패했을 경우
REDIS레디 스 연결은 어떻게 해제 레디 스 캐싱에 대한 런타임에 실패했을 경우
우리는 나머지 API는 응용 프로그램이 있습니다. 우리는 API 응답 캐싱 및 내부 방법 캐싱 레디 스를 사용합니다. 레디 스 연결은 우리의 API 아래로 제작됩니다. 우리는 원하는 레디 스 그 레디 스 연결이 실패 할 경우 캐시 또는 예외 대신에 우리의 API의 다운을 우회. 거기에 인터페이스 CacheErrorHandler는하지만하지 연결 문제 레디 스 레디 스 세트 작동 오류를 얻을 처리합니다. 우리는 봄 4.1.2를 사용하고 있습니다.
해결법
-
==============================
1.조금 실망의 종기이. (레디 스 구현) 귀하의 응용 프로그램에서 사용하는 캐싱. 레디 스 연결 / 오래된 폐쇄하거나 경우에, 당신은 바이 패스 캐싱 및 (아마도) (예를 들어, RDBMS)을 기본 데이터 저장소로 직접 이동에 응용 프로그램을 원한다. 응용 프로그램 서비스 로직은 유사 수 ...
조금 실망의 종기이. (레디 스 구현) 귀하의 응용 프로그램에서 사용하는 캐싱. 레디 스 연결 / 오래된 폐쇄하거나 경우에, 당신은 바이 패스 캐싱 및 (아마도) (예를 들어, RDBMS)을 기본 데이터 저장소로 직접 이동에 응용 프로그램을 원한다. 응용 프로그램 서비스 로직은 유사 수 ...
@Service class CustomerService ... { @Autowired private CustomerRepository customerRepo; protected CustomerRepository getCustomerRepo() { Assert.notNull(customerRepo, "The CustomerRepository was not initialized!"); return customerRepo; } @Cacheable(value = "Customers") public Customer getCustomer(Long customerId) { return getCustomerRepo().load(customerId); } ... }
모든 스프링 코어의 캐시 추상화의 문제는 캐시 "미스"값이 null 반환한다는 것입니다 확인 할 수있다. 이와 같이, 스프링 캐싱 인프라는 실제 서비스 방법 (즉 getCustomer)를 호출 진행한다. getCustomerRepo (). 부하의 반환에 유의하십시오 (고객 ID를) 호출은, 당신은 또한 지금 봄의 캐싱 인프라 시도 값을 캐시 경우를 처리 할 필요가있다.
간단 유지의 정신에서 우리는 AOP없이 할 것입니다,하지만 당신은 잘 (선택)로 사용하여이 AOP를 달성 할 수 있어야한다.
주류 (해야) 할 필요가, 같은를 SDR CacheManager 구현을 확장하는 "사용자 정의"RedisCacheManager입니다 ...
package example; import org.springframework.cache.Cache; import org.springframework.data.redis.cache.RedisCacheManager; ... class MyCustomRedisCacheManager extends RedisCacheManager { public MyCustomerRedisCacheManager(RedisTemplate redisTemplate) { super(redisTemplate); } @Override public Cache getCache(String name) { return new RedisCacheWrapper(super.getCache(name)); } protected static class RedisCacheWrapper implements Cache { private final Cache delegate; public RedisCacheWrapper(Cache redisCache) { Assert.notNull(redisCache, "'delegate' must not be null"); this.delegate = redisCache; } @Override public Cache.ValueWrapper get(Object key) { try { delegate.get(key); } catch (Exception e) { return handleErrors(e); } } @Override public void put(Object key, Object value) { try { delegate.put(key, value); } catch (Exception e) { handleErrors(e); } } // implement clear(), evict(key), get(key, type), getName(), getNativeCache(), putIfAbsent(key, value) accordingly (delegating to the delegate). protected <T> T handleErrors(Exception e) throws Exception { if (e instanceof <some RedisConnection Exception type>) { // log the connection problem return null; } else if (<something different>) { // act appropriately } ... else { throw e; } } } }
레디 스를 사용할 수없는 경우에 따라서, 아마 당신이 할 수있는 최선의 문제를 기록하고 서비스 호출이 일어날 수 있도록 진행한다. 분명히,이 성능을 방해하지만 적어도 그것은 문제가 존재한다는 인식을 제고 할 것이다. 분명히,이보다 강력한 알림 시스템에 연결 할 수 있지만, 가능성의 원유 예입니다. 중요한 것은 다른 서비스 응용 프로그램 서비스에 의존하는 (예를 들어, 레디 스)가, 실패했을 수 있습니다 동안 서비스를 계속 사용할 수있다.
레디 스의 존재와 함께 (내 이전의 설명 대)이 구현에서 나는 다음 전체 아니라 문제를 알고, 예외가 발생할 수 있도록 기본, 실제 RedisCache 구현에 위임하기로 결정했습니다, 그래서 당신은 적절하게 예외를 처리 할 수있다. 당신은 예외가 검사시 연결 문제와 관련이 있다는 확신한다면, 당신이 캐시 "미스"(즉, 나쁜 레디 스 연결 == 캐시 미스 인 것처럼 봄 캐싱 인프라를 진행할 수 있도록 "널 (null)"를 반환 할 수 있습니다, 이 경우).
나는이 "사용자 정의"CacheManager의 GemFire에 대한 구현 및 중추의 고객 중 하나의 유사한 프로토 타입을 구축으로이 문제를 도움이 될 것 같은 것을 알고있다. 특정 UC에서 캐시 '미스는 "생산은 봄의 캐싱 추상화를 통해 GemFire에 연결하는 새로운 세 응용 프로그램 클라이언트의 혼합을 가지고 응용 프로그램 도메인 객체의"오래된 버전 "에 의해 트리거 될했다. 응용 프로그램 도메인 개체 필드는 예를 들어 응용 프로그램의 최신 버전으로 변경합니다.
어쨌든,이 도움이 또는 더 많은 아이디어를 제공 바랍니다.
건배!
-
==============================
2.그래서, 난 또 다른 질문을 해결 오늘날 핵심 스프링 프레임 워크 캐싱 추상화 소스를 통해 발굴 된 그리고 CacheErrorHandler이 제대로 구현 된 경우, 다음 아마 문제가 레디 스 연결이 여전히 원하는 동작, 예를 들면 발생할 수 있습니다 보인다 (NULL 값의 반환에 트리거) 캐시 "미스".
그래서, 난 또 다른 질문을 해결 오늘날 핵심 스프링 프레임 워크 캐싱 추상화 소스를 통해 발굴 된 그리고 CacheErrorHandler이 제대로 구현 된 경우, 다음 아마 문제가 레디 스 연결이 여전히 원하는 동작, 예를 들면 발생할 수 있습니다 보인다 (NULL 값의 반환에 트리거) 캐시 "미스".
자세한 내용은 AbstractCacheInvoker 소스를 참조하십시오.
cache.get (키)으로 인한 결함이 레디 스 연결하므로 예외 핸들러가 호출된다에 예외가 발생한다 ..
catch (RuntimeException e) { getErrorHandler().handleCacheGetError(e, cache, key); return null; // If the exception is handled, return a cache miss }
CacheErrorHandler 제대로 캐시를 처리하는 경우, 널 (null) 값은 캐시 "미스"를 나타내는 반환됩니다 오류 "수"(그리고 / 예외를 던지기 다시하지 않습니다).
-
==============================
3.당신에게 @ 존 블룸 감사드립니다. 봄 부팅에 내 솔루션은 다음이다.
당신에게 @ 존 블룸 감사드립니다. 봄 부팅에 내 솔루션은 다음이다.
import org.slf4j.Logger; import org.slf4j.LoggerFactory; import org.springframework.cache.Cache; import org.springframework.data.redis.cache.RedisCacheManager; import org.springframework.data.redis.core.RedisOperations; import org.springframework.util.Assert; import java.util.concurrent.Callable; class CustomRedisCacheManager extends RedisCacheManager { private static Logger logger = LoggerFactory.getLogger(CustomRedisCacheManager.class); public CustomRedisCacheManager(RedisOperations redisOperations) { super(redisOperations); } @Override public Cache getCache(String name) { return new RedisCacheWrapper(super.getCache(name)); } protected static class RedisCacheWrapper implements Cache { private final Cache delegate; public RedisCacheWrapper(Cache redisCache) { Assert.notNull(redisCache, "delegate cache must not be null"); this.delegate = redisCache; } @Override public String getName() { try { return delegate.getName(); } catch (Exception e) { return handleException(e); } } @Override public Object getNativeCache() { try { return delegate.getNativeCache(); } catch (Exception e) { return handleException(e); } } @Override public Cache.ValueWrapper get(Object key) { try { return delegate.get(key); } catch (Exception e) { return handleException(e); } } @Override public <T> T get(Object o, Class<T> aClass) { try { return delegate.get(o, aClass); } catch (Exception e) { return handleException(e); } } @Override public <T> T get(Object o, Callable<T> callable) { try { return delegate.get(o, callable); } catch (Exception e) { return handleException(e); } } @Override public void put(Object key, Object value) { try { delegate.put(key, value); } catch (Exception e) { handleException(e); } } @Override public ValueWrapper putIfAbsent(Object o, Object o1) { try { return delegate.putIfAbsent(o, o1); } catch (Exception e) { return handleException(e); } } @Override public void evict(Object o) { try { delegate.evict(o); } catch (Exception e) { handleException(e); } } @Override public void clear() { try { delegate.clear(); } catch (Exception e) { handleException(e); } } private <T> T handleException(Exception e) { logger.error("handleException", e); return null; } } }
import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.Configuration; import org.springframework.data.redis.cache.RedisCacheManager; import org.springframework.data.redis.core.RedisTemplate; @Configuration public class RedisConfig { @Bean public RedisCacheManager redisCacheManager(RedisTemplate redisTemplate) { CustomRedisCacheManager redisCacheManager = new CustomRedisCacheManager(redisTemplate); redisCacheManager.setUsePrefix(true); return redisCacheManager; } }
-
==============================
4.실제로 내 응답 씨 @Vivek 아 디트에 관한 것이다 - 나는 같은 문제에 직면 : 새로운 API를 스프링 데이터 레디 스 및 RedisTemplate 당 RedisCacheManager을 구성하지. 유일한 옵션 - @ 존 블룸의 제안에 따라이 - 사용 측면이었다. 그리고 아래에있는 내 코드입니다.
실제로 내 응답 씨 @Vivek 아 디트에 관한 것이다 - 나는 같은 문제에 직면 : 새로운 API를 스프링 데이터 레디 스 및 RedisTemplate 당 RedisCacheManager을 구성하지. 유일한 옵션 - @ 존 블룸의 제안에 따라이 - 사용 측면이었다. 그리고 아래에있는 내 코드입니다.
@Aspect @Component public class FailoverRedisCacheAspect { private static class FailoverRedisCache extends RedisCache { protected FailoverRedisCache(RedisCache redisCache) { super(redisCache.getName(), redisCache.getNativeCache(), redisCache.getCacheConfiguration()); } @Override public <T> T get(Object key, Callable<T> valueLoader) { try { return super.get(key, valueLoader); } catch (RuntimeException ex) { return valueFromLoader(key, valueLoader); } } private <T> T valueFromLoader(Object key, Callable<T> valueLoader) { try { return valueLoader.call(); } catch (Exception e) { throw new ValueRetrievalException(key, valueLoader, e); } } } @Around("execution(* org.springframework.cache.support.AbstractCacheManager.getCache (..))") public Cache beforeSampleCreation(ProceedingJoinPoint proceedingJoinPoint) { try { Cache cache = (Cache) proceedingJoinPoint.proceed(proceedingJoinPoint.getArgs()); if (cache instanceof RedisCache) { return new FailoverRedisCache((RedisCache) cache); } else { return cache; } } catch (Throwable ex) { return null; } } }
모든 합리적인 시나리오에 잘 작동합니다 :
편집 : - 전용 "수"를, 나는 FailoverRedisCache마다 하나의 캐시 히트를 재차 생성 좋아하지 않는다 - 코드가 더 POC처럼지도가 있어야한다.
-
==============================
5.RedisCacheManager 인 후드 아래 및 레디 스에 대한 기본 CacheManager에 코어 SF 대리자가 지원 JSR-107 JCache 주석과 함께 모든 코어 스프링 프레임 워크 캐시 추상화 주석 (예컨대 @Cacheable).
RedisCacheManager 인 후드 아래 및 레디 스에 대한 기본 CacheManager에 코어 SF 대리자가 지원 JSR-107 JCache 주석과 함께 모든 코어 스프링 프레임 워크 캐시 추상화 주석 (예컨대 @Cacheable).
여기에 비슷한 스프링 XML 설정 메타 데이터의 RedisCacheManager을 구성합니다.
하나 개의 접근법은 각 (레디 스) CacheManger 동작의 연결 상태를 확인하기 위해 (간접적 RedisTemplate에서)를 RedisConnection을 사용 (레디 스) CacheManager위한 AOP 프록시를 작성하는 것이다.
연결이 실패, 또는 표준 캐시 작전을 위해 폐쇄되는 경우, (레디 스) CacheManager 따라서를 통과, 항상 (엔트리에 캐시 미스를 나타내는)를 돌려줍니다 getCache (문자열 이름)에 대한 RedisCache의 인스턴스를 반환 할 수 기본 데이터 저장소.
내가 레디 스 (또는 SDR)이 있지만,이 일을하고 아마 당신에게 당신의 자신의 몇 십오를 제공해야 모든 일에 전문가가 아니라 나처럼 어쩌면 더 나은 방법이있다 처리 할 수 있습니다.
건배.
-
==============================
6.나는 같은 문제를했지만, 불행하게도, 위의 방법 중 어느 것도 나를 위해 작동하지 않습니다. 나는 문제 점검 및 레디 스에 아무 관련이 없었다 경우 실행 명령이 시간 초과되지 않습니다 것을 발견했다. 그래서 나는 해결책 상추 라이브러리를 공부하기 시작합니다. 나는 아무 관련이 없을 때 명령을 거부하여 문제를 해결할 수 :
나는 같은 문제를했지만, 불행하게도, 위의 방법 중 어느 것도 나를 위해 작동하지 않습니다. 나는 문제 점검 및 레디 스에 아무 관련이 없었다 경우 실행 명령이 시간 초과되지 않습니다 것을 발견했다. 그래서 나는 해결책 상추 라이브러리를 공부하기 시작합니다. 나는 아무 관련이 없을 때 명령을 거부하여 문제를 해결할 수 :
@Bean public LettuceConnectionFactory lettuceConnectionFactory() { final SocketOptions socketOptions = SocketOptions.builder().connectTimeout(Duration.ofSeconds(10)).build(); ClientOptions clientOptions = ClientOptions.builder() .socketOptions(socketOptions) .autoReconnect(true) .disconnectedBehavior(ClientOptions.DisconnectedBehavior.REJECT_COMMANDS) .build(); LettuceClientConfiguration clientConfig = LettuceClientConfiguration.builder() .commandTimeout(Duration.ofSeconds(10)) .clientOptions(clientOptions).build(); RedisStandaloneConfiguration redisStandaloneConfiguration = new RedisStandaloneConfiguration(this.host, this.port); return new LettuceConnectionFactory(redisStandaloneConfiguration, clientConfig); }
from https://stackoverflow.com/questions/29003786/how-to-disable-redis-caching-at-run-time-if-redis-connection-failed by cc-by-sa and MIT license
'REDIS' 카테고리의 다른 글
[REDIS] Laravel + predis + 레디 스 클러스터 - 127.0.0.1:6379로 이동 / 연결 없음 (0) | 2020.01.02 |
---|---|
[REDIS] 설치 방법 및 ElasticBeanstalk에 레디 스를 구성합니다 (0) | 2020.01.02 |
[REDIS] 어떻게 레디 스 키를 만료됩니까? (0) | 2020.01.02 |
[REDIS] 숫자가 범위 내에 여부를 결정하는 레디 스 또는 MongoDB를? (0) | 2020.01.02 |
[REDIS] ubuntu14.04에서 레디 스 서버 : 이미 사용 바인드 주소 (0) | 2020.01.02 |