Redis - Bitmap 类型

Bitmap

位图的本质,还就是一个 集合,属于是 Set 类型针对整数的特化版本!--- 为了节省空间!

Redis Bitmap(位图)是一种通过位(bit)来存储和操作数据的特殊数据结构,它将每个元素映射到一个二进制位上,通过位的 0/1 状态表示元素的存在与否或状态。这种结构极大地节省了内存空间,适合处理大规模的二值状态数据。

🔍 核心特性与概念

Bitmap 的设计围绕 "高效存储二值状态",关键特性如下:

  • 位级存储:每个元素用 1 个二进制位(bit)表示,1 字节(Byte)可存储 8 个元素,1MB 可存储约 800 万个元素,内存效率极高。
  • 二值状态:每个位只能是 0 或 1,适合表示 "存在 / 不存在""在线 / 离线""已读 / 未读" 等二元属性。
  • 位运算支持:提供 AND、OR、XOR 等位操作,可高效计算多个 Bitmap 之间的交集、并集等。
  • 偏移量访问:通过整数偏移量(offset)定位元素,偏移量范围理论上可达 2^32-1(约 42 亿)。

📝 核心命令分类(附 C++ 示例)

以下示例基于 hiredis 客户端,需先安装依赖(sudo apt install libhiredis-dev)。

1. 基础操作(设置与查询)
命令功能 Redis 命令格式 C++ 代码示例
设置位的值 SETBIT key offset value user_login 中偏移量为 1001 的位设置值(1 = 登录,0 = 未登录)
获取位的值 GETBIT key offset 查询 user_login 中偏移量 1001 的用户是否登录
统计位为 1 的数量 BITCOUNT key [start end] 统计 user_login 中所有登录用户的数量(位为 1 的总数)

代码示例:用户登录状态统计

cpp 复制代码
#include <hiredis/hiredis.h>
#include <iostream>
using namespace std;

int main() {
    // 1. 连接 Redis
    redisContext* ctx = redisConnect("127.0.0.1", 6379);
    if (ctx->err) {
        cerr << "连接失败: " << ctx->errstr << endl;
        return 1;
    }

    // 2. 记录用户登录状态(SETBIT user_login 1001 1:用户ID=1001登录)
    // 设置用户1001、1003、1005登录(偏移量=用户ID)
    redisReply* reply = (redisReply*)redisCommand(ctx, "SETBIT user_login 1001 1");
    cout << "用户1001之前的登录状态(0=未登录): " << reply->integer << endl;
    freeReplyObject(reply);

    (void)redisCommand(ctx, "SETBIT user_login 1003 1");
    (void)redisCommand(ctx, "SETBIT user_login 1005 1");

    // 3. 查询用户1003是否登录(GETBIT user_login 1003)
    reply = (redisReply*)redisCommand(ctx, "GETBIT user_login 1003");
    cout << "用户1003当前登录状态(1=登录): " << reply->integer << endl;
    freeReplyObject(reply);

    // 4. 统计总登录用户数(BITCOUNT user_login)
    reply = (redisReply*)redisCommand(ctx, "BITCOUNT user_login");
    cout << "总登录用户数: " << reply->integer << endl; // 输出 3
    freeReplyObject(reply);

    // 5. 断开连接
    redisFree(ctx);
    return 0;
}
2. 位运算操作
命令功能 Redis 命令格式 说明
位运算并存储结果 BITOP operation destkey key [key ...] 对多个 Bitmap 执行 AND/OR/XOR/NOT 运算,结果存入 destkey
查找第一个为 0 或 1 的位 BITPOS key bit [start] [end] 从指定范围查找第一个值为 0 或 1 的位偏移量,可用于寻找未使用的 ID

代码示例:活跃用户交集计算

cpp 复制代码
// 假设 user_active_05(5日活跃)和 user_active_06(6日活跃)已存在
// 1. 计算连续两天活跃的用户(交集:AND 运算)
redisReply* reply = (redisReply*)redisCommand(
    ctx, "BITOP AND user_active_05_06 user_active_05 user_active_06"
);
cout << "交集计算影响的位数: " << reply->integer << endl;
freeReplyObject(reply);

// 2. 统计连续活跃用户数
reply = (redisReply*)redisCommand(ctx, "BITCOUNT user_active_05_06");
cout << "连续两天活跃的用户数: " << reply->integer << endl;
freeReplyObject(reply);

// 3. 查找第一个未登录的用户ID(BITPOS user_login 0)
reply = (redisReply*)redisCommand(ctx, "BITPOS user_login 0");
cout << "第一个未登录的用户ID: " << reply->integer << endl;
freeReplyObject(reply);

🎯 典型应用场景

Bitmap 适合需要 存储大量二值状态、进行高效位运算 的场景,具体包括:

用户行为统计

  • 签到系统:用一个 Bitmap 记录用户每月签到状态(偏移量 = 日期,1 = 签到),通过 BITCOUNT 统计月签到天数。
  • 活跃用户分析:每日用一个 Bitmap 记录活跃用户,通过 BITOP AND 计算连续 N 天活跃的用户。

权限控制

  • 用 Bitmap 存储用户权限(每个位代表一种权限),通过位运算快速判断用户是否拥有某权限(如 GETBIT user_perm 5 检查是否有编号 5 的权限)。

ID 去重与状态标记

  • 过滤已处理的任务 ID:用 Bitmap 标记已处理的任务(偏移量 = 任务 ID),避免重复处理。
  • 黑名单判断:用 Bitmap 存储黑名单用户,快速检查某用户是否在黑名单中。

数据压缩存储

  • 存储布尔数组:如某设备的传感器状态(0 = 正常,1 = 异常),相比数组存储节省大量内存。

📌 C++ 开发注意事项

  1. 偏移量范围offset 是无符号整数,最大支持 2^32-1(约 42 亿),但实际使用需考虑 Redis 内存限制。
  2. 初始化问题:未设置的位默认值为 0,无需预先初始化整个 Bitmap。
  3. 批量操作 :单次 SETBIT 只能操作一个位,批量设置需多次调用,高并发场景建议用管道(pipeline)优化。
  4. 位运算性能BITOP 性能与 Bitmap 大小相关,对超大 Bitmap 运算可能阻塞 Redis,建议在非高峰时段执行。
  5. 内存计算:Bitmap 占用内存 = (最大偏移量 + 1) / 8 字节,例如最大偏移量为 1 亿时,约占用 12MB 内存。
相关推荐
IvorySQL2 小时前
聚焦六大功能:PostgreSQL 18 新特性深度解析
数据库·postgresql·开源
饿了我会自己捡代码吃3 小时前
【MySQL】使用C/C++链接mysql数据库
c语言·数据库·mysql
gb42152873 小时前
DDD 与传统三层架构的详细对比
数据库·架构
不是三毛没有半3 小时前
Mysql 简单的语句回顾
数据库·mysql·oracle
abcefg_h4 小时前
MySQL查询详细介绍
数据库·mysql
whn19774 小时前
批量获取oracle的AWR报告方法
数据库·oracle
小旺不正经5 小时前
数据库表实现账号池管理
数据库·后端·算法
sanx185 小时前
一站式电竞平台解决方案:数据、直播、源码,助力业务飞速启航
前端·数据库·apache·数据库开发·时序数据库