java布隆过滤器解决redis缓存穿透_Redis的缓存穿透及解决方法——布隆过滤器BloomFilter...

目录redis

(2)解决方法session

1. Redis概述:

Redis是一个开源的Key-Value存储系统,其中Value支持String、list、set、hash、zset五种数据结构,这些数据都支持push/pop、add/remove、取交集并集、排序等丰富的操做,而且这些操做都是原子性的。并发

与同为NoSQL型缓存数据库的memcached相似,Redis的数据都存在内存中,数据的运算都在内存中进行,不会发生IO,这也是Redis为何这么快的一个缘由;区别是Redis具有持久化方式,会周期性的把更新的数据写入磁盘(RDB)或者把修改操做追加写入记录文件中(AOF)。分布式

也就是说,Redis的数据存放在内存中,但Redis也支持持久化将数据存入磁盘或文件。

Redis是单线程的,可是多任务并发时能够开启多个Redis,而且Redis支持主从同步,避免了宕机带来的影响,以及写时同步技术实现了数据读写分离(主机负责写入、从机负责读取)。

ps:Redis的特色是单线程+多路IO复用

2. Redis的主要应用场景:

(1)配合关系型数据库作高速缓存

针对对于高频次、热门访问的数据(热点数据),Redis基于内存能够有效避免IO;

另外对于分布式架构,能够作session分享。

(2)由于Redis的持久化能力,能够利用多样性的数据结构存储特定的数据

例如经过list,得出最新的n个数据;利用有序集合zset进行排序,得出排行榜,topN;利用Expire对key设置时效性;

利用自增incr、decr能够实现计数器、秒杀;

利用set集合去重;利用list集合构建队列;利用pub、sub模式发布订阅消息系统。

3. 缓存穿透及布隆过滤器

Redis的基于缓存,极大地提高了应用程序的性能和效率,特别是数据查询方面,可是也带来了一些问题,好比典型的

缓存穿透、缓存雪崩、缓存击穿。

本篇先讲缓存穿透及其解决办法。

(1)缓存穿透(大量查询一个不存在的key)定义

缓存穿透,是指查询一个数据库中不必定存在的数据;

正常使用缓存查询数据的流程是,依据key去查询value,数据查询先进行缓存查询,若是key不存在或者key已通过期,再对数据库进行查询,并把查询到的对象,放进缓存。若是数据库查询对象为空,则不放进缓存。

若是每次都查询一个不存在value的key,因为缓存中没有数据,因此每次都会去查询数据库;

当对key查询的并发请求量很大时,每次都访问DB,极可能对DB形成影响;

而且因为缓存不命中,每次都查询持久层,那么也失去了缓存的意义。

(2)解决方法

第一种是缓存层缓存空值

将数据库中的空值也缓存到缓存层中,这样查询该空值就不会再访问DB,而是直接在缓存层访问就行。

可是这样有个弊端就是缓存太多空值占用了更多的空间,能够经过给缓存层空值设立一个较短的过时时间来解决,例如60s。

第二种是布隆过滤器

将数据库中全部的查询条件,放入布隆过滤器中,

当一个查询请求过来时,先通过布隆过滤器进行查,若是判断请求查询值存在,则继续查;若是判断请求查询不存在,直接丢弃。

ps:布隆过滤器原理

原理就是一个对一个key进行k个hash算法获取k个值,在比特数组中将这k个值散列后设定为1,而后查的时候若是特定的这几个位置都为1,那么布隆过滤器判断该key存在。

布隆过滤器可能会误判,若是它说不存在那确定不存在,若是它说存在,那数据有可能实际不存在;

Redis的bitmap只支持2^32大小,对应到内存也就是512MB,误判率万分之一,能够放下2亿左右的数据,性能高,空间占用率及小,省去了大量无效的数据库链接。

所以咱们能够经过布隆过滤器,将Redis缓存穿透控制在一个可容范围内。

参考文章:

ps:布隆过滤器另外一个用途——推荐去重

例如新闻客户端的推送去重功能,当推荐系统推荐新闻时会从每一个用户的历史记录里进行筛选,过滤掉那些已经存在的记录。

实际上,若是历史记录存储在关系数据库里,去重就须要频繁地对数据库进行 exists 查询,当系统并发量很高时,数据库是很难扛住压力的。若是使用缓存把历史记录都放入缓存里,占用空间太大明显不现实,这个时候布隆过滤器就登场了,它就是专门用来解决这种去重问题的。它在起到去重的同时,在空间上还能节省 90% 以上,只是稍微有那么点不精确,也就是有必定的误判几率。

用户浏览记录存入数据库时,会在Filter上经过key的hash算法存储判断其是否存在,相似于数据存在数据库中,判断该数据是否存在的信息即元数据存放在BloomFilter中,避免了每次判断数据是否存在都要去数据库exist一遍;这样推送新闻时经过布隆过滤器判断,推送内容是否已经存在,若是存在则不推送,若是不存在则推送;

布隆过滤器能够准确过滤你已经看过的内容,没有看过的新内容,可能因为误判率过滤掉极小的一部分,这样就能够保证推荐给用户的都是无重复的。

  • 0
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
Sure!以下是一个示例代码,展示了如何在Java Spring Boot中使用布隆过滤器Redis解决缓存穿透问题: 首先,你需要在pom.xml文件中添加相应的依赖: ```xml <dependencies> <!-- Spring Boot Starter Redis --> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-data-redis</artifactId> </dependency> <!-- Guava Bloom Filter --> <dependency> <groupId>com.google.guava</groupId> <artifactId>guava</artifactId> <version>30.1-jre</version> </dependency> </dependencies> ``` 接下来,创建一个布隆过滤器的工具类 BloomFilterUtil.java: ```java import com.google.common.hash.BloomFilter; import com.google.common.hash.Funnels; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.data.redis.core.RedisTemplate; import org.springframework.stereotype.Component; import javax.annotation.PostConstruct; @Component public class BloomFilterUtil { @Autowired private RedisTemplate<String, Object> redisTemplate; private BloomFilter<String> bloomFilter; // 设置布隆过滤器的预计插入数据量和误判率 private static final int EXPECTED_INSERTIONS = 1000000; private static final double FPP = 0.001; @PostConstruct public void init() { // 创建布隆过滤器,并将其保存到RedisbloomFilter = BloomFilter.create(Funnels.stringFunnel(), EXPECTED_INSERTIONS, FPP); redisTemplate.opsForValue().set("bloomFilter", bloomFilter); } public boolean mightContain(String key) { // 从Redis中获取布隆过滤器 bloomFilter = (BloomFilter<String>) redisTemplate.opsForValue().get("bloomFilter"); // 使用布隆过滤器判断key是否可能存在 return bloomFilter.mightContain(key); } public void put(String key) { // 从Redis中获取布隆过滤器 bloomFilter = (BloomFilter<String>) redisTemplate.opsForValue().get("bloomFilter"); // 将key添加到布隆过滤器bloomFilter.put(key); // 将更新后的布隆过滤器保存到RedisredisTemplate.opsForValue().set("bloomFilter", bloomFilter); } } ``` 然后,在你需要使用布隆过滤器解决缓存穿透的地方,注入 BloomFilterUtil,并使用它来判断数据是否存在于缓存中: ```java import org.springframework.beans.factory.annotation.Autowired; import org.springframework.web.bind.annotation.GetMapping; import org.springframework.web.bind.annotation.PathVariable; import org.springframework.web.bind.annotation.RestController; @RestController public class CacheController { @Autowired private BloomFilterUtil bloomFilterUtil; @GetMapping("/data/{key}") public String getData(@PathVariable String key) { // 先使用布隆过滤器判断key是否可能存在于缓存中 if (bloomFilterUtil.mightContain(key)) { // 如果可能存在,再从缓存中获取数据 String data = redisTemplate.opsForValue().get(key); if (data != null) { return data; } } // 如果数据不在缓存中,进行其他操作(例如从数据库中查询数据) // ... return null; } } ``` 这样,当有大量的请求同时访问某个缓存时,在经过布隆过滤器的判断后,可以避免无效的缓存查询请求,减轻了数据库的负载压力。 请注意,以上代码只是示例,实际使用时需要根据具体的业务需求进行适当的修改和优化。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值