小知识,大挑战!本文正在参与“程序员必备小知识”创作活动。
简介
你们项目中使用到Redis了吗?我猜大部分都用了吧,没用到的就快要学一下了,为明年做下准备了。
缓存穿透
问题描述
缓存穿透是指网站攻击者或者其他一直访问不存在的数据,比如findById?id=-1,redis和数据库都没有,这时就会所有请求都打到数据库上,将数据库打崩,缓存也就失去了意义。
原因分析
- 代码自身原因等
- 其他网站恶意攻击等
如何解决
- 缓存空对象(伪代码如下)
public UserDTO getUserById(Long id) {
Object object = redisUtil.get(String.valueOf(id));
if (Optional.ofNullable(object).isPresent()) {
// 命中缓存
if (object instanceof NullValueResultDto) {
return null;
}
return (UserDto) object;
}
// 缓存没有命中,查询数据库放入缓存
Optional<User> userOptional = userService.getById(id);
userOptional.ifPresent(user -> {
// 存入缓存
redisUtil.set(String.valueOf(id), user);
});
return BeanUtils.copy2Bean(userOptional.orElseGet(() -> getAndSetNull(id)), UserDTO.class);
}
public User getAndSetNull(Long id) {
// 空对象存入缓存
redisUtil.set(String.valueOf(id), new NullValueResultDto());
return null;
}
需要注意的是:会缓存大量的空对象,浪费内存,可以设置有效期
- 布隆过滤器
布隆过滤器(英语:Bloom Filter)是1970年由布隆提出的。它实际上是一个很长的二进制向量和一系列随机映射函数。布隆过滤器可以用于检索一个元素是否在一个集合中。它的优点是空间效率和查询时间都远远超过一般的算法,缺点是有一定的误识别率和删除困难。
以上引用自维基百科
这里简单提一嘴,有兴趣的可以了解一下或者后面可以专门出一篇讲一下。
缓存击穿
问题描述
缓存击穿是指高并发情况下,缓存中没有但数据库有的数据(一般缓存时间到了)。这时,缓存中没有,大量用户请求打到了数据库上,把数据库打崩了。
原因分析
使用缓存时,获取不到的话会去数据库获取,可以看上面获取user的伪代码,获取到了后存到缓存。但由于是高并发下,访问量特别大,大量请求都去重建缓存,导致服务过慢。
如何解决
加个分布式锁,可以看下基于redis实现分布式锁的文章。
缓存雪崩
问题描述
大量key在存取时选择了相同的过期时间,导致大量key在某一时刻同时失效,请求全部打到数据库,造成数据库宕机。
原因分析
过多的缓存数据。
解决方案
不同的key设置不同的过期时间,尽量将其过期时间分布均匀。
总结
Redis缓存的三大问题知道了原因,怎么造成这三大问题的就会很老解决了,希望大家可以学到东西,欢迎评论想看什么样的文章。