Redis 亿级用户信息存储实践:bitmap 位图存储

2023-12-26 05:59

本文主要是介绍Redis 亿级用户信息存储实践:bitmap 位图存储,希望对大家解决编程问题提供一定的参考价值,需要的开发者们随着小编来一起学习吧!

bitmap简介

8 个 bit 组成一个 Byte,所以 bitmap 极大的节省储存空间

你可以把它理解为一个特殊处理过的 字符串
key代表业务属性、标签。一个 bit 位来表示某个元素对应的值或者状态。

bitmap 并不是一种数据结构,实际上它就是字符串,但是可以对字符串的位进行操作。

bitmap有自己的一套命令。可以把bitmap想象成一个以bit为单位的数组,数组的每个单元存储0和1,数组的下标叫做偏移量。

Redis 提供 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。
– <来自官方文档: https://redis.io/commands/setbit>
大概的空间占用计算公式是:($offset/8/1024/1024)MB

Available since 2.2.0.

Time complexity: O(1)

Sets or clears the bit at offset in the string value stored at key.

The bit is either set or cleared depending on value, which can be either 0 or 1.

When key does not exist, a new string value is created. The string is grown to make sure it can hold a bit at offset. The offset argument is required to be greater than or equal to 0, and smaller than 232 (this limits bitmaps to 512MB). When the string at key is grown, added bits are set to 0.

Warning: When setting the last possible bit (offset equal to 232 -1) and the string value stored at key does not yet hold a string value, or holds a small string value, Redis needs to allocate all intermediate memory which can block the server for some time. On a 2010 MacBook Pro, setting bit number 232 -1 (512MB allocation) takes ~300ms, setting bit number 230 -1 (128MB allocation) takes ~80ms, setting bit number 228 -1 (32MB allocation) takes ~30ms and setting bit number 226 -1 (8MB allocation) takes ~8ms. Note that once this first allocation is done, subsequent calls to SETBIT for the same key will not have the allocation overhead.

Redis bitmap 的命令

bitmap的命令

常用命令 作用
1、getbit key offset 用于获取Redis中指定key对应的值,中对应offset的bit
2、setbit key key offset value 用于修改指定key对应的值,中对应offset的bit
3、 bitcount key [start end] 用于统计字符串被设置为1的bit数
4、bitop and/or/xor/not destkey key [key …] 用于对多个key求逻辑与/逻辑或/逻辑异或/逻辑非

设置 offset 位的 01 值

127.0.0.1:6379> setbit user10001 0 1
(integer) 0
127.0.0.1:6379> setbit user10001 3 1
(integer) 0
127.0.0.1:6379> getbit user10001 0
(integer) 1
127.0.0.1:6379> getbit user10001 1
(integer) 0
127.0.0.1:6379> getbit user10001 2
(integer) 0
127.0.0.1:6379> getbit user10001 3
(integer) 1
127.0.0.1:6379> getbit user10001 7
(integer) 1

批量设置 offset 位的 01 值

使用 u1 类型批量设置 offset 位的 01 值:

127.0.0.1:6379> bitfield user10001 set u1 2 1 set u1 9 1 set u1 10 1
1) (integer) 0
2) (integer) 0
3) (integer) 0
127.0.0.1:6379> getbit user10001 10
(integer) 1
127.0.0.1:6379> getbit user10001 9
(integer) 1
127.0.0.1:6379> getbit user10001 8
(integer) 0
127.0.0.1:6379> getbit user10001 7
(integer) 1

bitmap的应用场景

使用经验:
type = string,BitMap 是 sting 类型,最大 512 MB。
注意 setbit 时的偏移量,可能有较大耗时
位图不是绝对好。

通过 bitcount可以很快速的统计,比传统的关系型数据库效率高很多

1、比如统计年活跃用户数量

用户的ID作为offset,当用户在一年内访问过网站,就将对应offset的bit值设置为“1”;

通过bitcount 来统计一年内访问过网站的用户数量

2、比如统计三天内活跃用户数量

时间字符串作为key,比如 “190108:active“ “190109:active”“190110:active” ;

用户的ID就可以作为offset,当用户访问过网站,就将对应offset的bit值设置为“1”;

统计三天的活跃用户,通过bitop or 获取一周内访问过的用户数量

3、连续三天访问的用户数量 bitop and

4、三天内没有访问的用户数量 bitop not

5、统计在线人数 设置在线key:“online:active”,当用户登录时,通过setbit设置

bitmap的优势,以统计活跃用户为例

每个用户id占用空间为1bit,消耗内存非常少,存储1亿用户量只需要12.5M

使用场景: 统计活跃用户

使用时间作为 cacheKey,然后用户 ID 为 offset,如果当日活跃过就设置为 1
那么我该如果计算某几天/月/年的活跃用户呢(暂且约定,统计时间内只有有一天在线就称为活跃),有请下一个 redis 的命令
命令

BITOP operation destkey key [key ...]

说明:对一个或多个保存二进制位的字符串 key 进行位元操作,并将结果保存到 destkey 上。
说明:BITOP 命令支持 AND 、 OR 、 NOT 、 XOR 这四种操作中的任意一种参数

//日期对应的活跃用户
$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;

假设当前站点有 5000W 用户,那么一天的数据大约为 50000000/8/1024/1024=6MB

布隆过滤器

bitmap - Redis布隆过滤器 (应对缓存穿透问题)

举例:比如爬虫服务器在爬取电商网站的商品信息时,首先经过缓存,如果缓存查不到,再去数据库获取信息,因为爬虫的效率很高,且sku很有可能是不存在或者已下架的,就会造成缓存穿透,大量请求被发送到数据库,导致服务器受到影响。

此时,可以在缓存层之前,添加一个布隆过滤器,布隆过滤器看作是一个bitmap,sku作为offset值,如果商品真实存在,bit值设为1。首先将商品数据初始化,当有请求时,通过getbit判断sku是否有效。如果布隆过滤器认为商品不存在,就拒绝访问,这样就可以保护存储层。

Data structures are nothing different. They are like the bookshelves of your application where you can organize your data. Different data structures will give you different facility and benefits. To properly use the power and accessibility of the data structures you need to know the trade-offs of using one.

大意是不同的数据结构有不同的适用场景和优缺点,你需要仔细权衡自己的需求之后妥善适用它们,布隆过滤器就是践行这句话的代表。

参考资料

https://blog.csdn.net/weixin_42383575/article/details/86684283

https://zhuanlan.zhihu.com/p/136337229

https://www.imooc.com/article/298707

https://www.jianshu.com/p/4c8e119f35db


http://www.taodudu.cc/news/show-8402039.html

相关文章:

  • 总线制和多线制示意图_总线制与多线制的区别
  • 节节提高 提升绿色IT三大新境界
  • 数据库select操作
  • 势不可挡!Android手机在英国手机市场上的销量节节攀升
  • 用 Apache Derby 进行开发 —— 取得节节胜利: 使用 Apache Derby 进行数据库开发,第 1 部分
  • 达梦数据库渠道建设取得新突破 数据库销售节节攀高
  • 《玩转Windows 7 》销售节节攀高
  • 中秋国庆_节节快乐
  • 用 Apache Derby 进行开发 —— 取得节节胜利: 用 Apache Derby 进行 Java 数据库开发,第 1 部分
  • 交换次数【第九届蓝桥杯国赛】
  • 职场节节攀升有十招
  • 9届国赛java试题 5: 交换次数
  • 20170117L07-1-2老男孩linux运维实战培训-初级第七节节课课前考试第一题route命令讲解...
  • 职场兵法:十大招数让你薪酬节节攀升
  • 第九届蓝桥杯 2018年国赛真题(Java 大学C组)
  • 在平板市场份额节节攀升的华为将发新平板
  • 用 Apache Derby 进行开发 —— 取得节节胜利: 介绍 Apache Derby
  • 第一盘节节登高的做法
  • Net Applications:IE份额还剩67% 对手节节追赶
  • 戴尔股价节节攀升,但去中国化导致老本行正被中国消费者抛弃
  • AIGC参数量节节攀升,对存储带来的挑战如何解决?
  • 主机与虚拟机都可以上网,但是互相ping不通
  • 算法一般都可以用哪几种控制结构组合而成(dell)
  • 【数据库】所有的视图都可以更新吗?请举例说明。
  • 【转】Tomcat webapps下面的东西都可以删除吗
  • MySQL设置所有IP地址都可以访问数据库
  • 为何 as sysdba的方式登陆oracle数据库,为何随便输入用户名和密码都可以登陆?
  • 给定N个非0的个位数字,用其中任意2个数字都可以组合成1个2位的数字。要求所有可能组合出来的2位数字的和。例如给定2、5、8,则可以组合出:25、28、52、58、82、85,它们的和为330。...
  • 是不是所有的文法都可以化为LL(1)文法?
  • C#如何定义全局变量,不同的子窗体和类都可以访问
  • 这篇关于Redis 亿级用户信息存储实践:bitmap 位图存储的文章就介绍到这儿,希望我们推荐的文章对编程师们有所帮助!



    http://www.chinasem.cn/article/538327

    相关文章

    springboot项目中整合高德地图的实践

    《springboot项目中整合高德地图的实践》:本文主要介绍springboot项目中整合高德地图的实践,具有很好的参考价值,希望对大家有所帮助,如有错误或未考虑完全的地方,望不吝赐教... 目录一:高德开放平台的使用二:创建数据库(我是用的是mysql)三:Springboot所需的依赖(根据你的需求再

    SpringBoot3应用中集成和使用Spring Retry的实践记录

    《SpringBoot3应用中集成和使用SpringRetry的实践记录》SpringRetry为SpringBoot3提供重试机制,支持注解和编程式两种方式,可配置重试策略与监听器,适用于临时性故... 目录1. 简介2. 环境准备3. 使用方式3.1 注解方式 基础使用自定义重试策略失败恢复机制注意事项

    MySQL MCP 服务器安装配置最佳实践

    《MySQLMCP服务器安装配置最佳实践》本文介绍MySQLMCP服务器的安装配置方法,本文结合实例代码给大家介绍的非常详细,对大家的学习或工作具有一定的参考借鉴价值,需要的朋友参考下... 目录mysql MCP 服务器安装配置指南简介功能特点安装方法数据库配置使用MCP Inspector进行调试开发指

    SQLite3命令行工具最佳实践指南

    《SQLite3命令行工具最佳实践指南》SQLite3是轻量级嵌入式数据库,无需服务器支持,具备ACID事务与跨平台特性,适用于小型项目和学习,sqlite3.exe作为命令行工具,支持SQL执行、数... 目录1. SQLite3简介和特点2. sqlite3.exe使用概述2.1 sqlite3.exe

    Redis Cluster模式配置

    《RedisCluster模式配置》:本文主要介绍RedisCluster模式配置,本文给大家介绍的非常详细,对大家的学习或工作具有一定的参考借鉴价值,需要的朋友参考下吧... 目录分片 一、分片的本质与核心价值二、分片实现方案对比 ‌三、分片算法详解1. ‌范围分片(顺序分片)‌2. ‌哈希分片3. ‌虚

    SQL中JOIN操作的条件使用总结与实践

    《SQL中JOIN操作的条件使用总结与实践》在SQL查询中,JOIN操作是多表关联的核心工具,本文将从原理,场景和最佳实践三个方面总结JOIN条件的使用规则,希望可以帮助开发者精准控制查询逻辑... 目录一、ON与WHERE的本质区别二、场景化条件使用规则三、最佳实践建议1.优先使用ON条件2.WHERE用

    MySQL存储过程之循环遍历查询的结果集详解

    《MySQL存储过程之循环遍历查询的结果集详解》:本文主要介绍MySQL存储过程之循环遍历查询的结果集,具有很好的参考价值,希望对大家有所帮助,如有错误或未考虑完全的地方,望不吝赐教... 目录前言1. 表结构2. 存储过程3. 关于存储过程的SQL补充总结前言近来碰到这样一个问题:在生产上导入的数据发现

    Springboot整合Redis主从实践

    《Springboot整合Redis主从实践》:本文主要介绍Springboot整合Redis主从的实例,具有很好的参考价值,希望对大家有所帮助,如有错误或未考虑完全的地方,望不吝赐教... 目录前言原配置现配置测试LettuceConnectionFactory.setShareNativeConnect

    Redis过期删除机制与内存淘汰策略的解析指南

    《Redis过期删除机制与内存淘汰策略的解析指南》在使用Redis构建缓存系统时,很多开发者只设置了EXPIRE但却忽略了背后Redis的过期删除机制与内存淘汰策略,下面小编就来和大家详细介绍一下... 目录1、简述2、Redis http://www.chinasem.cn的过期删除策略(Key Expir

    java中Optional的核心用法和最佳实践

    《java中Optional的核心用法和最佳实践》Java8中Optional用于处理可能为null的值,减少空指针异常,:本文主要介绍java中Optional核心用法和最佳实践的相关资料,文中... 目录前言1. 创建 Optional 对象1.1 常规创建方式2. 访问 Optional 中的值2.1