緩存三大問題
- 緩存擊穿
熱點key失效 - 緩存雪崩
大量key失效 - 緩存穿透
大量請求不存在的key
解決緩存穿透
1.設置空key,缺點:導致redis中存儲了大量空值,請求另一個不存在的key時,需要設置新的空key。
2. 布隆過濾器:利用hash將數據映射到位數組中,高速查找數據是否經已存在。
優點:佔用內存小,速度快。
缺點:隨着數據的增加,誤判率隨之增加;無法做到刪除數據;只能判斷數據是否一定不存在,而無法判斷數據是否一定存在。
<dependency>
<groupId>redis.clients</groupId>
<artifactId>jedis</artifactId>
<version>2.9.0</version>
</dependency>
<dependency>
<groupId>com.google.guava</groupId>
<artifactId>guava</artifactId>
<version>19.0</version>
</dependency>
package redis.布隆過濾器;
import com.google.common.hash.Funnels;
import com.google.common.hash.Hashing;
import redis.clients.jedis.Jedis;
import java.nio.charset.Charset;
/**
* @author ww
*/
public class BloomFilter {
static final int expectedInsertions = 100;//要插入多少數據
static final double fpp = 0.01;//期望的誤判率
//bit數組長度
private static long numBits;
//hash函數數量
private static int numHashFunctions;
static {
numBits = optimalNumOfBits(expectedInsertions, fpp);
numHashFunctions = optimalNumOfHashFunctions(expectedInsertions, numBits);
}
public static void main(String[] args) {
Jedis jedis = new Jedis("127.0.0.1", 6379);
for (int i = 0; i < 100; i++) {
long[] indexs = getIndexs(String.valueOf(i));
for (long index : indexs) {
jedis.setbit("codebear:bloom", index, true);
}
}
for (int i = 0; i < 100; i++) {
long[] indexs = getIndexs(String.valueOf(i));
for (long index : indexs) {
Boolean isContain = jedis.getbit("codebear:bloom", index);
if (!isContain) {
System.out.println(i + "肯定沒有重複");
}
}
System.out.println(i + "可能重複");
}
}
/**
* 根據key獲取bitmap下標
*/
private static long[] getIndexs(String key) {
long hash1 = hash(key);
long hash2 = hash1 >>> 16;
long[] result = new long[numHashFunctions];
for (int i = 0; i < numHashFunctions; i++) {
long combinedHash = hash1 + i * hash2;
if (combinedHash < 0) {
combinedHash = ~combinedHash;
}
result[i] = combinedHash % numBits;
}
return result;
}
private static long hash(String key) {
Charset charset = Charset.forName("UTF-8");
return Hashing.murmur3_128().hashObject(key, Funnels.stringFunnel(charset)).asLong();
}
//計算hash函數個數
private static int optimalNumOfHashFunctions(long n, long m) {
return Math.max(1, (int) Math.round((double) m / n * Math.log(2)));
}
//計算bit數組長度
private static long optimalNumOfBits(long n, double p) {
if (p == 0) {
p = Double.MIN_VALUE;
}
return (long) (-n * Math.log(p) / (Math.log(2) * Math.log(2)));
}
}
ps:redis中字符串利用位數組存儲二進制數據
參考鏈接:https://www.cnblogs.com/CodeBear/p/10911177.html