《Redis设计与实现》读书笔记(十) ——Redis对象相关其他设计与实现

《Redis设计与实现》读书笔记(十) ——Redis对象相关其他设计与实现

(原创内容,转载请注明来源,谢谢)

一、类型检查与命令多态

redis对键操作的命令分为两种,一种是可以对任意键进行操作的命令,如del、expire、rename、type、object等;另一种是只能对特定类型的键进行操作,redis的五种数据类型都有各自特定的键操作命令。

1、类型检查

redis的类型检查,是通过检查redisObject结构的type属性进行的。在执行一个特定命令之前,redis会先检查键对应的值对象的type属性,是否可以执行所需的命令:如果可以执行则执行;否则服务器将拒绝执行,并返回一个类型错误。

2、命令多态

redis每种数据类型,至少都有两种编码方式,命令多态就是指通过一个命令,可以执行不同的编码方式所提供的api。因此,redis的几乎每种操作命令都是多态的。对于同一个类型,操作不同的编码方式,称为基于编码的多态。

另外,还有上述提到的del、expire等,对于任意类型都可以操作,也是多态。这个是基于类型的多态。

二、内存回收

由于实现redis的C语言,不具备垃圾回收功能,因此redis构建了一套内存回收机制,是基于引用计数技术实现的内存回收。通过这一机制,程序可以通过追踪对象的引用计数信息,在适当的时候自动释放对象,并进行内存回收。

引用计数信息是redisObject结构中的refcount属性进行记录。

typedef structredisObject{
int refcount;
}robj;

上面的结构中省略结构中的其他信息。对象引用计数的信息,会随着对象使用状态的变化而改变,如下:

1)创建一个新对象时,refcount值是1。

2)对象被一个新程序使用,refcount值加1。

3)对象不再被某个程序使用,refcount值减1。

4)对象引用计数变成0时,对象所占的内存会被释放。

修改引用计数的api如下:

在对象的整个生命周期,可以分为创建对象、操作对象、释放对象。

三、对象共享

对象的引用计数属性,除了用于内存回收,还可以用于对象的共享。当多个键保存同一个值的时候,且值是整数类型的字符串对象时,redis会使用对象共享,让键指向同一个值。过程如下:

1)将数据库键的值指针指向一个现有的值对象。

2)将被共享的值对象的引用计数增1。

两个对象公用一个值的情况如下图:

对象共享机制对于节约内存有很大的帮助。redis初始化服务器的时候,会创建一万个字符串对象,是从0~9999的整数值,当服务器要用到这些值的时候,会使用共享对象。

共享对象的默认数量,可以通过修改文件redis.h中的常量REDIS_SHARED_INTEGERS进行修改。

因此,当如果创建了两个对象,值都是100,实际上就有三个对象引用,包括两个客户端创建的,和一个服务端持有的,如下图:

除了单独的字符串对象类型,在其他对象类型中,嵌套的字符串对象,也是会共享的。

另外,redis只共享整数类型的字符串对象,不共享字符串类型的字符串对象,是因为共享的对象如果是字符串,则比较字符串是否相同的过程比较耗时;同理,不把字符串对象以外的其他四种对象共享,也是为了避免对比带来的耗时。

四、对象空转时长

redisObject的最后一个属性——lru属性,是用于记录对象的最后一次被访问的时间。

typedef structredisObject{
unsigned lru:22;
}robj;

object idletime命令,可以打印出给定键的空转时长,这一时长是通过当前时间减去lru属性的值确定的。同时,该命令也具有特殊性。其他命令操作键,都会修改键的lru,而object idletime命令仅仅通过查询键的lru计算空转时长,并不修改lru。

如果配置中开启了maxmemory,并且服务器的回收算法设置为volatile-lru或者allkeys-lru,当服务器的内存超过了maxmemory所设定的上限,空转时长较高的键会被优先释放,从而回收内存。

五、redis对象总结

1、redis数据库的每个键和值都是一个redisObject对象。

2、redis有字符串、哈希、列表、集合、有序集合五种对象类型,每种对象类型至少2中编码方式(其中字符串对象有3中编码方式),不同的编码方式在不同的场景中具有高效的特定。

3、服务器执行某些命令之前,会先进行类型检查,对键进行类型检查,是检查键对应的值的类型。

4、redis具有对象的引用回收机制,当对象没有被使用,内存将被回收。

5、redis会共享0~9999共1万个整数值的字符串对象,这个数目可以通过配置文件修改。

6、redis会记录对象的最后访问时间,可以用来计算对象的空转时间。

——written by linhxx 2017.09.02

原文发布于微信公众号 - 决胜机器学习(phpthinker)

原文发表时间:2017-09-02

本文参与腾讯云自媒体分享计划,欢迎正在阅读的你也加入,一起分享。

发表于

我来说两句

0 条评论
登录 后参与评论

相关文章

来自专栏有趣的django

SQLAlchemy SQLAlchemy

1400
来自专栏IT杂记

INET_ATON()函数在MySQL5.6版本和5.7版本的差异

问题 ### The error occurred while setting parameters ### SQL: insert into t_gatewa...

1819
来自专栏水击三千

SQL语言学习-数据操纵语言

一般而言,数据库中数据的生命周期包括数据插入以及更新、数据删除3个阶段。首先需要用户或者系统将数据插入表。然后,对数据的使用,包括数据的检索以及数据的更新。最后...

28010
来自专栏java学习

java每日一练(2017/8/11)

(单选题) 1、关于下面的程序Test.java说法正确的是( )。 publicclass Test { staticString x="1"; sta...

2636
来自专栏aCloudDeveloper

C++基础题

刚在网上转看到几道对于巩固基础很有帮助的C++基础题,反正闲着也是闲着,就做了下,具体题型如下: 答案是我自己写,不一定对,如果有朋友看到不对的,欢迎指正,万分...

1885
来自专栏机器学习算法与Python学习

Python的22个编程技巧,Pick一下?

Python 提供了一个直观的在一行代码中赋值与交换(变量值)的方法,请参见下面的示例:

703
来自专栏Java技术分享

Redis常用命令整理

        *    匹配任意个(包括0个)字符

2059
来自专栏应兆康的专栏

Python Web - Flask笔记5

MySQL Workbench是一款专为MySQL设计的ER/数据库建模工具。它是著名的数据库设计工具DBDesigner4的继任者。你可以用MySQL Wor...

881
来自专栏数据存储

MySQL中用快速为select结果加序号

set @a=0;select @a:=@a+1,user,host from mysql.user;

1885
来自专栏码字搬砖

hive动态分区

hive分区可以方便快速定位,查找( 设置分区,可以直接定位到hdfs上相应的文件目录下,避免全表扫描)。 hive分区可以分为静态分区、动态分区,另外静动...

1183

扫码关注云+社区