Au cours du processus de développement, nous pouvons rencontrer des besoins de développement concernant l'enregistrement des utilisateurs, les statistiques des utilisateurs actifs ce jour-là et le statut en ligne de chaque utilisateur. Nous pouvons utiliser des méthodes traditionnelles pour concevoir en fonction des besoins correspondants. . Tables de base de données, etc., cela consomme beaucoup d'espace de stockage et les performances ne sont pas très bonnes. Ce qui suit présente une méthode simple à utiliser.
Avant de présenter la méthode d'implémentation, je vais d'abord vous présenter un mot-clé 'bitmap' dans Redis
Qu'est-ce que BitMap
C'est à utiliser un peu pour Représente la valeur ou le statut correspondant à un élément, où la clé est l'élément correspondant lui-même. Nous savons que 8 bits peuvent former un octet, donc le bitmap lui-même permettra d'économiser considérablement de l'espace de stockage.
BitMap dans Redis
Redis a ajouté plusieurs commandes liées au bitmap telles que setbit, getbit, bitcount et ainsi de suite depuis la version 2.2.0. Bien qu'il s'agisse d'une nouvelle commande, aucun nouveau type de données n'est ajouté, car les commandes telles que setbit ne sont que des extensions de set.
introduction à la commande setbit
Commande Valeur de décalage de la clé SETBIT
Complexité O(1)
Définir ou effacez la valeur binaire de la valeur de la clé (chaîne) au décalage (ne peut être que 0 ou 1).
Occupation de l'espace et temps nécessaire pour allouer de l'espace pour la première fois
Sur un MacBook Pro 2010, le décalage est de 2 ^ 32-1 (512 Mo alloués) prend environ 300 ms, et le le décalage est de 2 ^ 30-1 (128 Mo alloués) prend environ 80 ms, le décalage 2 ^ 28-1 (32 Mo alloués) prend environ 30 ms, le décalage 2 ^ 26-1 (8 Mo alloués) prend 8 ms.
La formule approximative de calcul de l'occupation de l'espace est : ($offset/8/1024/1024)Mo
Scénario d'utilisation 1 : connexion de l'utilisateur
De nombreux sites Web proposent une fonction d'enregistrement (la mise en œuvre des données n'est pas prise en compte ici) et doivent afficher le statut d'enregistrement du mois dernier. Que devons-nous faire si un bitmap est utilisé ? Le code se dévoile en un mot !
<?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;
Scénario d'utilisation 2 : compter les utilisateurs actifs
Utiliser le temps comme clé de cache, puis l'ID utilisateur est décalé S'il est actif ce jour-là, définissez-le sur 1
Ensuite. comment dois-je calculer un certain nombre de jours/mois/années d'utilisateurs actifs ? (Pour le moment, il est convenu qu'un seul jour de temps en ligne au cours de la période statistique est appelé actif : veuillez donner la prochaine commande redis<🎜). >commande BITOP opération destkey key [key...]
Description : Effectuez des opérations sur les bits sur une ou plusieurs clés de chaîne qui stockent les bits binaires et enregistrez les résultats dans destkey.
Remarque : la commande BITOP prend en charge n'importe quel paramètre des quatre opérations : AND, OR, NOT et 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可以运用的场景很多很多(当然也会受到一些限制),思维可以继续扩散~欢迎小伙伴给我留言探讨~
Ce qui précède est le contenu détaillé de. pour plus d'informations, suivez d'autres articles connexes sur le site Web de PHP en chinois!