用Redis bitmap统计活跃用户、留存
Spool的开发者博客,描述了Spool利用Redis的bitmaps相关的操作,进行网站活跃用户统计工作。
原文:http://blog.getspool.com/2011/11/29/fast-easy-realtime-metrics-using-redis-bitmaps/
Redis支持对String类型的value进行基于二进制位的置位操作。通过将一个用户的id对应value上的一位,通过对活跃用户对应的位进行置位,就能够用一个value记录所有活跃用户的信息。如下图所未,下图中的bitmap有9个位被置为1,表示这9个位上对应的用户是今天的活跃用户。其中第15位表示uid为15的用户,第一位表示uid为0的用户。(如果你的uid不是从1开始的,比如从100000开始,实际上你也可以相应的用uid减去初始值来表示其位数,比如1000000用户对应到bitmap的第一位)

具体的代码类似下面这样:
这样一次记录的复杂度是O(1),在Redis中速度非常快。
而我们通过每天换用一个不同的key来将每天的活跃用户状态记录分开存。并且可以通过一些与或运算计算出N天活跃用户,和连接N天活跃用户这样的统计数据。
如下图,第一行表示星期一的活跃用户情况,第二行表示周二的,以此类推。为样我们通过对N天的活跃用户记录取并集操作,就能得出在N天内活跃过的用户列表。

下面表格表示对应一天,一周,一个月统计时所花费的时间。

下面是具体的java代码片断:
算出一天的活跃用户数量
import java.util.BitSet;
...
Jedis redis = new Jedis("localhost");
...
public int uniqueCount(String action, String date) {
String key = action + ":" + date;
BitSet users = BitSet.valueOf(redis.get(key.getBytes()));
return users.cardinality();
}
计算某几个内活跃用户的数量(某一天活跃就算,所以是取并集)
import java.util.BitSet;
...
Jedis redis = new Jedis("localhost");
...
public int uniqueCount(String action, String... dates) {
BitSet all = new BitSet();
for (String date : dates) {
String key = action + ":" + date;
BitSet users = BitSet.valueOf(redis.get(key.getBytes()));
all.or(users);
}
return all.cardinality();
}
具体的用法还很多,比如你还可以对独特终端的用户单独记一个bitmap,这样就可以统计不同终端用户的活跃情况。有的同学会说用set也能实现同样的效果。但使用set在内存使用量上是会大很多的。
==========================================================================
看完这篇文章后,我测试了一下:
redis> SETBIT bit 10086 1
(integer) 0
redis> GETBIT bit 10086
(integer) 1
对使用大的offset的 SETBIT 操作来说,第一次内存分配可能造成 Redis 服务器被阻塞.因为Redis需要生成很长的二进制系列。
问题:
如果活跃用户在百万级别,使用Redis BitMap很划算。
如果如果活跃用户很少,而用户id都是10位以上的int。那就很浪费内存了。那还不如使用set集合呢。然后求交集就可以了。
我们可以计算内存:offset = 999 999 999 =》需要的内存999 999 999/8/1024/1024 = 119M左右。
如果统计的数据还有很多维度,且维度组合有上千种,使用这个方式就不划算。我们可以借鉴bitmap使用另外的方式来统计活跃留存:
留存的指标:
次日注册留存、
2日注册留存...
N日注册留存,
比如昨天注册了1000名用户中,在今天有300名用户又登录了,那么对应于昨天的注册留存就是30%;
从总体上看,这些指标依赖于核心变量——用户访问时间。
那我们可以使用bitMap来记录用户访问时间:
如果我们统计时间是从2013年开始,那么2013-01-01就是bit的第一位...以此类推,
2013年的最后一天,即是bit位的第365位。
这样我们已经记录用户所有天的是否登录。
然后我们计算留存:
留存计算:
1) 计算当天时间,对应对应的bit位,如今他是7月01日,bit位是182.
2)次日留存:
查看bit的(182-1)=181位是否存在,若存在,留存数+1
N日留存:
查看bit的(182-n)位是否存在,若存在,n日留存数+1
我们再来估算占用空间。一年365bit位。1000万用户,占用的空间=1000万 * 365bit/8 /1024/1024 = 430M
用Redis bitmap统计活跃用户、留存的更多相关文章
- redis 用setbit(bitmap)统计活跃用户
getspool.com的重要统计数据是实时计算的.Redis的bitmap让我们可以实时的进行类似的统计,并且极其节省空间.在模拟1亿2千8百万用户的模拟环境下,在一台MacBookPro上,典型的 ...
- 用mongo和redis查询排行榜、统计活跃用户
nosql数据库能解决关系型数据库遇到的性能和扩展性的问题,本博客将以mongodb和redis两种nosql数据库为基础,简单的介绍下面两个业务场景的解决方案: 1.查询排行榜(以当日总步数排名为例 ...
- 05 redis中的Setbit位图法统计活跃用户
一:场景=>>>长轮询Ajax,在线聊天时,能够用到 Setbit 的实际应用 场景: 1亿个用户, 每个用户 登陆/做任意操作 ,记为 今天活跃,否则记为不活跃 每周评出: 有奖活 ...
- 用redis统计大量用户的登陆情况[只判断是否活跃]
有这样的一个场景需求:有上亿的用户,要统计这批用户的登陆情况,例如一周连续登陆,连续三天是是否登陆,一周活跃天数等用户 存在的挑战 数据如何尽可能用小的空间存储 如何能快速获取指定的数据 如果使用文件 ...
- 使用 Redis 统计在线用户人数
在构建应用的时候, 我们经常需要对用户的一举一动进行记录, 而其中一个比较重要的操作, 就是对在线的用户进行记录. 本文将介绍四种使用 Redis 对在线用户进行记录的方案, 这些方案虽然都可以对在线 ...
- 基于Redis位图实现系统用户登录统计
项目需求,试着写了一个简单登录统计,基本功能都实现了,日志数据量小.具体性能没有进行测试~ 记录下开发过程与代码,留着以后改进! 1. 需求 1. 实现记录用户哪天进行了登录,每天只记录是否登录过,重 ...
- 拼多多后台开发面试真题:如何用Redis统计独立用户访问量
众所周至,拼多多的待遇也是高的可怕,在挖人方面也是不遗余力,对于一些工作3年的开发,稍微优秀一点的,都给到30K的Offer,当然,拼多多加班也是出名的,一周上6天班是常态,每天工作时间基本都是超过1 ...
- 拼多多面试真题:如何用 Redis 统计独立用户访问量!
阅读本文大概需要 2.8 分钟. 作者:沙茶敏碎碎念 众所周至,拼多多的待遇也是高的可怕,在挖人方面也是不遗余力,对于一些工作 3 年的开发,稍微优秀一点的,都给到 30K 的 Offer. 当然,拼 ...
- 如何用 Redis 统计独立用户访问量
众所周至,拼多多的待遇也是高的可怕,在挖人方面也是不遗余力,对于一些工作3年的开发,稍微优秀一点的,都给到30K的Offer,当然,拼多多加班也是出名的,一周上6天班是常态,每天工作时间基本都是超过1 ...
随机推荐
- Android 使用 HTTP 协议访问网络
正在看<第一行代码>,记录一下使用 HTTP 协议访问网络的内容吧! 在Android发送Http请求有两种方式,HttpURLConnection和HttpClient. 1.使用Htt ...
- ubuntu 换源
经过自己一番折腾后,发现用这个方法换源最简单.直接. sudo vi /etc/apt/sources.list 把sources.list里面的内容全部替换为一下内容 deb http://mirr ...
- Java Script基础(五) 内置对象Date
在JavaScript中,系统的内置对象有Date对象.Array对象.String对象和Math对象等. 1.Date:用于操作日期和时间. 2.Array:用于在单独的变量名中存储一系列的值. 3 ...
- javascript组件开发
最近忙于重构项目,今天周末把在重构中的一些思想记记: 一.javascript的组件开发:基类的封装 由于这次重构项目需要对各种组件进行封装,并且这些组件的实现方式都差不多,所以想到对组件封装一个ba ...
- 获取动态SQL的返回结果
1. 介绍说明 有时候在执行存储过程后,需要获取存储过程返回的列表,然后进行相应操作的情况,或者执行动态语句,获取返回结果的情况,通过EXEC ,sp_executesql可以实现该功能. 网上也有很 ...
- 四.CSS声明
概述 一条CSS规则包括选择符和声明两个部分,声明又包括属性和值,属性指出要影响样式的那个方面,而值用于把属性设定成什么 每个HTML元素有很多属性,可以用CSS来设定,但值却只有少数的几种 CSS属 ...
- hihocoder#1054 : 滑动解锁(深度优先搜索)
描述 滑动解锁是智能手机一项常用的功能.你需要在3x3的点阵上,从任意一个点开始,反复移动到一个尚未经过的"相邻"的点.这些划过的点所组成的有向折线,如果与预设的折线在图案.方向上 ...
- AFNetworking2.4.1 解析
http://wenku.baidu.com/view/6ec734a84028915f814dc26d.html
- HTML文件中使用Java程序
HTML文件中使用Java程序:简而言之,在HTML文件中引入java应用程序,并通过javascript调用其方法. 一. 运行环境 1.JAVA_HOME.CLASSPATH.PATH配置正确 ...
- 了解GDAL的图像处理/Python
GDAL是一个操作各种栅格地理数据格式的库.包括读取.写入.转换.处理各种栅格数据格式(有些特定的格式对一些操作如写入等不支持).它使用了一个单一的抽象数据模型就支持了大多数的栅格数据(GIS对栅格, ...