如果缓存服务器出现故障,是否可以使应用程序忽略缓存?

Pha*_*ate 7 java spring-data-redis spring-boot spring-cache

我有一个具有以下属性的 Spring Boot 应用程序:

spring.cache.type: redis
spring.redis.host: <hostname>
spring.redis.port: <hostport>
Run Code Online (Sandbox Code Playgroud)

现在,如果远程主机发生故障,应用程序也会因连接错误而失败。在这种情况下,我的缓存不是我的应用程序的核心,但它仅用于性能,我希望 spring 简单地绕过它并转到数据库检索其数据。

我发现这可以通过定义自定义 errorHandler 方法来实现,但为了做到这一点,我必须实现 CachingConfigurer bean...但这也迫使我重写每个方法(例如缓存管理器、缓存解析器、ecc. )。

@Configuration
public class CacheConfiguration implements CachingConfigurer{

@Override
public CacheManager cacheManager() {
    // TODO Auto-generated method stub
    return null;
}

@Override
public CacheResolver cacheResolver() {
    // TODO Auto-generated method stub
    return null;
}
...
@Override
public CacheErrorHandler errorHandler() {
    // the only method I need, maybe
    return null;
}
Run Code Online (Sandbox Code Playgroud)

我想避免这种情况......我只需要一种方法来告诉 spring“缓存崩溃了,但没关系:假装你根本没有缓存”

Joh*_*lum 4

@Phate - 绝对!我刚刚回答了一个相关问题(可能),使用 Apache Geode 或 Pivotal GemFire 作为具有 Spring 缓存抽象的 Spring Boot 应用程序中的缓存提供程序。

在那篇文章中,我没有完全禁用缓存,而是将 GemFire/Geode 切换为仅在本地模式下运行(GemFire/Geode 的可能配置)。但是,如果需要的话,可以应用相同的技术来完全禁用缓存。

本质上,在 Spring Boot 和 Spring 通常开始评估应用程序的配置之前,您需要一个预处理步骤。

在我的示例中,我实现了一个自定义 Spring 条件来检查集群(即服务器)的可用性。然后我将其应用Condition到我的@Configuration课堂上。

对于 Spring Boot,当 Spring Boot在应用程序的类路径上有效地看到(以及参见此处)Redis 和 Spring Data Redis 时,它会为 Redis 应用自动配置(作为存储和缓存提供程序) 。因此,本质上,Redis 仅在“条件”为true时才启用为缓存提供程序,主要是 由您的应用程序配置声明了一个bean ,这是您的责任。RedisConnectionFactory

那么,这会是什么样子呢?

就像我的 Apache Geode 和 Pivotal GemFire自定义 Spring Condition一样,您可以为 Redis 实现类似的 Condition,例如:

static RedisAvailableCondition implements Condition {

    @Override
    public boolean matches(ConditionContext conditionContext, 
            AnnotatedTypeMetadata annotatedTypeMetadata) {

        // Check the available of the Redis server, such as by opening a Socket
        // connection to the server node.
        // NOTE: There might be other, more reliable/robust means of checking 
        // the availability of a Redis server in the Redis community.
        Socket redisServer;

        try {

            Environment environment = conditionContext.getEnvironment();

            String host = environment.getProperty("spring.redis.host");
            Integer port = environment.getProperty("spring.redis.port", Integer.class);

            SocketAddress redisServerAddress = new InetSocketAddress(host, port);

            redisServer = new Socket();
            redisServer.connect(redisServerAddress);

            return true;
        }
        catch (Throwable ignore) {

            System.setProperty("spring.cache.type", "none");

            return false;
        }
        finally {
            // TODO: You need to implement this method yourself.
            safeCloseSocket(redisServer);
        }
    }
}

Run Code Online (Sandbox Code Playgroud)

此外,我还设置spring.cache.typeNONE,以确保在 Redis 不可用的情况下将缓存呈现为无操作。 这里NONE有更详细的解释

当然,您也可以使用后备缓存选项,使用其他缓存提供程序(例如简单的ConcurrentHashMap,但我将其作为练习留给您)。向前...

然后,在定义了RedisConnectionFactorybean 的 Spring Boot 应用程序配置类中(按照 Spring Boot 自动配置的预期),Condition使用 Spring 的@Conditiional注释添加此自定义,如下所示:

@Confgiuration
@Conditional(RedisAvailableCondition.class);
class MyRedisConfiguration {

    @Bean
    RedisConnectionFactory redisConnectionFactory() {
        // Construct and return new RedisConnectionFactory
    }
}
Run Code Online (Sandbox Code Playgroud)

这应该可以有效地处理 Redis 不可用的情况。

免责声明:我自己没有对此进行测试,但基于我的 Apache Geode/Pivotal GemFire 示例,该示例确实有效。因此,也许通过一些调整,这将满足您的需求。它还应该可以为您提供一些想法。

希望这可以帮助!

干杯!