前往小程序,Get更优阅读体验!
立即前往
首页
学习
活动
专区
工具
TVP
发布
社区首页 >专栏 >Redis源码学习之对象系统

Redis源码学习之对象系统

原创
作者头像
里奥搬砖
发布2018-10-16 19:17:40
4890
发布2018-10-16 19:17:40
举报

在前面的文章中,我介绍了Redis的底层数据结构,但Redis对外提供的命令并没有直接使用它们,而是基于它们构建更高级的数据对象,总共包括5中对象类型,分别为【字符串对象】、【列表对象】、【哈希对象】、【集合对象】和【有序集合对象】,Redis实现对象系统的思想是:每一种对象都使用多种底层数据结构进行实现,具体使用哪种数据结构基于使用场景进行选择,并且可以在触发条件时进行转换。

一.Redis对象结构体

640?wx_fmt=png
640?wx_fmt=png

1.type字段

表示该对象的类型具体枚举值如下图所示:

640?wx_fmt=png
640?wx_fmt=png

Redis对象类型枚举

Redis提供了【type】命令来获取某个对象具体的类型,例如:

127.0.0.1:6379> set a 1

OK

127.0.0.1:6379> type a

string

2.encoding字段

表示该对象是哪种编码,也就是底层使用哪种数据结构进行实现,具体枚举值如下图所示:

640?wx_fmt=png
640?wx_fmt=png

Redis对象编码枚举

Redis提供了【object encoding】命令来获取某个对象的编码,例如:

127.0.0.1:6379> object encoding a

"int"

3.lru字段

保存了该对象最后一次被访问的时间戳,主要用于计算这个对象的idle时长,以便根据idle时长选择是否对其内存进行回收。

Redis提供了【object idletime】命令来获取某个对象的idle时长,例如:

127.0.0.1:6379> object idletime a

(integer) 252

4.refcount字段

表示该对象被引用次数,当某个对象不再被引用时(即refcount=0),它占用的内存将被释放;此外,Redis还会在服务器初始化时创建一系列共享对象,例如值在[0,10000]区间内的整数,会被创建为类型为字符串、编码为整数的共享对象,其refcount字段永远为1,因而常驻在内存中,来避免创建相同对象,浪费内存。

Redis提供了【object refcount】命令来获取某个对象的引用次数,例如:

127.0.0.1:6379> object refcount a

(integer) 4

640?wx_fmt=png
640?wx_fmt=png

Redis共享对象(常用整数)

Redis在三种情况下会修改refcount的值

第一种:对象初始化时设置为1

第二种:对象被某个程序引用时,refcount加1

第三种:对象被某个程序弃用时,refcount减1,且如果减到0则释放其占用的内存

5.ptr字段

指向底层数据结构的指针,保存了数据的真实值。

二.Redis对象的操作

1.创建对象

640?wx_fmt=png
640?wx_fmt=png

其中,对于lru时钟的获取,Redis在3.0版本做了优化。

首先,Redis会有一个专门的线程作为定时事件,不停的刷新系统当前时间,而server.hz就是serverCron运行的频率。所以,在获取lru时钟的时候,会优先根据hz和时钟精度判断是否可以获取系统缓存的时钟值,如果不可以再进行系统调用获取时钟。

此外,Redis还封装了一系列的创建具体类型对象的方法。但实际上,除了嵌入式SDS之外,其他都是调用createObject方法。方法如下:

创建字符串对象

createStringObject(const char *ptr, size_t len)

创建SDS编码的字符串对象

createRawStringObject(const char *ptr, size_t len)

创建嵌入式SDS编码的字符串对象

createEmbeddedStringObject(const char *ptr, size_t len)

根据传入的longlong整型值,创建一个字符串对象

createStringObjectFromLongLong(long long value)

根据传入的long double类型值,创建一个字符串对象

createStringObjectFromLongDouble(long double value, inthumanfriendly)

创建压缩列表编码的列表对象

createZiplistObject(void);

创建集合对象

*createSetObject(void)

创建整型集合编码的集合对象

createIntsetObject(void)

创建哈希对象

createHashObject(void)

创建有序集合对象

createZsetObject(void)

创建压缩列表编码的有序集合对象

createZsetZiplistObject(void)

在后面分析每种对象的文章中我会逐一介绍。

2.释放对象

正如前文所说,Redis根据对象的refcount字段判断是否需要释放当前对象。

640?wx_fmt=png
640?wx_fmt=png

当某个程序弃用该对象时,Redis会对该对象的refcount值进行判断:

如果该值为非正数,则是一次异常调用

如果该值为1,则根据对象类型选择对应方法释放内存

如果该值大于1,则refcount--

而每种类型的释放方法中,又会根据编码去掉用底层数据结构的释放内存方法,以列表对象为例,如果该对象是双端列表实现,则调用双端列表的释放内存方法,否则释放压缩列表的释放内存方法:

640?wx_fmt=png
640?wx_fmt=png

3.计算对象空转时长

Redis基于近似LRU算法,计算某个对象的空转时长。在当前时钟大于等于对象的lru时钟时,说明该对象已经空转一段时间,返回他们的差值即可;而当前时钟小于lru时钟时,则需要将它们的差值(负数)与LRU时钟最大值进行相加再返回。Redis会在需要使用LRU策略清理内存时,从所有key中进行采样,从中淘汰空转时长最长的key。

640?wx_fmt=png
640?wx_fmt=png

4.对象交互命令

前文中提到,Redis针对对象实现了3个命令,分别为获取引用次数命令【object refcount】、获取编码命令【object encoding】和获取空转时长命令【object idletime】。

640?wx_fmt=png
640?wx_fmt=png

三.Redis对象思维导图

640?wx_fmt=png
640?wx_fmt=png

原创声明:本文系作者授权腾讯云开发者社区发表,未经许可,不得转载。

如有侵权,请联系 cloudcommunity@tencent.com 删除。

原创声明:本文系作者授权腾讯云开发者社区发表,未经许可,不得转载。

如有侵权,请联系 cloudcommunity@tencent.com 删除。

评论
登录后参与评论
0 条评论
热度
最新
推荐阅读
相关产品与服务
云数据库 Redis
腾讯云数据库 Redis(TencentDB for Redis)是腾讯云打造的兼容 Redis 协议的缓存和存储服务。丰富的数据结构能帮助您完成不同类型的业务场景开发。支持主从热备,提供自动容灾切换、数据备份、故障迁移、实例监控、在线扩容、数据回档等全套的数据库服务。
领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档