项目中性能需要使用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缓存实现流程
内部代码实现思路
其中内部实现需要考虑的细节点以及解决办法:
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);
}