使用Redis bitmaps进行快速、简单、实时统计

翻译 2013年07月31日 18:30:50

原文:Fast, easy, realtime metrics using Redis bitmaps

 (http://blog.getspool.com/2011/11/29/fast-easy-realtime-metrics-using-redis-bitmaps/



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


   

Bitmap以及Redis Bitmaps快速入门(Crash Course on Bitmap and Redis Bitmaps)

Bitmap(即Bitset)

    Bitmap是一串连续的2进制数字(0或1),每一位所在的位置为偏移(offset),在bitmap上可执行AND,OR,XOR以及其它位操作。


位图计数(Population Count)

    位图计数统计的是bitmap中值为1的位的个数。位图计数的效率很高,例如,一个bitmap包含10亿个位,90%的位都置为1,在一台MacBook Pro上对其做位图计数需要21.1ms。SSE4甚至有对整形(integer)做位图计数的硬件指令。



Redis Bitmaps

    Redis允许使用二进制数据的Key(binary keys) 和二进制数据的Value(binary values)。Bitmap就是二进制数据的value。Redis的 setbit(key, offset, value)操作对指定的key的value的指定偏移(offset)的位置1或0,时间复杂度是O(1)。


一个简单的例子:日活跃用户

    为了统计今日登录的用户数,我们建立了一个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)。

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


1亿2千8百万用户的性能比较(Performance comparison using 128 million users)

    下面的表格显示了在1亿2千8百万用户上完成的时间粒度为1天,一周,一个月的用户统计的时间消耗比较。

Period Time(ms)
Daily 50.2
Weekly 392.0
Monthly 1624.8



优化(Optimizations)

    前面的例子中,我们把日统计,周统计,月统计缓存到Redis,以加快统计速度。

   

    这是一种非常灵活的方法。这样进行缓存的额外红利是可以进行更多的统计,如每周活跃的手机用户—求手机用户的bitmap与周活跃用户的交集。或者,如果要统计过去n天的活跃用户数,缓存的日活跃用户使这样的统计变得简单——从cache中获取过去n-1天的日活跃用户bitmap和今天的bitmap,对它们做并集(Union),时间消耗是50ms。


示例代码(SampleCode)

下面的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();
    }	

下面的Java代码用来统计某个用户操作在一个指定多个日期的活跃用户。

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();
    }

References:

[1] Redis setbit command http://redis.io/commands/setbit


转载本文请注明作者和出处[Gary的影响力]http://garyelephant.me,请勿用于任何商业用途!

Author: Gary Gao( garygaowork[at]gmail.com) 关注互联网、分布式、高性能、NoSQL、自动化、软件团队

支持我的工作:  https://me.alipay.com/garygao




Redis用bitset(bitmap)来统计日活跃量

假设这样一个场景,假如每个网站有1亿的用户,那么我们怎么来统计这个网站的日登陆数或者说有哪些用户登录过这个网站。 最常见的做法就是设计一张用户登录表: user_login: user_uid    ...
  • qq_30788949
  • qq_30788949
  • 2017-07-02 14:31:31
  • 751

使用Redis之前5个必须了解的事情

使用Redis开发应用程序是一个很愉快的过程,但是就像其他技术一样,基于Redis的应用程序设计你同样需要牢记几点。在之前,你可能已经对关系型数据库开发的那一整个套路了然如胸,而基于Redis的应用程...
  • u011007180
  • u011007180
  • 2016-11-24 17:30:28
  • 1372

Redis Bitmaps简介

Redis Bitmaps简介Bitmaps并不是实际的数据类型,而是定义在String类型上的一个面向字节操作的集合。因为字符串是二进制安全的块,他们的最大长度是512M,最适合设置成2^32个不同...
  • iycynna_123
  • iycynna_123
  • 2017-05-09 08:55:38
  • 1392

分布式缓存Redis之Java客户端

写在前面  本学习教程所有示例代码见GitHub:https://github.com/selfconzrr/Redis_Learning  目前Redis的Java客户端主要有两种:Jedis、Re...
  • u011489043
  • u011489043
  • 2017-12-13 19:57:15
  • 505

关于Redis中缓存雪崩、缓存穿透、缓存预热、缓存更新、缓存降级等概念的入门及简单解决方案

     今天我简单的跟大家介绍一下关于Redis中缓存雪崩、缓存穿透、缓存预热、缓存更新、缓存降级等概念的入门及简单解决方案。由于水平有限,如果发现以上文章有错误或者需要改进的地方请大家指出,万分感...
  • qq_37606901
  • qq_37606901
  • 2018-03-15 16:30:32
  • 320

Redis-Bitmaps应用

Redis-Bitmaps应用 一.数据结构模型 Redis提供的Bitmaps这个“数据结构”可以实现对位的操作。Bitmaps本身不是一种数据结构,实际上就是字符串,但是它可以对字符串的位进行操作...
  • sunhuiliang85
  • sunhuiliang85
  • 2017-07-11 15:49:24
  • 1733

redis bitmaps(译文)

Bitmaps原链接请猛戳这里bitmaps不是一种实际的数据类型,本质上说,它是定义在字符串类型上的一组位操作方法。单个bitmaps的最大长度是512MB,即2^32个比特位。有两种类型的位操作:...
  • qmhball
  • qmhball
  • 2016-08-31 11:37:08
  • 756

用redis实现用户登录计数

最近有个问题 :实现显示用户本月登录日期 ,累计天数到一定数目可参加活动,和下图展示的功能类似。   过去看过使用redis bitmap进行活跃用户统计的例子,觉得和本功能非常match,决定...
  • orangeholic
  • orangeholic
  • 2014-09-03 11:28:39
  • 2887

redis:存储与计算:日活,留存,老用户等统计数据

 一.实战之前,先介绍一个概念bitmap 这个bitmap有啥用? 看这副图片,假如更精简的话,只有2个颜色,黄色和透明,1代表黄色,0代表没有颜色,是不是,只要你找到哪个点,...
  • weixin_36015816
  • weixin_36015816
  • 2016-11-18 15:27:50
  • 313

Redis-Bitmaps详解

一.数据结构模型Redis提供的Bitmaps这个“数据结构”可以实现对位的操作。Bitmaps本身不是一种数据结构,实际上就是字符串,但是它可以对字符串的位进行操作。可以把Bitmaps想象成一个以...
  • wuxing26jiayou
  • wuxing26jiayou
  • 2018-03-13 18:21:31
  • 62
收藏助手
不良信息举报
您举报文章:使用Redis bitmaps进行快速、简单、实时统计
举报原因:
原因补充:

(最多只允许输入30个字)