Heim  >  Artikel  >  Backend-Entwicklung  >  Die wunderbare Verwendung von Bitmap in Redis

Die wunderbare Verwendung von Bitmap in Redis

高洛峰
高洛峰Original
2017-02-09 10:30:321396Durchsuche

In Redis verwenden wir oft set, get und andere Befehle. Wenn Sie vorsichtig sind, ist Ihnen aufgefallen, dass es mehrere ähnliche Befehle namens setbit und getbit gibt.

Was ist BitMap?

Es verwendet ein Bit, um den Wert oder Status eines Elements darzustellen, und der Schlüssel ist das entsprechende Element selbst. 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, wird kein neuer Datentyp hinzugefügt, da Befehle wie setbit nur Erweiterungen von set sind.

Einführung in den Setbit-Befehl

BefehlSETBIT key offset value
KomplexitätO(1)
Setzen oder löschen Sie den Bitwert (String) des Schlüssels am Offset (nur 0 oder 1).

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 Anmeldefunktionen (nicht berücksichtigt). hier) Datenimplementierung ist wichtig) und muss den Check-in-Status im letzten Monat anzeigen. Was sollen 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, die aktive Benutzer haben (vorläufig vereinbart, nur ein Tag online während des statistischen Zeitraums wird als aktiv bezeichnet), führen Sie bitte einen Redis-Befehl aus
Befehl BITOP operation destkey key [key ...]
Erklärung: Für eine oder mehrere Bitoperationen an einem Zeichenfolgenschlüssel ausführen, der Binärbits enthält, und das Ergebnis im Zielschlüssel speichern.
Hinweis: Der BITOP-Befehl unterstützt alle Parameter der vier Operationen AND, OR, NOT und /1024/1024=6MB

//日期对应的活跃用户

$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;
Verwendungsszenario drei: Online-Status des Benutzers

Ich habe eine entwickelt Projekt vor einiger Zeit, und die andere Partei stellte mir eine Schnittstelle zur Verfügung, um abzufragen, ob der aktuelle Benutzer online ist. Ich weiß nicht, wie die andere Partei es macht, also habe ich selbst darüber nachgedacht, dass die Verwendung von Bitmap eine platzsparende und effiziente Methode ist. Es ist nur ein Schlüssel erforderlich, und wenn es online ist, wird es verschoben ist auf 1 gesetzt, und wenn es nicht online ist, wird es auf 1,0 gesetzt. Wie im obigen Szenario benötigt ein 5000-W-Benutzer nur 6 MB Speicherplatz.

Tatsächlich kann BitMap in vielen Szenarien verwendet werden (natürlich unterliegt es einigen Einschränkungen) und Ideen können sich weiterhin verbreiten~ Freunde können mir gerne eine Nachricht zur Diskussion hinterlassen~

//批量设置在线状态
$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,然后自己计算

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

*/

In Redis verwenden wir häufig Befehle wie set und get. Wenn Sie vorsichtig sind, ist Ihnen aufgefallen, dass es mehrere ähnliche Befehle namens setbit und getbit gibt.

Was ist BitMap?

stellt den Wert oder Status eines Elements durch ein Bit dar, und der Schlüssel ist das entsprechende Element selbst. 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

,

,

usw. hinzugefügt. Obwohl es sich um einen neuen Befehl handelt, wird kein neuer Datentyp hinzugefügt, da Befehle wie setbit nur Erweiterungen von getbit sind. bitcountsetbitEinführung in den Setbit-Befehlset

Befehl

Komplexität

SETBIT key offset valueSetzen oder löschen Sie den Bitwert (String) des Schlüssels am Offset (nur 0 oder 1).
O(1)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:


Nutzungsszenario 1: Benutzeranmeldung($offset/8/1024/1024)MB

Viele Websites bieten Anmeldefunktionen (nicht berücksichtigt). hier) Datenimplementierung ist wichtig) und muss den Check-in-Status im letzten Monat anzeigen. Was sollen 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 wird die Benutzer-ID versetzt. Wenn sie an diesem Tag aktiv ist, setzen Sie sie auf 1
Wie soll ich dann? Bestimmte Tage berechnen/ Was die aktiven Benutzer im Monat/Jahr betrifft (vorerst wird vereinbart, dass nur ein Tag online innerhalb des statistischen Zeitraums als aktiv bezeichnet wird), verwenden Sie bitte den nächsten Redis-Befehl
Befehl BITOP operation destkey key [key ...]
Beschreibung: Speichern Sie eine oder mehrere Binärdateien. Führen Sie Bitoperationen am Bitstring-Schlüssel durch und speichern Sie das Ergebnis im Zielschlüssel.
Hinweis: Der BITOP-Befehl unterstützt alle Parameter der vier Operationen AND, OR, NOT und /1024/1024=6MB

//日期对应的活跃用户

$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;
Verwendungsszenario drei: Online-Status des Benutzers

Ich habe eine entwickelt Projekt vor einiger Zeit, und die andere Partei stellte mir eine Schnittstelle zur Verfügung, um abzufragen, ob der aktuelle Benutzer online ist. Ich weiß nicht, wie die andere Partei das macht, also habe ich mir selbst überlegt, ob die Verwendung von Bitmap eine platzsparende und effiziente Methode ist ist auf 1 gesetzt, und wenn es nicht online ist, wird es auf 1,0 gesetzt. Wie im obigen Szenario benötigt ein 5000-W-Benutzer nur 6 MB Speicherplatz.

Tatsächlich kann BitMap in vielen Szenarien verwendet werden (natürlich unterliegt es einigen Einschränkungen) und Ideen können sich weiterhin verbreiten~ Freunde können mir gerne eine Nachricht zur Diskussion hinterlassen~

//批量设置在线状态
$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,然后自己计算

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

*/
Weitere Bitmaps in Redis Für verwandte Artikel beachten Sie bitte die chinesische PHP-Website!

Stellungnahme:
Der Inhalt dieses Artikels wird freiwillig von Internetnutzern beigesteuert und das Urheberrecht liegt beim ursprünglichen Autor. Diese Website übernimmt keine entsprechende rechtliche Verantwortung. Wenn Sie Inhalte finden, bei denen der Verdacht eines Plagiats oder einer Rechtsverletzung besteht, wenden Sie sich bitte an admin@php.cn
Vorheriger Artikel:Neue Funktionen von PHP 7Nächster Artikel:Neue Funktionen von PHP 7