位图BitMap

先来看一个问题:
:有20亿的用户,现在要快速统计出有多少个用户在登录态中,要怎么设计?
:用MySQL数据库表存起来,当用户登录了设置为1,退出时改为0,然后统计出条件为1的数量即可。

:如果放在像MySQL这样的数据库中,用户基数很大,这样会很频繁地改动数据库,IO多,拖累系统性能。
:换成Redis,定义一个set类型的key叫做uid_login,用户登录了就往set中添加,退出了就删除这个uid元素。通过scard命令获取成员数量,即已登陆的uid数量。还能以O(1)的时间复杂度去判断uid是否登录。

:假设其中有10亿个用户处于登录状态,那集合就有10个uid,按每个uid占用4个字节来计算,这个需要占用多少内存呢?
:10亿乘以4就就等于40亿字节,换算后大概就是4GB……

:那有没有更省内存的方法呢?
:用string类型来做,key命名为uid_login_用户id,如果登录了,就添加uid_login_用户id这个key,值为1;如果不存在,就删掉这个key,这样value就应该不会占用这么多了吧……

:key的数量会有10个亿,难道key就不占用内存吗?还有你要如何统计处于登录态的uid数量呢?
:……

现在,主角——BitMap出场

所谓bitmap,就是用每一位来存放某种状态,适用于大规模数据,但数据状态又不是很多的情况。通常是用来判断某个数据存不存在的。

bitmap的开源实现

SETBIT key offset value 给某个key的offset设置value
GETBIT key offset 获取key的offset值
BITCOUNT key [start] [end] 统计key中value为1的数量
BITOP operation destkey key [key...] key的与或非操做等
BITOPS key bit [start] [end]

key就是自定义的redis的key;offset就是偏移量,类似于数组下标;value就是比特位值,只能为0或1

例如:

key: user_login_status
offset: uid
用户10023登录 setbit user_login_status 10023 1
用户10023退出 setbit user_login_status 10023 0
判断用户是否在线:getbit user_login_status 10023
解决统计问题:bitcount user_login_status 得在线用户数

1个用户占1bit,比用set占用的32位优化了32倍,相对于刚开始的4GB现在直接变为125MB

那么如何获取已登陆且手机为iOS系统的用户呢?
给其新建一个key:user_ios代表用了IOS系统的用户
将user_login_status与user_ios做与操做就可以得到IOS系统用户了,即user_ios & user_login_status

所以要统计所有登录用户的数量呢?
user_login_status与user_ios做或操做就可以了

BitMap优点:
  • 排序、查找、去重等效率高
  • 占用内存空间低
BitMap缺点:
  • 结果数据不能重复,相当于就是排重过的
  • 如果数据只有两个:1和10000000,使用BitMap空间比较浪费,只有当数据比较密集时才有优势。但是也有开源工具实现了压缩算法。

Reference:

  1. https://www.bilibili.com/video/BV1e34y127dp?spm_id_from=333.337.search-card.all.click
  2. https://blog.csdn.net/qq_40100414/article/details/118719748
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值