redis存储结构

Posted haozi_ncepu

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了redis存储结构相关的知识,希望对你有一定的参考价值。

Base 2.8.7
Redis是一个包含了很多Key-Value对的大字典,这个字典支持的Value非常丰富,可以为 字符串、哈希表、列表、集合和有序集 ,基于这些类型丰富的value,扩展出了功能强大的操作,例如hmset、lpush、sadd等

字典

字典是Redis最基础的数据结构,一个字典即一个DB,Redis支持多DB

Redis字典采用Hash表实现,针对碰撞问题,其采用的方法为链地址法,即将多个哈希值相同的节点串连在一起, 从而解决冲突问题。
“链地址法”的问题在于当碰撞剧烈时,性能退化严重,例如:当有n个数据,m个槽位,如果m=1,则整个Hash表退化为链表,查询复杂度O(n)
为了避免Hash碰撞攻击,redis随机化了Hash表种子
Redis的方案是“双buffer”,正常流程使用一个buffer,当发现碰撞剧烈(判断依据为当前槽位数和Key数的对比),分配一个更大的buffer,然后逐步将数据从老的buffer迁移到新的buffer。

Redis字典结构如下:
[cpp]  view plain  copy
  1. typedef struct dict   
  2.     dictType *type;   
  3.     void *privdata;   
  4.     dictht ht[2]; //双buffer  
  5.     int rehashidx;   
  6.     int iterators;  
  7.  dict;  
  8.   
  9. typedef struct dictht   
  10.     dictEntry **table; //hash链表  
  11.     unsigned long size;  
  12.     unsigned long sizemask;  
  13.     unsigned long used;  
  14.  dictht;  
  15.   
  16. //数据节点<K,V>  
  17. typedef struct dictEntry   
  18.     void *key;  
  19.     union   
  20.         void *val;  
  21.         uint64_t u64;  
  22.         int64_t s64;  
  23.      v;  
  24.     struct dictEntry *next;  
  25.  dictEntry;  
redisObject是真正存储redis各种类型的结构,其内容如下:
[cpp]  view plain  copy
  1. typedef struct redisObject   
  2.     unsigned type:4; //逻辑类型  
  3.     unsigned notused:2;     /* Not used */  
  4.     unsigned encoding:4; //物理存储类型  
  5.     unsigned lru:22;        /* lru time (relative to server.lruclock) */  
  6.     int refcount;  
  7.     void *ptr;  //具体数据  
  8.  robj;  
其中type即redis支持的逻辑类型,包括:
[cpp]  view plain  copy
  1. #define REDIS_STRING 0  
  2. #define REDIS_LIST 1  
  3. #define REDIS_SET 2  
  4. #define REDIS_ZSET 3  
  5. #define REDIS_HASH 4  
enconding为物理存储方式,一种逻辑类型可以使用不同的存储方式,包括:
[cpp]  view plain  copy
  1. #define REDIS_ENCODING_RAW 0     /* Raw representation */  
  2. #define REDIS_ENCODING_INT 1     /* Encoded as integer */  
  3. #define REDIS_ENCODING_HT 2      /* Encoded as hash table */  
  4. #define REDIS_ENCODING_ZIPMAP 3  /* Encoded as zipmap */  
  5. #define REDIS_ENCODING_LINKEDLIST 4 /* Encoded as regular linked list */  
  6. #define REDIS_ENCODING_ZIPLIST 5 /* Encoded as ziplist */  
  7. #define REDIS_ENCODING_INTSET 6  /* Encoded as intset */  
  8. #define REDIS_ENCODING_SKIPLIST 7  /* Encoded as skiplist */  

字符串

Redis的所有的key都采用字符串保存,另外,Redis也支持字符串类型的value。
字符串类型即前文中看到的REDIS_STRING,其物理实现(enconding)可以为 REDIS_ENCODING_INT或REDIS_ENCODING_RAW 
REDIS_ENCODING_INT保存为long型,即redis会尝试将一个字符串转化为Long,可以转换的话,即保存为REDIS_ENCODING_INT
否则,Redis会将REDIS_STRING保存为字符串类型,即REDIS_ENCODING_RAW
字符串类型在redis中用sds封装,主要为了解决长度计算和追加效率的问题,其定义如下:
[cpp]  view plain  copy
  1. typedef char *sds;  
  2. struct sdshdr   
  3.     int len; <span style="font-family: Arial, Helvetica, sans-serif;">// buf 已占用长度</span>   
  4.     int free; <span style="font-family: Arial, Helvetica, sans-serif;">// buf 剩余可用长度</span>    
  5.     char buf[];<span style="font-family: Arial, Helvetica, sans-serif;">// 柔性数组,实际保存字符串数据的地方</span>  
  6. ;  
  7. static inline size_t sdslen(const sds s)   
  8.     struct sdshdr *sh = (void*)(s-(sizeof(struct sdshdr)));  
  9.     return sh->len;  
  10.   
  11. static inline size_t sdsavail(const sds s)   
  12.     struct sdshdr *sh = (void*)(s-(sizeof(struct sdshdr)));  
  13.     return sh->free;  
  14.   
有时间的同学可以详细看下Sds.h和Sds.c两个文件,还是很有意思的。

Hash表

Redis支持Value为Hash表,其逻辑类型为REDIS_HASH,REDIS_HASH可以有两种encoding方式: REDIS_ENCODING_ZIPLIST 和 REDIS_ENCODING_HT
REDIS_ENCODING_HT即前文提到的字典的实现
REDIS_ENCODING_ZIPLIST即ZIPLIST,是一种双端列表,且通过特殊的格式定义,压缩内存适用,以时间换空间。ZIPLIST适合小数据量的读场景,不适合大数据量的多写/删除场景
Hash表默认的编码格式为REDIS_ENCODING_ZIPLIST,在收到来自用户的插入数据的命令时:
1,调用hashTypeTryConversion函数检查键/值的长度大于 配置的hash_max_ziplist_value(默认64)
2,调用hashTypeSet判断节点数量大于 配置的hash_max_ziplist_entries (默认512)

以上任意条件满足则将Hash表的数据结构从REDIS_ENCODING_ZIPLIST转为REDIS_ENCODING_HT

列表

Redis支持Value为一个列表,其逻辑类型为REDIS_SET,REDIS_SET有两种encoding方式,REDIS_ENCODING_ZIPLIST和REDIS_ENCODING_LINKEDLIST
REDIS_ENCODING_ZIPLIST同上
REDIS_ENCODING_LINKEDLIST是比较正统双端链接表的实现:
[cpp]  view plain  copy
  1. typedef struct listNode   
  2.     struct listNode *prev;  
  3.     struct listNode *next;  
  4.     void *value;  
  5.  listNode;  
列表的默认编码格式为REDIS_ENCODING_ZIPLIST,当满足以下条件时,编码格式转换为REDIS_ENCODING_LINKEDLIST
1,元素大小大于list-max-ziplist-value(默认64)
2,元素个数大于 配置的list-max-ziplist-entries(默认512)

集合

Redis支持Value为集合,其逻辑类型为REDIS_SET,REDIS_SET有两种encoding方式: REDIS_ENCODING_INTSET 和 REDIS_ENCODING_HT(同上)
集合的元素类型和数量决定了encoding方式,默认采用REDIS_ENCODING_INTSET ,当满足以下条件时,转换为REDIS_ENCODING_HT:
1. 元素类型不是整数
2. 元素个数超过配置的“set-max-intset-entries”(默认512)
REDIS_ENCODING_INTSET是一个有序数组,使用的数据结构如下:
[cpp]  view plain  copy
  1. typedef struct intset   
  2.     uint32_t encoding;  //3种类型:INTSET_ENC_INT16、INTSET_ENC_INT32、INTSET_ENC_INT64  
  3.     uint32_t length; //元素个数  
  4.     int8_t contents[]; //元素实际存放的位置,按序排放  
  5. redis前传笔记:zset如何解决内部链表查找效率低下|跳表构建

    Redis性能调优

    玩转Redis-Lua脚本入门到实战-树形结构存储及查询

    首页轮播图的异步更新

    Redis数据存储

    Redis存储结构体信息,选hash还是string?