第8章 对象
Redis并没有直接使用SDS, 链表, 字典等数据结构来实现键值对数据库, 而是基于这些数据结构构建了一个对象系统, 包含字符串对象, 列表对象, 哈希对象, 集合对象和有序集合对象五类.
8.1 对象的类型与编码
每次在Redis中新建一个键值对时, 会至少创建两个对象, 分别用作键(总是字符串对象)和值
8.2 字符串对象
字符串对象的编码可以是int, raw和embstr
如果一个字符串保存的是可以用long表示的整数值, 那么字符串对象会将整数值保存到ptr里面(将void* 转换成long)
如果字符串长度大于32字节, 使用SDS(raw)
如果小于等于32字节, 使用embstr编码. redisObject和sdshdr保存在一块连续内存中.
申请和释放内存时都只用调用一次相关函数(raw需要两次, 分别针对redisObject和sdshdr)
更好地利用缓存带来的优势
embstr没配备修改程序, 因此该类型是只读的, 若要做出修改, 会被转换为raw类型
浮点数会被转换成字符串值进行保存.
字符串对象是Redis五种类型的对象中唯一一种会被其他四种类型对象嵌套的对象.
8.3 列表对象
列表对象可以是压缩列表(ziplist)或者双端链表(linkedlist).
当列表对象可以同时满足以下两个条件时,列表对象使用ziplist编码:
- 列表对象保存的所有字符串元素的长度都小于64字节
- 列表对象保存的元素数量小于512个
- 条件的具体上限值可以在配置文件中修改
8.4 哈希对象
哈希对象的编码可以是ziplist或者hashtable
- 以ziplist作为底层实现的哈希对象, 会依次将键和值加入列表末尾
- 以hashtable编码的哈希对象底层通过字典进行实现, 每个键值对的键和值都是字符串对象
当哈希对象可以同时满足以下两个条件时,哈希对象使用ziplist编码:
- 哈希对象保存的所有键值对的键和值的字符串长度都小于64字节;
- 哈希对象保存的键值对数量小于512个;
8.5 集合对象
集合对象的编码可以是intset或者hashtable
- 使用hashtable编码的集合对象使用字典作为底层实现, 字典的每个键都是一个字符串对象, 表示一个集合元素, 而字典的值呗设置为NULL.
当集合对象可以同时满足以下两个条件时,对象使用intset编码:
- 集合对象保存的所有元素都是整数值
- 集合对象保存的元素数量不超过512个
8.6 有序集合对象
有序集合的编码可以是ziplist或者skiplist
- 使用ziplist作为底层实现时, 每个集合元素使用两个挨在一起的压缩列表来保存, 分别记录元素的成员和分值(score). 元素按分值从小到大排列.
- skiplist编码的有序集合使用zset作为底层实现, 一个zset同时包含一个字典和一个跳跃表. 跳跃表按分值从小到大保存了所有集合元素, 字典则为有序集合创建了一个从成员到分值的映射, 键为成员, 值为分值. (字典和跳跃表会共享元素的成员和分值, 因此不会造成数据重复)
当有序集合对象可以同时满足以下两个条件时,对象使用ziplist编码:
- 有序集合保存的元素数量小于128个
- 有序集合保存的所有元素成员的长度都小于64字节
8.7 类型检查与命令多态
对任意类型的键均可执行的命令: DEL, EXPIRE, RENAME, TYPE, OBJECT等
只能对特定类型的键执行:
字符串键: SET, GET, APPEND, STRLEN等
哈希键: HDEL, HSET, HGET, HLEN等
列表键: RPUSH, LPOP, LINSERT, LLEN等
集合键: SADD, SPOP, SINTER, SCARD等
有序集合键: ZADD, ZCARD, ZRANK, ZSCORE等
在执行一个类型特定的命令前, Redis会进行检测
多态命令的实现
Redis还会根据对象的编码方式, 选择对应的命令实现代码. 无论具体是哪种底层实现, 都会执行命令, 因此称这样的命令是多态的.
8.8 内存回收
Redis为对象系统构建了一个引用计数的内存回收机制.
对象的引用计数信息refcount会随着对象的使用状态而不断变化:
- 在创建一个新对象时,refcount = 1
- 当对象被一个新程序使用时,refcount+1
- 当对象不再被一个程序使用时,refcount-1
- 当refcount == 0时,对象所占用的内存会被释放
8.9 对象共享
对象的引用计数还带有对象共享的作用.
Redis会在初始化服务器时, 创建一万个字符串对象, 涵盖从0-9999的所有整数值, 用作共享对象.
8.10 对象空转时长
redisObject还维护一个lru属性, 表示对象最后一次被命令程序访问的时间.
- 可以通过
OBJECT IDLETIME
打印出来 - 如果服务器打开了maxmemory选项, 并且服务器的回收内存算法为volatile-lru或者allkeys-lru, 那么当占用内存超过上限时, 空转时长较高的那部分键会优先被释放.
- Title: 第8章 对象
- Author: Huan Lee
- Created at : 2023-08-25 19:48:50
- Updated at : 2024-02-26 04:53:15
- Link: https://www.mirthfullee.com/2023/08/25/notion-第8章 对象-d6fbaebc/
- License: This work is licensed under CC BY-NC-SA 4.0.