網站首頁 編程語言 正文
一、序言
在實際開發中常常遇到如下需求:判斷當前元素是否存在于已知的集合中,將已知集合中的元素維護一個HashSet
,使用時只需耗時O(1)
的時間復雜度便可判斷出結果,Java內部或者Redis均提供相應的數據結構。使用此種方式除了占用內存空間外,幾乎沒有其它缺點。
當數據量達到億級別時,內存空間的占用顯著表現出來,BitMap
便是解決此類問題的一種途徑。
二、BitMap結構
1、內存消耗分析
Redis BitMap能夠存儲的數據范圍為[0,2^32-1]
,超過Integer.MAX_VALUE
上界值。
為了簡化討論,假設討論的集合元素的范圍為[0,Integer.MAX_VALUE]
,可以是其中的任何一個數。
使用HashSet
數據結構占用內存空間僅與集合中的元素數量(N)相關。當集合中元素數量為N時,所需的內存空間大概為N*4/1024/1024
MB,1億
條數據約占內存空間381MB
。
基于Redis的BitMap所占用的空間大小不與集合中元素數量相關,與集合中元素的最大值直接相關,因此BitMap所占用的內存空間范圍為[N / 8 / 1024 / 1024,Integer.MAX_VALUE / 8 / 1024 / 1024]
。
// 測試1億、5億、10億、Integer.MAX_VALUE Listitems = Arrays.asList(100000000, 500000000, 1000000000, Integer.MAX_VALUE); for (Integer item : items) { int size = item / 8 / 1024 / 1024; System.out.printf("如果集合中最大值為%-10s,則所占用的內存空間為%3sMB%n",item, size); }
這里給出了一組測試參考數據
如果集合中最大值為100000000 ,則所占用的內存空間為 11MB
如果集合中最大值為500000000 ,則所占用的內存空間為 59MB
如果集合中最大值為1000000000,則所占用的內存空間為119MB
如果集合中最大值為2147483647,則所占用的內存空間為255MB
當集合中數據增長到10億
條時,使用BItMap最大占用內存約為255MB
,而使用HashSet增長到3.8GB
。
2、命令行操作BitMap
使用Redis命令行可直接操作BitMap,將offset
位置的值標注為1,則表示當前數據存在。默認情況下未標注的位置值為0。
# 默認位不賦值為0,當數據存在于集合中,將對應位賦值為1 SETBIT key offset value # 查看對應位數據是否存在(1表示存在,0表示不存在) GETBIT key offset
3、客戶端操作BitMap
這里提供一個SpringBoot生態的RedisUtils
工具類,內部封裝操作Redis BitMap的工具方法。
// 將當前位置標記為true RedisUtils.setBit(BIT_MAP_KEY, orderId, true); // 獲取指定位置的值(對應數值是否存在) RedisUtils.getBit(BIT_MAP_KEY, orderId)
上述工具類的依賴如下,如果找不到Jar包,請直接使用Maven原始倉庫源,阿里云尚未同步完成。
xin.altitude.cms ucode-cms-common1.4.3
4、時間與空間復雜度
BitMap的存儲與取值時間復雜度為O(1)
,根據數值可直接映射下標。
BitMap占用內存空間復雜度為O(n)
,與集合中元素的最大值正相關,不是集合中元素的數量。
三、BitMap應用
1、回避緩存穿透
緩存穿透是指當前請求的數據在緩存中不存在,需要訪問數據庫獲取數據(數據庫中也不存在請求的數據)。緩存穿透給數據庫帶來了壓力,惡意緩存穿透甚至能造成數據庫宕機。
使用BitMap動態維護一個集合,當訪問數據庫前,先查詢數據的主鍵是否存在集合中,以此作為是否訪問數據庫的依據。
BitMap新增數據或者移除數據屬于輕量級操作,檢查操作的準確度依賴于動態集合維護的閉環的完整性。比如向數據庫增加數據時需要向BitMap中添加數據,從數據庫中刪除數據需要從BitMap中移除數據。如果要求嚴格的檢查可靠性,則可以單獨維護一個分布式定時任務,定期更新BitMap數據。
2、與布隆過濾器的區別
布隆過濾器與BitMap有相似的應用場景,但也有一定的區別。給定一個數,BitMap能準確知道是否存在于已知集合中;布隆過濾器能準確判斷是否不在集合中,卻不能肯定存在于集合中。
BitMap增加或者移除數據時間復雜度為O(1),方便快捷。布隆過濾器新建容易,剔除數據操作比較繁瑣。
在一些需要精確判斷的場景,優先選擇BitMap,比如判斷手機號是否已經注冊。
四、小結
Redis BitMap不是一種新的數據結構,是利用字符串類型做的一層封裝,看起來像一種新型數據結構。BitMap不像一種技術,更像是算法,在時間復雜度和空間復雜度之間尋找平衡點。
BitMap其它應用場景比如簽到打卡,統計在線人數等等。
原文鏈接:https://www.cnblogs.com/javazhishitupu/archive/2022/03/04/15962910.html
相關推薦
- 2022-07-08 python中的annotate函數使用_python
- 2022-01-03 antd獲取表單的所有數據
- 2022-09-25 文本文件與二進制文件的區別
- 2022-05-09 Python使用Plotly繪制常見5種動態交互式圖表_python
- 2022-06-09 Qt中QPainter與坐標的使用_C 語言
- 2023-04-12 如何徹底解決python?NameError:name?'__file__'?is?not?defi
- 2022-04-25 基于NPOI用C#開發的Excel以及表格設置_C#教程
- 2023-01-28 python元組的可變與不可變問題_python
- 最近更新
-
- window11 系統安裝 yarn
- 超詳細win安裝深度學習環境2025年最新版(
- Linux 中運行的top命令 怎么退出?
- MySQL 中decimal 的用法? 存儲小
- get 、set 、toString 方法的使
- @Resource和 @Autowired注解
- Java基礎操作-- 運算符,流程控制 Flo
- 1. Int 和Integer 的區別,Jav
- spring @retryable不生效的一種
- Spring Security之認證信息的處理
- Spring Security之認證過濾器
- Spring Security概述快速入門
- Spring Security之配置體系
- 【SpringBoot】SpringCache
- Spring Security之基于方法配置權
- redisson分布式鎖中waittime的設
- maven:解決release錯誤:Artif
- restTemplate使用總結
- Spring Security之安全異常處理
- MybatisPlus優雅實現加密?
- Spring ioc容器與Bean的生命周期。
- 【探索SpringCloud】服務發現-Nac
- Spring Security之基于HttpR
- Redis 底層數據結構-簡單動態字符串(SD
- arthas操作spring被代理目標對象命令
- Spring中的單例模式應用詳解
- 聊聊消息隊列,發送消息的4種方式
- bootspring第三方資源配置管理
- GIT同步修改后的遠程分支