玩歸玩、鬧歸鬧,別拿Bitmap開玩笑


先贊後看,養成習慣❤️

BitMap 是什麼

  • 8 個 bit 組成一個 Byte,所以 bitmap 極大的節省儲存空間
    你可以把它理解為一個特殊處理過的 字符串
  • key代表業務屬性、標籤。一個 bit 位來表示某個元素對應的值或者狀態。
    舉個例子:登記每天活躍用戶,key 代表 登錄時間, 1、2、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 中的 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 這四種操作中的任意一種參數

<code>//日期對應的活躍用戶
$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;
/<code>

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

用戶簽到、用戶在線狀態

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

有哪些需要注意

需要壓縮運算

我覺得 人對事物的認知,得經過懵懂但美好憧憬 -> 被欺騙(坑)感情 -> 再次審視自己和事物 才能建立起一個 客觀正確 的認知 -- 越欣賞越懂欣賞

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

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

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

存儲數據有限

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

<code>// 正常情況的 用戶 id:1、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 => 0,
1 => 1,
2 => 0,
3 => 1,
)
/<code>

可以用的的地方只有 'login20191230' 和 數組裡的 key

你會問 數組裡的 value 不是看起來也能改麼 我給你個表情自己領會。硬要折騰是可以的,只是收支不平衡就是了


分享到:


相關文章: