万一缓存服务器发生故障,是否可以使应用程序忽略缓存?

时间:2019-07-25 10:18:31

标签: java spring-boot spring-data-redis spring-cache

我有一个具有以下属性的spring boot应用程序:

spring.cache.type: redis
spring.redis.host: <hostname>
spring.redis.port: <hostport>

现在,如果远程主机失败,则应用程序也会失败,并出现连接错误。 由于在这种情况下,我的缓存不是应用程序的核心,而是仅用于性能,我希望Spring可以简单地绕过缓存并转到数据库以检索其数据。

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

@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;
}

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

3 个答案:

答案 0 :(得分:1)

在任何高速缓存发生故障的情况下,我们可以使用Circuit Breaker实现的任何一种将数据库用作后备选项。使用断路器模式的好处是,一旦缓存启动,请求将自动路由回缓存,因此切换可以无缝进行。

您还可以配置要回退到数据库之前要重试的次数,以及检查缓存是否在线备份的频率。

Spring云为hystrix和Resilience4j断路器实现提供了开箱即用的支持,并且易于与spring boot应用程序集成。

https://spring.io/projects/spring-cloud-circuitbreaker
https://resilience4j.readme.io/docs/circuitbreaker

答案 1 :(得分:0)

@Phate-绝对!我刚刚回答了related question(可能),使用Apache Geode或Pivotal GemFire作为带有Spring的Cache Abstraction的Spring Boot应用程序中的缓存提供程序。

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

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

在我的示例中,我实现了custom Spring Condition,用于检查集群(即服务器)的可用性。然后,我将Condition的{​​{1}} @Configuration转到我的RedisConnectionFactory类。

对于Spring Boot,当Spring Boot有效地applied(以及auto-configuration)Redis和Spring时,它对Redis(作为存储和缓存提供程序)应用sees数据Redis位于应用程序的类路径中。因此,从本质上讲,仅在“条件”为 true 时才将Redis启用为缓存提供程序,主要是 根据您的应用程序配置和职责,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); } } } bean是sees here

那么,这会是什么样?

就像我的Apache Geode和Pivotal GemFire declared一样,您可以为Redis实现类似的条件,例如:

spring.cache.type

此外,我还将NON设置为NONE,以确保在Redis不可用的情况下将缓存呈现为无操作。 custom Spring Condition会详细说明ConcurrentHashMap

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

然后,在定义了Condition bean(在Spring Boot的自动配置中已定义)的Spring Boot应用程序配置类中,使用Spring的@Conditiional添加此自定义@Confgiuration @Conditional(RedisAvailableCondition.class); class MyRedisConfiguration { @Bean RedisConnectionFactory redisConnectionFactory() { // Construct and return new RedisConnectionFactory } } 注释,就像这样:

app.post('/users/login', function (req, res) {

var email = req.body.email;
var password = req.body.password;
var form = {
    email,
    password
}

request.post({
    url: "https://website.com/users/login",
    body: form,
    json: true
}, function (error, response, body) {
    console.log('error:', error)
    console.log('body:', body.errmsg);
    console.log(body);
    if (body.user) {
        let auth = body.token
        console.log(auth) //I want to pass this auth to /logout
    } else {
        res.render('login', {
             email,
            password
        })
    }   
})

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

免责声明:我自己并未对此进行测试,但是基于有效的Apache Geode / Pivotal GemFire示例。因此,也许可以通过一些调整来满足您的需求。它还应该有助于给您一些想法。

希望这会有所帮助!

干杯!

答案 2 :(得分:0)

<块引用>

我必须实现 CachingConfigurer bean...但这也强制 我覆盖每个方法(例如缓存管理器,缓存 解析器,ecc。)

取而代之的是,您可以简单地扩展 frame 并仅覆盖 CachingConfigurerSupport 方法,返回一个自定义 errorHandler(),其方法实现是无操作的。见https://stackoverflow.com/a/68072419/1527469