Redis安全策略详解
目录
- 缓存穿透
- 缓存击穿
- 缓存雪崩
- 布隆过滤器
- 基于布隆过滤器解决缓存穿透问题
缓存穿透
高并发情况下查询一个不存在的key
产生的背景(原因):
缓存穿透是指使用不存在的key进行大量的高并发查询,导致缓存无法命中,每次请求都要都要穿透到后端数据库查询,使得数据库的压力非常大,甚至导致数据库服务压死;
解决方案:
- 接口层实现api限流、用户授权、id检查等;
- 从缓存和数据库都取不到数据的话,一样将数据库空值放入缓存中,设置30s有效期避免使用同一个id对数据库攻击压力大;
- 布隆过滤器
缓存击穿
高并发情况下查询的一个key突然过期
产生背景(原因):
在高并发的情况下,当一个缓存key过期时,因为访问该key请求较大,多个请求同时发现缓存过期,因此对多个请求同时数据库查询、同时向Redis写入缓存数据,这样会导致数据库的压力非常大;
解决方案:
- 使用分布式锁
保证在分布式情况下,使用分布式锁保证对于每个key同时只允许只有一个线程查询到后端服务,其他没有获取到锁的权限,只需要等待即可;这种高并发压力直接转移到分布式锁上,对分布式锁的压力非常大。
- 使用本地锁
使用本地锁与分布式锁机制一样,只不过分布式锁适应于服务集群、本地锁仅限于单个服务使用。
- 软过过期
设置热点数据永不过期或者异步延长过期时间;
缓存雪崩
高并发情况下大量的key 集中失效
产生背景(原因):
缓存雪崩指缓存服务器重启或者大量的缓存集中在某个时间段失效,突然给数据库产生了巨大的压力,甚至击垮数据库的情况。
解决思路:对不用的数据使用不同的失效时间,加上随机数
布隆过滤器
布隆过滤器适用于判断某个数据是否在集合中存在,不一定百分百准备, Bloom Filter基本实现原理采用位数组与联合函数一起实现;
布隆过滤器最大的问题:就是可能会存在一个误判的问题,如果向误判概率越低,则二进制数组会越大,同时也会非常占用空间
基于布隆过滤器解决缓存穿透问题
maven依赖
<dependency> <groupId>com.google.guava</groupId> <artifactId>guava</artifactId> <version>22.0</version> </dependency>
测试代码
public class BlongTest { /** * 在布隆中存放100万条数据 */ private static Integer size = 1000000; public static void main(String[] args) { BloomFilter<Integer> integerBloomFilter = BloomFilter.create(Funnels.integerFunnel(), size, 0.01); for (int i = 0; i < size; i++) { integerBloomFilter.put(i); } // 从布隆中查询数据是否存在 ArrayList<Integer> strings = new ArrayList<>(); for (int j = size; j < size + 10000; j++) { if (integerBloomFilter.mightContain(j)) { strings.add(j); } } System.out.println("误判数量:" + strings.size()); } }
解决缓存击穿代码
@RequestMapping("/getOrder") public OrderEntity getOrder(Integer orderId) { if (integerBloomFilter != null) { if (!integerBloomFilter.mightContain(orderId)) { System.out.println("从布隆过滤器中检测到该key不存在"); return null; } } // 1.先查询Redis中数据是否存在 OrderEntity orderRedisEntity = (OrderEntity) redisTemplateUtils.getObject(orderId + ""); if (orderRedisEntity != null) { System.out.println("直接从Redis中返回数据"); return orderRedisEntity; } // 2. 查询数据库的内容 System.out.println("从DB查询数据"); OrderEntity orderDBEntity = orderMapper.getOrderById(orderId); if (orderDBEntity != null) { System.out.println("将Db数据放入到Redis中"); redisTemplateUtils.setObject(orderId + "", orderDBEntity); } return orderDBEntity; } /** * 添加订单id到布隆过滤器中 */ @RequestMapping("/dbToBulong") public String dbToBulong() { List<Integer> orderIds = orderMapper.getOrderIds(); integerBloomFilter = BloomFilter.create(Funnels.integerFunnel(), orderIds.size(), 0.01); for (int i = 0; i < orderIds.size(); i++) { integerBloomFilter.put(orderIds.get(i)); } return "success"; }
到此这篇关于Redis安全策略详解的文章就介绍到这了,更多相关Redis安全内容请搜索我们以前的文章或继续浏览下面的相关文章希望大家以后多多支持我们!
赞 (0)