使用Spring Boot多次超时时禁用Redis

时间:2019-04-16 16:32:03

标签: spring-boot redis

我有一段时间(很少)在AWS EC2中部署了一个应用程序,我无法在Redis中连接并执行任何命令,我正在调查此问题的根本原因。

我正在使用Spring boot + Redis(Elasticcache)。

我正在使用包装器捕获任何异常以继续请求过程。

我的包装器

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 ValueWrapper get(Object key) {
    try {
        return delegate.get(key);
    } catch (Exception e) {
        return handleException(e);
    }
}

@Override
public <T> T get(Object o, Class<T> type) {
    try {
        return delegate.get(o, type);
    } 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) {
    log.error("handleException", e);
    return null;
}}

在我的redis配置中,我将超时设置为1s。因此,当1秒后未执行connect / command时,redis会引发如下异常:

Caused by: io.lettuce.core.RedisCommandTimeoutException: Command timed out

我的疑问: 有一种禁用临时缓存(不进行任何部署)的好方法,而redis不好吗?例如:使用电路断路器?

我想这样做:

    @Cacheable()
    myMethodCached(){
       myRealMethod();
    }

    myRealMethod(){}

在HystrixCommand中放入“ myMethodCached”,如果抛出超时,则会执行回退方法,而无需使用Redis。

这种方法的问题是,我需要为所有使用缓存的方法创建一个“后备”,我想全局“禁用”(将跳过所有缓存)。

是否有很好的解决方案可以在一段时间内“禁用” redis?

1 个答案:

答案 0 :(得分:0)

如果您使用的是 Spring Data Redis,则可以利用 Spring 的支持,通过自定义异常处理程序来处理这些临时中断和异常。

代码:

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

建议将超时时间设置为低于默认值(60000):

spring.cache.type=redis
spring.redis.timeout=100

然后在 Spring 上下文中创建自定义错误处理程序:

import lombok.extern.slf4j.Slf4j;
import org.springframework.cache.Cache;
import org.springframework.cache.annotation.CachingConfigurerSupport;
import org.springframework.cache.annotation.EnableCaching;
import org.springframework.cache.interceptor.CacheErrorHandler;
import org.springframework.context.annotation.Configuration;

@Slf4j
@EnableCaching
@Configuration
public class CacheConfiguration extends CachingConfigurerSupport {

    @Override
    public CacheErrorHandler errorHandler() {
        return new CacheErrorHandler() {
            @Override
            public void handleCacheGetError(RuntimeException exception, Cache cache, Object key) {
                log.info("Failure getting from cache: " + cache.getName() + ", exception: " + exception.toString());
            }

            @Override
            public void handleCachePutError(RuntimeException exception, Cache cache, Object key, Object value) {
                log.info("Failure putting into cache: " + cache.getName() + ", exception: " + exception.toString());
            }

            @Override
            public void handleCacheEvictError(RuntimeException exception, Cache cache, Object key) {
                log.info("Failure evicting from cache: " + cache.getName() + ", exception: " + exception.toString());
            }

            @Override
            public void handleCacheClearError(RuntimeException exception, Cache cache) {
                log.info("Failure clearing cache: " + cache.getName() + ", exception: " + exception.toString());
            }
        };
    }

}

Spring 应该在 100 毫秒后检测到故障并回退以检索通过 @Cacheable 注释方法检索到的数据,就像存在缓存未命中一样。每当缓存恢复时,Spring 将再次开始从缓存中提取。