先贊後看,養成習慣❤️
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 不是看起來也能改麼 我給你個表情自己領會。硬要折騰是可以的,只是收支不平衡就是了
閱讀更多 銳玩道 的文章