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 内存。
相关推荐
一只自律的鸡33 分钟前
【MySQL】第二章 基本的SELECT语句
数据库·mysql
liliangcsdn2 小时前
如何使用python创建和维护sqlite3数据库
数据库·sqlite
TDengine (老段)8 小时前
TDengine 数学函数 DEGRESS 用户手册
大数据·数据库·sql·物联网·时序数据库·iot·tdengine
TDengine (老段)8 小时前
TDengine 数学函数 GREATEST 用户手册
大数据·数据库·物联网·时序数据库·iot·tdengine·涛思数据
RoboWizard8 小时前
扩容刚需 金士顿新款Canvas Plus存储卡
java·spring·缓存·电脑·金士顿
安当加密8 小时前
云原生时代的数据库字段加密:在微服务与 Kubernetes 中实现合规与敏捷的统一
数据库·微服务·云原生
爱喝白开水a9 小时前
LangChain 基础系列之 Prompt 工程详解:从设计原理到实战模板_langchain prompt
开发语言·数据库·人工智能·python·langchain·prompt·知识图谱
想ai抽9 小时前
深入starrocks-多列联合统计一致性探查与策略(YY一下)
java·数据库·数据仓库
武子康9 小时前
Java-152 深入浅出 MongoDB 索引详解 从 MongoDB B-树 到 MySQL B+树 索引机制、数据结构与应用场景的全面对比分析
java·开发语言·数据库·sql·mongodb·性能优化·nosql
longgyy9 小时前
5 分钟用火山引擎 DeepSeek 调用大模型生成小红书文案
java·数据库·火山引擎