redis缓存
@[TOC]
redis缓存
1.缓存概述:
缓存(Cache)的作用是减少服务器对数据库的访问频率,从而提高数据库的稳定性。 访问的流程如下。
流程图:
代码逻辑
public Goods searchArticleById(Long goodsId){ Object object = redisTemplate.opsForValue().get(String.valueOf(goodsId)); if(object != null){// 缓存查询到了结果 return (Goods)object; } // 开始查询数据库 Goods goods = goodsMapper.selectByPrimaryKey(goodsId); if(goods!=null){ // 将结果保存到缓存中 redisTemplate.opsForValue().set(String.valueOf(goodsId),goods,60,TimeUnit.MINUTES);; } return goods; }
2.缓存方式
缓存中的数据在redis中的存储方式有两种,一种是永久存在,不设置过期时间,第二种是设置过期时间。这两种方式都需要尽可能的保证数据的一致性(和数据源中的数据保持同步)。
2.1 不设置过期时间
当我们将缓存数据的key设置为永久存在时会存在数据同步和内存消耗逐渐增大的情况,解决方式如下:
数据同步:1.禁止直接操作数据源,避免因数据直接被改动而造成缓存数据不一致的问题。 2.如果有其他系统操作同一个数据源,这种情况肯定会产生数据不一致的情况。 3.系统执行DML操作时,应该将缓存中对于的数据删除。用户下一次相关请求是直接从数据源获取。
内存消耗:随着业务的增多,缓存数据必然会越来越多,所占用的内存也随之增多,系统的压力也会变大,这时一种方式是给key设置过期时间,但是过期时间长短不太好把握,这时我们可以通过设置redis最大内存来实现,并让redis按照一定的规则淘汰不需要的缓存键,这种方式在redis只作为缓存是非常实用。
**具体实现方式:**修改redis配置文件(redis.conf)中的maxmemory参数即可,限制redis最大可用内存大小(单位字节),当超出了这个限制时redis会依据maxmemory-policy参数指定的策略来删除不需要的key直到redis占用的内存小与指定内存。 LRU:(Least recently used,最近最少使用)算法根据数据的历史访问记录来进行淘汰数据,其核心思想是“如果数据最近被访问过,那么将来被访问的几率也更高” LFU:(Least Frequently Used)算法根据数据的历史访问频率来淘汰数据,其核心思想是“如果数据过去被访问多次,那么将来被访问的频率也更高”
2.2设置过期时间
对保存到redis中的key设置过期时间,但同样也会遇到问题,比如过期时间怎么设置,内存资源同样也会过大。
内存资源同样需要设置maxmemory来限制redis使用的最大内存和配置maxmemory-policy来指定删除策略。
过期时间设置过期时间不要统一设置固定的时间,比如60分钟,这样会造成相同时间点大量缓存被清空,数据库访问量突然增大的情况,我们应该对过期时间设置合理范围内的随机值。比如:采取不同分类商品,缓存不同周期。在同一分类中的商品,加上一个随机因子。这样能进尽可能分散缓存过期时间,而且,热门类目(女装)的商品缓存时间长一些,冷门类目(图书)的商品缓存时间短一些,也能节省缓存服务的资源。
public Goods searchArticleById(Long goodsId){ Object object = redisTemplate.opsForValue().get(String.valueOf(goodsId)); if(object != null){// 缓存查询到了结果 return (Goods)object; } // 开始查询数据库 Goods goods = goodsMapper.selectByPrimaryKey(goodsId); if(goods!=null){ Random random = new Random(); // 将结果保存到缓存中 if(goods.getGoodsCategory().equals("女装")){ int time = 3600 + random.nextInt(3600); // 热门商品 redisTemplate.opsForValue() .set(String.valueOf(goodsId) ,goods ,time ,TimeUnit.MINUTES); }else{ int time = 600 + random.nextInt(600); // 冷门商品 redisTemplate.opsForValue() .set(String.valueOf(goodsId) ,goods ,time ,TimeUnit.MINUTES); } }else{ // 防止缓存穿透 redisTemplate.opsForValue() .set(String.valueOf(goodsId) ,null ,60 ,TimeUnit.MINUTES); } return goods; }
3.名称解释
缓存穿透
缓存穿透,是指查询一个数据库一定不存在的数据。正常的使用缓存流程大致是,数据查询先进行缓存查询,如果key不存在或者key已经过期,再对数据库进行查询,并把查询的到的对象,放进缓存。如果数据库查询对象为空,则不放进缓存。
public Goods searchArticleById(Long goodsId){ Object object = redisTemplate.opsForValue().get(String.valueOf(goodsId)); if(object != null){// 缓存查询到了结果 return (Goods)object; } // 开始查询数据库 Goods goods = goodsMapper.selectByPrimaryKey(goodsId); if(goods!=null){ // 将结果保存到缓存中 redisTemplate.opsForValue().set(String.valueOf(goodsId),goods,60,TimeUnit.MINUTES); }else{ redisTemplate.opsForValue().set(String.valueOf(goodsId),null,60,TimeUnit.SECONDS); } return goods; }
采用缓存空值的方式,如果从数据库查询的对象为空,也放入缓存,只是设定的缓存过期时间较短,比如设置为60秒。
缓存雪崩
缓存雪崩,是指在某一段时间段,缓存集中过期失效,解决方式就是上面设置过期时间中使用的方式,灵活设置过期时间。
缓存击穿
缓存击穿,是指一个key非常热点,在不停的扛着大并发,大并发集中对这一个点进行访问,当这个key在失效的瞬间,持续的大并发就穿破缓存,直接请求数据库,就像在一个屏蔽上凿开了一个洞。解决方式直接设置为永久key就可以了, mutex key互斥锁可以学习下,但是一般情况下用不上!
4.总结
1.设置redis最大使用内存是必须的 2.通过不同的策略设置过期时间 3.如果是热点key我们可以直接设置为永久key
转载于:https://my.oschina.net/u/4116675/blog/3047668
- 点赞
- 收藏
- 分享
- 文章举报
- Redis缓存数据库介绍与环境搭建
- c#连接Redis缓存数据库Redis的安装与配置
- Redis缓存加速
- Redis缓存在教师工作坊VectorCache与RowCache应用场景
- redis缓存的安装和使用
- Redis缓存之Set使用
- Redis缓存异常的容错实现方法( .net)
- 初学Redis(4)——简单实现Redis缓存中的排序功能
- .NET基于Redis缓存实现单点登录SSO的解决方案
- 初学Redis(四)简单实现Redis缓存中的排序功能
- 利用Spring的aop整合redis缓存
- JavaWeb项目中加入redis缓存
- thinkphp3.2.3 版本使用redis缓存的时候无法使用认证
- .NET基于Redis缓存实现单点登录SSO的解决方案[转]
- Laravel之路——file缓存修改为redis缓存
- 架构之路之spring集成redis缓存
- yii2使用redis缓存购物车和接口ip限制
- spring整合redis缓存并以注解(@Cacheable、@CachePut、@CacheEvict)形式使用
- redis缓存的使用
- Redis缓存中使用Kryo序列化工具并且修改内容同时更新缓存