当前位置: 首页 > 后端技术 > Java

这样10亿数据量只需要100MB的内存

时间:2023-04-01 15:13:31 Java

下面我给大家送上java学习资料。本文主要和大家分享redis的高级特性:位操作。本文中的redis测试代码基于以下环境:操作系统:MacOS64位版本:Redis5.0.764位运行方式:standalonemoderedis位操作reids位操作也叫位数组操作,位图,它提供了SETBIT、GETBIT、BITCOUNT、BITTOP四种命令,用于操作二进制位数组。先来看一波基本操作示例:SETBIT语法:SETBITkeyoffsetvalue即:commandkeyoffset0/1setbit命令用于写入位数组指定偏移量的二进制位设置值,偏移量开始从0开始计数,只允许写入1或0。如果写入了0和1以外的值,写入会失败:GETBIT语法:GETBITkeyoffset即:commandkeyoffsetgitbit命令用于获取位数组的指定偏移量二进制值:BITCOUNT语法:BITCOUNTkey即:commandkeybitcount命令用于获取指定key的位数组中值为1的二进制位数。我们把offset0的值写成1,offset10的值写成值为1,offset8的值为0:BITOP语法:BITOPoperationdestkeykey[key…]即:命令操作结果目标keykey1key2...bitop命令可以对多个位数组的键进行与(按位与),或(按位或),异或(按位异或)运算,并将运算结果设置为destkey:解析底层数据结构===========SDS是redis中的一种数据结构,称为简单动态字符串(SimpleDynamicString),是二进制安全的。在大多数情况下,redis中的字符串是用SDS存储的。SDS的数据结构:`structsdshdr{``#记录buff数组中使用的字节数``#也是存储在SDS中的字符串的长度``intlen;`#记录未使用的字节数buff数组中的数量``intfree;``#字节数组,字符串存储在这个数组``charbuff\[\];``}`数据存储示例:SDS的优点:时间复杂度为O(1)消除缓冲区溢出并减少修改字符串长度时所需的内存重新分配次数。二进制安全API操作与某些C字符串函数兼容。redis中的位数组存储的是String字符串数据格式,而string对象使用的是上面提到的SDS简单动态字符串数据结构。大家都知道一个字节是用8个二进制位存储的,也就是8个0或者1,也就是一个字节可以存储0到127的十进制数,也就是包括了所有的数字和英文大小写的字母和标点符号.1Byte=8bit1KB=1024Byte1MB=1024KB1GB=1024MB位数组在redis存储世界中,每个字节也是8位,初始为:`00000000`位运算在对应的偏移处在offset上设置0或1,比如第三位设置为1,即:`00001000``#对应redis操作:``setbitkey31`在此基础上,如果要在13的偏移量处设置1,即:`setbitkey131``#在redis中对应的存储是:``0010|0000|0000|1000`时间复杂度GETBIT命令时间复杂度O(1)STEBIT命令时间复杂度O(1)BITCOUNT命令时间复杂度O(n)BITOP命令时间复杂度O(n),O(n2)让我们看看GETBIT以及为什么是SETBIT命令的时间复杂度O(1)。当我们执行一个SETBITkey100861的值时,reids的计算方法如下:得到要写入bit数组的哪个字节:10086÷8=1260,需要写入该bit的下标1260的字节array得到要写入的字节数:10086mod8=6,该字节需要写入的下标为6,即第7位。通过这两种计算方式,可以清楚的看出位操作的GETBIT和SETBIT是常量计算,所以它的时间复杂度是O(1)。BITCOUNT命令需要遍历整个bit数组的所有元素,计算出有多少个值为1。当然,对于大数据位,redis会有一整套复杂的执行bitcount命令的优化算法,但是核心想法还是一样的。就是减少部分遍历查询的次数。比如用128位作为遍历,那么遍历的次数就是所有的数字除以128。BITTOP命令根据不同的操作有不同的执行方式。比如在AND运算中,需要校验1的位值。存储空间的计算根据上面的介绍,相信大家已经知道如何根据位数组数据结构来计算存储数据的内存大小了雷迪斯。比如有100亿条数据,那么它需要的字节数组为:1000000000÷8÷1024÷1024≈119.21MB,也就是说,存储10亿条数据只需要大约119MB的内存空间,这对于目前16G和32G集群版本的redis,一点问题都没有。需要注意的是,如果你的数据量不大,那么起始偏移量就不要设置的太大,同样会占用空间。比如我们只需要存储几百条数据,但是offset是非常大的,这样会造成内存空间的大量浪费。应用场景在实际项目开发中,有很多业务适合使用redisbits来实现。用户签到场景,以每日日期字符串为key,以用户id为偏移量统计每日用户签到情况、用户签到总数、活跃人数用户,以及用户日活、月活、留存率等统计数据可以存储在redis位数组中,仍然以每天的日期为key,当用户活跃时,写入offset作为用户标识的位值1。月活也是如此。用户是否在线和在线用户总数也是用一个位数组,用户id映射偏移量,在线标志为1,离线标志为0。可以实现用户在线和离线的查询和在线用户总数的统计。用户在app中的全局消息提示为小红点。现在大部分APP都有站内信的功能。当有消息时,会提示一个小红点,表示用户有新消息。来源:今日头条/i6767642839267410445