溫馨提示×

溫馨提示×

您好,登錄后才能下訂單哦!

密碼登錄×
登錄注冊×
其他方式登錄
點(diǎn)擊 登錄注冊 即表示同意《億速云用戶服務(wù)條款》

Redis的Bitmap如何使用

發(fā)布時間:2022-03-29 14:10:00 來源:億速云 閱讀:257 作者:iii 欄目:大數(shù)據(jù)

本文小編為大家詳細(xì)介紹“Redis的Bitmap如何使用”,內(nèi)容詳細(xì),步驟清晰,細(xì)節(jié)處理妥當(dāng),希望這篇“Redis的Bitmap如何使用”文章能幫助大家解決疑惑,下面跟著小編的思路慢慢深入,一起來學(xué)習(xí)新知識吧。

I. 基本使用

1. 配置

我們使用 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:

2. 使用姿勢

bitmap 主要就三個操作命令,setbit,getbit以及 bitcount

a. 設(shè)置標(biāo)記

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 配置與使用#序列化問題

b. 判斷存在與否

即 getbit key index,如果返回 1,表示存在否則不存在

/**
 * 判斷是否標(biāo)記過
 *
 * @param key
 * @param offest
 * @return
 */
public Boolean container(String key, long offest) {
    return redisTemplate.opsForValue().getBit(key, offest);
}

c. 計(jì)數(shù)

即 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());
        }
    });
}

3. 應(yīng)用場景

前面的基本使用比較簡單,在介紹 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)行說明

a. 日活統(tǒng)計(jì)

統(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ù)快

c. 點(diǎn)贊

點(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 的選擇和上面的考量范圍差不多

d. 布隆過濾器 bloomfilter

布隆過濾器可謂是大名鼎鼎了,我們這里簡單的介紹一下這東西是啥玩意

  • 底層存儲為一個 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è)資訊頻道。

向AI問一下細(xì)節(jié)

免責(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)容。

AI