Bitmap在Redis中的应用(转)

原文:https://cloud.tencent.com/developer/news/387248

作者:一叶而不知秋

作为铺垫,我们先来介绍一些Bitmap的相关内容:

位图主要用于快速检索关键字状态,通常要求关键字是一个连续的序列(或者关键字是一个连续序列中的大部分), 最基本的情况,使用1bit标示一个关键字的状态(可标示两种状态),但根据需要也可以使用2bit(标示4种状态),3bit(标示8种状态)。 位图的主要应用场合:标示连续(或接近连续,即大部分会出现)的关键字序列的状态(状态数/关键字个数 越小越好)。

几种应用场景:

(1)磁盘空闲块的管理

很多文件系统采用bitmap管理磁盘空闲块,如果该块是空闲的,标为0,已使用则标为1; Ext3文件系统中使用位图来管理磁盘空闲块(空闲inode节点)。文件系统创建后,该文件系统拥有的块数以及inode节点数都是确定的,数据块区包含一系列连续的块(块号是连续的),于是可以用位图来标示数据块的分配状态(已分配、未分配两种状态,1bit即可标示)。

如下图,假设ext3的数据块从128开始,一直到1024,则需要1024-128 = 996bit = 128字节的位图空间。如下图,第1bit标示128号块已经被分配,第2bit标示129号块未被分配,依次类推。使用位图的高效性在于:1bit标示状态,节省存储空间,通过关键字来定位位图(偏移是固定的),效率高。

(2)区域服务器路由场景

腾讯的QQ号用一个数字标示,范围从0到20亿,每个QQ号都有可能出现,所有的QQ号被分散的存储北京、上海、深圳、武汉四个城市的服务器中,现在需要一个路由服务器快速的将登陆的QQ路由到正确的服务器,路由服务器可以读取四个QQ服务器的数据,并构建路由表(需全部存在内存中,内存限制1G),路由表该如何存储?

关键:QQ号从0-20亿,每个号码都有可能出现;服务器通过0、1、2、3标示,这四种状态可以用2bit来标示,于是可以考虑使用位图来描述路由表。

解法:从0~20亿,为每个QQ号分配2bit,路由服务器从QQ服务器中获取信息,并设置QQ于服务器号的对应关系。当QQ登录时,路由服务器根据QQ号定位到其对应的状态,并返回对应的服务器号。总的内存大小20亿 * 2 /8 = 5亿字节(约为0.5G)。

(3)大量数据的快速排序、查找、去重

关键:去掉电话号码的800后面就是7位的十进制整数,每个整数都有可能出现而且不会重复出现,可以采用各种排序算法对这些数据进行排序,但时间复杂度都在O(NlogN)及以上。

解法:因每个七位以内的整数都有可能出现,可以用1bit来标示电话号是否出现,遍历整个电话号序列,设置相应的位,遍历位图收集位被设置的号码即可,时间复杂度为O(N);

【去重】场景:2.5亿个整数中找出不重复的整数的个数,内存空间不足以容纳这2.5亿个整数。 关键:一个数字的状态只有三种,分别为不存在,只有一个,有重复。因此,我们只需要2bits就可以对一个数字的状态进行存储了,假设我们设定一个数字不存在为00,存在一次01,存在两次及其以上为11。那我们大概需要存储空间几十兆左右。

解法:遍历一次这2.5亿个数字,如果对应的状态位为00,则将其变为01;如果对应的状态位为01,则将其变为11;如果为11,,对应的状态位保持不变。 最后,我们将状态位为01的进行统计,就得到了不重复的数字个数,时间复杂度为O(n)。

Redis与Bitmap

因为redis的key和value本身就支持二进制的存储方式,所以bitmap只是一个独特的扩展,并不是新的数据类型。他的最大长度就是512M,即2^32个不同字节。

bitmap相关指令介绍:

getbit key offset //获取字符串类型键指定位置的二进制位的值

bitcount key [start] [end] //获取字符串类型键中为1的二进制位个数,start、end是字节的范围

bitpos key value start end //指定区间查询某个key的二进制位中首次出现0或1的位置(start和end是字节位置,不是bit位置)

bitop operation destkey key [key …] //bitop命令可以对多个字符串进行位运算,并将结果存储在destkey参数指定的键中。bitop支持的运算操作有AND、OR、XOP和NOT。

魔术指令 bitfield:

bitfield key [GET type offset] [SET type offset value] [INCRBY type offset increment] [OVERFLOW WRAP|SAT|FAIL] bitfield 有三个子指令,分别是 get/set/incrby,它们都可以对指定位片段进行读写,但是最多只能处理 64 个连续的位,如果超过 64 位,就得使用多个子指令,bitfield 可以一次执行多个子指令。

示例:

应用场景:

(1)用户签到

Bitmap在Redis中的应用(转)

1个用户1年会占用大约:1bit*365/8=45.625字节;

如果使用普通的 key/value,每个用户要记录 365 个,当用户量巨大时,需要的存储空间是惊人的。

(2)用户在线状态

只需要一个key,用户ID为offset,如果在线就设置为1,不在线就设置为0,1000万用户只需要100000000bit/8*=1.2MB的空间;

Bitmap在Redis中的应用(转)

(3)统计活跃用户

使用时间作为cacheKey,然后用户ID为offset,如果当日活跃过就设置为1;

如果想计算某几天的活跃用户呢(暂且约定,统计时间内只要有一天在线就称为活跃);

Bitmap在Redis中的应用(转)

Original: https://www.cnblogs.com/ajianbeyourself/p/15682237.html
Author: 奋斗终生
Title: Bitmap在Redis中的应用(转)

原创文章受到原创版权保护。转载请注明出处:https://www.johngo689.com/528918/

转载文章受原作者版权保护。转载请注明原作者出处!

(0)

大家都在看

  • Apache Shiro反序列化漏洞(Shiro550)

    1.漏洞原理: Shiro 是 Java 的一个安全框架,执行身份验证、授权、密码、会话管理 shiro默认使用了CookieRememberMeManager,其处理cookie…

    Linux 2023年6月13日
    070
  • fork创建进程的步骤___Spring-boot-Starter启动器和其加载的过程___redis怎么监视正在执行的命令

    fork创建进程的步骤 我们都知道,在Linux中调用fork()函数,会创建一个子进程,那么在创建这个子进程的过程中,发生了些什么事情? 首先,我们要知道,fork()函数其实是…

    Linux 2023年5月28日
    0110
  • MAC安装redis

    一、安装命令使用mac的包管理工具brew一行命令搞定安装。若未安装brew,命令行先输入以下命令安装brew。 /usr/bin/ruby -e “$(curl -f…

    Linux 2023年5月28日
    096
  • 四大高阶函数、匿名函数、递归

    四大高阶函数: map、reduce、filter、sorted 1.map函数: 根据提供的函数对指定序列做映射 使用可迭代对象(指定的序列)中的每个元素调用函数,将返回值作为新…

    Linux 2023年6月8日
    0108
  • 【MQTT】在Linux下sqlite3的使用

    安装sqlite3 #下载 wget https: #解压 tar -xzvf sqlite-autoconf-3310100.tar.gz sqlite3库函数 1. 打开/创建…

    Linux 2023年6月13日
    077
  • postgres 切换数据库提示remaining connection slots are reserved for non-replication superuser connections

    场景 使用下面命令在pg终端内,切换数据库时提示 \c db_name pg_user; # pg_user是非超级用户 报错 psql: FATAL: 53300: remain…

    Linux 2023年6月8日
    093
  • 命令大全目录

    linux 本文来自博客园,作者:ivanlee717,转载请注明原文链接:https://www.cnblogs.com/ivanlee717/p/16341641.html O…

    Linux 2023年6月7日
    0133
  • Java基础系列–09_集合2

    昨天介绍了集合的主要架构体系,今天主要的目的是学习集合的迭代器的遍历和List的特有功能。 迭代器:概述: 由于多种集合的数据结构不同,所以存储方式不同,取出方式也不同。但是他们都…

    Linux 2023年6月7日
    075
  • 更改网卡名称

    CentOS7使用了”一致性网络命名方法” 更改配置文件内容 关闭”一致性网络设备命名法” 更新GRUB、内核配置 grub2-mk…

    Linux 2023年6月6日
    087
  • SWAP交换分区扩容

    第一章 扩容当前swap 交换分区 注:这种需要停止当前业务,否则会产生影响 [17:09:31 root@libin3 ~]# free -h total used free s…

    Linux 2023年6月13日
    092
  • JavaScript闭包

    <!doctype html> <html lang="en"> <head> <title>&#x95…

    Linux 2023年6月13日
    076
  • MANIFEST.MF文件对Import-Package/Export-Package重排列

    众所周知,MANIFEST.MF文件中的空格开头的行是相当于拼接在上一行末尾的。很多又长又乱的Import-Package或者Export-Package,有时候想要搜索某个pac…

    Linux 2023年6月13日
    0108
  • 学习一下 JVM (三) — 了解一下 垃圾回收

    一、简单了解几个概念 1、什么是垃圾(Garbage)?什么是垃圾回收(Garbage Collection,简称 GC)? (1)什么是垃圾(Garbage)?这里的垃圾 指的是…

    Linux 2023年6月11日
    0100
  • SQL51 查找字符串中逗号出现的次数

    本题链接本题表结构如下所示。 +—-+————–+ | id | string | +—-+————–+ | 1 | 10,A,B | …

    Linux 2023年6月13日
    093
  • Linux下 lsof 命令详解

    lsof 是 List Open File 的缩写, 它主要用来获取被进程打开文件的信息,我们都知道,在Linux中,一切皆文件,lsof命令可以查看所有已经打开了的文件,比如: …

    Linux 2023年6月13日
    095
  • nacos集群部署

    使用外置数据源-mysql 如果是使用外部数据源,只能是mysql数据库。这样的话需要在mysql数据库里面创建一个数据库,初始化语句在conf目录下,再分配一个可以读写该库的账号…

    Linux 2023年6月8日
    096
亲爱的 Coder【最近整理,可免费获取】👉 最新必读书单  | 👏 面试题下载  | 🌎 免费的AI知识星球