Redis教程

redis-不同业务场景下的统计数据

本文主要是介绍redis-不同业务场景下的统计数据,对大家解决编程问题具有一定的参考价值,需要的程序猿们随着小编来一起学习吧!

1、为什么 String 类型内存开销大?

String 类型具体是怎么保存数据的呢?当你保存 64 位有符号整数时,String 类型会把它保存为一个 8 字节的 Long 类型整数,这种保存方式通常也叫作 int 编码方式。但是,当你保存的数据中包含字符时,String 类型就会用简单动态字符串(Simple Dynamic String,SDS)结构体来保存,如下图所示:

为了节省内存空间,Redis 还对 Long 类型整数和 SDS 的内存布局做了专门的设计。一方面,当保存的是 Long 类型整数时,RedisObject 中的指针就直接赋值为整数数据了,这样就不用额外的指针再指向整数了,节省了指针的空间开销。另一方面,当保存的是字符串数据,并且字符串小于等于 44 字节时,RedisObject 中的元数据、指针和 SDS 是一块连续的内存区域,这样就可以避免内存碎片。这种布局方式也被称为 embstr 编码方式。当然,当字符串大于 44 字节时,SDS 的数据量就开始变多了,Redis 就不再把 SDS 和 RedisObject 布局在一起了,而是会给 SDS 分配独立的空间,并用指针指向 SDS 结构。这种布局方式被称为 raw 编码模式。为了帮助你理解 int、embstr 和 raw 这三种编码模式,如下所示:

Redis 会使用一个全局哈希表保存所有键值对,哈希表的每一项是一个 dictEntry 的结构体,用来指向一个键值对。dictEntry 结构中有三个 8 字节的指针,分别指向 key、value 以及下一个 dictEntry,三个指针共 24 字节,如下图所示

 

 但是,这三个指针只有 24 字节,为什么会占用了 32 字节呢?这就要提到 Redis 使用的内存分配库 jemalloc 了。jemalloc 在分配内存时,会根据我们申请的字节数 N,找一个比 N 大,但是最接近 N 的 2 的幂次数作为分配的空间,这样可以减少频繁分配的次数。

而一个 RedisObject 包含了 8 字节的元数据和一个 8 字节指针,这个指针再进一步指向具体数据类型的实际数据所在

二、用什么数据结构可以节省内存?

压缩列表:表头有三个字段 zlbytes(总字节长度)、zltail (最后一个元素的偏移量)和 zllen(元素的个数),分别表示列表长度、列表尾的偏移量,以及列表中的 entry 个数。压缩列表尾还有一个 zlend,表示列表结束。

三、不同的业务场景采用不同的结构

聚合统计(统计每天的新增用户数和第二天的留存用户数等),利用set集合的差集、并集

排序统计 (排行榜以及统计评论列表中的最新评论等) list(但是不支持分页数据)  sorted set

二值状态 (每日签到,签到统计等) bitmap (基于string)

基数统计(uv统计 需要去重)  hash set(数据量太大消耗内存空间)HyperLogLog (基于string)但是有误差

Set、Sorted Set、Hash、List、Bitmap、HyperLogLog 汇总表

 需要注意的是:

1、如果是在集群模式使用多个key聚合计算的命令,一定要注意,因为这些key可能分布在不同的实例上,多个实例之间是无法做聚合运算的,这样操作可能会直接报错或者得到的结果是错误的!

2、当数据量非常大时,使用这些统计命令,因为复杂度较高,可能会有阻塞Redis的风险,建议把这些统计数据与在线业务数据拆分开,实例单独部署,防止在做统计操作时影响到在线业务。

这篇关于redis-不同业务场景下的统计数据的文章就介绍到这儿,希望我们推荐的文章对大家有所帮助,也希望大家多多支持为之网!