redis中的bitmap_面试|千亿级网站如何统计活跃用户?妙用redis中bitMap

d2146639f0e21b269a3a15a96e49f26a.png

BitMap是什么

就是通过一个bit位来表示某个元素对应的值或者状态,其中的key就是对应元素本身。我们知道8个bit可以组成一个Byte,所以bitmap本身会极大的节省储存空间。你可以把它理解为一个特殊处理过的 字符串,key代表业务属性、标签。一个 bit 位来表示某个元素对应的值或者状态

Redis中的BitMap

Redis从2.2.0版本开始新增了setbit,getbit,bitcount等几个bitmap相关命令。虽然是新命令,但是并没有新增新的数据类型,因为setbit等命令只不过是在set上的扩展。

setbit命令介绍

指令 SETBIT key offset value复杂度 O(1)设置或者清空 key 的 value(字符串)在 offset 处的 bit 值(只能只 0 或者 1)。

空间占用、以及第一次分配空间需要的时间

  • offset 为 2^32-1(分配 512MB)需要~ 300ms
  • offset 为 2^30-1(分配 128MB)需要~ 80ms
  • offset 为 2^28-1(分配 32MB)需要~ 30ms
  • offset 为 2^26-1(分配 8MB)需要 8ms。

    大概的空间占用计算公式是:($offset/8/1024/1024)MB

统计活跃用户

使用时间作为 cacheKey,然后用户 ID 为 offset,如果当日活跃过就设置为 1,那么我该如果计算某几天/月/年的活跃用户呢(暂且约定,统计时间内只有有一天在线就称为活跃),使用 redis 的命令

BITOP operation destkey key [key ...]说明:对一个或多个保存二进制位的字符串 key 进行位元操作,并将结果保存到 destkey 上。说明:BITOP 命令支持 AND 、 OR 、 NOT 、 XOR 这四种操作中的任意一种参数
//设置20200429 活跃用户1127.0.0.1:6379> setbit 20200429 1 1(integer) 0//设置20200429 活跃用户2127.0.0.1:6379> setbit 20200429 2 1(integer) 0//设置20200430 活跃用户1127.0.0.1:6379> setbit 20200430 1 1(integer) 0//设置20200430 活跃用户2127.0.0.1:6379> setbit 20200430 2 1(integer) 0//设置20200430 活跃用户3127.0.0.1:6379> setbit 20200430 3 1(integer) 0//使用命令AND统计在0429并且0430活跃的用户设置到key "active:users"127.0.0.1:6379> BITOP and active:users 20200429 20200430(integer) 1//0429并且0430活跃的用户也就是咱们的用户1 和用户2 记录数是 2127.0.0.1:6379> bitcount active:users(integer) 2127.0.0.1:6379> //使用命令OR统计在0429并且0430活跃的用户设置到key "active:users1"  127.0.0.1:6379> bitop or active:users1 20200429 20200430(integer) 1//0429、0430活跃的用户也就是咱们的用户1 和用户2 用户3 记录数是 3127.0.0.1:6379> bitcount active:users1 (integer) 3

假设当前站点有 1亿 用户,那么一天的数据大约为 100000000/8/1024/1024≈12MB

其他应用场景

用户签到:很多网站都提供了签到功能(这里不考虑数据落地事宜),并且需要展示最近一个月的签到情况,如果使用bitmap我们怎么做? 根据日期 offset =hash % 365 ; key = 年份#用户id,可以这样搞

用户在线状态:只需要一个key,然后用户ID为offset,如果在线就设置为1,不在线就设置为0,和上面的场景一样,1亿用户只需要12MB的空间。

有哪些需要注意

Redis Bitmap 的好在于 ta 压缩存储空间。在日常用法中,这种压缩的代价是要经过 CPU 运算的。

大量数据的 setBit 会造成大量的网络请求。所以一般是 程序中 把 id 数组 pack() 设进位图变成一个 String。再一次性 set 进 Redis。

这就意味着 取出来的时候需要 unpack() 把 String 解压成 id 数组。不过得益于算法,这一步并不算太复杂

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值