这么设计,Redis 10亿数据量只需要100MB内存
本文主要和大家分享一下redis的高级特性:bit位操作。
本文redis试验代码基于如下环境:
操作系统:Mac OS 64位 版本:Redis 5.0.7 64 bit 运行模式:standalone mode
redis位操作
reids位操作也叫位数组操作、bitmap,它提供了SETBIT、GETBIT、BITCOUNT、BITTOP四个命令用于操作二进制位数组。
先来看一波基本操作示例:
SETBIT
语法:SETBIT key offset value
即:命令 key 偏移量 0/1
setbit命令用于写入位数组指定偏移量的二进制位设置值,偏移量从0开始计数,且只允许写入1或者0,如果写入非0和1的值则写入失败:
GETBIT
语法:GETBIT key offset
即:命令 key 偏移量
gitbit命令用于获取位数组指定偏移量上的二进制值:
BITCOUNT
语法:BITCOUNT key
即:命令 key
bitcount命令用于获取指定key的位数组中值为1的二进制位的数量,之前我们写入了偏移量0的值为1,偏移量10 的值为1,偏移量8的值为0:
BITOP
语法:BITOP operation destkey key [key…]
即:命令 操作 结果目标key key1 key2 …
bitop命令可以对多个位数组的key进行and(按位与)、or(按位或)、xor(按位异或)运算,并将运算结果设置到destkey中:
底层数据结构分析
SDS是redis中的一种数据结构,叫做简单动态字符串(Simple Dynamic String),并且它是一种二进制安全的,在大多数的情况下redis中的字符串都用SDS来存储。
SDS的数据结构:
struct sdshdr {
#记录buff数组中已使用字节的数量
#也是SDS所保存字符串的长度
int len;
#记录buff数组中未使用字节的数量
int free;
#字节数组,字符串就存储在这个数组里
char buff\[\];
}
数据存储示例:
SDS的优点:
- 时间复杂度为O(1)
- 杜绝缓冲区溢出
- 减少修改字符串长度时候所需的内存重分配次数
- 二进制安全的API操作
- 兼容部分C字符串函数
redis中的位数组采用的是String字符串数据格式来存储,而字符串对象使用的正是上文说的SDS简单动态字符串数据结构。
大家都知道的是一个字节用的是8个二进制位来存储的,也就是8个0或者1,即一个字节可以存储十进制0~127的数字,也即包含了所有的数字、英文大小写字母以及标点符号。
1Byte=8bit 1KB=1024Byte 1MB=1024KB 1GB=1024MB
位数组在redis存储世界里,每一个字节也是8位,初始都是:
0 0 0 0 0 0 0 0
而位操作就是在对应的offset偏移量上设置0或者1,比如将第3位设置为1,即:
0 0 0 0 1 0 0 0
#对应redis操作即:
setbit key 3 1
在此基础上,如果要在偏移量为13的位置设置1,即:
setbit key 13 1
#对应redis中的存储为:
0 0 1 0 | 0 0 0 0 | 0 0 0 0 | 1 0 0 0
时间复杂度
GETBIT命令时间复杂度O(1)
STEBIT命令时间复杂度O(1)
BITCOUNT命令时间复杂度O(n)
BITOP命令时间复杂度O(n)、O(n2)
我们来看GETBIT以及SETBIT命令的时间复杂度为什么是O(1),当我们执行一个SETBIT key 10086 1的值的时候,reids的计算方式如下:
获取到要写入位数组中的哪个字节:10086÷8=1260,需要写入到位数组的下标1260的字节
获取要写入到这个字节的第几位:10086 mod 8 = 6,需要写入到这个字节的下标为6即第7位上去。
通过这两种计算方式大家可以清晰的看到,位操作的GETBIT和SETBIT都是常量计算,因此它的时间复杂度为O(1)。
而BITCOUNT命令需要对整个位数组的所有元素进行遍历算出值为1的有多少个,当然redis对于大数据了的bit执行bitcount命令会有一整套复杂的优化的算法,但是核心思路还是这个意思,无非是减少部分遍历查询次数。比如以128位为一次遍历,那么他的遍历次数就是所有的位数除以128。
BITTOP命令则是根据不同的操作有不同的执行方式。比如AND操作,则需要查看位值为1的即可。
存储空间计算
根据上面的介绍,相信大家已经知道了基于redis的位数组数据结构存储的数据占用内存大小是怎么计算的了。比如有100亿的数据,那么它需要的字节数组:
1000000000÷8÷1024÷1024≈119.21MB
也就是存储10亿的数据只需要119MB左右的内存空间,这对于现在动辄16G、32G集群版的redis,完全没有问题。
需要注意的是,如果你的数据量不大,那就不要把起始偏移量搞的很大,这样也是占空间的,比如我们只需要存储几百条数据,但是其中的偏移量却很大,这就会造成了很大的内存空间浪费。
应用场景
实际项目开发中有很多业务都适合采用redis的bit来实现。
用户签到场景
每天的日期字符串作为一个key,用户Id作为offset,统计每天用户的签到情况,总的用户签到数
活跃用户数统计
用户日活、月活、留存率等均可以用redis位数组来存储,还是以每天的日期作为key,用户活跃了就写入offset为用户id的位值1。
同理月活也是如此。
用户是否在线以及总在线人数统计
同样是使用一个位数组,用户的id映射偏移量,在线标识为1,下线标识为0。即可实现用户上下线查询和总在线人数的统计
APP内用户的全局消息提示小红点
现在大多数的APP里都有站内信的功能,当有消息的时候,则提示一个小红点,代表用户有新的消息。
这么设计,Redis 10亿数据量只需要100MB内存的更多相关文章
- 面试题 :10亿url去重只给4G内存
我能想到的有以下几种: 用语言判断去重,ex表格去重,数据库去重,文件名字去重, 有人说:10亿url ex表放不下!! 可以用树和折半的思想将10亿url,变成单元最小化的树,然后用ex表去重 ex ...
- Redis基本使用及百亿数据量中的使用技巧分享(附视频地址及观看指南)
作者:依乐祝 原文地址:https://www.cnblogs.com/yilezhu/p/9941208.html 主讲人:大石头 时间:2018-11-10 晚上20:00 地点:钉钉群(组织代码 ...
- [翻译] C# 8.0 新特性 Redis基本使用及百亿数据量中的使用技巧分享(附视频地址及观看指南) 【由浅至深】redis 实现发布订阅的几种方式 .NET Core开发者的福音之玩转Redis的又一傻瓜式神器推荐
[翻译] C# 8.0 新特性 2018-11-13 17:04 by Rwing, 1179 阅读, 24 评论, 收藏, 编辑 原文: Building C# 8.0[译注:原文主标题如此,但内容 ...
- 从SQL Server到MySQL,近百亿数据量迁移实战
从SQL Server到MySQL,近百亿数据量迁移实战 狄敬超(3D) 2018-05-29 10:52:48 212 沪江成立于 2001 年,作为较早期的教育学习网站,当时技术选型范围并不大:J ...
- 掌握这些 Redis 技巧,百亿数据量不在话下!
一.Redis封装架构讲解 实际上NewLife.Redis是一个完整的Redis协议功能的实现,但是Redis的核心功能并没有在这里面,而是在NewLife.Core里面. 这里可以打开看一下,Ne ...
- Oracle普通表->分区表转换(9亿数据量)
背景介绍: 环境:Linux 5.5 + Oracle 10.2.0.4 某普通表T,由于前期设计不当没有分区,如今几年来的数据量已达9亿+, 空间占用大约350G,在线重定义为分区表不现实,故采取申 ...
- 怎么对10亿数据量级的mongoDB作高效的全表扫描
转自:http://quentinxxz.iteye.com/blog/2149440 一.正常情况下,不应该有这种需求 首先,大家应该有个概念,标题中的这个问题,在大多情况下是一个伪命题,不应该被提 ...
- R语言操作mysql上亿数据量(ff包ffbase包和ETLUtils包)
平时都是几百万的数据量,这段时间公司中了个大标,有上亿的数据量. 现在情况是数据已经在数据库里面了,需要用R分析,但是完全加载不进来内存. 面对现在这种情况,R提供了ff, ffbase , ETLU ...
- POI3.8解决导出大数据量excel文件时内存溢出的问题
POI3.8的SXSSF包是XSSF的一个扩展版本,支持流处理,在生成大数据量的电子表格且堆空间有限时使用.SXSSF通过限制内存中可访问的记录行数来实现其低内存利用,当达到限定值时,新一行数据的加入 ...
随机推荐
- 浅析 MVC
MVC(Model–View–Controller) Model:数据模型 负责操作所有数据View:视图 负责所有UI界面Controller:控制器 负责其他 //数据放在m const m = ...
- MySQL进阶之MySQL索引以及索引优化
本文配合B站学习视频BV1es411u7we使用效果更佳. 1. MySQL版本 主流版本:5.x版 5.0 - 5.1:早期产品的延续,升级维护 5.4 - 5.x:MySQL整合了三方公司的新存储 ...
- 力扣Leetcode 98. 验证二叉搜索树
验证二叉搜索树 给定一个二叉树,判断其是否是一个有效的二叉搜索树. 假设一个二叉搜索树具有如下特征: 节点的左子树只包含小于当前节点的数. 节点的右子树只包含大于当前节点的数. 所有左子树和右子树自身 ...
- javaScript 推荐书籍 由简单到入门,初级到高级。
- Docker 搭建 Redis Cluster 集群环境
使用 Docker 搭建 Redis Cluster,最重要的环节就是容器通信的问题,这一块我们在之前的文章中已经给大家解决了<Docker 网络模式详解及容器间网络通信>,本篇文章主要练 ...
- 【IDEA】【SpringBoot】基于idea对springboot程序远程调试
一.开启远程调试前提:本地代码与服务器代码一致(实测:不关键的代码稍微有点不一样好像也不会有多大问题). 二.开启远程调试步骤 1.开发工具配置 idea端打开Edit configurations, ...
- BootStrap-select插件动态添加option无法显示
问题描述: 在使用bootstrap-select插件时出现下拉框无法显示动态追加的option,经过查看element元素发现,select标签已经append进去了所需的option选项,但是页面 ...
- Zookeeper源码解读
1.1. 客户端源码 1.1.1. 总体流程 启动客户端 zkCli.sh文件里面的配置 实际运行 public static void main(String args[]) throws Keep ...
- Eclipse插件打开编辑器
今天终于可以闲一天,想来想去就乱写点东西吧,说不定对有些新人有点帮助呢-_- 用Eclipse API的方式来打开编辑器,可能对任何一个插件开发者都不是很陌生的操作了.但是,还是建议你忍着看一下,全当 ...
- HTML模仿实现京东登录页面
<!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8&quo ...