设为首页 加入收藏

TOP

项目中多级缓存设计实践总结(二)
2023-07-25 21:38:56 】 浏览:49
Tags:项目中 计实践
ride public long read() { return 0; } }) .build(new CacheLoader<String, Optional<T>>() { @Override public Optional<T> load(String key) { T cacheObject = getObjectFromDb(key); log.debug("find the local guava cache of key: {} is {}", key, cacheObject); return Optional.ofNullable(cacheObject); } }); public T get(String key) { try { if (StrUtil.isEmpty(key)) { return null; } Optional<T> optional = guavaCache.get(key); return optional.orElse(null); } catch (ExecutionException e) { log.error("get cache object from guava cache failed."); e.printStackTrace(); return null; } } public void invalidate(String key) { if (StrUtil.isEmpty(key)) { return; } guavaCache.invalidate(key); } public void invalidateAll() { guavaCache.invalidateAll(); } /** * 从数据库加载数据 * @param id * @return */ public abstract T getObjectFromDb(Object id); }

我们将getObjectFromDb方法留给子类自己去实现。以下是例子:

/**
 * @author valarchie
 */
@Component
@Slf4j
@RequiredArgsConstructor
public class GuavaCacheService {

    @NonNull
    private ISysDeptService deptService;

    public final AbstractGuavaCacheTemplate<SysDeptEntity> deptCache = new AbstractGuavaCacheTemplate<SysDeptEntity>() {
        @Override
        public SysDeptEntity getObjectFromDb(Object id) {
            return deptService.getById(id.toString());
        }
    };
}

Redis(三级缓存)

项目中会持续增长的数据比如用户、订单等相关数据。这些数据比较多,不适合放在内存级缓存当中,而应放在缓存中间件Redis当中去。Redis是支持持久化的,当我们的服务器重新启动时,依然可以从Redis中加载我们原先存储好的数据。

但是使用Redis缓存还有一个可以优化的点。我们可以自己本地再做一个局部的缓存来缓存Redis中的数据来减少网络IO请求,提高数据访问速度。 比如我们Redis缓存中有一万个用户的数据,但是一分钟之内可能只有不到1000个用户在请求数据。我们便可以在Redis中嵌入一个局部的Guava缓存来提供性能。以下是RedisCacheTemplate.

/**
 * 缓存接口实现类 三级缓存
 * @author valarchie
 */
@Slf4j
public class RedisCacheTemplate<T> {

    private final RedisUtil redisUtil;
    private final CacheKeyEnum redisRedisEnum;
    private final LoadingCache<String, Optional<T>> guavaCache;

    public RedisCacheTemplate(RedisUtil redisUtil, CacheKeyEnum redisRedisEnum) {
        this.redisUtil = redisUtil;
        this.redisRedisEnum = redisRedisEnum;
        this.guavaCache = CacheBuilder.newBuilder()
            // 基于容量回收。缓存的最大数量。超过就取MAXIMUM_CAPACITY = 1 << 30。依靠LRU队列recencyQueue来进行容量淘汰
            .maximumSize(1024)
            .softValues()
            // 没写访问下,超过5秒会失效(非自动失效,需有任意put get方法才会扫描过期失效数据。
            // 但区别是会开一个异步线程进行刷新,刷新过程中访问返回旧数据)
            .expireAfterWrite(redisRedisEnum.expiration(), TimeUnit.MINUTES)
            // 并行等级。决定segment数量的参数,concurrencyLevel与maxWeight共同决定
            .concurrencyLevel(64)
            // 所有segment的初始总容量大小
            .initialCapacity(128)
            .build(new CacheLoader<String, Optional<T>>() {
                @Override
                public Optional<T> load(String cachedKey) {
                    T cacheObject = redisUtil.getCacheObject(cachedKey);
                    log.debug("find the redis cache of key: {} is {}", cachedKey, cacheObject);
                    return Optional.ofNullable(cacheObject);
                }
            });
    }

    /**
     * 从缓存中获取对象   如果获取不到的话  从DB层面获取
     * @param id
     * @return
     */
    public T getObjectById(Object id) {
        String cachedKey = generateKey(id);
        try {
            Optional<T> optional = guavaCache.get(cachedKey);
//            log.debug("find the guava cache of key: {}", cachedKey);

            if (!optional.isPresent()) {
                T objectFromDb = getObjectFromDb(id);
                set(id, objectFromDb);
                return objectFromDb;
            }

            return optional.get();
        } catch (ExecutionException e) {
            e.printStackTrace();
            re
首页 上一页 1 2 3 4 下一页 尾页 2/4/4
】【打印繁体】【投稿】【收藏】 【推荐】【举报】【评论】 【关闭】 【返回顶部
上一篇程序员面试找替身 “作弊” 入职.. 下一篇maven 多模块项目的测试覆盖率分..

最新文章

热门文章

Hot 文章

Python

C 语言

C++基础

大数据基础

linux编程基础

C/C++面试题目