项目中性能需要使用redis做数据缓存,主要是存储业务必须对象,为了提高性能就简要设计了下简易缓存,通过过期时间特性来及时更新缓存数据。具体实现思路如下图Redis存储在内存,读取性能好,但是不能存放太大数据,单个key数据太大,在大流量高并发情况下会打爆网卡,使用redis缓存时候数据量较大一定要谨慎。我抽空简单整理了下实现流程和思路,希望对刚入门学习者有帮助,不到之处勿喷。

Redis 优势

Redis是key-value存储非关系型数据库,数据存储在内存中,它可以用作数据库、缓存和消息中间件。 它支持多种类型的数据结构,如 字符串(strings), 散列(hashes), 列表(lists), 集合(sets), 有序集合(sorted sets) 等;

• 性能极高 – Redis能读的速度是110000次/s,写的速度是81000次/s 。
• 丰富的数据类型 – Redis支持二进制案例的 Strings, Lists, Hashes, Sets 及 Ordered Sets 数据类型操作。
• 原子 – Redis的所有操作都是原子性的,同时Redis还支持对几个操作全并后的原子性执行。
• 丰富的特性 – Redis还支持 publish/subscribe, 通知, key 过期等等特性。

本次实现使用到redis hash、string、ttl、过期设置等相关操作,封装到基类中方便重用;

这里通过流程建议说下当时考虑的流程和时间解决思路,BaseCahe代码可以根据自己理解去实现,主要实现是采用了抽象类和抽象方法进行实现,目的是为了使用方只需要写DB查询业务方法和简单参数设置,使用方无需关系内部getData的实现。

Redis缓存实现流程

redis 对象 存取效率 redis对象存储方式_redis缓存对象

内部代码实现思路

redis 对象 存取效率 redis对象存储方式_redis 对象 存取效率_02

其中内部实现需要考虑的细节点以及解决办法:

1、redis读取失败的时候需要考虑需要做异常处理返回数据库数据

redis读写失败我是直接返回DB查询数据

2、读取对象时候如果读取DB方法返回数据为空是否要缓存到Redis中,是否需要使用方通过传入参数开关

返回数据为空一种是无数据,一种可能是异常返回,这种情况需要考虑是否要存储到缓存中。目前由于业务场景下未做自定义开关,而是通过设置相对较短的缓存时间过期后DB进行查询

3、缓存设置过期时间未成功如果处理

采用ttl方法对缓存时间进行验证,如果反响设置未成功通过重试方式进行补偿设置

4、缓存过大如何处理,是采用监控方式还是禁止写入到缓存当中

目前通过缓存写入的时候获取存入序列化后字符串字节数进行监控,跟进应用号配置对应提醒邮箱,提醒使用方进行优化

5、多应用缓存重复如何重用

正常情况下缓存前缀每个应用统一设置,但是可以通过设置参数对象可设置自定义缓存前缀,方便多应用缓存重用

6、缓存方法实现请求参数不一致如何解决

目前采用Object[] params来实现,后期可通过泛型来进行参数传入

7、对象存储目前支持常用类型

HashMap、Map、List、Class对象,对象采用fastjson序列化后存储,同时采用hash可以支持多个field存储和获取

使用代码示例
方便理解这里贴一下使用代码DEMO,最外层只调用getData即可;

/**
 * 数据对象缓存实现示例
 */
@Component
public class SaleUserCache extends BaseCache<SaleUserInfo> {


    /**
     * 数据库数据查询时间
     *
     * @param params 查询参数
     * @return 缓存输出对象
     * @throws CacheException 缓存内部抛出异常
     */
    @Override
    protected SaleUserInfo getExternalData(Object[] params) throws CacheException {
        return null;
    }

    /**
     * hash缓存key
     *
     * @param params 查询参数,可以支持动态key参数使用
     * @return 缓存key
     */
    @Override
    protected String cacheKey(Object[] params) {
        return "SaleUserInfo_" + params[0].toString();
    }

    /**
     * 缓存基础配置
     * 过期时间设置(可分钟、小时、天等)
     * 缓存管理名称
     * 缓存前缀自定义设置
     *
     * @return 缓存基础配置对象
     */
    @Override
    protected CacheConfig cacheConfig() {
        CacheConfig cacheConfig = new CacheConfig();
        cacheConfig.setTimeUnit(CacheConfig.TimeUnit.MINUTES);
        cacheConfig.setTime(10);
        cacheConfig.setCacheName("销售员据对象");
        cacheConfig.setCacheKeyPrefix("DEMO_");
        return cacheConfig;
    }

    /**
     * hash缓存 flied
     *
     * @param params 查询参数,可以支持动态key参数使用,也可以和key一致
     * @return flied
     */
    @Override
    protected String storeKey(Object[] params) {
        return params[0].toString();
    }
}

调用示例

/**
     * 使用缓存示例
     */
    @Autowired
    public SaleUserCache saleUserCache;
    
    public SaleUserInfo getUser(String userId){
       return saleUserCache.getData(userId);
    }