使用spring boot多次超时时禁用redis

Posted

技术标签:

【中文标题】使用spring boot多次超时时禁用redis【英文标题】:Disable redis when many timeouts using spring boot 【发布时间】:2019-09-06 19:56:04 【问题描述】:

我在 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 配置中,我将超时设置为 1 秒。因此,当连接/命令在 1s 后未执行时,redis 会抛出如下异常:

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

我的疑问: 有一个很好的方法可以暂时禁用缓存(无需任何部署),而redis不好?例如:使用断路?

我想这样做:

    @Cacheable()
    myMethodCached()
       myRealMethod();
    

    myRealMethod()

在HystrixCommand中放入“myMethodCached”,如果抛出超时,则不使用redis执行fallback方法。

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

“禁用”redis一段时间有没有好的解决方案?

【问题讨论】:

【参考方案1】:

如果您使用的是 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 将再次开始从缓存中拉取。

【讨论】:

以上是关于使用spring boot多次超时时禁用redis的主要内容,如果未能解决你的问题,请参考以下文章

实战服务调用幂等性:Spring Boot 集成 Redis

会话超时时,如何从 Spring Security 向 angularjs 应用程序发送响应?

原创Spring Boot集成Redis的玩法

Spring Security 3.1 - 发生会话超时时自动重定向到登录页面

在 junit 测试中禁用 RedisHttpSessionConfiguration

Spring Boot + Redis 解决重复提交问题,还有谁不会??