RedisObject
RedisObject 的结构:
typedef struct redisObject {
    //类型
    unsigned type:4;
    // 编码
    unsigned encoding:4;
    // 指向数据结构的指针
    void *ptr;
    // 高 16 位用来记录访问时间,用于 LRU
    // 低 8 位用来记录访问频率,用于 LFU
    unsigned lru:24;
    // 引用计数
    int refcount;
    // 数据指针
    void *ptr;
    // ...
} robj;
对象的类型
type 属性指定类型:
-------------------------------------------
    类型常量   |  对象的名称  | 调用 type 命令
-------------------------------------------
 REDIS_STRING |  字符串对象  |  "string"
 REDIS_LIST   |  列表对象    |  "list"
 REDIS_HASH   |  哈希对象    |  "hash"
 REDIS_SET    |  集合对象    |  "set"
 REDIS_ZSET   |  有序集合对象 |  "zset"
编码和底层实现
encoding 属性指定编码:
--------------------------------------------------------------------------------------
    类型常量   |             编码常量         |          数据结构        | object encoding
--------------------------------------------------------------------------------------
 REDIS_STRING |  REDIS_ENCODING_INT        |      long 类型的整数      |   "int"
 REDIS_STRING |  REDIS_ENCODING_EMBSTR     | embstr 编码的简单动态字符串 |   "embstr"
 REDIS_STRING |  REDIS_ENCODING_RAW        |       简单动态字符串       |   "raw"
 REDIS_LIST   |  REDIS_ENCODING_ZIPLIST    |          压缩列表         |   "ziplist"   [version 3.2 之前] 
 REDIS_LIST   |  REDIS_ENCODING_LINKEDLIST |          双端列表         |   "linkedlist"[version 3.2 之前] 
 REDIS_LIST   |  REDIS_ENCODING_QUICKLIST  |          快速列表         |   "quicklist" [version 3.2 之后]
 REDIS_HASH   |  REDIS_ENCODING_ZIPLIST    |          压缩列表         |   "ziplist"
 REDIS_HASH   |  REDIS_ENCODING_HT         |            字典          |   "hashtable"
 REDIS_SET    |  REDIS_ENCODING_INTSET     |          整数集合         |   "intset"
 REDIS_SET    |  REDIS_ENCODING_HT         |            字典          |   "hashtable"
 REDIS_ZSET   |  REDIS_ENCODING_ZIPLIST    |          压缩列表         |   "ziplist"
 REDIS_ZSET   |  REDIS_ENCODING_SKIPLIST   |           跳跃表          |   "skiplist"
RedisObject 的优势
- 在执行命令之前,根据对象的类型即可判断一个对象是否可以执行给定的命令
 - 在不同场景采用不同数据结构实现,优化对象在不同场景下的使用效率
 - 基于引用计数技术的内存回收机制和对象共享机制
 - 记录访问时间,计算键的空转时间,如果服务器打开了 
maxmemory选项,并且服务器用于回收内存的算法为volatile-lru或者allkeys-lru,那么当服务器占用的内存数超过了maxmemory选项所设置的上限值时,空转时长较高的那部分键会优先被服务器释放,从而回收内存 
字符串对象
- int
 
8 个字节的长整数
- embstr
 
<=39 字节的字符串
- raw
 
>39 字节的字符串
embstr 与 raw 的区别:
- 创建和释放内存时,
raw需要调用两次函数,而embstr只需要调用一次函数 embstr编码的字符串对象的所有数据都保存在一块连续的内存里面,能够更好的利用缓存的优势- 当字符串的长度增加需要重新分配内存时,
embstr整体重新分配空间,所以embstr实现为只读 
列表对象
- 压缩列表
    
- 列表对象保存的所有字符串元素的长度都小于 64 字节
 - 列表对象保存的元素数量小于 512 个
 
 
- 双端列表
 
不满足条件的列表对象采用双端列表
        **注意:在 Redis 3.2 之后,列表对象的数据结构采用 quicklist**
quicklist 是一个节点为压缩列表的双端列表,设计的原因:
- 双端列表的优缺点
 
优点:操作方便
缺点:存储前后指针,内存开销较大,且地址不联系,容易产生碎片
- 压缩列表的优缺点:
 
优点:整块连续内存,存储效率高
缺点:操作不方便,每次数据变动都会引发内存的分配和数据拷贝
结合双端列表和压缩列表的 quicklist 就产生了,随之也引发了新问题:
压缩列表的长度
长度过短,退化为双端列表
长度过长,退化为压缩列表
redis 提供了可进行配置的参数:
# Lists are also encoded in a special way to save a lot of space.
# The number of entries allowed per internal list node can be specified
# as a fixed maximum size or a maximum number of elements.
# For a fixed maximum size, use -5 through -1, meaning:
# -5: max size: 64 Kb  <-- not recommended for normal workloads
# -4: max size: 32 Kb  <-- not recommended
# -3: max size: 16 Kb  <-- probably not recommended
# -2: max size: 8 Kb   <-- good
# -1: max size: 4 Kb   <-- good
# Positive numbers mean store up to _exactly_ that number of elements
# per list node.
# The highest performing option is usually -2 (8 Kb size) or -1 (4 Kb size),
# but if your use case is unique, adjust the settings as necessary.
list-max-ziplist-size -2
当列表很长,两端的数据被高频访问,中间的数据被低频访问的场景
redis 提供了可进行配置的参数,可以将中间的数据进行压缩:
# Lists may also be compressed.
# Compress depth is the number of quicklist ziplist nodes from *each* side of
# the list to *exclude* from compression.  The head and tail of the list
# are always uncompressed for fast push/pop operations.  Settings are:
# 0: disable all list compression
# 1: depth 1 means "don't start compressing until after 1 node into the list,
#    going from either the head or tail"
#    So: [head]->node->node->...->node->[tail]
#    [head], [tail] will always be uncompressed; inner nodes will compress.
# 2: [head]->[next]->node->node->...->node->[prev]->[tail]
#    2 here means: don't compress head or head->next or tail->prev or tail,
#    but compress all nodes between them.
# 3: [head]->[next]->[next]->node->node->...->node->[prev]->[prev]->[tail]
# etc.
list-compress-depth 0
哈希对象
- 压缩列表
    
- 哈希对象保存的所有字符串元素的长度都小于 64 字节
 - 哈希对象保存的元素数量小于 512 个
 
 
这两个上限值可进行修改:
# Hashes are encoded using a memory efficient data structure when they have a
# small number of entries, and the biggest entry does not exceed a given
# threshold. These thresholds can be configured using the following directives.
hash-max-ziplist-entries 512
hash-max-ziplist-value 64
- 字典
 
不满足条件的哈希对象采用字典
Redis 使用 MurmurHash2 这种运行速度快、随机性好的哈希算法作为哈希函数,对于哈希冲突问题,Redis 采用链表法来解决。
集合对象
- 整数集合
    
- 集合对象保存的所有元素都是整数值
 - 集合对象保存的元素数量小于 512 个
 
 
第二个条件的上限值可进行修改:
# Sets have a special encoding in just one case: when a set is composed
# of just strings that happen to be integers in radix 10 in the range
# of 64 bit signed integers.
# The following configuration setting sets the limit in the size of the
# set in order to use this special memory saving encoding.
set-max-intset-entries 512
- 字典
 
不满足条件的集合对象采用字典
有序集合对象
- 压缩列表
    
- 有序集合对象保存的所有字符串元素的长度都小于 64 字节
 - 有序集合对象保存的元素数量小于 128 个
 
 
这两个上限值可进行修改:
# Similarly to hashes and lists, sorted sets are also specially encoded in
# order to save a lot of space. This encoding is only used when the length and
# elements of a sorted set are below the following limits:
zset-max-ziplist-entries 128
zset-max-ziplist-value 64
skiplist
不满足条件的有序集合对象采用 skiplist 编码,其底层使用 zset,其中同时包含一个字典和跳跃表