在前面的笔记中,我们介绍了redis中主要的数据结构:SDS,链表,字典,压缩列表等。但是并没有直接使用这些数据结构来提供键值对,而是通过我们常用的字符串、列表、哈希、集合和有序集合提供服务。
对象类型和编码
每当我们在创建一个新的键值对的时候,我们会创建至少两个对象,一个用于键值对的键,一个用于键值对的值。redis中的对象都有一个redisObject对象。主要包含以下属性:
- type:记录对象的类型,取值为字符串、列表、哈希、集合和有序集合。对于键值对来说,键是一个字符串对象,而值则是上面五个中的任意一个。
- encoding:对象所使用的编码,也就是这个对象的底层是采用什么数据结构实现的
- ptr:底层实现数据结构的指针
- lru:记录对象最后一次被命令访问的时间,可以用于计算其空转时长
对象类型 | 底层实现类型 | 备注 |
字符串 | int,SDS | 浮点值也是采用字符串值来进行保存的。在保存一个浮点值的时候,先将其转换为字符串然后进行存储 |
列表 | 压缩列表或者链表 | 列表对象保存的字符串元素长度小于64,且元素的数量小于512,那么采用压缩列表实现;否则采用链表 |
哈希 | 压缩列表或者哈希表 | 采用压缩列表存储的时候,如果新插入一个键值对,那么先将键插入压缩列表,然后将保存值的节点插入,因此键值两个节点总是挨在一起的。而采用哈希表存储,那么键值对的key和value都是字符串对象。采用压缩列表存储的条件是存储的字符串长度小于64且节点数小于512 |
集合 | 整数集合或者字典 | 使用字典作为底层实现的时候,字典的键为集合的值,但是对应的value是一个空值 |
有序集合 | 压缩列表和跳跃表 | 使用压缩列表的时候,每个集合元素使用两个紧挨在一起的节点存储,第一个存储的是元素成员,第二个存储的是其对应的分值。是按照分值进行从小到大排序的 |
五种对象的使用场景
对象类型 | 应用场景 |
字符串 | 缓存功能:最经典的使用场景,redis作为缓存层,mysql作为存储层,绝大部分请求从redis中获取 计数器:比如视频的点赞数,常用命令incr 共享session |
链表 | 用于模拟队列,栈,比如实现阻塞队列等,生产者利用lupsh从列表左侧插入数据,消费者用brpop获取尾部元素 |
集合 | 标签,去重 |
有序集合 | 排序的集合,比如直播时礼物赠送榜的存储,或者其他需要排名的集合 |
哈希 | 比如用户信息的管理 |
对象的内存回收
通过引用计数来实现内存回收机制。主要通过一个refcount属性统计对象的引用计数,根据这个refcount的值来进行内存的回收。在创建一个对象的时候,计数值就会初始化为1,当被一个新程序使用的时候,引用计数值就会加一,反之则会减一,当引用计数值变为0的时候,会释放所占用的内存。