百度360必应搜狗淘宝本站头条
当前位置:网站首页 > 技术教程 > 正文

「每天一道面试题」 Redis bitmap

mhr18 2024-11-27 11:54 25 浏览 0 评论

Redis bitmap

什么是Redis bitmap

Redis 的 bitmap 是通过一个 bit 位来表示某个元素对应的值或者状态,其中的 key 就是对应元素本身。Bitmaps 本身不是一种数据结构,实际上它就是字符串(key 对应的 value 就是上图中最后的一串二进制),但是它可以对字符串的位进行操作。

Bitmaps 单独提供了一套命令,所以在 Redis 中使用 Bitmaps 和使用字符串的方法不太相同。可以把 Bitmaps 想象成一个以 "位" 为单位的数组,数组的每个单元只能存储 0 和 1,数组的下标在 Bitmaps 中叫做偏移量。

bitmap特点

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

Bitmaps 单独提供了一套命令, 所以在 Redis 中使用 Bitmaps 和使用字符串的方法不太相同。 可以把 Bitmaps 想象成一个以位为单位的数组, 数组的每个单元只能存储 0 和 1,数组的下标在 Bitmaps 中叫做偏移量。

bitmap优缺点

优点

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

限制

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

bitmap命令详解

设置值SETBIT

语法

SETBIT key offset value

说明

对 key 所储存的字符串值,设置或清除指定偏移量上的位(bit)。位的设置或清除取决于 value 参数,可以是 0 也可以是 1 。当 key 不存在时,自动生成一个新的字符串值。

字符串会进行伸展(grown)以确保它可以将 value 保存在指定的偏移量上。当字符串值进行伸展时,空白位置以 0 填充。offset 参数必须大于或等于 0 ,小于 2^32 (bit 映射被限制在 512 MB 之内)。对使用大的 offset 的 SETBIT 操作来说,内存分配可能造成 Redis 服务器被阻塞。

返回值

字符串值指定偏移量上原来储存的位(bit)。

示例




从以上示例我们可以看出,我们使用 SETBIT 命令可以设置某个位的值,如果没有设置值的位默认值为 0,同时,SETBIT 只能设置 0 和 1,我们设置了 2,提示我们出错了。

获取值GETBIT

语法

GETBIT key offset

说明

对 key 所储存的字符串值,获取指定偏移量上的位(bit)。当 offset 比字符串值的长度大,或者 key 不存在时,返回 0。

返回值

字符串值指定偏移量上的位(bit)。

示例




从以上示例我们可以看出,我们使用 SETBIT 命令可以设置某个位的值,使用 GETBIT 可以获取某个位的值。

获取值为1个数BITCOUNT

语法

BITCOUNT key start

说明

计算给定字符串中,被设置为 1 的比特位的数量。一般情况下,给定的整个字符串都会被进行计数,通过指定额外的 start 或 end 参数,可以让计数只在特定的位上进行。

start 和 end 参数的设置和 GETRANGE 命令类似,都可以使用负数值: 比如 -1 表示最后一个字节,-2 表示倒数第二个字节,以此类推。不存在的 key 被当成是空字符串来处理,因此对一个不存在的 key 进行 BITCOUNT 操作,结果为 0。

返回值

被设置为 1 的位的数量。

示例



从以上示例我们可以看出,我们使用 SETBIT 命令设置某个位的值,最后我们使用 BITCOUNT 可以获取被设置为 1 的位的个数。

注意

BITCOUNT 命令返回的是一个指定 key 中位的值为 1 的个数(是以 byte 为单位不是 bit)”,这就是坑的所在。所以 bitcount 0 0 那么就应该是第一个 "字节" 中 1 的数量的,注意是字节,第一个字节也就是 1,2,3,4,5,6,7,8 这八个位置上。

bitmap运算BITOP

语法

BITOP operation destkey key [key ...]

说明

对一个或多个保存二进制位的字符串 key 进行位元操作,并将结果保存到 destkey 上。operation 可以是 AND 、 OR 、 NOT 、 XOR 这四种操作中的任意一种:

  • BITOP AND destkey key [key ...] ,对一个或多个 key 求逻辑并,并将结果保存到 destkey。
  • BITOP OR destkey key [key ...] ,对一个或多个 key 求逻辑或,并将结果保存到 destkey。
  • BITOP XOR destkey key [key ...] ,对一个或多个 key 求逻辑异或,并将结果保存到 destkey。
  • BITOP NOT destkey key ,对给定 key 求逻辑非,并将结果保存到 destkey。

除了 NOT 操作之外,其他操作都可以接受一个或多个 key 作为输入。当 BITOP 处理不同长度的字符串时,较短的那个字符串所缺少的部分会被看作 0。空的 key 也被看作是包含 0 的字符串序列。

返回值

保存到 destkey 的字符串的长度,和输入 key 中最长的字符串长度相等。

示例

AND 操作具体如下:


从以上示例我们可以看出,使用 BITOP 可以操作两个或者多个 bitmaps,并且只有两位都是 1 时,结果对应的位才为 1。

注意

BITOP 的复杂度为 O(N) ,当处理大型矩阵(matrix)或者进行大数据量的统计时,最好将任务指派到附属节点(slave)进行,避免阻塞主节点。

计算偏移量

语法

BITPOS key bit [start][end]

说明

返回字符串里面第一个被设置为 1 或者 0 的 bit 位。返回一个位置,把字符串当做一个从左到右的字节数组,第一个符合条件的在位置 0,其次在位置 8,等等。

GETBIT 和 SETBIT 相似的也是操作字节位的命令。默认情况下整个字符串都会被检索一次,只有在指定 start 和 end 参数(指定 start 和 end 位是可行的),该范围被解释为一个字节的范围,而不是一系列的位。所以 start=0 并且 end=2 是指前三个字节范围内查找。

注意,返回的位的位置始终是从 0 开始的,即使使用了 start 来指定了一个开始字节也是这样。和 GETRANGE 命令一样,start 和 end 也可以包含负值,负值将从字符串的末尾开始计算,-1 是字符串的最后一个字节,-2 是倒数第二个,等等。不存在的 key 将会被当做空字符串来处理。

返回值

命令返回字符串里面第一个被设置为 1 或者 0 的 bit 位。如果我们在空字符串或者 0 字节的字符串里面查找 bit 为 1 的内容,那么结果将返回 -1。如果我们在字符串里面查找 bit 为 0 而且字符串只包含 1 的值时,将返回字符串最右边的第一个空位。

如果有一个字符串是三个字节的值为 0xff 的字符串,那么命令 BITPOS key 0 将会返回 24,因为 0-23 位都是 1。基本上,我们可以把字符串看成右边有无数个 0。然而,如果你用指定 start 和 end 范围进行查找指定值时,如果该范围内没有对应值,结果将返回 -1。

示例



我们首先使用了 SETBIT 设置位的值,接着,我们分别使用了 BITPOS 获取了第一个 1 的偏移量和第一位为 0 的偏移量,我们可以看出,第一个为 1 的偏移量就是我们设置的 100.

bitmap使用场景

视频属性的无限延伸

需求描述

一个拥有亿级数据量的短视频 app,视频存在各种属性(是否加锁、是否特效等等),需要做各种标记。

可能想到的解决方案

  1. 存储在 mysql 中,肯定不行,一个是随着业务增长属性一直增加,并且存在有时间限制的属性,直接对数据库进行加减字段是非常不合理的做法。即使是存在一个字段中用 json 等压缩技术存储也存在读效率的问题,并且对于大几亿的数据来说,废弃的字段回收起来非常麻烦。
  2. 直接记录在 redis 中,根据业务属性+uid 为 key 来存储。读写效率角度没毛病,但是存储的角度来说key的数据量都大于 value 了,太耗费空间了。即使是用 json 等压缩技术来存储。也存在问题,解压需要时间,并且大几亿的数据回收也是难题。

设计方案

使用 redis 的 bitmap 进行存储。key 由属性 id+视频分片 id 组成。value 按照视频 id 对分片范围取模来决定偏移量 offset。10 亿视频一个属性约 120m 还是挺划算的。

用户在线状态

需求描述

需要对子项目提供一个接口,来提供某用户是否在线?

设计方案

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

统计活跃用户

需求描述

需要计算活跃用户的数据情况。

设计方案

使用时间作为缓存的 key,然后用户 id 为 offset,如果当日活跃过就设置为 1。之后通过 bitOp 进行二进制计算算出在某段时间内用户的活跃情况。

用户签到

需求分析

用户需要进行签到,对于签到的数据需要进行分析与相应的运运营策略。

设计方案

使用 redis 的 bitmap,由于是长尾的记录,所以 key 主要由 uid 组成,设定一个初始时间,往后每加一天即对应 value 中的 offset 的位置。

原文参考:嗨客网(www.haicoder.net)Redis bitmap

相关推荐

【推荐】一个开源免费、AI 驱动的智能数据管理系统,支持多数据库

如果您对源码&技术感兴趣,请点赞+收藏+转发+关注,大家的支持是我分享最大的动力!!!.前言在当今数据驱动的时代,高效、智能地管理数据已成为企业和个人不可或缺的能力。为了满足这一需求,我们推出了这款开...

Pure Storage推出统一数据管理云平台及新闪存阵列

PureStorage公司今日推出企业数据云(EnterpriseDataCloud),称其为组织在混合环境中存储、管理和使用数据方式的全面架构升级。该公司表示,EDC使组织能够在本地、云端和混...

对Java学习的10条建议(对java课程的建议)

不少Java的初学者一开始都是信心满满准备迎接挑战,但是经过一段时间的学习之后,多少都会碰到各种挫败,以下北风网就总结一些对于初学者非常有用的建议,希望能够给他们解决现实中的问题。Java编程的准备:...

SQLShift 重大更新:Oracle→PostgreSQL 存储过程转换功能上线!

官网:https://sqlshift.cn/6月,SQLShift迎来重大版本更新!作为国内首个支持Oracle->OceanBase存储过程智能转换的工具,SQLShift在过去一...

JDK21有没有什么稳定、简单又强势的特性?

佳未阿里云开发者2025年03月05日08:30浙江阿里妹导读这篇文章主要介绍了Java虚拟线程的发展及其在AJDK中的实现和优化。阅前声明:本文介绍的内容基于AJDK21.0.5[1]以及以上...

「松勤软件测试」网站总出现404 bug?总结8个原因,不信解决不了

在进行网站测试的时候,有没有碰到过网站崩溃,打不开,出现404错误等各种现象,如果你碰到了,那么恭喜你,你的网站出问题了,是什么原因导致网站出问题呢,根据松勤软件测试的总结如下:01数据库中的表空间不...

Java面试题及答案最全总结(2025版)

大家好,我是Java面试陪考员最近很多小伙伴在忙着找工作,给大家整理了一份非常全面的Java面试题及答案。涉及的内容非常全面,包含:Spring、MySQL、JVM、Redis、Linux、Sprin...

数据库日常运维工作内容(数据库日常运维 工作内容)

#数据库日常运维工作包括哪些内容?#数据库日常运维工作是一个涵盖多个层面的综合性任务,以下是详细的分类和内容说明:一、数据库运维核心工作监控与告警性能监控:实时监控CPU、内存、I/O、连接数、锁等待...

分布式之系统底层原理(上)(底层分布式技术)

作者:allanpan,腾讯IEG高级后台工程师导言分布式事务是分布式系统必不可少的组成部分,基本上只要实现一个分布式系统就逃不开对分布式事务的支持。本文从分布式事务这个概念切入,尝试对分布式事务...

oracle 死锁了怎么办?kill 进程 直接上干货

1、查看死锁是否存在selectusername,lockwait,status,machine,programfromv$sessionwheresidin(selectsession...

SpringBoot 各种分页查询方式详解(全网最全)

一、分页查询基础概念与原理1.1什么是分页查询分页查询是指将大量数据分割成多个小块(页)进行展示的技术,它是现代Web应用中必不可少的功能。想象一下你去图书馆找书,如果所有书都堆在一张桌子上,你很难...

《战场兄弟》全事件攻略 一般事件合同事件红装及隐藏职业攻略

《战场兄弟》全事件攻略,一般事件合同事件红装及隐藏职业攻略。《战场兄弟》事件奖励,事件条件。《战场兄弟》是OverhypeStudios制作发行的一款由xcom和桌游为灵感来源,以中世纪、低魔奇幻为...

LoadRunner(loadrunner录制不到脚本)

一、核心组件与工作流程LoadRunner性能测试工具-并发测试-正版软件下载-使用教程-价格-官方代理商的架构围绕三大核心组件构建,形成完整测试闭环:VirtualUserGenerator(...

Redis数据类型介绍(redis 数据类型)

介绍Redis支持五种数据类型:String(字符串),Hash(哈希),List(列表),Set(集合)及Zset(sortedset:有序集合)。1、字符串类型概述1.1、数据类型Redis支持...

RMAN备份监控及优化总结(rman备份原理)

今天主要介绍一下如何对RMAN备份监控及优化,这里就不讲rman备份的一些原理了,仅供参考。一、监控RMAN备份1、确定备份源与备份设备的最大速度从磁盘读的速度和磁带写的带度、备份的速度不可能超出这两...

取消回复欢迎 发表评论: