Home  >  Article  >  Backend Development  >  Redis implements user check-in, counts active users, and user online status

Redis implements user check-in, counts active users, and user online status

假装我是个程序员
假装我是个程序员Original
2018-05-19 15:07:506376browse

During the development process, we may encounter development needs for user check-in, statistics of active users on the day, and the online status of each user. We may use traditional methods and design according to the corresponding needs. Database tables, etc. This consumes a lot of storage space, and the performance is not very good. The following will introduce a simple and easy to use method.

Before introducing the implementation method, I will first introduce you to a keyword 'bitmap' in Redis

What is BitMap

It is to use a bit to Represents the value or status corresponding to an element, where the key is the corresponding element itself. We know that 8 bits can form a Byte, so the bitmap itself will greatly save storage space.

BitMap in Redis

Redis has added several bitmap-related commands such as setbit, getbit, bitcount, etc. starting from version 2.2.0. Although it is a new command, no new data types are added, because commands such as setbit are just extensions of set.

setbit command introduction

Instruction SETBIT key offset value
Complexity O(1)
Set or clear the bit value of the key's value (string) at offset (can only be 0 or 1).

Space occupation, and the time required to allocate space for the first time

On a 2010 MacBook Pro, the offset is 2^32-1 (512MB allocated) takes ~300ms, and the offset is 2^ 30-1 (allocated 128MB) takes ~80ms, offset 2^28-1 (allocated 32MB) takes ~30ms, offset 2^26-1 (allocated 8MB) takes 8ms. 2ef1f59ecc11fa5a5b1caab1352e88c6
The approximate space occupation calculation formula is: ($offset/8/1024/1024)MB

Usage scenario 1: User sign-in

Many websites provide a check-in function (data implementation is not considered here), and need to display the check-in status in the past month. What should we do if bitmap is used? The code is revealed in one word!

<?php
$redis = new Redis();
$redis->connect(&#39;127.0.0.1&#39;);


//用户uid
$uid = 1;

//记录有uid的key
$cacheKey = sprintf("sign_%d", $uid);

//开始有签到功能的日期
$startDate = &#39;2017-01-01&#39;;

//今天的日期
$todayDate = &#39;2017-01-21&#39;;

//计算offset
$startTime = strtotime($startDate);
$todayTime = strtotime($todayDate);
$offset = floor(($todayTime - $startTime) / 86400);

echo "今天是第{$offset}天" . PHP_EOL;

//签到
//一年一个用户会占用多少空间呢?大约365/8=45.625个字节,好小,有木有被惊呆?
$redis->setBit($cacheKey, $offset, 1);

//查询签到情况
$bitStatus = $redis->getBit($cacheKey, $offset);
echo 1 == $bitStatus ? &#39;今天已经签到啦&#39; : &#39;还没有签到呢&#39;;
echo PHP_EOL;

//计算总签到次数
echo $redis->bitCount($cacheKey) . PHP_EOL;

/**
* 计算某段时间内的签到次数
* 很不幸啊,bitCount虽然提供了start和end参数,但是这个说的是字符串的位置,而不是对应"位"的位置
* 幸运的是我们可以通过get命令将value取出来,自己解析。并且这个value不会太大,上面计算过一年一个用户只需要45个字节
* 给我们的网站定一个小目标,运行30年,那么一共需要1.31KB(就问你屌不屌?)
*/
//这是个错误的计算方式
echo $redis->bitCount($cacheKey, 0, 20) . PHP_EOL;

Usage scenario two: counting active users

Use time as cacheKey, and then the user ID is offset. If it is active that day, set it to 1
Then how should I calculate certain days? What about the active users of /month/year (for the time being, it is agreed that online only one day within the statistical period is called active), please give the next redis command
Command BITOP operation destkey key [key...]
Explanation : Perform bit operations on one or more string keys that store binary bits, and save the results to destkey.
Note: The BITOP command supports any parameter of the four operations: AND, OR, NOT, and XOR

//日期对应的活跃用户

$data = array(

&#39;2017-01-10&#39; => array(1,2,3,4,5,6,7,8,9,10),

&#39;2017-01-11&#39; => array(1,2,3,4,5,6,7,8),

&#39;2017-01-12&#39; => array(1,2,3,4,5,6),

&#39;2017-01-13&#39; => array(1,2,3,4),

&#39;2017-01-14&#39; => array(1,2)

);



//批量设置活跃状态

foreach($data as $date=>$uids) {

$cacheKey = sprintf("stat_%s", $date);

foreach($uids as $uid) {

$redis->setBit($cacheKey, $uid, 1);

}

}



$redis->bitOp(&#39;AND&#39;, &#39;stat&#39;, &#39;stat_2017-01-10&#39;, &#39;stat_2017-01-11&#39;, &#39;stat_2017-01-12&#39;) . PHP_EOL;

//总活跃用户:6

echo "总活跃用户:" . $redis->bitCount(&#39;stat&#39;) . PHP_EOL;



$redis->bitOp(&#39;AND&#39;, &#39;stat1&#39;, &#39;stat_2017-01-10&#39;, &#39;stat_2017-01-11&#39;, &#39;stat_2017-01-14&#39;) . PHP_EOL;

//总活跃用户:2

echo "总活跃用户:" . $redis->bitCount(&#39;stat1&#39;) . PHP_EOL;



$redis->bitOp(&#39;AND&#39;, &#39;stat2&#39;, &#39;stat_2017-01-10&#39;, &#39;stat_2017-01-11&#39;) . PHP_EOL;

//总活跃用户:8

echo "总活跃用户:" . $redis->bitCount(&#39;stat2&#39;) . PHP_EOL;

使用场景三:用户在线状态

前段时间开发一个项目,对方给我提供了一个查询当前用户是否在线的接口。不了解对方是怎么做的,自己考虑了一下,使用bitmap是一个节约空间效率又高的一种方法,只需要一个key,然后用户ID为offset,如果在线就设置为1,不在线就设置为0,和上面的场景一样,5000W用户只需要6MB的空间。

//批量设置在线状态
$uids = range(1, 500000);

foreach($uids as $uid) {

$redis->setBit(&#39;online&#39;, $uid, $uid % 2);

}

//一个一个获取状态

$uids = range(1, 500000);

$startTime = microtime(true);

foreach($uids as $uid) {

echo $redis->getBit(&#39;online&#39;, $uid) . PHP_EOL;

}

$endTime = microtime(true);

//在我的电脑上,获取50W个用户的状态需要25秒

echo "total:" . ($endTime - $startTime) . "s";




/**

* 对于批量的获取,上面是一种效率低的办法,实际可以通过get获取到value,然后自己计算

* 具体计算方法改天再写吧,之前写的代码找不见了。。。

*/

其实BitMap可以运用的场景很多很多(当然也会受到一些限制),思维可以继续扩散~欢迎小伙伴给我留言探讨~

The above is the detailed content of Redis implements user check-in, counts active users, and user online status. For more information, please follow other related articles on the PHP Chinese website!

Statement:
The content of this article is voluntarily contributed by netizens, and the copyright belongs to the original author. This site does not assume corresponding legal responsibility. If you find any content suspected of plagiarism or infringement, please contact admin@php.cn