Während des Entwicklungsprozesses können wir auf Entwicklungsanforderungen für den Benutzer-Check-in, Statistiken der aktiven Benutzer am Tag und den Online-Status jedes Benutzers stoßen. Wir können traditionelle Methoden verwenden, um entsprechend den entsprechenden Anforderungen zu entwerfen .Datenbanktabellen usw. Dies verbraucht viel Speicherplatz und die Leistung ist nicht sehr gut. Im Folgenden wird eine einfache und benutzerfreundliche Methode vorgestellt.
Bevor ich die Implementierungsmethode vorstelle, werde ich Ihnen zunächst ein Schlüsselwort „Bitmap“ in Redis vorstellen.
Was ist BitMap?
Es ist ein wenig zu verwenden Stellt den Wert oder Status dar, der einem Element entspricht, wobei der Schlüssel das entsprechende Element selbst ist. Wir wissen, dass 8 Bits ein Byte bilden können, sodass die Bitmap selbst erheblich Speicherplatz spart.
BitMap in Redis
Redis hat seit Version 2.2.0 mehrere Bitmap-bezogene Befehle wie setbit, getbit, bitcount usw. hinzugefügt. Obwohl es sich um einen neuen Befehl handelt, werden keine neuen Datentypen hinzugefügt, da Befehle wie setbit lediglich Erweiterungen von set sind.
Einführung in den Setbit-Befehl
Befehl SETBIT-Tasten-Offsetwert
Komplexität O(1)
Set oder löschen Sie den Bitwert des Schlüsselwerts (String) am Offset (kann nur 0 oder 1 sein).
Speicherplatzbelegung und die Zeit, die zum erstmaligen Zuweisen von Speicherplatz benötigt wird
Auf einem 2010 MacBook Pro beträgt der Offset 2^32-1 (512 MB zugewiesen) und dauert ca. 300 ms Offset ist 2^ 30-1 (zugewiesen 128 MB) dauert ~80 ms, Offset 2^28-1 (zugewiesen 32 MB) dauert ~30 ms, Offset 2^26-1 (zugewiesen 8 MB) dauert 8 ms.
Die ungefähre Formel zur Berechnung der Raumbelegung lautet: ($offset/8/1024/1024)MB
Nutzungsszenario 1: Benutzeranmeldung
Viele Websites bieten eine Check-in-Funktion (die Datenimplementierung wird hier nicht berücksichtigt) und müssen den Check-in-Status im letzten Monat anzeigen. Was sollten wir tun, wenn Bitmap verwendet wird? Der Code wird in einem Wort offenbart!
<?php $redis = new Redis(); $redis->connect('127.0.0.1'); //用户uid $uid = 1; //记录有uid的key $cacheKey = sprintf("sign_%d", $uid); //开始有签到功能的日期 $startDate = '2017-01-01'; //今天的日期 $todayDate = '2017-01-21'; //计算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 ? '今天已经签到啦' : '还没有签到呢'; 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;
Verwendungsszenario 2: Aktive Benutzer zählen
Zeit als Cache-Schlüssel verwenden und dann die Benutzer-ID verschieben. Wenn sie an diesem Tag aktiv ist, setzen Sie sie auf 1
Dann Wie soll ich eine bestimmte Anzahl von Tagen/Monaten/Jahren berechnen? (Vorerst wird vereinbart, dass nur ein Tag Online-Zeit innerhalb des statistischen Zeitraums als aktiv bezeichnet wird. Bitte geben Sie den nächsten Redis-Befehl ein.) >Befehl BITOP-Operation destkey key [key...]
Beschreibung: Führt Bitoperationen an einem oder mehreren Zeichenfolgenschlüsseln durch, die Binärbits speichern, und speichert die Ergebnisse im destkey.
Hinweis: Der BITOP-Befehl unterstützt alle Parameter der vier Operationen: AND, OR, NOT und XOR
//日期对应的活跃用户 $data = array( '2017-01-10' => array(1,2,3,4,5,6,7,8,9,10), '2017-01-11' => array(1,2,3,4,5,6,7,8), '2017-01-12' => array(1,2,3,4,5,6), '2017-01-13' => array(1,2,3,4), '2017-01-14' => array(1,2) ); //批量设置活跃状态 foreach($data as $date=>$uids) { $cacheKey = sprintf("stat_%s", $date); foreach($uids as $uid) { $redis->setBit($cacheKey, $uid, 1); } } $redis->bitOp('AND', 'stat', 'stat_2017-01-10', 'stat_2017-01-11', 'stat_2017-01-12') . PHP_EOL; //总活跃用户:6 echo "总活跃用户:" . $redis->bitCount('stat') . PHP_EOL; $redis->bitOp('AND', 'stat1', 'stat_2017-01-10', 'stat_2017-01-11', 'stat_2017-01-14') . PHP_EOL; //总活跃用户:2 echo "总活跃用户:" . $redis->bitCount('stat1') . PHP_EOL; $redis->bitOp('AND', 'stat2', 'stat_2017-01-10', 'stat_2017-01-11') . PHP_EOL; //总活跃用户:8 echo "总活跃用户:" . $redis->bitCount('stat2') . PHP_EOL;
使用场景三:用户在线状态
前段时间开发一个项目,对方给我提供了一个查询当前用户是否在线的接口。不了解对方是怎么做的,自己考虑了一下,使用bitmap是一个节约空间效率又高的一种方法,只需要一个key,然后用户ID为offset,如果在线就设置为1,不在线就设置为0,和上面的场景一样,5000W用户只需要6MB的空间。
//批量设置在线状态 $uids = range(1, 500000); foreach($uids as $uid) { $redis->setBit('online', $uid, $uid % 2); } //一个一个获取状态 $uids = range(1, 500000); $startTime = microtime(true); foreach($uids as $uid) { echo $redis->getBit('online', $uid) . PHP_EOL; } $endTime = microtime(true); //在我的电脑上,获取50W个用户的状态需要25秒 echo "total:" . ($endTime - $startTime) . "s"; /** * 对于批量的获取,上面是一种效率低的办法,实际可以通过get获取到value,然后自己计算 * 具体计算方法改天再写吧,之前写的代码找不见了。。。 */
其实BitMap可以运用的场景很多很多(当然也会受到一些限制),思维可以继续扩散~欢迎小伙伴给我留言探讨~
Das obige ist der detaillierte Inhalt vonRedis implementiert den Benutzer-Check-in, zählt aktive Benutzer und ermittelt den Online-Status der Benutzer. Für weitere Informationen folgen Sie bitte anderen verwandten Artikeln auf der PHP chinesischen Website!