如果 redis 连接失败,如何在运行时禁用 Redis 缓存 [英] How to disable Redis Caching at run time if redis connection failed

查看:61
本文介绍了如果 redis 连接失败,如何在运行时禁用 Redis 缓存的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我们有rest api应用程序.我们使用 redis 进行 API 响应缓存和内部方法缓存.如果 redis 连接,那么它会使我们的 API 关闭.如果 redis 连接失败或出现任何异常,我们希望绕过 redis 缓存,而不是关闭我们的 API.有一个接口 CacheErrorHandler 但它处理的是 redis get set 操作失败而不是 redis 连接问题.我们使用的是 Spring 4.1.2.

We have rest api application. We use redis for API response caching and internal method caching. If redis connection then it is making our API down. We want to bypass the redis caching if that redis connection fails or any exception instead of making our API down. There is a interface CacheErrorHandler but it handles the redis get set operation failures not redis connection problems. We are using Spring 4.1.2.

推荐答案

让我们稍微总结一下.您的应用程序使用缓存(使用 Redis 实现).如果 Redis 连接陈旧/关闭或其他情况,那么您希望应用程序绕过缓存并(大概)直接转到底层数据存储(例如 RDBMS).应用程序服务逻辑可能类似于...

Let's boil this down a bit. Your application uses caching (implemented with Redis). If the Redis connection is stale/closed or otherwise, then you want the application to bypass caching and (presumably) go directly to an underlying data store (e.g. RDBMS). The application Service logic might look similar to...

@Service
class CustomerService ... {

    @Autowired
    private CustomerRepository customerRepo;

    protected CustomerRepository getCustomerRepo() {
        Assert.notNull(customerRepo, "The CustomerRepository was not initialized!");
        return customerRepo;
    }

    @Cacheable(value = "Customers")
    public Customer getCustomer(Long customerId) {
        return getCustomerRepo().load(customerId);
    }
    ...
}

在 Spring 核心的缓存抽象中,确定缓存未命中"的所有重要事项是返回的值为 null.因此,Spring Caching Infrastructure 将继续调用实际的 Service 方法(即 getCustomer).请记住 getCustomerRepo().load(customerId) 调用的返回,您还需要处理 Spring 的缓存基础结构现在尝试缓存值的情况.

All that matters in Spring core's Caching Abstraction to ascertain a Cache "miss" is that the value returned is null. As such, Spring Caching Infrastructure will then proceed in calling the actual Service method (i.e. getCustomer). Keep in mind on the return of the getCustomerRepo().load(customerId) call, you also need to handle the case where Spring's Caching Infrastructure attempts to now cache the value.

本着保持简单的精神,我们将不使用 AOP,但您应该也可以使用 AOP(您的选择)来实现这一点.

In the spirit of keeping it simple, we will do without AOP, but you should be able to achieve this using AOP as well (your choice).

您(应该)只需要一个自定义"RedisCacheManager 扩展 SDR CacheManager 实现,类似...

All you (should) need is a "custom" RedisCacheManager extending the SDR CacheManager implementation, something like...

package example;

import org.springframework.cache.Cache;
import org.springframework.data.redis.cache.RedisCacheManager;
...

class MyCustomRedisCacheManager extends RedisCacheManager {

    public MyCustomerRedisCacheManager(RedisTemplate redisTemplate) {
        super(redisTemplate);
    }

    @Override
    public Cache getCache(String name) {
        return new RedisCacheWrapper(super.getCache(name));
    }


    protected static class RedisCacheWrapper implements Cache {

        private final Cache delegate;

        public RedisCacheWrapper(Cache redisCache) {
            Assert.notNull(redisCache, "'delegate' must not be null");
            this.delegate = redisCache;
        }

        @Override
        public Cache.ValueWrapper get(Object key) {
            try {
              delegate.get(key);
            }
            catch (Exception e) {
                return handleErrors(e);
            }
        }

        @Override
        public void put(Object key, Object value) {
            try {
                delegate.put(key, value);
            }
            catch (Exception e) {
                handleErrors(e);
            }
        }

        // implement clear(), evict(key), get(key, type), getName(), getNativeCache(), putIfAbsent(key, value) accordingly (delegating to the delegate).

        protected <T> T handleErrors(Exception e) throws Exception {
            if (e instanceof <some RedisConnection Exception type>) {
                // log the connection problem
                return null;
            }
            else if (<something different>) { // act appropriately }
            ...
            else {
                throw e;
            }
        }
    }
}

因此,如果 Redis 不可用,也许您能做的最好的事情就是记录问题并继续让服务调用发生.显然,这会妨碍性能,但至少会提高对存在问题的认识.显然,这可以与更强大的通知系统相关联,但这是可能性的一个粗略示例.重要的是,您的服务仍然可用,而应用程序服务所依赖的其他服务(例如 Redis)可能已失败.

So, if Redis is unavailable, perhaps the best you can do is log the problem and proceed to let the Service invocation happen. Clearly, this will hamper performance but at least it will raise awareness that a problem exists. Clearly, this could be tied into a more robust notification system, but it is a crude example of the possibilities. The important thing is, your Service remains available while the other services (e.g. Redis) that the application service depends on, may have failed.

在这个实现中(与我之前的解释相比)我选择委托给底层的实际 RedisCache 实现来让异常发生,然后完全知道 Redis 存在问题,以便您可以适当地处理异常.但是,如果您在检查时确定异常与连接问题有关,则可以返回null"以让 Spring Caching Infrastructure 继续进行,就好像它是缓存未命中"一样(即错误的 Redis 连接 == 缓存未命中,在这种情况下).

In this implementation (vs. my previous explanation) I chose to delegate to the underlying, actual RedisCache implementation to let the Exception occur, then knowing full well a problem with Redis exists, and so that you can deal with the Exception appropriately. However, if you are a certain that the Exception is related to a connection problem upon inspection, you can return "null" to let Spring Caching Infrastructure proceed as if it were a Cache "miss" (i.e. bad Redis Connection == Cache miss, in this case).

我知道这样的事情应该可以帮助您解决问题,因为我为 GemFire 和 Pivotal 的一位客户构建了一个类似的自定义"CacheManager 实现原型.在那个特定的 UC 中,缓存未命中"必须由应用程序域对象的过时版本"触发,其中生产有新旧应用程序客户端的混合,通过 Spring 的缓存抽象连接到 GemFire.例如,应用程序域对象字段会在应用程序的较新版本中发生变化.

I know something like this should help your problem as I built a similar prototype of a "custom" CacheManager implementation for GemFire and one of Pivotal's customers. In that particular UC, the Cache "miss" had to be triggered by an "out-of-date version" of the application domain object where production had a mix of newer and older application clients connecting to GemFire through Spring's Caching Abstraction. The application domain object fields would change in newer versions of the app for instance.

无论如何,希望这对您有所帮助或给您更多想法.

Anyway, hope this helps or gives you more ideas.

干杯!

这篇关于如果 redis 连接失败,如何在运行时禁用 Redis 缓存的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆