Redis高级特性之Bitmap使用姿势及应用场景介绍,经典好文

本文详细介绍了Redis的Bitmap高级特性和应用场景,包括设置与判断标记位、统计计数,并通过实例展示了如何用于日活统计、点赞功能和布隆过滤器。还探讨了在不同数据规模下,Bitmap相对于其他数据结构的优势和选择策略。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

@Autowired

private StringRedisTemplate redisTemplate;

/**

  • 设置标记位

  • @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() {

@Override

public Boolean doInRedis(RedisConnection connection) throws DataAccessException {

return connection.setBit(key.getBytes(), offset, tag);

}

});

}

上面两种写法的核心区别,就是key的序列化问题,第一种写法使用默认的jdk字符串序列化,和后面的 getBytes() 会有一些区别,关于这个,有兴趣的小伙伴可以看一下我之前的博文: RedisTemplate配置与使用#序列化问题

b. 判断存在与否

=========

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

/**

  • 判断是否标记过

  • @param key

  • @param offest

  • @return

*/

public Boolean container(String key, long offest) {

return redisTemplate.opsForValue().getBit(key, offest);

}

c. 计数

=====

即 bitcount key ,统计和

/**

  • 统计计数

  • @param key

  • @return

*/

public long bitCount(String key) {

return redisTemplate.execute(new RedisCallback() {

@Override

public Long doInRedis(RedisConnection redisConnection) throws DataAccessException {

return redisConnection.bitCount(key.getBytes());

}

});

}

3. 应用场景

========

前面的基本使用比较简单,在介绍String数据结构的时候也提过,我们重点需要关注的是bitmap的使用场景,它可以干嘛用,什么场景下使用它会有显著的优势

  • 日活统计

  • 点赞

  • bloomfilter

上面三个场景虽有相似之处,但实际的应用场景还是些许区别,接下来我们逐一进行说明

a. 日活统计

=======

统计应用或网站的日活,这个属于比较常见的case了,如果是用redis来做这个事情,首先我们最容易想到的是Hash结构,一般逻辑如下

  • 根据日期,设置key,如今天为 2020/10/13 , 那么key可以为 app_20_10_13

  • 其次当用户访问时,设置field为userId, value设置为true

  • 判断日活则是统计map的个数 hlen app_20_10_13

上面这个逻辑有毛病么?当然没有问题,但是想一想,当我们的应用做的很nb的时候,每天的日活都是百万,千万级时,这个内存开销就有点吓人了

接下来我们看一下bitmap可以怎么做

setbit app_20_10_13 uesrId 1

bitcount app_20_10_13

简单对比一下上面两种方案

============

当数据量小时,且userid分布不均匀,小的为个位数,大的几千万,上亿这种,使用bitmap就有点亏了,因为userId作为index,那么bitmap的长度就需要能容纳最大的userId,但是实际日活又很小,说明bitmap中间有大量的空白数据

反之当数据量很大时,比如百万/千万,userId是连续递增的场景下,bitmap的优势有两点:1.存储开销小, 2.统计总数快

c. 点赞

=====

点赞的业务,最主要的一点是一个用户点赞过之后,就不能继续点赞了(当然某些业务场景除外),所以我们需要知道是否可以继续点赞

上面这个hash当然也可以实现,我们这里则主要讨论一下bitmap的实现逻辑

like_1121

getbit like_1121 userId

Hash以及bitmap的选择和上面的考量范围差不多

d. 布隆过滤器bloomfilter

===================

布隆过滤器可谓是大名鼎鼎了,我们这里简单的介绍一下这东西是啥玩意

  • 底层存储为一个bitmap

  • 当来一个数据时,经过n个hash函数,得到n个数值

  • 将hash得到的n个数值,映射到bitmap,标记对应的位置为1

如果来一个数据,通过hash计算之后,若这个n个值,对应的bitmap都是1,那么表示这个数据可能存在;如果有一个不为1,则表示这个数据一定不存在

请注意:不存在时,是一定不存在;存在时,则不一定

========================

从上面的描述也知道,bloomfilter的底层数据结构就是bitmap,当然它的关键点在hash算法;根据它未命中时一定不存在的特性,非常适用于缓存击穿的问题解决

【一线大厂Java面试题解析+后端开发学习笔记+最新架构讲解视频+实战项目源码讲义】

浏览器打开:qq.cn.hn/FTf 开源分享

体验说明

====

Redis的布隆过滤器主要针对>=4.0,通过插件的形式提供,项目源码地址为: https://github.com/RedisBloom/RedisBloom ,下面根据readme的说明,简单的体验一下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 判断是否存在,请注意它没有删除哦

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值