Redis布隆過濾器的原理和應用場景,解決快取穿透
來源:哪吒程式設計
上一篇分享了圖解Redis,Redis更新策略、快取一致性問題,今天分享一下Redis布隆過濾器的原理和應用場景,解決快取穿透,實現快速入門,豐富個人簡歷,提高面試level,給自己增加一點談資,秒變面試小達人,BAT不是夢。
一、布隆過濾器BloomFilter是什麼
布隆過濾器BloomFilter是一種專門用來解決去重問題的高階資料結果。
實質就是一個大型位陣列和幾個不同的無偏hash函式,無偏表示分佈均勻。由一個初值為零的bit陣列和多個雜湊函式組成,用來判斷某個資料是否存在,它和HyperLogLog一樣,不是那麼的精準,存在一定的誤判機率。
二、布隆過濾器BloomFilter能幹嘛?
高效地插入和查詢,佔用空間少,返回的結果是不確定的,一個元素如果判斷結果為存在,它不一定存在;不存在時,一定不存在。
因為不同的字串的hashcode可能相同,布隆過濾器BloomFilter是根據hashcode判斷的,如果某個hashcode存在,它對應的字串不一定是你想要的那個字串;但是,hashcode不存在時,你所要的字串,肯定不存在,細品~
布隆過濾器BloomFilter只能新增元素,不能刪除元素。
這和上面提到的hashcode判定原理是一樣的,相同hashcode的字串會儲存在一個index,刪除時,是將某個index移除,此時,就可能移除擁有相同hashcode的不同字串,細品~
三、布隆過濾器使用場景
1、解決快取穿透問題
一般情況下,先查詢Redis快取,如果Redis中沒有,再查詢MySQL。當資料庫中也不存在這條資料時,每次查詢都要訪問資料庫,這就是快取穿透。
在Redis前面新增一層布隆過濾器,請求先在布隆過濾器中判斷,如果布隆過濾器不存在時,直接返回,不再反問Redis和MySQL。
如果布隆過濾器中存在時,再訪問Redis,再訪問資料庫。
完美解決快取穿透問題。
2、黑名單
如果黑名單非常大,上千萬了,存放起來很耗費空間,在布隆過濾器中實現黑名單功能,是一個很好的選擇。
3、網頁爬蟲對URL的去重,避免爬取相同的URL地址
四、操作布隆過濾器BloomFilter
1、使用布隆過濾器
(1)初始化bitmap
布隆過濾器 本質上 是由長度為 m 的位向量或位列表(僅包含 0 或 1 位值的列表)組成,最初所有的值均設定為 0。
(2)新增key
使用多個hash函式對key進行hash運算,得到一個整數索引值,對位陣列長度進行取模運算得到一個位置,每個hash函式都會得到一個不同的位置,將這幾個位置的值置為1就表示新增成功。
例如,我們新增一個字串“哪吒程式設計”,對字串進行多次hash(key) → 取模執行→ 得到坑位。
2、刪除key
只要有其中一位是零就表示這個key不存在,但如果都是1,則不一定存在對應的key。
3、判斷是否存在
向布隆過濾器查詢某個key是否存在時,先把這個 key 透過相同的多個 hash 函式進行運算,檢視對應的位置是否都為 1,
只要有一個位為零,那麼說明布隆過濾器中這個 key 不存在;
如果這幾個位置全都是 1,那麼說明極有可能存在;
因為這些位置的 1 可能是因為其他的 key 存在導致的,也就是前面說過的hash衝突
五、程式碼例項
1、使用Redis做快取
public class StudentSerivce {
public static final String CACHE_KEY = "student:";
@Resource
private StudentMapper studentMapper;
@Resource
private RedisTemplate redisTemplate;
public void addstudent(Student student){
int i = studentMapper.insertStudent(student);
if(i > 0)
{
//到資料庫裡面,重新撈出新資料出來,做快取
student=studentMapper.selectByKey(student.getId());
//快取key
String key=CACHE_KEY+student.getId();
//往mysql裡面插入成功隨後再從mysql查詢出來,再插入redis
redisTemplate.opsForValue().set(key,student);
}
}
public Student findstudentById(Integer studentId){
Student student = null;
String key=CACHE_KEY+studentId;
// 查詢redis
student = (Student) redisTemplate.opsForValue().get(key);
// redis沒有,查詢mysql
if(student==null){
// 從mysql查出來student
student=studentMapper.selectByPrimaryKey(studentId);
// mysql有,redis沒有
if (student != null) {
// mysql的資料寫入redis
redisTemplate.opsForValue().set(key,student);
}
}
return student;
}
}
2、布隆過濾器
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
/**
* 布隆過濾器 -> redis -> mysql
* @autor 哪吒程式設計
* @date 2023-04-17
*/
@Service
public class StudentServiceImpl implements StudentService {
public static final String CACHE_KEY = "student:";
@Autowired
private StudentMapper studentMapper;
@Autowired
private RedisTemplate redisTemplate;
public void addstudent(student student){
int i = studentMapper.insertSelective(student);
if(i > 0) {
//到資料庫裡面,重新撈出新資料出來,做快取
student=studentMapper.selectByPrimaryKey(student.getId());
//快取key
String key=CACHE_KEY+student.getId();
//往mysql裡面插入成功隨後再從mysql查詢出來,再插入redis
redisTemplate.opsForValue().set(key,student);
}
}
public student findstudentById(Integer studentId){
student student = null;
//快取key的名稱
String key=CACHE_KEY+studentId;
// 查詢redis
student = (student) redisTemplate.opsForValue().get(key);
//redis沒有,查詢mysql
if(student==null) {
student=studentMapper.selectByPrimaryKey(studentId);
// mysql有,redis沒有
if (student != null) {
// 把mysql撈到的資料寫入redis
redisTemplate.opsForValue().set(key,student);
}
}
return student;
}
/**
* BloomFilter -> redis -> mysql
* 白名單:whites
*/
public student findStudentByIdWithBloomFilter (Integer studentId) {
student student = null;
String key = CACHE_KEY + studentId;
//布隆過濾器校驗,無是絕對無,有是可能有
if(!checkWithBloomFilter("whites",key)) {
log.info("白名單無此顧客資訊:{}",key);
return null;
}
//查詢redis
student = (Student) redisTemplate.opsForValue().get(key);
//redis沒有,查詢mysql
if (student == null) {
student = studentMapper.selectByPrimaryKey(studentId);
// mysql有,redis沒有
if (student != null) {
// 把mysql撈到的資料寫入redis
redisTemplate.opsForValue().set(key, student);
}
}
return student;
}
/**
* 查詢布隆過濾器中是否存在
*/
public boolean checkWithBloomFilter(String checkItem,String key) {
int hashValue = Math.abs(key.hashCode());
long index = (long) (hashValue % Math.pow(2, 32));
return redisTemplate.opsForValue().getBit(checkItem, index);
}
}
六、總結
有,是可能有;無,是肯定無; 使用時z,初始化值儘可能滿足實際元素長度,避免擴容; 當實際元素數量超過初始長度時,應該對布隆過濾器進行重建,再將所有的歷史元素批次新增進去;
來自 “ ITPUB部落格 ” ,連結:http://blog.itpub.net/70027824/viewspace-2947021/,如需轉載,請註明出處,否則將追究法律責任。
相關文章
- Redis快取穿透解決方案--布隆過濾器Redis快取穿透過濾器
- 布隆過濾器解決快取穿透問題過濾器快取穿透
- 從快取穿透聊到布隆過濾器快取穿透過濾器
- Redis 應用-布隆過濾器Redis過濾器
- 布隆過濾器的原理及應用過濾器
- 【實戰問題】-- 快取穿透之布隆過濾器(1)快取穿透過濾器
- Redis 布隆過濾器實戰「快取擊穿、雪崩效應」Redis過濾器快取
- 布隆過濾器-使用場景的思考過濾器
- Redis詳解(十三)------ Redis布隆過濾器Redis過濾器
- 快取問題(二) 布隆過濾器(Bloom Filter) 介紹和原理快取過濾器OOMFilter
- Redis-布隆過濾器Redis過濾器
- 詳解布隆過濾器的原理和實現過濾器
- Redis 中的布隆過濾器Redis過濾器
- 布隆過濾器 與 Redis BitMap過濾器Redis
- 布隆過濾器實戰【防止快取擊穿】過濾器快取
- 詳解布隆過濾器原理與實現過濾器
- 布隆過濾器過濾器
- Redis布隆過濾器分析與總結Redis過濾器
- Guava的布隆過濾器Guava過濾器
- 布隆過濾器的概述過濾器
- Redis 快取穿透、快取雪崩原理及解決方案Redis快取穿透
- 演算法(3)---布隆過濾器原理演算法過濾器
- 布隆過濾器(Bloom Filter)詳解過濾器OOMFilter
- 布隆過濾器(BloomFilter)原理 實現和效能測試過濾器OOMFilter
- 布隆過濾器(Bloom Filter)過濾器OOMFilter
- 大白話布隆過濾器過濾器
- 布隆過濾器 Bloom Filter過濾器OOMFilter
- Bloom Filter 布隆過濾器OOMFilter過濾器
- 淺談布隆過濾器過濾器
- Redis解讀(4):Redis中HyperLongLog、布隆過濾器、限流、Geo、及Scan等進階應用Redis過濾器
- 快取穿透、快取擊穿、快取雪崩的場景以及解決方法快取穿透
- 一文徹底弄清Redis的布隆過濾器Redis過濾器
- 利用 Redis 的 bitmap 實現簡單的布隆過濾器Redis過濾器
- PHP實現布隆過濾器PHP過濾器
- Xor過濾器:比布隆Bloom過濾器更快,更小過濾器OOM
- 【Redis場景3】快取穿透、擊穿問題Redis快取穿透
- Redis應用場景及快取問題Redis快取
- 5分鐘掌握布隆過濾器過濾器