redis 使用 get 命令读取 bitmap 类型的数据

本文涉及的产品
云原生内存数据库 Tair,内存型 2GB
云数据库 Redis 版,标准版 2GB
推荐场景:
搭建游戏排行榜
简介: 在签到统计场景中,可以使用 bitmap 数据类型高效的存储签到数据,但 getbit 命令只能获取某一位值,就无法最优的满足部分业务场景了。

在签到统计场景中,可以使用 bitmap 数据类型高效的存储签到数据,但 getbit 命令只能获取某一位值,就无法最优的满足部分业务场景了。

比如我们按年去存储一个用户的签到情况,365 天,只需要 365 / 8 ≈ 46 Byte,1KW 用户量一年也只需要 44 MB 就足够了。


setbit sign:uid:year 0 1 #第1天
setbit sign:uid:year 1 1 #第2天
...
setbit sign:uid:year 364 1 #第365天

但如果我想获取某个用户一年的签到统计,使用 bitget 命令的话...要循环读取 365 次,这是没办法接受的。

如果能一次读取到以字符串

"1000100010100100...001"

的形式表示的位状态数据,就很好做后续的处理了。

bitmap 其实也是一种特殊的字符串数据,使用 get 命令是可以读取出来的,但是以 16 进制的流数据返回的,这里就涉及到网络编程中数据传输的打包/解包的知识,redis 使用 get 命令读取 bitmap 数据时,将二进制数据打包成了 16 进制返回给我们,所以我们要对此数据包以 16 进制解包,然后转为二进制字符串。给出转换方法:

<?php

// 第1天的签到
$redis->setBit('sign:uid:year', 0, 1);
// 第234天的签到
$redis->setBit('sign:uid:year', 233, 1);
// 第365天的签到
$redis->setBit('sign:uid:year', 364, 1);

// 使用 get 命令一次性读取用户的 bitmap 签到数据
$bitmap_str = $redis->get("sign:uid:year");

// 对数据流使用网络字节序(大端)解包拿到16进制数据的字符串形式
$hex_str = unpack("H*", $bitmap_str)[1];

// hex str 的长度
$hex_str_len = strlen($hex_str);
// 为了防止 hex to dec 时发生溢出
// 我们需要切分 hex str,使得每一份 hex str to dec 时都能落在 int 类型的范围内
// 因为 2 位 16 进制表示一个字节,所以用系统 int 类型的字节长度去分组是绝对安全的
$chunk_size = PHP_INT_SIZE;

// 对 hex str 做分组对齐,否则 str 的最后几位可能会被当作低位数据处理
// 比如 fffff 以 4 位拆分 'ffff', 'f' 后 最后一组 'f' 就被低位数据处理了
// 对齐后 fffff000 分组 'ffff', 'f000' 就能保证 'f' 的数据位了
$hex_str = str_pad($hex_str, $hex_str_len + ($chunk_size - ($hex_str_len % $chunk_size)), 0, STR_PAD_RIGHT);

// 防止 hexdec 时溢出 使用 PHP_INT_SIZE 个 16 进制字符一组做拆分
// 因 16 进制 2 位标识一个字节 所以 PHP_INT_SIZE 是绝对不会溢出的
$hex_str_arr = str_split($hex_str, $chunk_size);

// 位数据的二进制字符串
$bitmap_bin_str = '';
array_walk($hex_str_arr, function($hex_str_chunk) use (&$bitmap_bin_str, $chunk_size) {
    $bitmap_bin_str .= str_pad(decbin(hexdec($hex_str_chunk)), $chunk_size * 4, 0, STR_PAD_LEFT);
});

// 一次读取redis即可拿到 bitmap O(n)次操作的数据
echo $bitmap_bin_str{0} . PHP_EOL; //第1天
echo $bitmap_bin_str{233} . PHP_EOL;//第234天
echo $bitmap_bin_str{364} . PHP_EOL;//第365天

注释较多,业务代码不多,多多理解~

来源:https://segmentfault.com/a/1190000017470443

相关实践学习
基于Redis实现在线游戏积分排行榜
本场景将介绍如何基于Redis数据库实现在线游戏中的游戏玩家积分排行榜功能。
云数据库 Redis 版使用教程
云数据库Redis版是兼容Redis协议标准的、提供持久化的内存数据库服务,基于高可靠双机热备架构及可无缝扩展的集群架构,满足高读写性能场景及容量需弹性变配的业务需求。 产品详情:https://www.aliyun.com/product/kvstore     ------------------------------------------------------------------------- 阿里云数据库体验:数据库上云实战 开发者云会免费提供一台带自建MySQL的源数据库 ECS 实例和一台目标数据库 RDS实例。跟着指引,您可以一步步实现将ECS自建数据库迁移到目标数据库RDS。 点击下方链接,领取免费ECS&RDS资源,30分钟完成数据库上云实战!https://developer.aliyun.com/adc/scenario/51eefbd1894e42f6bb9acacadd3f9121?spm=a2c6h.13788135.J_3257954370.9.4ba85f24utseFl
相关文章
|
7天前
|
缓存 NoSQL Linux
【Azure Redis 缓存】Windows和Linux系统本地安装Redis, 加载dump.rdb中数据以及通过AOF日志文件追加数据
【Azure Redis 缓存】Windows和Linux系统本地安装Redis, 加载dump.rdb中数据以及通过AOF日志文件追加数据
【Azure Redis 缓存】Windows和Linux系统本地安装Redis, 加载dump.rdb中数据以及通过AOF日志文件追加数据
|
10天前
|
NoSQL Redis 数据库
Redis AOF重写问题之同一数据产生两次磁盘IO如何解决
Redis AOF重写问题之同一数据产生两次磁盘IO如何解决
Redis AOF重写问题之同一数据产生两次磁盘IO如何解决
|
7天前
|
缓存 NoSQL 算法
【Azure Redis 缓存】Redis导出数据文件变小 / 在新的Redis复原后数据大小压缩近一倍问题分析
【Azure Redis 缓存】Redis导出数据文件变小 / 在新的Redis复原后数据大小压缩近一倍问题分析
|
7天前
|
缓存 NoSQL Redis
【Azure Redis 缓存】Azure Cache for Redis 是否记录具体读/写(Get/Set)或删除(Del)了哪些key呢?
【Azure Redis 缓存】Azure Cache for Redis 是否记录具体读/写(Get/Set)或删除(Del)了哪些key呢?
|
7天前
|
NoSQL 网络协议 Shell
【Azure 应用服务】App Service 项目部署成功后,应用连接 Azure Redis时报错 Could not get a resource from the pool
【Azure 应用服务】App Service 项目部署成功后,应用连接 Azure Redis时报错 Could not get a resource from the pool
|
7天前
|
SQL 缓存 NoSQL
【Azure Redis 缓存】使用Azure Redis服务时候,如突然遇见异常,遇见命令Timeout performing SET xxxxxx等情况,如何第一时间查看是否有Failover存在呢?
【Azure Redis 缓存】使用Azure Redis服务时候,如突然遇见异常,遇见命令Timeout performing SET xxxxxx等情况,如何第一时间查看是否有Failover存在呢?
|
7天前
|
缓存 监控 NoSQL
【Azure Redis 缓存】Azure Redis出现了超时问题后,记录一步一步的排查出异常的客户端连接和所执行命令的步骤
【Azure Redis 缓存】Azure Redis出现了超时问题后,记录一步一步的排查出异常的客户端连接和所执行命令的步骤
|
8天前
|
缓存 NoSQL 测试技术
【Azure Redis 缓存 Azure Cache For Redis】使用Redis自带redis-benchmark.exe命令测试Azure Redis的性能
【Azure Redis 缓存 Azure Cache For Redis】使用Redis自带redis-benchmark.exe命令测试Azure Redis的性能
|
9天前
|
缓存 NoSQL Java
【Azure Redis 缓存 Azure Cache For Redis】当使用Jedis客户端连接Redis时候,遇见JedisConnectionException: Could not get a resource from the pool / Redis connection los
【Azure Redis 缓存 Azure Cache For Redis】当使用Jedis客户端连接Redis时候,遇见JedisConnectionException: Could not get a resource from the pool / Redis connection los
|
存储 缓存 移动开发
Redis 命令执行过程(上)
今天我们来了解一下 Redis 命令执行的过程。在之前的文章中《当 Redis 发生高延迟时,到底发生了什么》我们曾简单的描述了一条命令的执行过程,本篇文章展示深入说明一下,加深读者对 Redis 的了解。
Redis 命令执行过程(上)
下一篇
云函数