olylakers 发表于 2013-1-26 12:31:30

Redis数据结构分析

Redis有内存数据库的赞誉,其支持一下几种数据结构:
1.      String
2.      Hashes
3.      List
4.      Set
本文从源代码角度来分析各种数据结构在Redis内部是如何存储和读取的。
在介绍各种数据结构之前,首先来介绍下redisObject这个Struct, String,Hash,List和Set在Redis内部都是以redisObject来存储的
 
/* A redis object, that is a type able to hold a string / list / set *//* The actual Redis Object */#define REDIS_LRU_CLOCK_MAX ((1<<21)-1) /* Max value of obj->lru */#define REDIS_LRU_CLOCK_RESOLUTION 10 /* LRU clock resolution in seconds */typedef struct redisObject {    unsigned type:4;    unsigned storage:2;   /* REDIS_VM_MEMORY or REDIS_VM_SWAPPING */    unsigned encoding:4;    unsigned lru:22;      /* lru time (relative to server.lruclock) */    int refcount;    void *ptr;    /* VM fields are only allocated if VM is active, otherwise the   * object allocation function will just allocate   * sizeof(redisObjct) minus sizeof(redisObjectVM), so using   * Redis without VM active will not have any overhead. */} robj;  type:String, Hash,List,Set,Sorted set;
storage:这个参数只是在VM开启后才能用到,当VM有很大的性能问题,基本不建议开启;
encoding:编码方式: raw/int/ht/zmap/linkedlist/ziplist/intset;
 
lru:LRU期限,Redis默认的LRU时间是1.5年,所有基本不需要考虑key被LRU掉的问题
refcount:被引用的次数,因为Redis有shareObject的概念,目前只支持共享StringObject。Redis的共享对象有两大类比:第一类:Redis server的各种操作需要经常用到的各类对象,如:Redis Command的分隔符 "\r\n",用于Redis command的reply的"+OK\r\n"或者"-ERR\r\n"等对象,因为在Redis的各种操作这类对象要被频繁使用,所以就在启动 Redis的时候创建好,然后共用这些对象,减少时间成本和空间成本;第二,类的共享对象就是对应于数字的StringObject,如:Set "olylakers1" 1234;Set "olylakes2" 1234;在Redis内部,"olylakers1"和"olylakers2"这两个key都指向由数字1234转化的StringObject。这样在海量数据和特定存储内容下,可以节省大量的内存空间。可用通过REDIS_SHARED_INTEGERS这个参数来指定Redis启动的时候创建多 少个第二类共享对象,默认的参数是10000,即创建的StrongObject个取值范围是0-9999之间。
Ptr:对象数据;
 
redisObjects都是存放在redisDb里面的,Redis默认的是创建16个db:
 
typedef struct redisDb {    dict *dict;               /* The keyspace for this DB */    dict *expires;            /* Timeout of keys with a timeout set */    dict *blocking_keys;      /* Keys with clients waiting for data (BLPOP) */    dict *io_keys;            /* Keys with clients waiting for VM I/O */    dict *watched_keys;         /* WATCHED keys for MULTI/EXEC CAS */    int id;} redisDb;         redisDb维护了各种dict,所以说redis内部基本的数据存储结构就是一个dict,dict就是一个字典的数据结构,比较特殊的就是每个dict含有两个table,即两个dictht,这是为了实现增量rehashe准备的,当redis的dict在进行rehashe的时候,新的数据插将被添加到dictht ht当中,反之则添加到ht中
 
typedef struct dict {    dictType *type;    void *privdata;    dictht ht;    int rehashidx; /* rehashing not in progress if rehashidx == -1 */    int iterators; /* number of iterators currently running */} dict;typedef struct dictht {    dictEntry **table;    unsigned long size;    unsigned long sizemask;    unsigned long used;} dictht; Redis在响应各种命令的时候,把接收到的命令参数(key和value等)都转化成type=REDIS_STRING 的redisObject,最终执行命令将key和value存储到redisDb的dict的时候,存储的形式和内容是不相同的:在dict里面,key存储的是redisObject里面的prt所指向的数据,而value存储的则是和命令对应的redisObject,如执行list的命令lpush listname content,redisDb里面,存放的一条记录key为内容listname的字符串,而value(此value不是命令对应的value)存储的则是一个redisObject(type= REDIS_ENCODING_ZIPLIST, prt=ziplist),然后把content对应的内容add到ziplist上。
最后通过一张图来展示Redis内部DB的实现和其支持的各种data types在redis DB内的存储方式
Redis DB & data types
 
 
 
页: [1]
查看完整版本: Redis数据结构分析