redis常用业务场景
如何解决缓存穿透带来的问题
如果是多次查询相同不存在的值,可以将该空值也给添加至redis中,并且给失效时间,因为防止后面该条数据会有更新。
问题:如何在海量数据(例如10亿无序,不定长,不重复)快速判断某一元素是否存在?
分析思路:
首先,10亿条数据肯定不能直接去mysql,因为mysql数据是在磁盘上,会很慢。
能否直接放到redis???
也不可以,因为如果全放到redis,就无法保证redis和mysql的数据一致性。
所以我们必须要有个存储的数据的容器,常见的数据结构有:
数组,链表,树,hashMap........
如果一条数据有10kb,那么十亿条数据就有几百G的大小,普通的服务器无法承受。
所以需要找一种最简单的数据结构
布隆过滤器详解
1):数据结构是位数组(二进制向量)
2):一系列随机hash映射函数
布隆过滤器根据key通过多次hash算法计算出位数组的下标,根据下标位置判断出是否存在
布隆过滤器结果具有以下特点:
1)如果布隆过滤器判断元素存在,真实结果不一定存在(因为可能会出现hash碰撞)
2)如果布隆过滤器判断不存在,则元素一定不存在
3)如果元素实际存在,则布隆过滤器一定存在
4)如果元素实际不存在,则布隆过滤器可能存在
手撕代码:统计布隆过滤去命中率
<dependency>
<groupId>com.google.guava</groupId>
<artifactId>guava</artifactId>
<version>21.0</version>
</dependency>
import com.google.common.base.Charsets;
import com.google.common.hash.BloomFilter;
import com.google.common.hash.Funnels;
import java.text.NumberFormat;
import java.util.*;
public class BloomFilterDemo {
//模拟一共有100万条数据
private static final int count = 1000000;
public static void main(String[] args) {
BloomFilter<CharSequence> bloomFilter = BloomFilter.create(Funnels.stringFunnel(Charsets.UTF_8), count);
//实际存在的key,取出使用
List<String> list = new ArrayList<String>();
//实际存在的key,判断是否存在
Set<String> set = new HashSet<String>();
for (int i = 0; i < count; i++) {
String uuid = UUID.randomUUID().toString();
list.add(uuid);
set.add(uuid);
bloomFilter.put(uuid);
}
//正确判断的次数
int right = 0;
//错误判断的次数
int error = 0;
for (int i = 0; i < 10000; i++) {
String data = i % 100 == 0 ? list.get(i) : UUID.randomUUID().toString();
if (bloomFilter.mightContain(data)) {
if (set.contains(data)) {
right++;
continue;
}
error++;
}
}
NumberFormat percentInstance = NumberFormat.getPercentInstance();
percentInstance.setMinimumFractionDigits(2);
float wrong = (float) error / 9900;
float bingo = (float) (9900-wrong) / 9900;
System.out.println("判断100个元素存在的数据,布隆过滤器认为存在的有:"+right+"\t"
+"判断9900个元素不存在的数据,布隆过滤器认为不存在的有:"+error+"\t命中率为:"+percentInstance.format(bingo)
+"误判率为:"+percentInstance.format(wrong));
}
运行结果:
判断100个元素存在的数据,布隆过滤器认为存在的有:100 判断9900个元素不存在的数据,布隆过滤器认为不存在的有:290 命中率为:100.00%误判率为:2.93%
1:离线数据加载到布隆过滤器
2:布隆过滤器查询
3:过滤器不存在,则直接返回
4:过滤器存在,cache不存在,从数据库查询
5:数据库返回