找回密码
 立即注册
搜索
热搜: 活动 交友 discuz
查看: 357|回复: 0

[基础] Redis 实战篇:巧用 Bitmap 实现亿级数据统计

  [复制链接]
发表于 2023-2-22 20:55 | 显示全部楼层 |阅读模式

一、使用场景:统计用户签到、连续登录或者总登录次数

二、速度要快、占用空间要小。仅用于统计。综上特点:选择redis的BitMap功能。

三、命令行实现BitMap签到

签到

  1. 用户id为123的用户2021年3月1号签到

    $ setBit sign:123:202103 0 1
  2. 用户id为123的用户2021年3月2号签到

    $ setBit sign:123:202103 1 1

获取签到

  1. 查看用户id为123的用户2021年3月1号签到

    $ getBit sign:123:202103 0
  2. 查看用户id为123的用户2021年3月2号签到

    $ getBit sign:123:202103 1
  3. 查看用户id为123的用户2021年3月 首次签到

    $ bitPos sign:123:202103 1
  4. 查看用户id为123的用户2021年3月 首次漏签

    $ bitPos sign:123:202103 0
  5. 查看用户指定范围内的签到 返回的是十进制

    bitfield sign:123:202103 get u3 6

统计签到

  • 获取用户当月签到次数

    $ bitCount sign:123:202103

四、PHP实现BitMap签到

签到

  1. 用户id为123的用户2021年3月8号签到

    <?php
    
        $redis = new Redis();
        $redis->connect('127.0.0.1', 6379);
        $key = 'sign:123:202103';
        $day = 8;
        $redis->setBit($key, $day, 1);
    ?>
  2. 用户id为123的用户2021年3月10号签到

    <?php
    
        $redis = new Redis();
        $redis->connect('127.0.0.1', 6379);
        $key = 'sign:123:202103';
        $day = 10;
        $redis->setBit($key, $day, 1);
    ?>

查看签到

  1. 查看用户id为123的用户2021年3月10号签到

    <?php
    
        $redis = new Redis();
        $redis->connect('127.0.0.1', 6379);
        $key = 'sign:123:202103';
        $day = 8;
        $sign = $redis->getBit($key, $day);
        var_dump($sign);
    ?>
  2. 查看用户id为123的用户2021年3月份的签到情况( bitmap 实际就是 string 类型,使用 Get)

    <?php
    
        $redis = new Redis();
        $redis->connect('127.0.0.1', 6379);
        $key = 'sign:123:202103';
        $sign = $redis->get($key); //这里查出来的是二进制字符串
        $bitmap_bin_str = StrToBin($sign);
        for($i = 1; $i <= 31; $i++) {
            echo $i.'号签到'.$bitmap_bin_str{$i-1}.PHP_EOL;
        }
        # 二进制字符串转字符
        function StrToBin($str){
            $arr = preg_split('/(?<!^)(?!$)/u', $str);
            foreach($arr as &$v){
                $temp = unpack('H*', $v); $v = base_convert($temp[1], 16, 2);
                unset($temp);
            }
            return join(' ',$arr);
        }
    ?>
  3. 查看用户id为123的用户2021年3月 首次签到

    <?php
    
    $redis = new Redis();
    $redis->connect('127.0.0.1', 6379);
    $key = 'sign:123:202103';
    $day = $redis->bitPos($key,1);
    var_dump($day);
    ?>
    <?php
    
    $redis = new Redis();
    $redis->connect('127.0.0.1', 6379);
    $key = 'sign:123:202103';
    $day = $redis->bitPos($key,0);
    var_dump($day);
    ?>
    1. 查看用户id为123的用户2021年3月 首次漏签

统计签到

  1. 查看用户id为123的用户2021年3月份签到次数

    <?php
    
        $redis = new Redis();
        $redis->connect('127.0.0.1', 6379);
        $key = 'sign:123:202103';
        $count = $redis->bitcount($key,0,-1);
        var_dump($count);
    ?>
  2. 查看用户id为123的用户2021年3月8号连续签到次数

    <?php
    
        $redis = new Redis();
        $redis->connect('127.0.0.1', 6379);
        $key = 'sign:123:202103';
        $str = '1111001110000000000000000000000'; //用户当月签到情况
        $day = 8;
        if ($str{$day-1} == '0') {
            var_dump(0);
            exit;
        }
        $count = 1;
        for ($i=$day; $i>=0; $i--) {
            // var_dump($i-1);
            $sign = ($str{$i-1}) & ($str{$i-2});
            if ($sign == 1) {
                $count += 1;
            } else {
                break;
            }
        }
        var_dump($count);
    ?>

五、使用经验和资料参考

使用经验

  • BitMap 是 sting 类型,最大 512 MB

  • 注意 setbit 时的偏移量,可能有较大耗时

  • 位图不是绝对好,获取不到签到的准确时间,只能判断指定日期有没有签到。

  • redis配合mysql使用,当月数据存redis,上月数据同步到mysql(一个月数据的签到存一条mysql数据)。

  • 签到日志可以配合nongoDB使用。

 

 

 

参考文章:

https://blog.csdn.net/han_xuefeng/article/details/115962109

https://my.oschina.net/magebyte/blog/5057536

https://blog.csdn.net/qq_23564667/article/details/110631589

https://blog.csdn.net/a772304419/article/details/103969412
 

您需要登录后才可以回帖 登录 | 立即注册

本版积分规则

Archiver|手机版|小黑屋|学习笔记

GMT+8, 2024-5-18 13:01 , Processed in 0.024256 second(s), 13 queries , APCu On.

Powered by Discuz! X3.5

© 2001-2024 Discuz! Team.

快速回复 返回顶部 返回列表