You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

Redis不可用时如何规避RedisConnectionFailureException执行原方法

解决方案

Spring Cache框架原生提供了无侵入扩展点,不需要在业务代码中手动编写try/catch块,即可实现Redis连接故障时自动降级执行原方法逻辑,分为全局配置和方法级配置两种方案:


方案1:全局容错配置(推荐,一次配置所有缓存方法生效)

Spring Cache的缓存操作异常统一由CacheErrorHandler处理,默认实现会直接抛出缓存层异常,你只需要替换为自定义的容错实现,即可让所有缓存操作遇到异常时静默降级,触发原方法执行:

  1. 编写自定义缓存异常处理器
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.cache.Cache;
import org.springframework.cache.interceptor.CacheErrorHandler;

public class RedisFallbackCacheErrorHandler implements CacheErrorHandler {
    private static final Logger log = LoggerFactory.getLogger(RedisFallbackCacheErrorHandler.class);

    @Override
    public void handleCacheGetError(RuntimeException exception, Cache cache, Object key) {
        log.warn("Redis查询异常,key:{}, 原因:{},将降级执行原业务方法", key, exception.getMessage());
        // 不抛出异常,Spring会判定为缓存未命中,自动执行原方法
    }

    @Override
    public void handleCachePutError(RuntimeException exception, Cache cache, Object key, Object value) {
        log.warn("Redis写入异常,key:{}, 原因:{}", key, exception.getMessage());
        // 写入失败不抛出,不影响业务正常返回结果
    }

    @Override
    public void handleCacheEvictError(RuntimeException exception, Cache cache, Object key) {
        log.warn("Redis删除异常,key:{}, 原因:{}", key, exception.getMessage());
    }

    @Override
    public void handleCacheClearError(RuntimeException exception, Cache cache) {
        log.warn("Redis清空异常,缓存名:{}, 原因:{}", cache.getName(), exception.getMessage());
    }
}
  1. 注册处理器到Spring缓存配置
import org.springframework.cache.annotation.CachingConfigurerSupport;
import org.springframework.cache.interceptor.CacheErrorHandler;
import org.springframework.context.annotation.Configuration;

@Configuration
public class CacheAutoConfig extends CachingConfigurerSupport {
    @Override
    public CacheErrorHandler errorHandler() {
        return new RedisFallbackCacheErrorHandler();
    }
}

配置完成后,所有标注@Cacheable、@CachePut、@CacheEvict的方法,遇到Redis连接失败、操作超时等缓存层异常时,都不会抛出异常,会自动执行原业务逻辑返回结果。


方案2:方法级容错配置(仅对指定方法生效)

如果不需要全局开启容错,只想给核心查询方法单独配置降级逻辑,可以自定义带容错能力的Redis缓存管理器,在注解上单独指定即可:

  1. 编写容错版缓存管理器
import org.springframework.cache.annotation.EnableCaching;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.data.redis.cache.RedisCacheConfiguration;
import org.springframework.data.redis.cache.RedisCacheManager;
import org.springframework.data.redis.cache.RedisCacheWriter;
import org.springframework.data.redis.connection.RedisConnectionFactory;
import java.time.Duration;

@Configuration
@EnableCaching
public class FallbackCacheConfig {
    @Bean
    public RedisCacheManager fallbackRedisCacheManager(RedisConnectionFactory connectionFactory) {
        RedisCacheConfiguration defaultConfig = RedisCacheConfiguration.defaultCacheConfig()
                .entryTtl(Duration.ofHours(2)); // 按需设置缓存过期时间

        RedisCacheWriter faultTolerantWriter = new RedisCacheWriter() {
            private final RedisCacheWriter defaultWriter = RedisCacheWriter.nonLockingRedisCacheWriter(connectionFactory);

            @Override
            public void put(String name, byte[] key, byte[] value, Duration ttl) {
                try {
                    defaultWriter.put(name, key, value, ttl);
                } catch (Exception ignored) {}
            }

            @Override
            public byte[] get(String name, byte[] key) {
                try {
                    return defaultWriter.get(name, key);
                } catch (Exception e) {
                    // 查询异常返回null,等价于缓存未命中
                    return null;
                }
            }

            @Override
            public byte[] putIfAbsent(String name, byte[] key, byte[] value, Duration ttl) {
                try {
                    return defaultWriter.putIfAbsent(name, key, value, ttl);
                } catch (Exception e) {
                    return null;
                }
            }

            @Override
            public void remove(String name, byte[] key) {
                try {
                    defaultWriter.remove(name, key);
                } catch (Exception ignored) {}
            }

            @Override
            public void clean(String name, byte[] pattern) {
                try {
                    defaultWriter.clean(name, pattern);
                } catch (Exception ignored) {}
            }
        };

        return new RedisCacheManager(faultTolerantWriter, defaultConfig);
    }
}
  1. 在需要容错的方法上指定该缓存管理器
@Cacheable(value = GET_PRODUCT_CACHE, cacheManager = "fallbackRedisCacheManager")
public ProductDetailMock getProduct(final String productId) {
    ...
}

该方案不会影响其他缓存方法的原有逻辑,仅对指定了fallbackRedisCacheManager的方法生效。


注意事项

  • 两种方案均完全不侵入业务代码,不需要修改原有方法的业务逻辑
  • 异常降级时建议保留warn级别日志,方便后续排查Redis服务故障,不要完全静默吞掉所有异常
  • 如果需要更细粒度的容错策略,还可以结合AOP对特定缓存名、特定异常类型做差异化降级处理

内容的提问来源于stack exchange,提问作者Rubén Morales

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.27 00:36:20