当前位置: 首页 > news >正文

小城市网站建设宝塔 wordpress

小城市网站建设,宝塔 wordpress,海外互联网推广平台,网站 建设文档目录总纲redis的k,v键值对新的三大类型五种经典数据类型redisObject结构图示结构讲解数据类型与数据结构关系图示string数据类型三大编码格式SDS详解代码结构为什么要重新设计源码解析三大编码格式hash数据类型ziplist和hashtable编码格式ziplist详解结构剖析ziplist的优势(为什… 目录总纲redis的k,v键值对新的三大类型五种经典数据类型redisObject结构图示结构讲解数据类型与数据结构关系图示string数据类型三大编码格式SDS详解代码结构为什么要重新设计源码解析三大编码格式hash数据类型ziplist和hashtable编码格式ziplist详解结构剖析ziplist的优势(为什么要在设计一个结构出来)zlentry详解OBJ_ENCODING_HT详解list数据类型quicklist编码格式压缩配置项list-compress-depthlist-max-ziplist-sizeset数据类型set-max-intset-entrieszset数据类型skiplist(跳跃表)复杂度优缺点最终总结结构表结构图示时间复杂度文字描述总纲 redis的k,v键值对 redis是key-value存储系统,其中key类型一般为字符串,value类型为redis对象(redisObject) redis定义了redisObject结构体,来表示string,hash,list,set,zset等数据类型 每个键值对都会有一个dictEntry 新的三大类型 bitmap: 本质是stringhyperLogLog: 本质是stringGEO: 本质是Zset 五种经典数据类型 redisObject 为了便于操作,redis采用了redisObject结构来统一五种不同的数据类型,这样所有的数据类型就都可以以相同的形式在函数间传递而不使用特定的类型结构.同时,为了识别不同的数据类型,redisObject中定义了type和encoding字段对不同的数据类型加以区分.简单的讲,redisObject就是stirng,hash,list,set,zset的父类,可以在函数间传递时隐藏具体的类型信息,所以作者把他抽象出来. 结构图示 结构讲解 type:4 指的是当前值对象的数据类型encoding:4 指的是当前值对象底层存储的编码类型lru:LRU_BITS 采用lru算法清除内存中的对象int refcount 记录对象引用次数void *ptr 指向真正的底层数据结构的指针 数据类型与数据结构关系图示 string数据类型 三大编码格式 格式解释补充说明int保存long型(长整型)的64位(8个字节)有符号整数只有整数才会使用int,如果是浮点数,Redis内部会转为字符串值在保存,如果是整数,超过long的最大值的话就会转变为embstr类型embstrSDS(Simple Dynamic String简单动态字符串),保存长度小于44字节的字符串长度大于44字节就会转变为raw类型raw保存长度大于44字节的字符串 SDS详解 Redis没有直接复用C语言的字符串,而是新建了属于自己的结构----SDS.在Redis数据库里,包含字符串的键值对都是由SDS实现的(Redis中所有的键都是由字符串对象实现的,即底层是由SDS实现,Redis中所有的值对象中包含的字符串对象底层也是由SDS实现) 代码结构 struct __attribute__ ((__packed__)) sdshdr8 {uint8_t len; /* 当前字符数组的长度 */uint8_t alloc; /* 当前字符数组总共分配的内存大小 */unsigned char flags; /* 当前字符串数组的属性,用来标识是sdshdr8还是sdshdr16等等 */char buf[]; /* 字符串真正的值 */ }; struct __attribute__ ((__packed__)) sdshdr16 {uint16_t len; /* used */uint16_t alloc; /* excluding the header and null terminator */unsigned char flags; /* 3 lsb of type, 5 unused bits */char buf[]; }; struct __attribute__ ((__packed__)) sdshdr32 {uint32_t len; /* used */uint32_t alloc; /* excluding the header and null terminator */unsigned char flags; /* 3 lsb of type, 5 unused bits */char buf[]; }; struct __attribute__ ((__packed__)) sdshdr64 {uint64_t len; /* used */uint64_t alloc; /* excluding the header and null terminator */unsigned char flags; /* 3 lsb of type, 5 unused bits */char buf[]; };有多个定义,数值越高,存储的字符数组越大 为什么要重新设计 C语言SDS字符串长度处理需要从头遍历,一直到遇到\0为止,时间复杂度为O(N)直接记录当前字符串长度,直接读取,时间复杂度为O(1)内存重新分配分配内存空间超过后,会导致数组下标越级或者内存分配溢出空间预分配:sds修改以后len长度小于1M,那么将会分配与len长度相同的未使用空间,如果修改后大于1m,那么将分配1m的使用空间 惰性空间释放:sds缩短不会回收内存,而是用free记录多余的空间,后续变更直接使用free记录的空间,减少内存的分配次数二进制安全二进制数据不是规则的字符串格式,可能会包含特殊字符,比如 \0等,此时C语言就会读取结束根据len长度来判断字符串结束的,二进制的安全问题就得以解决了 源码解析 Redis启动时会预先建立10000个分别是0-9999的redisObject变量作为共享对象,这就意味着如果set字符串的键值在0-9999之间的话,则可以直接指向共享对象而不需要在建立新对象,此时键值不占空间 三大编码格式 redis的Object.c源代码的tryObjectEncoding方法 /* Try to encode a string object in order to save space */ robj *tryObjectEncoding(robj *o) {long value;sds s o-ptr;size_t len;serverAssertWithInfo(NULL,o,o-type OBJ_STRING);if (!sdsEncodedObject(o)) return o;if (o-refcount 1) return o;len sdslen(s);if (len 20 string2l(s,len,value)) {//字符串如果小于等于20且字符串转long型成功if ((server.maxmemory 0 ||!(server.maxmemory_policy MAXMEMORY_FLAG_NO_SHARED_INTEGERS)) value 0 value OBJ_SHARED_INTEGERS){//配置maxmemory且值在10000以内.直接使用共享对象的值decrRefCount(o);incrRefCount(shared.integers[value]);return shared.integers[value];} else {if (o-encoding OBJ_ENCODING_RAW) {sdsfree(o-ptr);o-encoding OBJ_ENCODING_INT;o-ptr (void*) value;return o;} else if (o-encoding OBJ_ENCODING_EMBSTR) {decrRefCount(o);return createStringObjectFromLongLongForValue(value);}}}//如果长度小于embstr的长度,就转为embstr// 作者定义长度为44字节 #define OBJ_ENCODING_EMBSTR_SIZE_LIMIT 44//embstr的含义就是嵌入式的string,从内存上讲就是字符串的sds结构体与其对应的redisObject对象//分配在同一块连续的内存空间if (len OBJ_ENCODING_EMBSTR_SIZE_LIMIT) {robj *emb;if (o-encoding OBJ_ENCODING_EMBSTR) return o;emb createEmbeddedStringObject(s,sdslen(s));decrRefCount(o);return emb;}//大于44的直接就是raw对象trimStringObjectIfNeeded(o);/* 返回最终的对象 */return o; }对于embstr,由于其实现是只读的,因此在对embstr修改时,都会先转化为raw再进行修改,因此,只要是修改embstr对象,修改后的对 象一定是raw的,无论是否达到了44个字节 redis内部会根据用户给的不同键值而使用不同的编码格式,自适应的选择较优的内部编码格式,而这一切对用户完全透明 hash数据类型 ziplist和hashtable编码格式 参数名称参数解释默认值hash-max-ziplist-entries使用压缩列表保存时哈希集合中的最大元素个数哈希对象保存的键值对数量小于512个hash-max-ziplist-value使用压缩列表保存时哈希集合中单个元素的最大长度所有的键值对的键和值的字符串长度都小于等于64byte(一个英文字母一个字节)时用ziplist,反之用hashtablehash类型键的字段数小于hash-max-ziplist-entries并且每个字段名和字段值的长度小于hash-max-ziplist-value的时候,redis才会使用OBJ_ENCODING_ZIPLIST(ziplist)来存储,前述的条件任意一个不满足就会转变为OBJ_ENCODING_HT(hashtable)的编码格式 ziplist升级到hashtable可以,但是他不会在进行降级 ziplist详解 ziplist是一种紧凑的编码格式,总体思想是多花时间来换取节约空间,即以部分读写性能为代价,来换取极高的内存空间利用率.因此只会用于字段个数少,且字段值也比较小的场景,压缩列表内存利用率极高的原因与其连续内存的热醒是分不开的 embstr也是嵌入式string,内存与redisObject是连续不分开的,redis在这方面特别重视(因为他主要就是玩内存的,他想去尽量的减少内存碎片) 结构剖析 ziplist是一个经过特殊编码的双向链表,不过他并不存储指向上一个节点和下一个节点的指针,而是去存储上一个节点长度和当前节点的长度. 结构图示: 属性类型长度用途zlbytesuint32_t4字节记录整个压缩列表占用的内存字节数:在对压缩列表进行内存重分配,或者计算zlend的位置时使用zltailuint32_t4字节记录压缩列表表尾节点距离压缩列表的起始地址有多少字节,通过这个偏移量,程序无须遍历整个压缩列表就可以确定表尾节点的地址zllenuint16_t2字节记录了压缩列表包含的节点数量:当这个属性的值小于UINT16_MAX(65536)时,这个属性的值就是压缩列表包含节点的数量;当这个值等于UINT16_MAX时,节点的真实数量需要遍历整个压缩列表才能计算得出entryX列表节点不定压缩列表包含的各个节点,节点的长度由节点保存的内容决定zlenduint8_t1字节特殊值0xFF(二进制八个1),用于标记压缩列表的末端 ziplist的优势(为什么要在设计一个结构出来) 普通的双向链表会有两个指针,在存储数据很小的情况下,我们存储的实际数据大小很可能还没有指针占用的内存大,得不偿失.所以ziplist没用指针,而是改为维护上一个和当前entry的长度,通过长度推算下一个元素在什么位置,牺牲读取的性能来获得最高效的存储空间,是典型的的时间换空间的思想.键表在内存中一般都是不连续的(因为可以靠指针,不用考虑连续的问题),遍历相对较慢,而ziplist正好解决了这个问题,他是内存上要求必须连续的,但是由于他每个节点的长度可以不相等,所以遍历的时候需要记录长度信息作为偏移量用来遍历整个链表.使之能够跳到上一个节点或者是下一个节点头节点里同时还存在一个参数len.和string类型的sds相似,这里是用来记录链表长度的,因此获取链表长度时不用再遍历整个链表,直接拿到len值就可以了,时间复杂度为O(1) zlentry详解 entry的代码结构: //压缩链表节点结构 typedef struct zlentry {unsigned int prevrawlensize; /* 存储上一个链表节点的长度数值所需要的字节数(1字节或者5字节,为了对齐填充) */unsigned int prevrawlen; /* 上一个链表节点占用的长度 */unsigned int lensize; /* 存储当前链表节点长度数值所需要的字节数*/unsigned int len; /* 当前链表节点占用的长度 */unsigned int headersize; /* 当前链表节点的头部大小(prevrawlensizelensize),即非数据域大小 */unsigned char encoding; /* 编码方式 */unsigned char *p; /* 压缩链表以字符串的形式保存,该指针指向当前节点起始位置 */ } zlentry;OBJ_ENCODING_HT详解 OBJ_ENCODING_HT这种编码方式内部才是真正的哈希表结构,可以实现O(1)级别的读写操作,在Redis内部,从OBJ_ENCODING_HT类型到底层真正的散列表数据结构是一层层的嵌套下去的,如图所示: list数据类型 quicklist编码格式 在redis里面,list用quicklist来存储,quicklist存储了一个双向链表,每个节点都是一个ziplist,他是ziplist加上linkedlist的结合体 图示: 压缩配置项 list-compress-depth 表示一个quicklist两端不被压缩的节点个数,这里的节点是quicklist双向链表的节点,含义如下 0:是个特殊值,表示都不压缩,这是Redis的默认值1:表示quicklist两端各有一个节点不压缩,中间的节点压缩2:表示quicklist两端各有两个节点不压缩,中间的节点压缩3:表示quicklist两端各有三个节点不压缩,中间的节点压缩 依次类推下去… list-max-ziplist-size 当取正值的时候,表示按照数据项个数来限定每个quicklist节点上的ziplist长度.比如当这个数据项设置为5的时候,表示每个quicklist节点的ziplist最多包含五个数据项.当取负值的时候,表示按照占用字节数来限定每个quicklist节点上的ziplist长度.这时,他只能取-1到-5这五个值 -5: 每个quicklist节点上的ziplist大小不能超过64KB-4: 每个quicklist节点上的ziplist大小不能超过32KB-3: 每个quicklist节点上的ziplist大小不能超过16KB-2: 每个quicklist节点上的ziplist大小不能超过8KB(-2也是Redis给的默认值)-1: 每个quicklist节点上的ziplist大小不能超过4KB set数据类型 Redis用inset和hashtable两种编码格式来存储set,如果元素都是整数类型并且个数小于512个,就用intset存储,如果不是整数类型,就用hashtable(数组加链表的存储结构).key就是元素的值,value为null set-max-intset-entries 默认值为512,配置整型set的元素最大个数,超过的话就会变为hashtable zset数据类型 当有序集合中包含的元素数量超过服务器属性server.zset_max_ziplist_entries的值(默认值是128),或者有序集合中新添加元素的member的长度大于服务器属性server.zset_max_ziplist_value的值(默认值为64)时,redis会使用跳跃表作为有序集合的底层实现。否则会使用ziplist作为有序列表的底层实现。 skiplist(跳跃表) 跳表是可以实现二分查找的有序链表.他是一种以空间换取时间的结构,由于链表无法进行二分查找,因此借鉴数据库的索引思想,提取出链表中关键节点(索引),先在关键节点上查找,在进入下层的链表查找,提取多层关键节点,就形成了二分查找的跳跃表结构. 总结来说跳表 链表 多级索引(两两取首升级为索引,一级一级进行嵌套) 复杂度 时间复杂度为O(logN),空间复杂度为O(n),新增修改删除的时间复杂度也是O(logN) 优缺点 典型的空间换时间的策略,而且只有在数据量大的时候才能体现出来优势,比较适应读多写少的场景,所以使用范围比较有限,这里需要注意,数据量大的同时写太多的话可能会一直需要调整各级别的索引,所以会耗时较多 最终总结 结构表 类型编码对象REDIS_STRINGREDIS_ENCODING_INT使用整数值实现的字符串对象REDIS_STRINGREDIS_ENCODING_EMBSTR使用embstr编码的简单动态字符串实现的嵌入式字符串对象REDIS_STRINGREDIS_EMCODING_RAW使用简单动态字符串实现的字符串REDIS_LISTREDIS_ENCODING_ZIPLIST使用压缩列表ziplist实现的列表对象REDIS_LISTREDIS_ENCODING_LINKEDLIST使用双端链表quicklist实现的列表对象REDIS_HASHREDIS_ENCODING_ZIPLIST使用压缩列表ziplist实现的哈希对象REDIS_HASHREDIS_ENCODING_HT使用字典hashtable实现的哈希对象REDIS_SETREDIS_ENCODING_INSET使用整数集合实现的集合对象REDIS_SETREDIS_ENCODING_HT使用字典实现的集合对象REDIS_ZSETREDIS_ENCODING_ZIPLIST使用压缩列表实现的有序集合对象REDIS_ZSETREDIS_ENCODING_SKIPLIST使用跳跃表和字典实现的有序集合对象 结构图示 时间复杂度 文字描述 string字符串(redis会根据当前值的类型和大小决定使用哪种内部编码实现)int:8个字节的长整型embstr:小于等于44个字节的嵌入式字符串(内存地址与redisObject连续)raw:大于44个字节的字符串hash哈希ziplist(压缩列表):当哈希元素个数小于hash-max-ziplist-entries配置(默认512个),同时所有值都小于hash-max-ziplist-value配置(默认64字节)时,Redis会采用ziplist作为哈希的内部实现,ziplist内存更加的紧凑和节省,所以节约内存方面比起来hashtable要优秀hashtable(哈希表):当哈希类型无法满足ziplist的条件时,Redis就会改用hashtable作为哈希的内部实现,因为此时的ziplist的读写效率下降,而hashtable的读写复杂度为O(1)list列表ziplist:当列表的元素个数小于list-max-ziplist-entries配置(默认512个),同时列表中每个元素的值都小于list-max-ziplist-value配置(默认是64个字节)时.Redis会采用ziplist来作为列表的内部实现来减少内存的使用linkedlist(链表):当列表类型无法满足ziplist的条件时,Redis会采用quicklist作为内部实现.quick是linkedlist和ziplist的结合,以ziplist为节点的链表(linkedlist)set集合inset(整数集合):当集合中的元素都是整数且元素个数小于set-max-inset-entries配置(默认512个)时,Redis会采用inset来作为集合的内部实现,从而减少内存的使用hashtable:当集合类型无法满足inset时,Redis会采用hashtable作为内部实现zset有序集合ziplist:当有序集合的元素个数小于zset-max-ziplist-entries配置(默认128个),同时每个元素的值都小于zset-max-ziplist-value配置(默认64字节)时,Redis会采用ziplist来作为有序集合的内部实现,ziplist可以有效减少内存的使用skiplist(跳跃表):当ziplist条件不满足时,有序集合会使用skiplist作为内部实现,因为此时ziplist的读写效率会下降 感觉这些多种编码数据结构实现的设计就是在时间和空间上寻求一种平衡,毕竟redis追求的是极致的性能,他就是从这些小细节的架构上体现出来的高性能的标杆
http://www.dnsts.com.cn/news/72927.html

相关文章:

  • 如何使用网站营销插件 wordpress开发
  • discuz 企业网站网站建设讨论会
  • 网站做301有什么用天水市建设局网站吊篮管理通知
  • 分享几个x站好用的关键词有哪些vue做的网站
  • 招聘类网站建设wordpress登录卡死
  • 网站推广优化外包公司哪家好电商运营平台有哪些
  • 如何用dedecms做网站网络营销导向企业网站建设的原则包括
  • 网站建设网站软件淘宝购物网站
  • 爱站网关键词查询网站的工具南宁武鸣区建设局网站
  • 同一个域名在一个服务器做两件网站如何搭建自己的博客
  • 中国交通建设网官方网站怎样创建一个自己的网站
  • 如何做免费的网站推广自动搭建网站源码
  • h5网站建设服务网站建设目标规划
  • 中科时代建设官方网站平面设计网页
  • jsp网站购物车怎么做破解版成年猫咪版永久
  • 企业做网站大概多少钱软文广告范例大全
  • 济南做网站哪家公司好坊子网站建设
  • 域名解析网站建站边检站
  • 郑州企业建站模板佛山外贸网站建设资讯
  • 小米网站的建设目的没有网站域名备案信息
  • 黑白灰网站个人淘宝客网站
  • 广安网站seo装修公司网络推广方案
  • 建设一个域名抢注的网站怎么做局域网asp网站
  • 销售网站内容设计电商型网站是否是趋势
  • 设计网站建设价格wordpress 空间 域名
  • 网站建设需要多少钱小江网页设计设计坞网站官方下载
  • 一个网站需要哪些东西唐兴数码网站
  • 自己做的网站被黑了怎么办专业制作效果图公司
  • 玉环哪里有做网站自己设计t恤的平台
  • 南宁网络营销网站怀化市住房与城乡建设厅网站