用Redis bitmap统计活跃用户、留存

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

  

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

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

时间: 2024-11-06 11:49:42

用Redis bitmap统计活跃用户、留存的相关文章

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

getspool.com的重要统计数据是实时计算的.Redis的bitmap让我们可以实时的进行类似的统计,并且极其节省空间.在模拟1亿2千8百万用户的模拟环境下,在一台MacBookPro上,典型的统计如“日用户数”(dailyunique users) 的时间消耗小于50ms, 占用16MB内存.Spool现在还没有1亿2千8百万用户,但是我们的方案可以应对这样的规模.我们想分享这是如何做到的,也许能帮到其它创业公司. Bitmap以及Redis Bitmaps快速入门(Crash Cour

用户频次分布、新增用户留存、活跃用户留存

select * from a WHERE a.field1 NOT IN (select field1 from b) select * from a WHERE NOT EXISTS (select 1 from b where a.field1 = b.field1) 表a的条件加在最后,表b的条件加在括弧中. select id from aa left join bb on aa.id=bb.id and bb.id is null select count(uid) as onl,d

位图法统计活跃用户

Setbit 的实际应用 场景: 1亿个用户, 每个用户 登陆/做任意操作 ,记为 今天活跃,否则记为不活跃 每周评出: 有奖活跃用户: 连续7天活动每月评,等等... 思路: Userid dt active1 2013-07-27 11 2013-0726 1 如果是放在表中, 1:表急剧增大,2:要用group ,sum运算,计算较慢 用: 位图法 bit-mapLog0721: '011001...............0' ......log0726 : '011001.......

[PHP]基于Sort Set进行活跃用户统计

作者:zhanhailiang 日期:2014-12-14 参考文章: 使用Redis bitmap进行活跃用户统计 本文提供基于Sort Set进行活跃用户统计的PHP版本: https://github.com/billfeller/billfeller.github.io/blob/master/code/UserTj.php

利用redis setbit和bitmap统计用户数

公司的统计系统接到一个需求,统计时间段内发生过某行为的用户总数.并且时间段的长度是可变的.公司业务用户数量巨大,而且统计系统是实时统计,所以数据的存储.计算效率都需要一个比较好的方案.下面是互联网上的一篇文章,利用redis bitmap. getspool.com的重要统计数据是实时计算的.Redis的bitmap让我们可以实时的进行类似的统计,并且极其节省空间.在模拟1亿2千8百万用户的模拟环境下,在一台MacBookPro上,典型的统计如“日用户数”(dailyunique users)

活跃用户统计

一,功能背景 领导偶然间问起我们的考核系统使用情况如何,最近考虑下做个活跃用户统计功能 二,功能设计 针对性能上要求实时统计,用户名都为8位数字等特点,拟采用redis方案: 使用bitmap,用户登录的同时,将用户所在的位置为1 三,代码 1,直接上代码 public void setUserActive(Integer id) { Date currentTime = new Date(); String currentStr = new SimpleDateFormat("yyyy-MM-

使用 Redis 统计在线用户人数

在构建应用的时候, 我们经常需要对用户的一举一动进行记录, 而其中一个比较重要的操作, 就是对在线的用户进行记录. 本文将介绍四种使用 Redis 对在线用户进行记录的方案, 这些方案虽然都可以对在线用户的数量进行统计, 但每个方案都有一些自己特有的操作, 并且各个方案的性能特征以及资源消耗也各有不同. 方案 1 :使用有序集合 每当一个用户上线时, 我们就执行 ZADD 命令, 将这个用户以及它的在线时间添加到指定的有序集合中: ZADD "online_users" <use

基本数据统计--新增、活跃、留存

这三个数据基本反应了 产品 运营情况 新增一般反应一个产品的市场拓展能力,是活水涌入. 活跃是收入的主要来源 留存一般指新增留存(也有活跃留存),新增用户第n天后任然活跃的人数,有1日后留存,2日后留存,n日后留存.它反应了忠诚度.也反应了新增用户有多少是不理智的增加(类似股票第一日不理智追高买入,次日抛售形成缺口---补缺) 用户有两个表示法:设备和账户. 统计基于某个纬度,这个纬度可以是:总体.渠道(channel).版本(version)等. 所以有总体新增.渠道新增.版本新增等,活跃和留

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

阅读本文大概需要 2.8 分钟. 作者:沙茶敏碎碎念 众所周至,拼多多的待遇也是高的可怕,在挖人方面也是不遗余力,对于一些工作 3 年的开发,稍微优秀一点的,都给到 30K 的 Offer. 当然,拼多多加班也是出名的,一周上 6 天班是常态,每天工作时间基本都是超过 12 个小时,也是相当辛苦的. 废话不多说,今天我们来聊一聊拼多多的一道后台面试真题,是一道简单的架构类的题目: 拼多多有数亿的用户,那么对于某个网页,怎么使用 Redis 来统计一个网站的用户访问数呢? 使用 Hash 哈希是