闲谈redis的bitmap

bitmap的原理

bitmap就是通过最小的单位bit(8bit = 1b = 0.001kb)来进行0或者1的设置,表示某个元素对应的值或者状态。一个bit的值,或者是0,或者是1;也就是说一个bit能存储的最多信息是2。

优点

  • 基于最小的单位bit进行存储,所以非常省空间。
  • 设置时候时间复杂度O(1)、读取时候时间复杂度O(n),操作是非常快的。
  • 二进制数据的存储,进行相关计算的时候非常快。
  • 方便扩容

缺点

redis中bit映射被限制在512MB之内,所以最大是2^32位。建议每个key的位数都控制下,因为读取时候时间复杂度O(n),越大的串读的时间花销越多。

用法

setBit

给一个指定key的值得第offset位 赋值为value。

  • 参数:key offset value: bool or int (1 or 0)
  • 返回值:LONG: 0 or 1

getBit

返回一个指定key的二进制信息

  • 参数:key offset
  • 返回值:LONG

bitCount

返回一个指定key中位的值为1的个数(是以byte为单位不是bit)

  • 参数:key start offset
  • 返回值:LONG

bitOp

对不同的二进制存储数据进行位运算(AND、OR、NOT、XOR)

  • 参数:operation destkey key [key …]
  • 返回值:LONG

使用场景

用户在线状态

使用bitmap是一个节约空间效率又高的一种方法,只需要一个key,然后用户id为偏移量offset,如果在线就设置为1,不在线就设置为0,3亿用户只需要36MB的空间。

$status = 1;
$redis->setBit('online', $uid, $status);
$redis->getBit('online', $uid);

统计用户连续活跃天数

设定一个初始时间,往后没加一天即对应value中的offset的位置。

$start_date = '20170708';
$end_date = '20170709';
$offset = floor((strtotime($start_date) - strtotime($end_date)) / 86400);
$redis->setBit('sign_123456', $offset, 1);

//算活跃天数
$redis->bitCount('sign_123456', 0, -1)

 

<think>嗯,用户想了解RedisBitmap的长度计算方法。首先,我需要回忆一下BitmapRedis中的实现。根据引用[2]和[4],Bitmap是基于String类型的,每个bit位代表一个二值状态。每个String最大是512MB,所以最多可以存储的位数应该是512MB乘以8,也就是2^32位,也就是4294967296个位。 接下来,用户问的是长度计算方法。当用户设置某个偏移量的位时,比如使用SETBIT命令,偏移量可以是0到2^32-1之间的值。实际占用的空间会根据最大的偏移量自动扩展。例如,如果最大的偏移量是100,那么需要的字节数就是100/8向上取整,即13字节。不过,Redis底层是动态字符串,会自动分配空间,可能预留一些空间以减少频繁分配的开销。 另外,引用[5]提到读取的时间复杂度是O(n),所以过大的Bitmap会影响性能。需要注意每个key的位数控制。计算长度的方法应该是取最大的偏移量加一,因为偏移量是从0开始的。例如,最大的偏移量是n,那么长度就是n+1位。存储空间的话,字节数是(n+1 +7)/8取整,也就是向上取整的除法。 还要注意,当使用BITCOUNT等命令时,返回的是被设置为1的位数,而不是总长度。总长度需要根据最大的偏移量来计算。比如,如果用户从未设置过偏移量100,那么实际的长度可能较小,但一旦设置了较大的偏移量,长度就会扩展。 总结一下,长度计算主要依据最大的偏移量,存储空间是最大偏移量除以8向上取整,而总位数是最大偏移量加一。需要提醒用户注意性能问题,避免过大的偏移量导致处理时间增加。</think>### Redis Bitmap 长度计算方法详解 在 Redis 中,Bitmap(位图)的**最大理论长度**为 $2^{32}$ 位(即 4,294,967,296 位),对应的存储上限为 512MB[^5]。实际长度由用户设置的**最大偏移量(offset)**决定,具体规则如下: --- #### 1. **存储结构基础** - Bitmap 底层使用 String 类型存储,每个字节(8 位)表示 8 个连续的二进制位[^2][^4]。 - 偏移量从 0 开始计算,例如设置 `offset=5` 对应第 6 位(索引从 0 开始)。 --- #### 2. **长度计算规则** **公式**: $$ 实际占用字节数 = \left\lceil \frac{最大偏移量 + 1}{8} \right\rceil $$ $$ 总位数 = 最大偏移量 + 1 $$ **示例**: - 若设置 `SETBIT key 15 1`(最大偏移量 15): - 总位数 = 15 + 1 = 16 位 - 占用字节数 = ⌈16 / 8⌉ = 2 字节 - 若设置 `SETBIT key 1000000 1`(最大偏移量 1,000,000): - 总位数 = 1,000,001 位 - 占用字节数 = ⌈1,000,001 / 8⌉ ≈ 125,000 字节(约 122KB) --- #### 3. **动态扩容机制** Redis 会根据操作自动扩展存储空间: - 未设置的偏移量默认值为 0。 - 例如,首次执行 `SETBIT key 1000 1` 时,Redis 会分配足够字节覆盖 0-1000 的偏移量,即 ⌈1001/8⌉ = 126 字节[^3]。 --- #### 4. **注意事项** 1. **性能影响**:读取操作(如 `BITCOUNT`)的时间复杂度为 $O(n)$,n 为实际占用字节数。建议控制最大偏移量以降低延迟。 2. **稀疏位图优化**:若偏移量分布稀疏(例如集中在高位),Redis 仍会分配连续内存,可能造成空间浪费。 --- #### 代码示例(Python) ```python def calculate_bitmap_size(max_offset): total_bits = max_offset + 1 total_bytes = (max_offset + 8) // 8 # 等价于向上取整 return total_bits, total_bytes # 示例:计算 offset=15 的存储需求 bits, bytes = calculate_bitmap_size(15) print(f"总位数: {bits}, 占用字节: {bytes}") # 输出: 总位数: 16, 占用字节: 2 ``` ---
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值