【Redis】位图以及位图的使用场景(统计在线人数和用户在线状态)

  • BITCOUNT统计大数据量的性能问题

位图


位图的最大优点之一是,它们在存储信息时通常可以节省大量空间

位图不是一个真实的数据类型,而是定义在字符串类型上的面向位的操作的集合。由于字符串类型是二进制安全的二进制大对象,并且最大长度是 512MB,适合于设置 232 个不同的位。

位操作分为两组:常量时间单个位的操作,像设置一个位为 1 或者 0,或者获取该位的值。对一组位的操作,例如计算指定范围位的置位数量。

1字节=1B=23 b=8位

1KB=210 B

1MB=210KB

512MB=29 X 210KB X 210B X 23b = 232b ;

基本使用

我们上面知道了 位图其实是一个字符串; 那么其实我们也可以用 get set来进行操作的;

位图操作的是二进制;

SETBIT key 索引 值0/1

SETBIT 是设置二进制索引上的某个值为0或者还是1; 如果设置了高索引位,则其余位置自动填充为0;

在这里插入图片描述

刚刚设置的 key 为 f 在 第1、2、7 号为设置了1 其余的都是0;

二进制表现形式是 0110 0001

当然我们知道位图是用字符串来存的; 可以用get命令来看看 输出来的是a; 因为对于的ASCII码就是 a

在这里插入图片描述

注意:一般我们看二进制的时候可能习惯的是从右边往左边看, 但是索引的话还是从左边往右边数的; 最左边的是以0号索引开始;

GETBIT key 索引

这里索引是位数索引

127.0.0.1:6379> GETBIT f 1

(integer) 1

127.0.0.1:6379> GETBIT f 0

(integer) 0

通过SET 一次设置单个位图的所有位

例如我们上面设置的位图 f; 我们设置的时候只需了3次命令; 如果我们知道这个值是多少 可以通过SET来直接设置;比如

127.0.0.1:6379> set g a

OK

127.0.0.1:6379> get g

“a”

127.0.0.1:6379> GETBIT g 1

(integer) 1

127.0.0.1:6379> GETBIT g 0

(integer) 0

BITFIELD 设置多个位

bitfield 有三个子指令,分别是get/set/incrby,它们都可以对指定位片段进行读写,但是最多只能处理 64 个连续的位,如果超过 64 位,就得使用多个子指令,bitfield 可以一次执行多个子指令

BITFIELD key [GET type offset] [SET type offset value] [INCRBY type offset increment] [OVERFLOW WRAP|SAT|FAIL]

127.0.0.1:6379> BITFIELD mykey2 set u1 1 1 set u1 2 1 set u1 7 1

  1. (integer) 0

  2. (integer) 0

  3. (integer) 0

127.0.0.1:6379> get mykey2

“a”

BITCOUNT

计算字符串中的设置位数(填充计数) 报告设置为1的位数。

时间复杂度O(N)

BITCOUNT key [start end] #start和end参数指的是字节的索引 不是位的索引

例如设置一个字符串abcde

127.0.0.1:6379> set mykey abcde

OK

127.0.0.1:6379> get mykey

“abcde”

127.0.0.1:6379> BITCOUNT mykey 0 0 //是计算第一个字符 a的位数

(integer) 3

127.0.0.1:6379> BITCOUNT mykey 0 1 //是计算前两个个字符 ab的位数

(integer) 6

127.0.0.1:6379> BITCOUNT mykey 0 2

(integer) 10

127.0.0.1:6379> BITCOUNT mykey 1 1 //是计算第2个字符 b的位数

(integer) 3

BITPOS 查找指定值为0或1的第一位。

BITPOS key bit [start] [end] #start和end参数指的是字节的索引 不是位的索引

还是value=abcde的值

他们的二进制分别为

a=0110 0001 b=0110 0010

BITPOS mykey 1 0 0 表示找第一个字符a的第一个位是1的索引;

那么a的第一个为是1的所以是1

127.0.0.1:6379> BITPOS mykey 1 0 0

(integer) 1

BITPOS mykey 1 1 1 表示找第二个字符b的第一个位是1的索引;

a=0110 0001 b=0110 0010 我们自己数一下也就值得索引在9位

127.0.0.1:6379> BITPOS mykey 1 1 1

(integer) 9

位图的使用场景


记录用户一年的签到情况

假如有这么一个需求

  1. 记录每个用户的一年中每天的签到情况

  2. 统计某个时间段 用户的签到天数

  3. 可以查询某个时间段的签到情况

想要实现上面的需求. 最笨最笨的方法是当用户签到了就在数据库中插入一条数据; 然后需要的时候再查询出来;那么上面的需求也能满足;

但是这种方式就太浪费内存了;一个用户一年365天就有最多365条数据;那么假如有1亿个用户 这数据是很庞大的; 当然我们还是有很多聪明的方式来解决这个问题;这里就不讨论了;我们直接讨论如何用redis中的位图来实现;

一年365天的签到情况;只有 签到了或者没签到两种情况;很适合用位图 0/1来做;

一年只需要 365位就足够记录一个用户的签到情况了; 365位,只需要46 个字节 (一个字节有8位) 就可以完全容纳下,这就大大节约了存储空间。

可以设置功能上线当天比如 2020-1-1为索引 0; 后面签到的时候日期做一个差值就可以算出来位数了;

查询某个时间段的签到情况

redis中并没有批量查询的位图的命令;只有单个查询getbit ,所以只能一个个执行; 为了减少网络开销; 可以通过管道 或者写lua脚本来批量查询

统计 用户的签到总天数

最后

很多程序员,整天沉浸在业务代码的 CRUD 中,业务中没有大量数据做并发,缺少实战经验,对并发仅仅停留在了解,做不到精通,所以总是与大厂擦肩而过。

我把私藏的这套并发体系的笔记和思维脑图分享出来,理论知识与项目实战的结合,我觉得只要你肯花时间用心学完这些,一定可以快速掌握并发编程。

不管是查缺补漏还是深度学习都能有非常不错的成效,需要的话记得帮忙点个赞支持一下

整理不易,觉得有帮助的朋友可以帮忙点赞分享支持一下小编~

  • 4
    点赞
  • 8
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
1. 缓存 Redis最常见的应用场景是缓存。将热点数据存储在Redis缓存中,可以极大地提升应用程序的性能,减轻后端数据库的负担。Redis支持多种数据结构,如字符串、哈希表、列表、集合和有序集合等,可以满足不同类型的缓存需求。 2. 消息队列 Redis提供了一种名为“发布/订阅”的机制,可以用于实现消息队列。发布者将消息发布到指定的频道,订阅者从频道订阅消息。Redis还支持阻塞式读取,当没有消息可读时,订阅者会一直等待,直到有新消息到达。 3. 计数器 Redis的原子性操作可以用于实现计数器。例如,可以使用INCR命令将一个键的值增加1,DECR命令将一个键的值减少1。Redis还支持位图操作,可以用于统计用户登录次数、在线时长等数据。 4. 分布式锁 Redis的分布式锁机制可以用于解决分布式系统中的并发问题。通过将锁的状态存储在Redis中,可以实现对资源的独占访问。Redis提供了多种实现分布式锁的方式,如SETNX命令、Lua脚本、Redlock算法等。 5. 地理位置 Redis提供了一些地理位置相关的命令,如GEOADD、GEODIST和GEORADIUS等。这些命令可以用于存储和查询地理位置信息,例如,可以记录商店的坐标,并查询附近的商店信息。 6. 排行榜 Redis的有序集合可以用于实现排行榜。将每个用户的得分作为有序集合中的分值,可以按照得分排名。Redis还支持多种操作,如ZADD、ZINCRBY、ZRANK和ZREVRANGE等,可以方便地对排行榜进行操作。 7. 分布式缓存 Redis可以作为分布式缓存使用,可以将数据存储在多个Redis实例中,提高可靠性和性能。Redis提供了多种分布式缓存方案,如Redis Sentinel、Redis Cluster和Twemproxy等。
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值