Redis中对象

Redis系列

1. 概念

Redis使用对象表示数据库键和值,每创建一个键值对,至少创建了两个对象,键对象和值对象。每个对象用redisObject表示,该结构中有三个和保存数据有关的属性typeencodingptr

typedef struct redisObject{
	//类型
	unsigned type:4;
	//编码
	unsigned encoding:4;
	//指向底层数据结构的指针
	void *ptr;
	//...
}

2. 类型

type记录了对象的类型,值如下:

对象对象 type 属性的值TYPE 命令的输出
字符串对象REDIS_STRING“string”
列表对象REDIS_LIST“list”
哈希对象REDIS_HASH“hash”
集合对象REDIS_SET“set”
有序集合对象REDIS_ZSET“zset”

对于Redis来说,键总是字符串对象,值可以是上面的任何一种,因此:当成一个数据库键为“字符串键”,指的是这个键对应的值是字符串,以此类推,查看类型命令:type [key]

3. 对象的底层编码

对象所使用的底层数据结构编码常量OBJECT ENCODING 命令输出
整数REDIS_ENCODING_INT“int”
embstr 编码的简单动态字符串(SDS)REDIS_ENCODING_EMBSTR“embstr”
简单动态字符串REDIS_ENCODING_RAW“raw”
字典REDIS_ENCODING_HT“hashtable”
双端链表REDIS_ENCODING_LINKEDLIST“linkedlist”
压缩列表REDIS_ENCODING_ZIPLIST“ziplist”
整数集合REDIS_ENCODING_INTSET“intset”
跳跃表和字典REDIS_ENCODING_SKIPLIST“skiplist”

通过encding设定对象使用的编码,而不是为特定类型的对象关联一种特定的编码,极大提高了Redis灵活性和效率,因为Redis可以根据不同的场景为每一个对象设置不同的编码。举个例子,在列表对象包含元素较少时使用压缩列表作为对象的底层实现,因为:

  1. 压缩列表比双端列表省内存,且在元素较少时,在内存中可以以连续块方式保存压缩列表,可以更快被载入到缓存中
  2. 随着元素增多,压缩列表优势就逐渐消失了,对象底层实现会转向功能更强、更适合保存大量数据的双端列表上

每种类型的对象都至少可以使用两种不同的编码:

对象类型对象编码对象时机
REDIS_STRINGREDIS_ENCODING_INT使用整数值实现的字符串对象。字符串为整数值,如:set number 10086
REDIS_STRINGREDIS_ENCODING_EMBSTR使用 embstr 编码的简单动态字符串实现的字符串对象。字符串,且长度小于39
REDIS_STRINGREDIS_ENCODING_RAW使用简单动态字符串实现的字符串对象。字符串,且长度大于39
REDIS_LISTREDIS_ENCODING_ZIPLIST使用压缩列表实现的列表对象。元素长度小于64字节,且元素数量小于512
REDIS_LISTREDIS_ENCODING_LINKEDLIST使用双端链表实现的列表对象。有元素长度大于64字节,或者元素数量大于512
REDIS_HASHREDIS_ENCODING_ZIPLIST使用压缩列表实现的哈希对象。键和值字符串长度都小于64,且键值对数量小于512
REDIS_HASHREDIS_ENCODING_HT使用字典实现的哈希对象。有键或者值字符串长度大于64,或者键值对数量大于512
REDIS_SETREDIS_ENCODING_INTSET使用整数集合实现的集合对象。所有元素是整数值,且元素不大于512
REDIS_SETREDIS_ENCODING_HT使用字典实现的集合对象。有元素不是整数值,或者有元素不大于512
REDIS_ZSETREDIS_ENCODING_ZIPLIST使用压缩列表实现的有序集合对象。元素数小于128个,且元素长度都小于64字节
REDIS_ZSETREDIS_ENCODING_SKIPLIST使用跳跃表和字典实现的有序集合对象。元素数大于128个,或者有元素长度都大于64字节

3.1 字符串

embstrraw在对象执行命令时效果一样,但是使用前者保存短字符串有以下好处

  1. embstr编码将创建字符串所需内存分配次数从raw两次降为一次,所以释放内存次数也响应减少
  2. embstr编码的字符串都保存在一块连续的内存中,所以能更好的的利用缓存带来的优势

浮点数使用字符串保存的,保存时程序先将浮点数转换为字符串在保存,使用时,程序现将字符串转换为浮点数执行运算后在转换为字符串存起来
Redis没有修改embstr字符串对象的方法,因此对embstr执行修改命令时,辉县将其转换为raw然后执行修改命令,因此embstr执行修改命令后,无论长度多少都会编程raw

4. 类型检查和命令多态

Redis命令可以分为两类:

  1. 可以执行任何类型的键:DELEXPIRERENAMETYPEOBJECT
  2. 针对特定类型的,如:
    1. SETGETAPPENDSTRLEN只针对字符串
    2. HDELHSETHGETHLEN只针对哈希键

4.1 类型检查的实现

通过redisObject的type属性实现的,执行一个特定命令之前,服务器先检查输入数据库键的值是否为执行命令所需的类型,是的话执行,反之返回一个类型错误,如LLEN

Created with Raphaël 2.3.0 客户端发送LLEN<key>命令 服务器检查key的值对象是否为列表对象? 执行 返回一个类型错误 yes no

4.2 多态命令实现

Redis除了会根据值对象判断是否能够执行特定的命令外,还会根据值对象的编码方式,选择正确的命令实现来执行命令。
如:列表对象由ziplistlinkedlist两种编码可用,前者使用压缩列表API实现列表命令,后者使用双端链表API来实现列表命令。
现在如果要对一个键执行LLEN,服务器除了确保执行的是列表键之外,还需要根据值编码选择正确的命令实现:

  1. 如果对象编码是ziplist,说明是压缩列表,程序将使用ziplistLen函数返回列表长度
  2. 如果对象编码是linkedlist,说明是双端列表,程序将使用listLenth函数返回列表长度

借用面向对象术语,可以认为LLEN命令是多态的,只要执行该命令,无论是压缩列表还是双端列表,命令都可以正确执行。
DELEXPIRE区别在于,DELEXPIRE是基于类型的多态,LLEN是基于编码的多态

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值