文章目錄
- 一、什么是 bitmap
- 1-1、Bitmap 相關命令
- 二、bitmap 和 set 對比
- 2-1、數據準備
- 2-2、內存對比
- 2-3、性能對比
- 三、布隆過濾器
- 3-1、理論
- 主要作用
- 如何將數據放到過濾器內呢?
- 注意事項
- 布隆過濾器 有兩個重要的參數
- 3-2、代碼實現
- 3-3、Java中的hash函數
最近面試,面試官問了一個場景題,遺憾的是我沒能答上來,后經老大指點,這里來做個總結。
如果微博某個大V發了一條消息,怎么統計有多少人看過了。
每一個訪問記錄肯定是要入庫的,但頁面展示的時候,我們不可能都去數據庫 count 一下。最開始我說使用redis的set數據結構把用戶id存進去,但這并不是一個很好的答案,因為它消耗的內存太大。
redis有一種數據結構 bitmap,在特定的數據場景下,它很適合來做這種統計,為什么說是特定的場景,下面我們來分析。
一、什么是 bitmap
Bitmap是一種精簡而高效的數據結構,通過二進制位存儲大規模布爾值信息,常用于快速處理用戶在線狀態、權限管理以及行為記錄等應用場景。
可以簡單把它想象成是趨于無限大的數組,只是這個數組的每個位置只能存儲 1 和 0。它可以快速的統計出有多少個 1,也可以快速統計某個區間內有多少個 1。
基于此我們可以創建一個 bitmap, key就是這條消息的id,每個位置就對應一個用戶,1 就表示看過。
1-1、Bitmap 相關命令
二、bitmap 和 set 對比
如果只是想統計有多少個用戶訪問過,且某個用戶是否訪問過,其實 set類型,也可以滿足我們的要求,實際上我上次也是這么回答的,但結果是不對的,下面來看分析。
看一種數據結構是否好,無非是看它消耗的存儲空間和運行速率,基于此我們來對比一下 bitmap 和 set的內存消耗和運行速率。
2-1、數據準備
我們以10w數據為基準來進行測試,插入數據的腳本如下
@Scheduled(fixedRate = 1000 * 60 * 60)
public void fun() {redisTemplate.setKeySerializer(new StringRedisSerializer());redisTemplate.setValueSerializer(new StringRedisSerializer());redisTemplate.setHashKeySerializer(new StringRedisSerializer());long start = System.currentTimeMillis();ValueOperations<String, Object> valueOps = redisTemplate.opsForValue();for (int i = 0; i < 100000; i++) {String uuid = UUID.randomUUID().toString();redisTemplate.opsForSet().add("set10w_uuid", uuid);redisTemplate.opsForSet().add("set10w_incr", String.valueOf(i));valueOps.setBit("bitMap10w_hash", Murmur3.hash_x86_32(uuid.getBytes(), uuid.length(), 0),true);valueOps.setBit("bitMap10w_hash_size", Math