Redis 使用文档.docx

上传人:b****3 文档编号:3808196 上传时间:2022-11-25 格式:DOCX 页数:45 大小:499.37KB
下载 相关 举报
Redis 使用文档.docx_第1页
第1页 / 共45页
Redis 使用文档.docx_第2页
第2页 / 共45页
Redis 使用文档.docx_第3页
第3页 / 共45页
Redis 使用文档.docx_第4页
第4页 / 共45页
Redis 使用文档.docx_第5页
第5页 / 共45页
点击查看更多>>
下载资源
资源描述

Redis 使用文档.docx

《Redis 使用文档.docx》由会员分享,可在线阅读,更多相关《Redis 使用文档.docx(45页珍藏版)》请在冰豆网上搜索。

Redis 使用文档.docx

Redis使用文档

Redis内存存储结构分析

2011/10/16

  1Redis内存存储结构

  本文是基于Redis-v2.2.4版本进行分析.

  1.1Redis内存存储总体结构

  Redis是支持多key-value数据库(表)的,并用RedisDb来表示一个key-value数据库(表).redisServer中有一个redisDb*db;成员变量,RedisServer在初始化时,会根据配置文件的db数量来创建一个redisDb数组.客户端在连接后,通过SELECT指令来选择一个reidsDb,如果不指定,则缺省是redisDb数组的第1个(即下标是0)redisDb.一个客户端在选择redisDb后,其后续操作都是在此redisDb上进行的.下面会详细介绍一下redisDb的内存结构.

  

  redis的内存存储结构示意图

  redisDb的定义:

  19typedefstructredisDb

  {

  dict*dict;/*ThekeyspaceforthisDB*/

  dict*expires;/*Timeoutofkeyswithatimeoutset*/

  dict*blocking_keys;/*Keyswithclientswaitingfordata(BLPOP)*/

  dict*io_keys;/*KeyswithclientswaitingforVMI/O*/

  dict*watched_keys;/*WATCHEDkeysforMULTI/EXECCAS*/

  intid;

  }redisDb;

  struct

  redisDb中,dict成员是与实际存储数据相关的.dict的定义如下:

  63typedefstructdictEntry

  {

  void*key;

  void*val;

  structdictEntry*next;

  }dictEntry;

  typedefstructdictType

  {

  unsignedint(*hashFunction)(constvoid*key);

  void*(*keyDup)(void*privdata,constvoid*key);

  void*(*valDup)(void*privdata,constvoid*obj);

  int(*keyCompare)(void*privdata,constvoid*key1,constvoid*key2);

  void(*keyDestructor)(void*privdata,void*key);

  void(*valDestructor)(void*privdata,void*obj);

  }dictType;

  /*Thisisourhashtablestructure.Everydictionaryhastwoofthisaswe

  *implementincrementalrehashing,fortheoldtothenewtable.*/

  typedefstructdictht

  {

  dictEntry**table;

  unsignedlongsize;

  unsignedlongsizemask;

  unsignedlongused;

  }dictht;

  typedefstructdict

  {

  dictType*type;

  void*privdata;

  dicththt[2];

  intrehashidx;/*rehashingnotinprogressifrehashidx==-1*/

  intiterators;/*numberofiteratorscurrentlyrunning*/

  }dict;

  dict是主要是由structdictht的哈唏表构成的,之所以定义成长度为2的(dicththt[2])哈唏表数组,是因为redis采用渐进的rehash,即当需要rehash时,每次像hset,hget等操作前,先执行N步rehash.这样就把原来一次性的rehash过程拆散到进行,防止一次性rehash期间redis服务能力大幅下降.这种渐进的rehash需要一个额外的structdictht结构来保存.

  structdictht主要是由一个structdictEntry指针数组组成的,hash表的冲突是通过链表法来解决的.

  structdictEntry中的key指针指向用sds类型表示的key字符串,val指针指向一个structredisObject结构体,其定义如下:

  typedefstructredisObject

  {

  unsignedtype:

4;

  unsignedstorage:

2;/*REDIS_VM_MEMORYorREDIS_VM_SWAPPING*/

  unsignedencoding:

4;

  unsignedlru:

22;/*lrutime(relativetoserver.lruclock)*/

  intrefcount;

  void*ptr;

  /*VMfieldsareonlyallocatedifVMisactive,otherwisethe

  *objectallocationfunctionwilljustallocate

  *sizeof(redisObjct)minussizeof(redisObjectVM),sousing

  *RediswithoutVMactivewillnothaveanyoverhead.*/

  }robj;

  //type占4bit,用来表示key-value中value值的类型,目前redis支持:

string,list,set,zset,hash5种类型的值.

  /*Objecttypes*/

  #defineREDIS_STRING0

  #defineREDIS_LIST1

  #defineREDIS_SET2

  #defineREDIS_ZSET3

  #defineREDIS_HASH4

  #defineREDIS_VMPOINTER8

  //storage占2bit,表示此值是在内存中,还是swap在硬盘上.

  //encoding占4bit,表示值的编码类型,目前有8种类型:

  /*Objectsencoding.SomekindofobjectslikeStringsandHashescanbe

  *internallyrepresentedinmultipleways.The‘encoding’fieldoftheobject

  *issettooneofthisfieldsforthisobject.*/

  #defineREDIS_ENCODING_RAW0/*Rawrepresentation*/

  #defineREDIS_ENCODING_INT1/*Encodedasinteger*/

  #defineREDIS_ENCODING_HT2/*Encodedashashtable*/

  #defineREDIS_ENCODING_ZIPMAP3/*Encodedaszipmap*/

  #defineREDIS_ENCODING_LINKEDLIST4/*Encodedasregularlinkedlist*/

  #defineREDIS_ENCODING_ZIPLIST5/*Encodedasziplist*/

  #defineREDIS_ENCODING_INTSET6/*Encodedasintset*/

  #defineREDIS_ENCODING_SKIPLIST7/*Encodedasskiplist*/

  /*如type是REDIS_STRING类型的,则其值如果是数字,就可以编码成REDIS_ENCODING_INT,以节约内存.

  *如type是REDIS_HASH类型的,如果其entry小于配置值:

hash-max-zipmap-entries或value字符串的长度小于hash-max-zipmap-value,则可以编码成REDIS_ENCODING_ZIPMAP类型存储,以节约内存.否则采用Dict来存储.

  *如type是REDIS_LIST类型的,如果其entry小于配置值:

list-max-ziplist-entries或value字符串的长度小于list-max-ziplist-value,则可以编码成REDIS_ENCODING_ZIPLIST类型存储,以节约内存;否则采用REDIS_ENCODING_LINKEDLIST来存储.

  *如type是REDIS_SET类型的,如果其值可以表示成数字类型且entry小于配置值set-max-intset-entries,则可以编码成REDIS_ENCODING_INTSET类型存储,以节约内存;否则采用Dict类型来存储.

  *lru:

是时间戳

  *refcount:

引用次数

  *void*ptr:

指向实际存储的value值内存块,其类型可以是string,set,zset,list,hash,编码方式可以是上述encoding表示的一种.

  *至于一个key的value采用哪种类型来保存,完全是由客户端的指令来决定的,如hset,则值是采用REDIS_HASH类型表示的,至于那种编码(encoding),则由redis根据配置自动决定.

  */1.2Dict结构

  Dict结构在<1.1Redis内存存储结构>;已经描述过了,这里不再赘述.

  1.3zipmap结构

  如果redisObject的type成员值是REDIS_HASH类型的,则当该hash的entry小于配置值:

hash-max-zipmap-entries或者value字符串的长度小于hash-max-zipmap-value,则可以编码成REDIS_ENCODING_ZIPMAP类型存储,以节约内存.否则采用Dict来存储.

  zipmap其实质是用一个字符串数组来依次保存key和value,查询时是依次遍列每个key-value对,直到查到为止.其结构示意图如下:

  为了节约内存,这里使用了一些小技巧来保存key和value的长度.如果key或value的长度小于ZIPMAP_BIGLEN(254),则用一个字节来表示,如果大于ZIPMAP_BIGLEN(254),则用5个字节保存,第一个字节为保存ZIPMAP_BIGLEN(254),后面4个字节保存key或value的长度.

  初始化时只有2个字节,第1个字节表示zipmap保存的key-value对的个数(如果key-value对的个数超过254,则一直用254来表示,zipmap中实际保存的key-value对个数可以通过zipmapLen()函数计算得到).

  hset(nick,wuzhu)后,

  第1个字节保存key-value对(即zipmap的entry数量)的数量1

  第2个字节保存key_len值4

  第3~6保存key“nick”

  第7字节保存value_len值5

  第8字节保存空闭的字节数0(当该key的值被重置时,其新值的长度与旧值的长度不一定相等,如果新值长度比旧值的长度大,则realloc扩大内存;如果新值长度比旧值的长度小,且相差大于4bytes,则realloc缩小内存,如果相差小于4,则将值往前移,并用empty_len保存空闲的byte数)

  第9~13字节保存value值“wuzhu”

  hset(age,30)

  插入key-value对(“age”,30)

  hset(nick,tide)

  插入key-value对(“nick”,”tide”),后可以看到empty_len为1,

  1.4ziplist结构

  如果redisObject的type成员值是REDIS_LIST类型的,则当该list的elem数小于配置值:

hash-max-ziplist-entries或者elem_value字符串的长度小于hash-max-ziplist-value,则可以编码成REDIS_ENCODING_ZIPLIST类型存储,以节约内存.否则采用Dict来存储.

  ziplist其实质是用一个字符串数组形式的双向链表.其结构示意图如下

  ziplistheader由3个字段组成:

  ziplist_bytes:

用一个uint32_t来保存,构成ziplist的字符串数组的总长度,包括ziplistheader,

  ziplist_tail_offset:

用一个uint32_t来保存,记录ziplist的尾部偏移位置.

  ziplist_length:

用一个uint16_t来保存,记录ziplist中elem的个数

  ziplistnode也由3部分组成:

  prevrawlen:

保存上一个ziplistnode的占用的字节数,包括:

保存prevarwlen,currawlen的字节数和elemvalue的字节数.

  currawlen&encoding:

当前elemvalue的raw形式存款所需的字节数及在ziplist中保存时的编码方式(例如,值可以转换成整数,如示意图中的”1024”,raw_len是4字节,但在ziplist保存时转换成uint16_t来保存,占2个字节).

  (编码后的)value

  可以通过prevrawlen和currawlen&encoding来遍列ziplist.

  ziplist还能到一些小技巧来节约内存.

  len的存储:

如果len小于ZIP_BIGLEN(254),则用一个字节来保存;否则需要5个字节来保存,第1个字节存ZIP_BIGLEN,作为标识符.

  value的存储:

如果value是数字类型的,则根据其值的范围转换成ZIP_INT_16B,ZIP_INT_32B或ZIP_INT_64B来保存,否则用raw形式保存.

  1.5adlist结构

  38typedefstructlistNode

  {

  structlistNode*prev;

  structlistNode*next;

  void*value;

  }listNode;

  typedefstructlistIter

  {

  listNode*next;

  intdirection;

  }listIter;

  typedefstructlist

  {

  listNode*head;

  listNode*tail;

  void*(*dup)(void*ptr);

  void(*free)(void*ptr);

  int(*match)(void*ptr,void*key);

  unsignedintlen;

  }list;

  常见的双向链表,不作分析.

  1.6intset结构

  intset是用一个有序的整数数组来实现集合(set).structintset的定义如下:

  11typedefstructintset

  {

  uint32_tencoding;

  uint32_tlength;

  int8_tcontents[];

  }intset;

  encoding:

来标识数组是int16_t类型,int32_t类型还是int64_t类型的数组.至于怎么先择是那种类型的数组,是根据其保存的值的取值范围来决定的,初始化时是int16_t,根据set中的最大值在[INT16_MIN,INT16_MAX],[INT32_MIN,INT32_MAX],[INT64_MIN,INT64_MAX]的那个取值范围来动态确定整个数组的类型.例如set一开始是int16_t类型,当一个取值范围在[INT32_MIN,INT32_MAX]的值加入到set时,则将保存set的数组升级成int32_t的数组.

  length:

表示set中值的个数

  contents:

指向整数数组的指针

  1.7zset结构

  首先,介绍一下skiplist的概念,然后再分析zset的实现.

  1.7.1SkipList介绍

  1.7.1.1有序链表

  1)SearchingakeyinaSortedlinkedlist

  

  7//Searchinganelementx

  cell*p=head;

  while(p->next->keynext;

  returnp;

  Note:

wereturntheelementproceedingeithertheelementcontainingx,orthesmallestelementwithakeylargerthanx(ifxdoesnotexists)

  2)insertingakeyintoaSortedlinkedlist

  

  //Toinsert35-

  p=find(35);

  CELL*p1=(CELL*)malloc(sizeof(CELL));

  p1->key=35;

  p1->next=p->next;

  p->next=p1;

  3)deleteingakeyfromasortedlist

  

  //Todelete37-

  p=find(37);

  CELL*p1=p->next;

  p->next=p1->next;

  free(p1);

  1.7.1.2SkipList(跳跃表)定义

  SKIPLIST:

Adatastructureformaintaingasetofkeysinasortedorder.

  Consistsofseverallevels.

  Allkeysappearinlevel1

  Eachlevelisasortedlist.

  Ifkeyxappearsinleveli,thenitalsoappearsinalllevelsbelowi

  

  Anelementinlevelipoints(viadownpointer)totheelementwiththesamekeyinthelevelbelow.

  Ineachlevelthekeysandappear.(Inourimplementation,INT_MINandINT_MAX

  Toppointstothesmallestelementinthehighestlevel.

  

  1.7.1.3SkipList(跳跃表)操作

  1)AnemptySkipList

  

  2)Findinganelementwithkeyx

  p=top

  While

(1)

  {

  while(p->next->keynext;

  If(p->down==NULL)returnp->next

  p=p->down;

  }

  Observethatwereturnx,ifexists,orsucc(x)ifxisnotintheSkipList

  3)InsertingnewelementX

  Determinekthenumberoflevelsinwhichxparticipates(explainedlater)

  Dofind(x),andinsertxtotheappropriateplacesinthelowestklevels.(aftertheelementsatwhichthesearchpathturnsdownorterminates)

  Example–inserting119.k=2

  Ifkislargerthanthecurrentnumberoflevels,addnewlevels(andupdatetop)

  Example–inser(119)whenk=4

  

  Determiningk

  k–thenumberoflevelsatwhichanelementxparticipate.

  UsearandomfunctionOurRnd()—returns1or0(True/False)withequalprobability.

  k=1;

  While(OurRnd())k++;

  Deleteingakeyx

  Findxinallthelevelsitparticipates,anddeleteitusingthestanda

展开阅读全文
相关资源
猜你喜欢
相关搜索

当前位置:首页 > 工程科技 > 能源化工

copyright@ 2008-2022 冰豆网网站版权所有

经营许可证编号:鄂ICP备2022015515号-1