您好,登錄后才能下訂單哦!
本文小編為大家詳細(xì)介紹“Redis的Bitmap如何使用”,內(nèi)容詳細(xì),步驟清晰,細(xì)節(jié)處理妥當(dāng),希望這篇“Redis的Bitmap如何使用”文章能幫助大家解決疑惑,下面跟著小編的思路慢慢深入,一起來學(xué)習(xí)新知識吧。
我們使用 SpringBoot 2.2.1.RELEASE
來搭建項(xiàng)目環(huán)境,直接在pom.xml
中添加 redis 依賴
<dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-data-redis</artifactId> </dependency>
如果我們的 redis 是默認(rèn)配置,則可以不額外添加任何配置;也可以直接在application.yml
配置中,如下
spring: redis: host: 127.0.0.1 port: 6379 password:
bitmap 主要就三個操作命令,setbit
,getbit
以及 bitcount
即setbit
,主要是指將某個索引,設(shè)置為 1(設(shè)置 0 表示抹去標(biāo)記),基本語法如下
# 請注意這個index必須是數(shù)字,后面的value必須是0/1 setbit key index 0/1
對應(yīng)的 SpringBoot 中,借助 RestTemplate 可以比較容易的實(shí)現(xiàn),通常有兩種寫法,都可以
@Autowired private StringRedisTemplate redisTemplate; /** * 設(shè)置標(biāo)記位 * * @param key * @param offset * @param tag * @return */ public Boolean mark(String key, long offset, boolean tag) { return redisTemplate.opsForValue().setBit(key, offset, tag); } public Boolean mark2(String key, long offset, boolean tag) { return redisTemplate.execute(new RedisCallback<Boolean>() { @Override public Boolean doInRedis(RedisConnection connection) throws DataAccessException { return connection.setBit(key.getBytes(), offset, tag); } }); }
上面兩種寫法的核心區(qū)別,就是 key 的序列化問題,第一種寫法使用默認(rèn)的 jdk 字符串序列化,和后面的getBytes()
會有一些區(qū)別,關(guān)于這個,有興趣的小伙伴可以看一下我之前的博文: RedisTemplate 配置與使用#序列化問題
即 getbit key index
,如果返回 1,表示存在否則不存在
/** * 判斷是否標(biāo)記過 * * @param key * @param offest * @return */ public Boolean container(String key, long offest) { return redisTemplate.opsForValue().getBit(key, offest); }
即 bitcount key
,統(tǒng)計(jì)和
/** * 統(tǒng)計(jì)計(jì)數(shù) * * @param key * @return */ public long bitCount(String key) { return redisTemplate.execute(new RedisCallback<Long>() { @Override public Long doInRedis(RedisConnection redisConnection) throws DataAccessException { return redisConnection.bitCount(key.getBytes()); } }); }
前面的基本使用比較簡單,在介紹 String 數(shù)據(jù)結(jié)構(gòu)的時候也提過,我們重點(diǎn)需要關(guān)注的是 bitmap 的使用場景,它可以干嘛用,什么場景下使用它會有顯著的優(yōu)勢
日活統(tǒng)計(jì)
點(diǎn)贊
bloomfilter
上面三個場景雖有相似之處,但實(shí)際的應(yīng)用場景還是些許區(qū)別,接下來我們逐一進(jìn)行說明
統(tǒng)計(jì)應(yīng)用或網(wǎng)站的日活,這個屬于比較常見的 case 了,如果是用 redis 來做這個事情,首先我們最容易想到的是 Hash 結(jié)構(gòu),一般邏輯如下
根據(jù)日期,設(shè)置 key,如今天為 2020/10/13
, 那么 key 可以為 app_20_10_13
其次當(dāng)用戶訪問時,設(shè)置 field 為 userId, value 設(shè)置為 true
判斷日活則是統(tǒng)計(jì) map 的個數(shù)hlen app_20_10_13
上面這個邏輯有毛病么?當(dāng)然沒有問題,但是想一想,當(dāng)我們的應(yīng)用做的很 nb 的時候,每天的日活都是百萬,千萬級時,這個內(nèi)存開銷就有點(diǎn)嚇人了
接下來我們看一下 bitmap 可以怎么做
同樣根據(jù)日期設(shè)置 key
當(dāng)用戶訪問時,index 設(shè)置為 userId,setbit app_20_10_13 uesrId 1
日活統(tǒng)計(jì) bitcount app_20_10_13
簡單對比一下上面兩種方案
當(dāng)數(shù)據(jù)量小時,且 userid 分布不均勻,小的為個位數(shù),大的幾千萬,上億這種,使用 bitmap 就有點(diǎn)虧了,因?yàn)?userId 作為 index,那么 bitmap 的長度就需要能容納最大的 userId,但是實(shí)際日活又很小,說明 bitmap 中間有大量的空白數(shù)據(jù)
反之當(dāng)數(shù)據(jù)量很大時,比如百萬/千萬,userId 是連續(xù)遞增的場景下,bitmap 的優(yōu)勢有兩點(diǎn):1.存儲開銷小, 2.統(tǒng)計(jì)總數(shù)快
點(diǎn)贊的業(yè)務(wù),最主要的一點(diǎn)是一個用戶點(diǎn)贊過之后,就不能繼續(xù)點(diǎn)贊了(當(dāng)然某些業(yè)務(wù)場景除外),所以我們需要知道是否可以繼續(xù)點(diǎn)贊
上面這個 hash 當(dāng)然也可以實(shí)現(xiàn),我們這里則主要討論一下 bitmap 的實(shí)現(xiàn)邏輯
比如我們希望對一個文章進(jìn)行點(diǎn)贊統(tǒng)計(jì),那么我們根據(jù)文章 articleId 來生成 redisKey=like_1121
,將 userId 作為 index
首先是通過getbit like_1121 userId
來判斷是否點(diǎn)贊過,從而限制用戶是否可以操作
Hash 以及 bitmap 的選擇和上面的考量范圍差不多
布隆過濾器可謂是大名鼎鼎了,我們這里簡單的介紹一下這東西是啥玩意
底層存儲為一個 bitmap
當(dāng)來一個數(shù)據(jù)時,經(jīng)過 n 個 hash 函數(shù),得到 n 個數(shù)值
將 hash 得到的 n 個數(shù)值,映射到 bitmap,標(biāo)記對應(yīng)的位置為 1
如果來一個數(shù)據(jù),通過 hash 計(jì)算之后,若這個 n 個值,對應(yīng)的 bitmap 都是 1,那么表示這個數(shù)據(jù)可能存在;如果有一個不為 1,則表示這個數(shù)據(jù)一定不存在
請注意:不存在時,是一定不存在;存在時,則不一定
從上面的描述也知道,bloomfilter 的底層數(shù)據(jù)結(jié)構(gòu)就是 bitmap,當(dāng)然它的關(guān)鍵點(diǎn)在 hash 算法;根據(jù)它未命中時一定不存在的特性,非常適用于緩存擊穿的問題解決
體驗(yàn)說明
Redis 的布隆過濾器主要針對>=4.0,通過插件的形式提供,項(xiàng)目源碼地址為: https://github.com/RedisBloom/RedisBloom,下面根據(jù) readme 的說明,簡單的體驗(yàn)一下 redis 中 bloomfilter 的使用姿勢
# docker 方式安裝 docker run -p 6379:6379 --name redis-redisbloom redislabs/rebloom:latest # 通過redis-cli方式訪問 docker exec -it redis-redisbloom bash # 開始使用 # redis-cli 127.0.0.1:6379> keys * (empty array) 127.0.0.1:6379> bf.add newFilter hello (integer) 1 127.0.0.1:6379> bf.exists newFilter hello (integer) 1 127.0.0.1:6379> bf.exists newFilter hell (integer) 0
bloomfilter 的使用比較簡單,主要是兩個命令bf.add
添加元素,bf.exists
判斷是否存在,請注意它沒有刪除哦
讀到這里,這篇“Redis的Bitmap如何使用”文章已經(jīng)介紹完畢,想要掌握這篇文章的知識點(diǎn)還需要大家自己動手實(shí)踐使用過才能領(lǐng)會,如果想了解更多相關(guān)內(nèi)容的文章,歡迎關(guān)注億速云行業(yè)資訊頻道。
免責(zé)聲明:本站發(fā)布的內(nèi)容(圖片、視頻和文字)以原創(chuàng)、轉(zhuǎn)載和分享為主,文章觀點(diǎn)不代表本網(wǎng)站立場,如果涉及侵權(quán)請聯(lián)系站長郵箱:is@yisu.com進(jìn)行舉報,并提供相關(guān)證據(jù),一經(jīng)查實(shí),將立刻刪除涉嫌侵權(quán)內(nèi)容。