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的第一位)

  

  具体的代码类似下面这样:

redis.setbit(play:yyyy-mm-dd, user_id, 1)

  这样一次记录的复杂度是O(1),在Redis中速度非常快。

  而我们通过每天换用一个不同的key来将每天的活跃用户状态记录分开存。并且可以通过一些与或运算计算出N天活跃用户,和连接N天活跃用户这样的统计数据。

  如下图,第一行表示星期一的活跃用户情况,第二行表示周二的,以此类推。为样我们通过对N天的活跃用户记录取并集操作,就能得出在N天内活跃过的用户列表。

  

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

  

  下面是具体的java代码片断:

  算出一天的活跃用户数量

import redis.clients.jedis.Jedis;

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 redis.clients.jedis.Jedis;

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统计活跃用户、留存的更多相关文章

  1. redis 用setbit(bitmap)统计活跃用户

    getspool.com的重要统计数据是实时计算的.Redis的bitmap让我们可以实时的进行类似的统计,并且极其节省空间.在模拟1亿2千8百万用户的模拟环境下,在一台MacBookPro上,典型的 ...

  2. 用mongo和redis查询排行榜、统计活跃用户

    nosql数据库能解决关系型数据库遇到的性能和扩展性的问题,本博客将以mongodb和redis两种nosql数据库为基础,简单的介绍下面两个业务场景的解决方案: 1.查询排行榜(以当日总步数排名为例 ...

  3. 05 redis中的Setbit位图法统计活跃用户

    一:场景=>>>长轮询Ajax,在线聊天时,能够用到 Setbit 的实际应用 场景: 1亿个用户, 每个用户 登陆/做任意操作 ,记为 今天活跃,否则记为不活跃 每周评出: 有奖活 ...

  4. 用redis统计大量用户的登陆情况[只判断是否活跃]

    有这样的一个场景需求:有上亿的用户,要统计这批用户的登陆情况,例如一周连续登陆,连续三天是是否登陆,一周活跃天数等用户 存在的挑战 数据如何尽可能用小的空间存储 如何能快速获取指定的数据 如果使用文件 ...

  5. 使用 Redis 统计在线用户人数

    在构建应用的时候, 我们经常需要对用户的一举一动进行记录, 而其中一个比较重要的操作, 就是对在线的用户进行记录. 本文将介绍四种使用 Redis 对在线用户进行记录的方案, 这些方案虽然都可以对在线 ...

  6. 基于Redis位图实现系统用户登录统计

    项目需求,试着写了一个简单登录统计,基本功能都实现了,日志数据量小.具体性能没有进行测试~ 记录下开发过程与代码,留着以后改进! 1. 需求 1. 实现记录用户哪天进行了登录,每天只记录是否登录过,重 ...

  7. 拼多多后台开发面试真题:如何用Redis统计独立用户访问量

    众所周至,拼多多的待遇也是高的可怕,在挖人方面也是不遗余力,对于一些工作3年的开发,稍微优秀一点的,都给到30K的Offer,当然,拼多多加班也是出名的,一周上6天班是常态,每天工作时间基本都是超过1 ...

  8. 拼多多面试真题:如何用 Redis 统计独立用户访问量!

    阅读本文大概需要 2.8 分钟. 作者:沙茶敏碎碎念 众所周至,拼多多的待遇也是高的可怕,在挖人方面也是不遗余力,对于一些工作 3 年的开发,稍微优秀一点的,都给到 30K 的 Offer. 当然,拼 ...

  9. 如何用 Redis 统计独立用户访问量

    众所周至,拼多多的待遇也是高的可怕,在挖人方面也是不遗余力,对于一些工作3年的开发,稍微优秀一点的,都给到30K的Offer,当然,拼多多加班也是出名的,一周上6天班是常态,每天工作时间基本都是超过1 ...

随机推荐

  1. iOS之GCD的DEMO

    由DEMO得知,串行队列同步执行会按照顺序一步一步执行,不会开辟线程 由DEMO得知,串行队列异步执行,队列中的任务会一步一步按顺序执行,队列外的任务不确定.会开辟线程 由DEMO得知,并行队列同步执 ...

  2. hdu 3280 动态规划

    思路:dp[i][j]表示区间i,j变为回文串最少的代价. #include<map> #include<set> #include<cmath> #include ...

  3. POJ 3422 Kaka's Matrix Travels K取方格数

    题目:给出n*n的方格矩阵,现在从左上方走m次到右下方,问m次能够获得的最大价值和. 分析:最大费用流.拆点进行限制每个格子只取一次,假设点x拆成 x,xx,右边(假设有)y,yy,下方(假设有)z, ...

  4. C++之时间统计

    1.最精确 QueryPerformanceFrequency(&nFreq); cout <<nFreq.QuadPart<<endl;//获得计数频率 QueryP ...

  5. canvas基础2--绘制图形

    栅格 绘制矩形 不同于SVG,HTML中的元素canvas只支持一种原生的图形绘制:矩形.所有其他的图形的绘制都至少需要生成一条路径.不过,我们拥有众多路径生成的方法让复杂图形的绘制成为了可能. 首先 ...

  6. arcsde service(esri_sde)服务启动后又停止

    由于最近几天我们公司换了新办公楼,各种服务器得重新配置.当我试图直接将arcsde Service的服务器IP改为现在的地址,就报上面如题的错误. SQL服务器是好的,不用管它,只要确保它是开启的.只 ...

  7. ASP.Net上传中文文件乱码

    只要在Head中添加即可解决:<meta http-equiv='Content-Type' content='text/html; charset=utf-8' />

  8. javascript之基本包装类型(Boolean,Number,String)基础篇

    前几天整理了javascript中Array方面的知识,但是String中的一些方法多多少少和Array里的方法有些类似容易混淆,就顺便连同String所在的包装类一起整理一下,希望可以帮助到初学者, ...

  9. 支持向量机 support vector machine

    SVM(support Vector machine) (1) SVM(Support Vector Machine)是从瓦普尼克(Vapnik)的统计学习理论发展而来的,主要针对小样本数据进行学习. ...

  10. 济南学习 Day 3 T2 pm

    LYK 快跑!(run)Time Limit:5000ms Memory Limit:64MB题目描述LYK 陷进了一个迷宫! 这个迷宫是网格图形状的. LYK 一开始在(1,1)位置, 出口在(n, ...