redis与缓存
2019-08-09 21:56
120 查看
版权声明:本文为博主原创文章,遵循 CC 4.0 by-sa 版权协议,转载请附上原文出处链接和本声明。
本文链接:https://blog.csdn.net/fql123455/article/details/98988410
1.什么是缓存
缓存是计算机内存里的一段数据
2.缓存的特点
由于缓存数据在内存中 所以读写缓存中的数据非常快
3.为什么项目中使用缓存
- 项目中使用缓存可以在一定程度上减轻数据库压力
- 可以提高现有网站中查询效率 加快网站响应速度
4.项目中是不是所有数据都需要缓存
不是 加入缓存主要数据:查询居多 增删改极少
5.mybatis自身缓存缺陷
- 自身实现缓存的数据会占用一定应用服务器内存 导致应用服务器处理请求的速度可能变慢 这种缓存也叫本地缓存。
- 本地缓存在集群架构下不能实现缓存共享。
- 为了解决本地缓存存在的问题可以实现分布式缓存服务器 memcached redis
6.现有项目中使用redis做分布式缓存的实现
1.基于现有mybatis提供cache接口实现自定义缓存
- 自定义缓存实现类 implements Cache 要求必须存在一个带有String类型id参数构造方法
- 要求实现getId方法 这个方法必须返回值当前namespace
public class RedisCache implements Cache { private final String id; private Jedis cache = new Jedis("192.168.160.129",6379); public RedisCache(String id) { this.id = id; } @Override public String getId() { return id; } // 返回缓存所有键值对的数量 @Override public int getSize() { Long dbSize = cache.dbSize(); return dbSize.intValue(); } // 向缓存中存入数据 @Override public void putObject(Object key, Object value) { System.out.println("put object key:"+key); // 将对象序列化成字节数组 byte[] keyBs = SerializationUtils.serialize((Serializable) key); byte[] valueBs = SerializationUtils.serialize((Serializable) value); cache.set(keyBs, valueBs); } // 从缓存中获取数据 @Override public Object getObject(Object key) { byte[] keyBs = SerializationUtils.serialize((Serializable) key); byte[] valueBs = cache.get(keyBs); if (valueBs != null) { // 第一次到缓存找数据的时候 , 返回的是null return SerializationUtils.deserialize(valueBs); } return null; } // 清除缓存 @Override public Object removeObject(Object key) { // 先获取一下删除的对象 byte[] keyBs = SerializationUtils.serialize((Serializable) key); byte[] valueBs = cache.get(keyBs); Object obj = SerializationUtils.deserialize(valueBs); cache.del(keyBs);// 执行删除操作 return obj; } // 清空缓存 @Override public void clear() { cache.flushDB(); } @Override public ReadWriteLock getReadWriteLock() { return null; } @Override public boolean equals(Object o) { if (getId() == null) { throw new CacheException("Cache instances require an ID."); } if (this == o) { return true; } if (!(o instanceof Cache)) { return false; } Cache otherCache = (Cache) o; return getId().equals(otherCache.getId()); } @Override public int hashCode() { if (getId() == null) { throw new CacheException("Cache instances require an ID."); } return getId().hashCode(); }
- 在mapper文件中指定使用自定义缓存
<!--使用自定义二级缓存--> <cache type="com.baizhi.cache.RedisCache"></cache>
7.redis结合mybatis实现缓存存在的问题
1. 缓存穿透
1.概念
缓存穿透是指用户查询数据,在数据库中没有,自然缓存中也不会存在。这样就导致在缓存中查找后,又进行数据库的查找,进行了两次无用的操作。
2.解决方案
- 使用布隆过滤器,将所有可能存在的数据哈希到一个足够大的bitmap中,一个一定不存在的数据会被bitmap拦截掉,从而避免了对底层存储系统查询的压力。
- 空数据也缓存,但他的缓存过期时间很短,最长不超过5分钟,进而避免空数据进行数据库的查询。
2.缓存雪崩
1.概念
由于大量的缓存,在同一时刻到达失效时间,而新缓存未到,形成大面积的缓存过期。所有原本应该访问缓存的请求全部,同时去查询数据库,造成数据库CPU和内存过大的并发压力,严重造成宕机,造成系统崩溃。
2.解决方案
- 队列、加锁: 保证不会在同一时刻对数据库的大量访问。
- 分散失效时间:在原有失效时间的基础上加上一个随机值,比如1-5分钟随机,这样可以避免大面积缓存在同一时间过期。
- 添加缓存标记:给每一个缓存数据增加相应的缓存标记,记录缓存是否失效,如果失效,则更新数据缓存。
3.缓存预热
1.概念
缓存预热这个应该是一个比较常见的概念,相信很多小伙伴都应该可以很容易的理解,缓存预热就是系统上线后,将相关的缓存数据直接加载到缓存系统。这样就可以避免在用户请求的时候,先查询数据库,然后再将数据缓存的问题!用户直接查询事先被预热的缓存数据!
2.思路
- 直接写个缓存刷新页面,上线时手工操作
- 数据量不大,可以在项目启动的时候自动进行加载
- 定时刷新缓存
4.缓存降级
1.概念
当访问量剧增、服务出现问题(如响应时间慢或不响应)或非核心服务影响到核心流程的性能时,仍然需要保证服务还是可用的,即使是有损服务。系统可以根据一些关键数据进行自动降级,也可以配置开关实现人工降级。
2.降级原则
参考日志级别设置预案
- 一般:比如有些服务偶尔因为网络抖动或者服务正在上线而超时,可以自动降级
- 警告:有些服务在一段时间内成功率有波动(如在95~100%之间),可以自动降级或人工降级,并发送告警
- 错误:比如可用率低于90%,或者数据库连接池被打爆了,或者访问量突然猛增到系统能承受的最大阀值,此时可以根据情况自动降级或者人工降级
- 严重错误:比如因为特殊原因数据错误了,此时需要紧急人工降级
相关文章推荐
- 针对缓存在Redis中的聊天消息的持久化方案分析
- redis(四)redis与Mybatis的无缝整合让MyBatis透明的管理缓存
- Python的Flask框架使用Redis做数据缓存的配置方法
- PHP 利用redis 做统计缓存mysql的压力
- 缓存 memcached 与 redis
- Spring Boot集成Redis实现缓存
- 分布式缓存技术redis学习系列(六)—— 深入理解Spring Redis的使用
- Redis整合Spring结合使用缓存实例
- Redis的缓存原理看一遍就知道
- 一个简单的redis缓存工具
- 第三方缓存软件:Redis 和 Memcached
- spring 配置 cache 缓存使用 ConcurrentMap EhCache Redis
- 配置redis缓存失效时间
- 网站缓存技术总结( ehcache、memcache、redis对比)
- hibernate redis 二级缓存
- 构建高性能数据库缓存之redis主从复制
- .NET分布式缓存Redis从入门到实战
- spring整合redis客户端及缓存接口设计
- springboot项目使用redis数据库作缓存
- Redis实现Mybatis的二级缓存