https://www.cnblogs.com/devilwind/p/7374017.html
为了统计今日登录的用户数,我们建立了一个bitmap,每一位标识一个用户ID。当某个用户访问我们的网页或执行了某个操作,就在bitmap中把标识此用户的位置为1。在Redis中获取此bitmap的key值是通过用户执行操作的类型和时间戳获得的。
这个简单的例子中,每次用户登录时会执行一次redis.setbit(daily_active_users, user_id, 1)。将bitmap中对应位置的位置为1,时间复杂度是O(1)。统计bitmap结果显示有今天有9个用户登录。Bitmap的key是daily_active_users,它的值是1011110100100101。
因为日活跃用户每天都变化,所以需要每天创建一个新的bitmap。我们简单地把日期添加到key后面,实现了这个功能。例如,要统计某一天有多少个用户至少听了一个音乐app中的一首歌曲,可以把这个bitmap的redis key设计为play:yyyy-mm-dd-hh。当用户听了一首歌曲,我们只是简单地在bitmap中把标识这个用户的位置为1,时间复杂度是O(1)。
[java]
- Redis.setbit(play:yyyy-mm-dd, user_id, 1)
Redis.setbit(play:yyyy-mm-dd, user_id, 1)
今天听过歌曲的用户就是key是play:yyyy-mm-dd的bitmap的位图计数。如果要按周或月统计,只要对这周或这个月的所有bitmap求并集,得出新的bitmap,在对它做位图计数。
利用这些bitmap做其它复杂的统计也非常容易。例如,统计11月听过歌曲的高级用户(premium user):
(play:2011-11-01∪ play:2011-11-02∪ … ∪ play:2011-11-30)∩premium:2011-11
redis中bit映射被限制在512MB之内,所以最大是0.5*2^30 * 8(每个字节8位)=2^32
缺点就是如果用户稀疏,会浪费内存,对uid hash空间更小
(拼多多面试真题:如何用Redis统计独立用户访问量https://blog.csdn.net/weixin_38405253/article/details/92285696),也使用这种方式
加上本篇文章,3篇文章使用的技术本质都是:
以能够保存到int最大值(hash)2^31-1或unsigned int 最大值2^32-1的bit数组,长度为2^31或2^32,以bit为value的数组
优点是大数据量下省空间,缺点是小数据量下耗空间
比如:
优点:上千万个ip白名单,用hash保存存在大量hash冲突拖累性能
缺点:某个ip白名单10个ip,申请了一个4g长度 512m内存的byte数组