您的位置:首页 > 数据库 > Redis

redis与缓存

2019-08-09 21:56 120 查看
版权声明:本文为博主原创文章,遵循 CC 4.0 by-sa 版权协议,转载请附上原文出处链接和本声明。 本文链接:https://blog.csdn.net/fql123455/article/details/98988410

1.什么是缓存

缓存是计算机内存里的一段数据

2.缓存的特点

由于缓存数据在内存中 所以读写缓存中的数据非常快

3.为什么项目中使用缓存

  1. 项目中使用缓存可以在一定程度上减轻数据库压力
  2. 可以提高现有网站中查询效率 加快网站响应速度

4.项目中是不是所有数据都需要缓存

不是 加入缓存主要数据:查询居多 增删改极少

5.mybatis自身缓存缺陷

  1. 自身实现缓存的数据会占用一定应用服务器内存 导致应用服务器处理请求的速度可能变慢 这种缓存也叫本地缓存。
  2. 本地缓存在集群架构下不能实现缓存共享。
  3. 为了解决本地缓存存在的问题可以实现分布式缓存服务器 memcached redis

6.现有项目中使用redis做分布式缓存的实现

1.基于现有mybatis提供cache接口实现自定义缓存

  1. 自定义缓存实现类 implements Cache 要求必须存在一个带有String类型id参数构造方法
  2. 要求实现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();
}
  1. 在mapper文件中指定使用自定义缓存
<!--使用自定义二级缓存-->
<cache type="com.baizhi.cache.RedisCache"></cache>

7.redis结合mybatis实现缓存存在的问题

1. 缓存穿透

1.概念

缓存穿透是指用户查询数据,在数据库中没有,自然缓存中也不会存在。这样就导致在缓存中查找后,又进行数据库的查找,进行了两次无用的操作。

2.解决方案

  1. 使用布隆过滤器,将所有可能存在的数据哈希到一个足够大的bitmap中,一个一定不存在的数据会被bitmap拦截掉,从而避免了对底层存储系统查询的压力。
  2. 空数据也缓存,但他的缓存过期时间很短,最长不超过5分钟,进而避免空数据进行数据库的查询。

2.缓存雪崩

1.概念

由于大量的缓存,在同一时刻到达失效时间,而新缓存未到,形成大面积的缓存过期。所有原本应该访问缓存的请求全部,同时去查询数据库,造成数据库CPU和内存过大的并发压力,严重造成宕机,造成系统崩溃。

2.解决方案

  1. 队列、加锁: 保证不会在同一时刻对数据库的大量访问。
  2. 分散失效时间:在原有失效时间的基础上加上一个随机值,比如1-5分钟随机,这样可以避免大面积缓存在同一时间过期。
  3. 添加缓存标记:给每一个缓存数据增加相应的缓存标记,记录缓存是否失效,如果失效,则更新数据缓存。

3.缓存预热

1.概念

缓存预热这个应该是一个比较常见的概念,相信很多小伙伴都应该可以很容易的理解,缓存预热就是系统上线后,将相关的缓存数据直接加载到缓存系统。这样就可以避免在用户请求的时候,先查询数据库,然后再将数据缓存的问题!用户直接查询事先被预热的缓存数据!

2.思路

  1. 直接写个缓存刷新页面,上线时手工操作
  2. 数据量不大,可以在项目启动的时候自动进行加载
  3. 定时刷新缓存

4.缓存降级

1.概念

当访问量剧增、服务出现问题(如响应时间慢或不响应)或非核心服务影响到核心流程的性能时,仍然需要保证服务还是可用的,即使是有损服务。系统可以根据一些关键数据进行自动降级,也可以配置开关实现人工降级。

2.降级原则

参考日志级别设置预案

  1. 一般:比如有些服务偶尔因为网络抖动或者服务正在上线而超时,可以自动降级
  2. 警告:有些服务在一段时间内成功率有波动(如在95~100%之间),可以自动降级或人工降级,并发送告警
  3. 错误:比如可用率低于90%,或者数据库连接池被打爆了,或者访问量突然猛增到系统能承受的最大阀值,此时可以根据情况自动降级或者人工降级
  4. 严重错误:比如因为特殊原因数据错误了,此时需要紧急人工降级
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: