redis精進 - 玩歸玩、鬧歸鬧,別拿Bitmap開玩笑

先贊後看,養成習慣❤️php

BitMap 是什麼

  • 8 個 bit 組成一個 Byte,因此 bitmap 極大的節省儲存空間
    你能夠把它理解爲一個特殊處理過的 字符串
  • key表明業務屬性、標籤。一個 bit 位來表示某個元素對應的值或者狀態。
    舉個例子:登記天天活躍用戶,key 表明 登陸時間, 一、二、3...表明 用戶id
key 0 1 2 3 4 5 6 7
login20191230 0 0 1 0 0 0 0 0
login20191231 0 1 0 0 1 0 0 0
login20200101 0 0 1 0 0 0 0 0

那麼根據上面位圖能夠得出:
用戶id:1 在 20191231 登陸過
用戶id:2 在 20191230,20200101 登陸過
用戶id:4 在 20191231 登陸過
其他沒有登陸

redis

Redis 中的 BitMap

已是源於 2.2.0 版本的 "新技術"。我以爲你會看到那個 雙引號 不會當真的
新增了setbit,getbit,bitcount等幾個 bitmap 相關命令。但其實 setbit 等命令只不過是在 set 上的擴展而已。算法

setbit 命令介紹

指令 SETBIT key offset value
複雜度 O(1)
設置或者清空 key 的 value(字符串)在 offset 處的 bit 值(只能只 0 或者 1)。數組

空間佔用、以及第一次分配空間須要的時間

在一臺 2010MacBook Pro 上網絡

  • offset 爲 2^32-1(分配 512MB)須要~ 300ms
  • offset 爲 2^30-1(分配 128MB)須要~ 80ms
  • offset 爲 2^28-1(分配 32MB)須要~ 30ms
  • offset 爲 2^26-1(分配 8MB)須要 8ms。 -- <來自官方文檔>
    大概的空間佔用計算公式是:($offset/8/1024/1024)MB

使用場景

統計活躍用戶

使用時間做爲 cacheKey,而後用戶 ID 爲 offset,若是當日活躍過就設置爲 1
那麼我該若是計算某幾天/月/年的活躍用戶呢(暫且約定,統計時間內只有有一天在線就稱爲活躍),有請下一個 redis 的命令
命令 BITOP operation destkey key [key ...]
說明:對一個或多個保存二進制位的字符串 key 進行位元操做,並將結果保存到 destkey 上。
說明:BITOP 命令支持 AND 、 OR 、 NOT 、 XOR 這四種操做中的任意一種參數ui

//日期對應的活躍用戶
$data = array(
    '2020-01-10' => array(1,2,3,4,5,6,7,8,9,10),
    '2020-01-11' => array(1,2,3,4,5,6,7,8),
    '2020-01-12' => array(1,2,3,4,5,6),
    '2020-01-13' => array(1,2,3,4),
    '2020-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_2020-01-10', 'stat_2020-01-11', 'stat_2020-01-12');

//總活躍用戶:6
echo "總活躍用戶:" . $redis->bitCount('stat') . PHP_EOL;

$redis->bitOp('AND', 'stat1', 'stat_2020-01-10', 'stat_2020-01-11', 'stat_2020-01-14') . PHP_EOL;

//總活躍用戶:2
echo "總活躍用戶:" . $redis->bitCount('stat1') . PHP_EOL;

$redis->bitOp('AND', 'stat2', 'stat_2020-01-10', 'stat_2020-01-11') . PHP_EOL;

//總活躍用戶:8
echo "總活躍用戶:" . $redis->bitCount('stat2') . PHP_EOL;
複製代碼

假設當前站點有 5000W 用戶,那麼一天的數據大約爲 50000000/8/1024/1024=6MBspa

用戶簽到、用戶在線狀態

這些都大同小異我就不,慢性謀殺大家的時間了。Peace&Love

code

有哪些須要注意

須要壓縮運算

我以爲 人對事物的認知,得通過懵懂但美好憧憬 -> 被欺騙(坑)感情 -> 再次審視本身和事物 才能創建起一個 客觀正確 的認知 -- 越欣賞越懂欣賞ip

Redis Bitmap 的好在於 ta 壓縮存儲空間。在平常用法中,這種壓縮的代價是要通過 CPU 運算的。文檔

大量數據的 setBit 會形成大量的網絡請求。因此通常是 程序中 把 id 數組 pack() 設進位圖變成一個 String。再一次性 set 進 Redis。

這就意味着 取出來的時候須要 unpack() 把 String 解壓成 id 數組。不過得益於算法,這一步並不算太複雜

存儲數據有限

另外ta 存儲的數據至關有限,舉個例子:

// 正常狀況的 用戶 id:一、3 登陸數組:
'login20191230' => array(
    1 => array(
        'user_id' => 1,
        'login_ip' => 'x.x.x.x',
        'usage_agent' => 'xxx'
    ),
    3 => array(
        'user_id' => 3,
        'login_ip' => 'x.x.x.x',
        'usage_agent' => 'xxx'
    ),
)

// bitmap 的 登陸數組
'login20191230' => array(
    0 => 01 => 12 => 03 => 1,
)
複製代碼

能夠用的的地方只有 'login20191230' 和 數組裏的 key

你會問 數組裏的 value 不是看起來也能改麼 我給你個表情本身領會😑。硬要折騰是能夠的,只是收支不平衡就是了

相關文章
相關標籤/搜索