Redis 各个数据类型理解

本贴最后更新于 915 天前,其中的信息可能已经时移世改

1、redis 分 5 大数据类型

String (字符串类型,SDS 结构的,可变长度的字符串)
list (列表)

set (无序,没有重复的集合)
zset(有序)
hash (哈希数据结构)

2、公共 redis 结构体

redis 针对每种数据类型都由 RedisObject 对象

typedef struct redisObject{
     //类型
     unsigned type:4;
     //编码
     unsigned encoding:4;
     //指向底层数据结构的指针
     void *ptr;
     //引用计数
     int refcount;
     //记录最后一次被程序访问的时间
     unsigned lru:22;
 
}robj

redis 中每个基本数据类型都由此公共结构体描述
type 的取值范围:
图片.png

redis 命令行操作,显示 key 的 Type 类型

type key

图片.png

注意:在 Redis 中,键总是一个字符串对象,而值可以是字符串、列表、集合等对象,所以我们通常说的键为字符串键,表示的是这个键对应的值为字符串对象,我们说一个键为集合键时,表示的是这个键对应的值为集合对象。

2.1、encoding 属性和 *prt 指针

prt 指针类似于 C 语言中的指针,指向 Redis 底层真实的数据结构的头地址

而具体是什么数据类型的数据结构,则由 encoding 决定
图片.png

每种类型的数据结构都至少使用了 2 种编码,编码方式清单如下:
图片.png

查看 Value 使用的编码,命令如下

OBJECT ENCODING    key

图片.png

比如 String 类型的数据结构,可以由 int、embstr 或者 Raw 编码方式实现

3、String 类型

字符串类型是很常用的类型 。所有 key-value 对的 Key 是 string 类型,字符串类型长度不超过 512MB。
字符串类型的三种编码格式

  • int :使用字符串类型存储数字类型,比如 put intkey 8876

  • raw:保存长字符串,长度大于 44 字节的字符串(redis3.2 版本之前是 39 字节,之后是 44 字节)

  • embstr:保存不超过 44 字节的字符串(redis3.2 版本之前是 39 字节,之后是 44 字节)

    int 编码是用来保存整数值,而 raw 和 embstr 用来存储字符串(长度大小不同使用不同编码方式)。
    raw 和 embstr 的存储区别:
    图片.png
    embstr 编码方式,存放的 RedisObject 头信息和一定长度的后缀(Sds 实现)是一次性申请内存空间的。因此 raw 查找快(因为直接可以在 Redisobject 后通过偏移量获取),但是 eMbstr 的字符串如果需要变长了,则需要重新申请并分配 RedisObject 头节点空间和 sds 空间,因此,Embstr 设置为只读的。

    而 raw 不一样,他的 RedisObject 头信息节点和后面的 sds 实现的字符串是分 2 次申请内存空间的,申请内存空间代价相比 embstr 高,而且后面节点也需要头信息,因此存储效率略微低些。但是存储字符串长度,是最大 512MB

  • 注意
    如果 Redis 的字符串采用的 Int 编码存储的数据的大小超过 Long 的最大值,则 Redis 的字符串类型编码自动变成 Raw。
    对于 embstr 编码,由于 Redis 没有对其编写任何的修改程序(embstr 是只读的),在对 embstr 对象进行修改时,都会先转化为 raw 再进行修改,因此,只要是修改 embstr 对象,修改后的对象一定是 raw 的,无论是否达到了 44 个字节。

4、List 数据类型

list 存储简单的字符串对象,其实是一个队列,可以在队列头和队列尾分别插入数据。底层是 用链表实现的队列。

4.1、List 编码格式

4.1.1、Ziplist 编码格式

即同时满足如下条件时,使用 zipList 编码方式存储 List:

  • 队列元素个数小于 512 个
  • 每个队列元素数据大小,小于 64 字节
  • 图片.png

4.1.2、linkedlist 编码格式

不同时都满足上述 2 个条件数据,即采用 Linkedlist 存储,结构如下:
图片.png
上面两个条件可以在 redis.conf 配置文件中的 list-max-ziplist-value 选项和 list-max-ziplist-entries 选项进行配置。

5、哈希数据结构

hashs 数据结构,key 是字符串,Value 可能是一个键值对集合
底层编码方式:

5.1、Ziplist 编码格式

为了节省空间,Ziplist 把加入进去的键值对,每次都往列表的尾部插入
图片.png

5.2、Hashtable 编码格式

图片.png

底层采用数据字典方式,通过 hash 算法,计算 Key 在 hash 字典表中的位置,然后通过引用,找到 Value 对象:

在前面介绍压缩列表时,我们介绍过压缩列表是 Redis 为了节省内存而开发的,是由一系列特殊编码的连续内存块组成的顺序型数据结构,相对于字典数据结构,压缩列表用于元素个数少、元素长度小的场景。其优势在于集中存储,节省空间。

5.3、hash 数据结构 的 底层编码转换 规则

同时满足下面 2 个条件

  • 列表中元素个数小于 512
  • 列表中每个元素占用空间大小,都小于 64 字节
    Redis 自动将 Ziplist 转为 Hashtable 存储

6、集合数据结构

7、有序集合数据结构

8、Redis 各个数据结构的应用场景

string 存储字符串,数字类型自加,计数等。基于 Sds 机制实现,是二进制安全的(二进制安全参考 https://www.zhihu.com/question/28705562),可以存放视频,音频,图片等

list 当作简单消息队列使用;使用 lrange 实现分页查询

hash 用来存储用户登陆 session 数据,做单点登陆功能的后端实现

set 无序,不重复集合,用来去重

Zset 有序集合,用来排序,排行榜,使用 TOP N 命令操作

9、Redis 的内存回收和共享

Redis 内存回收策略:
1)volatile-lru 利用 LRU 算法移除设置过过期时间的 key (LRU:最近使用 Least Recently Used )
2)allkeys-lru 利用 LRU 算法移除任何 key
3)volatile-random 移除设置过过期时间的随机 key
4)allkeys-random 移除随机 key
5)volatile-ttl 移除即将过期的 key(minor TTL)
6)noeviction noeviction 不移除任何 key,只是返回一个写错误 ,默认为此选项

10、对象的空转时长

见 redisObject 对象:

typedef struct redisObject{
     //类型
     unsigned type:4;
     //编码
     unsigned encoding:4;
     //指向底层数据结构的指针
     void *ptr;
     //引用计数
     int refcount;
     //记录最后一次被程序访问的时间
     unsigned lru:22;
 
}robj

最后一个属性:lru
该属性记录了对象最后一次被命令程序访问的时间。
使用命令 OBJECT IDLETIME key 查询 Key 的 lru
图片.png
如果内存回收算法使用的是:
 
1)volatile-lru 利用 LRU 算法移除设置过过期时间的 key (LRU:最近使用 Least Recently Used )

2)allkeys-lru 利用 LRU 算法移除任何 key
则有使用到 lru 属性支撑算法。

  • Redis

    Redis 是一个开源的使用 ANSI C 语言编写、支持网络、可基于内存亦可持久化的日志型、Key-Value 数据库,并提供多种语言的 API。从 2010 年 3 月 15 日起,Redis 的开发工作由 VMware 主持。从 2013 年 5 月开始,Redis 的开发由 Pivotal 赞助。

    284 引用 • 248 回帖 • 124 关注

相关帖子

欢迎来到这里!

我们正在构建一个小众社区,大家在这里相互信任,以平等 • 自由 • 奔放的价值观进行分享交流。最终,希望大家能够找到与自己志同道合的伙伴,共同成长。

注册 关于
请输入回帖内容 ...