1、redis的数据结构

(1)动态字符串(SDS)

redis自身构建了一个简单动态字符串的抽象类型,SDS,在redis里,包含字符串的键值对在底层都是由SDS来实现的。

除了用来保存数据库的字符串值之外,SDS还被用来作缓冲区:AOF模块中的AOF缓冲区、客户端输入缓冲区。

SDS的结构:free,当free属性值为0时,表示SDS没有分配未使用空间;len,SDS保存的字符串长度;buf[],char数组类型,将保存的字符串值拆分保存,最后跟一个空字符  \0  ,空字符不计算到len属性里。

SDS的特性:len属性,在获取字符串长度时时间复杂会降低,仅为O(1),避免了获取字符串长度成为redis性能瓶颈,

      通过len属性杜绝缓冲区溢出

      通过空间预分配和惰性空间分配来减少修改字符串时带来的内存重分配次数,空间预分配,当SDS中保存一个长度为5的字符串,此时SDS的属性len=5,free=0,在其后添加一个长度为5的字符串,再加上一个空字符,此时长度为len=5+5+1 =11而SDS会在分配一个长度为11的空闲空间,SDS属性len=11,free=11;惰性空间,SDS属性len=11,free=0,减少字符串3位,此时SDS属性len=8,free=3,SDS不会把空余空间收回,而是交给free进行记录,以供下次使用

      可以保存文本和二进制数据

(2)链表

链表可以提供高效的节点重排能力、顺序性节点访问、并且可以通过增删节点来灵活的调节链表长度,因此redis中对链表应用很广泛,例如列表键、发布/订阅、慢查询、监视器、构建客户区缓冲区等

每个链表节点都由一个ListNode结构表示,都有执向前节点和后节点的指针以及链表长度等信息,redis中实现的是双向无环链表,根据不同类型的特定函数,可以保存不同类型的值

(3)字典(symbol table)

用于保存键值对的抽象数据结构,字典中一个键可以和一个值进行关联,redis中数据库底层就是通过自身构建的字典来实现的,对数据库的增删改查也都是在对字典进行操作

Redis中字典的底层是由哈希表实现的,一个哈希表有多个哈希节点,每个节点保存了字典的一个键值对,字典的结构包含类型特定函数 type属性;私有数据privdata;哈希表ht[2]每个字典携带两个哈希表,一个存储数据,一个rehash时使用;rehash索引 trehashidx,当rehash不再进行时,值为-1

Redis中字典所使用的哈希表中主要包含哈希表数组 table、哈希表大小size、哈希表大小掩码值sizemask用于计算索引值、哈希表已有节点数量used

哈希表数组table使用dictEntry结构,dictEntry结构都保存着一个键值对和一个指向下一个节点的指针,形成一个链表,这个指针还可以将多个哈希值相同的键值对连接在一起,避免发生键冲突的问题

当要将一个新的键值对添加到字典里时,需要先根据键值对的键计算出哈希值和索引值,redis中使用MurmurHash2算法来计算哈希值,然后根据索引值,将包含新键值对的哈希表放到字典中哈希数组指定的索引上。

当哈希表中保存的键值对过多或过少时,需要对哈希表的大小进行处理,此时可以通过重新散列(rehash)来处理

重新散列的过程:根据ht[0]哈希表的used属性定义ht[1]的大小,扩展操作中ht[1]的大小是第一个大于等于ht[0].used*2的2^n,如果是收缩操作,ht[1]的大小是第一个大于等于ht[0].used的2^n,例如:扩展:ht[0].used =4,4*2=8,8=2^3,那么ht[1]的大小就是8,收缩:若ht[0].used=6,第一个大于等于6的2的n次方是2^3,那么ht[1]的大小就是8

        将ht[0]中的键值对重新计算哈希值和索引值,然后保存到ht[1]指定位置上

        释放ht[0],将ht[1]设置为ht[0],并在ht[1]新建一个空白的哈希表,以供下一次rehash使用

(4)跳跃表(skiplist)

一种有序的数据结构,通过在每个节点维持多个指向其他节点的指针,实现快速访问,Redis中有序集合键(set)底层由跳跃表来实现以及集群节点中跳跃表作内部数据结构。

跳跃表由zskiplistNode结构和zskiplist结构组成,zskiplistNode表示跳跃表节点,zskiplist用于存储跳跃表节点相关信息,包含跳跃表的表头节点header属性、跳跃表的表尾节点tail属性、记录跳跃表层数最大的节点数level属性、跳跃表长度length属性

(5)压缩列表(ziplist)

redis中列表和哈希的底层实现之一,当要保存少量的整数值、小数值或者较短的字符串,redis就会使用压缩列表作为底层实现

压缩列表的出现是为了redis 节约内存,它是由一系列的特殊编码的连续内存块组成顺序型结构,一个压缩列表可以包含任意多个节点,每个节点可以保存一个字节数组或一个整数值

(6)整数集合(intset)

Redis中集合的底层实现之一,当集合中都是整数时,redis默认使用整数集合作为集合的底层实现。intset结构包含三个属性,encoding编码格式、length数量、contents[]保存数据的数组,从小到大排序,是整数集合的底层实现,数组保存的数据类型由encoding来确定,程序会根据新添加的数据类型来改变数组的类型

2、redis的对象

redis中基于数据结构来创建了一个对象系统,系统中包含字符串对象、列表对象、哈希对象、集合对象和有序集合对象,通过这些对象来实现数据库、键值对,redis队象系统还通过引用计数技术实现内存回收机制和对象共享机制

redis使用对象来表示数据库中的键和值,每当我们在数据库中新建一个键值对时,我们都会创建至少两个对象,键值对的键和键值对的值

redis中每个对象都是由redisobject结构表示,包含type属性、encoding(编码类型属性)、ptr(指向底层实现数据结构的,数据结构有对象的encoding决定)

每种不同类型的对象都至少使用两种编码

(1)字符串对象

字符串编码的对象可以是int、raw、embstr

字符串对象保存的是整数值并且这个整数值可以用long类型表示,那么字符串对象会把整数值保存在ptr属性里并设置编码为int

字符串对象保存的是字符串值,若长度大于32字节,那么字符串对象会把字符串值保存在SDS里,并设置编码为raw,若小于32字节,那么字符串对象会设置编码为embstr

字符串对象保存的是long double 类型的值,那么字符串对象编码设置为embstr或raw

(2)列表对象

列表对象的编码是zipList(压缩列表)或者linkedlist(双端链表)

linkedList编码的列表对象在底层双端链表中包含了多个字符串对象

字符串对象是redis对象中唯一一个被其他四种类型嵌套的对象

列表对象保存的字符串长度<64字节,数量小于<512个,使用zipList,反之使用linkedlist,但是这两个值在配置文件中可以修改,list-max-ziplist-value和list-max-ziplist-entries

(3)哈希对象

哈希对象编码是ziplist(底层压缩列表)和hashtable(底层字典,每一个键、值都是字符串对象)

哈希对象对象保存的字符串长度<64字节,数量小于<512个,使用zipList,反之使用hashtable,但是这两个值在配置文件中可以修改,hash-max-ziplist-value和hash-max-ziplist-entries

(4)集合对象

集合对象编码是intset(底层整数集合)和hashtable(底层字典,每一个键、值都是字符串对象)

集合对象保存的值都是整数值且数量不超过512个,使用inset,反之使用hashtable,数量值在配置文件中可以修改,set-max-inset-value

(5)有序集合对象

有序集合对象编码是ziplist(底层压缩列表,从小到大排序)和skiplist(底层zset,一个zset包含一个跳跃表和一个字典,从小到大排序)

有序集合同时使用跳跃表和字典实现的原因:通过保留字典和跳跃表的优点,提高有序集合的查找和范围性操作的性能和效率

有序集合对象保存的值数量小于128,所有成员长度<64字节,使用ziplist,反之使用skiplist,但是这两个值在配置文件中可以修改,zset-max-ziplist-value和zset-max-ziplist-entries

(6)内存回收

redis在自己的对象系统中构建一个引用计数技术实现的内存回收机制,程序跟踪对象的引用计数信息,适当的时候自动释放对象并进行内存回收。

每个对象的引用计数信息由redisObject结构的refcount属性记录。

创建一个新对象时,初始化计数值为1,当对象被一个新程序使用时,引用计数加一,不再被程序使用时,引用计数减一,当引用计数为0时,对象占用的内存会被释放。

(7)对象共享

redis对象共享通过对象的计数属性实现,将数据库键的指针值指向同一个现有的值对象,被共享的值对象的引用计数增加一。

但是共享对象不包含字符串对象,若是字符串对象共享,验证时间会大大提升,验证int类型,复杂度为O(1),而验证字符串类型复杂度为O(N),多个对象复杂度为O(N^2)

(8)其他

SET、GET、APPEND、STRLEN等命令只能对字符串键执行

HDEL、HSET、HGET、HLEN等命令只能对哈希键执行

RPUSH、LPOP、LINSERT、LLEN等命令只能对列表键执行

SADD、SPOP、SINTER、SCARD等命令只能对集合键执行

ZADD、ZCARD、ZRANK、ZSCORE等命令只能对有序集合键执行

Redis小记(一)的更多相关文章

  1. Redis 小记

    最近感觉自己像是又回到了起点,知识层面上落人太多,尤其是去年早些时候几乎啥也没干成,觉得什么也不会了,只能再次从零开始,所以决定再喝两个疗程的巩固巩固. 话不多说,我们先来看看 Redis 官方是怎么 ...

  2. 「Nosql」Redis小记-内存解析&内存消耗篇

    *博客搬家:初版发布于 2017/08/12 18:32    原博客地址:https://my.oschina.net/sunqinwen/blog/1507171 Redis内存消耗分析 注:本文 ...

  3. Redis小记(三)

    1.复制 通过slaveof命令或设置slaveof选项,实现一个服务器去复制另一个服务器,被复制的是主服务器,执行复制的是从服务器,复制过程中主从双方数据库保持数据一致 2.8版本以前,可分为初次复 ...

  4. Redis小记(二)

    1.redis数据库 redis数据库属于内存数据库,若不将数据存到磁盘中,服务器进程退出,数据也会消失 redis所有数据库都保存在redisServer结构的db数组中,db数组的每一项都是一个r ...

  5. MongoDB 小记

    之前本人说过一款非关系型数据库的代表 Redis 的 < Redis 小记 >文章,觉得意犹未尽,今天就来介绍一款数据库 MongoDB ,先来看一下 MongoDB是一款基于分布式文件存 ...

  6. Redis Sentinel配置小记

    Sentinel是一个管理多个redis实例的工具,它可以实现对redis的监控.通知.自动故障转移.sentinel不断的检测redis实例是否可以正常工作,通过API向其他程序报告redis的状态 ...

  7. Docker 小记 — MySQL 与 Redis 配置

    前言 本篇随笔是继 "Docker Engine" 与 "Compose & Swarm" 之后的一个实例补充,初衷是记录测试环境中的一次 MySQL ...

  8. Redis 学习小记

    由于是学习笔记,我就不来各种啰嗦,介绍这个介绍那个,也不上交给国家,或者各种对比,相信如果你真心用 redis 的话,就不会去跟 MySql,Memcached,MongoDB 等做对比了. 我原先用 ...

  9. 小记redis持久化的机制

    刚学redis,就经常看到两种持久化机制在眼头晃,RDB和AOF,然而当时学的还知道这两东西是啥玩意,过段时间又忘了,中文记忆这两种概念总感觉有些别扭.今心血来潮翻看redis的配置文件,豁然开朗,仿 ...

随机推荐

  1. 两台Windows Server 2012 R2数据库同步

    文件服务器/备库(192.168.0.1) 数据库服务器/备份文件服务器(192.168.0.2) 数据库实时同步 一.在主数据库服务器里,同样打开隐藏文件,找到C:\ProgramData\MySQ ...

  2. IntelliJ IDEA下git版本回退,版本还原

    原文链接:https://blog.csdn.net/hehyyoulan/article/details/80005272

  3. java开发,入职半年,对未来迷茫,如何发展?

    分享-更多精彩图片尽在大师助手 个人建议,在JAVA方面,先学好JAVA SE.不管如何,基础才是上层建筑的一切.推荐去看jdk源码,推荐1.6或者1.7版本.因为1.8版本的源码中会有很多lambd ...

  4. 好看的css渐变颜色大全网址

    60个渐变颜色 https://webkul.github.io/coolhue/ 60个非常有用的CSS代码片段 https://baijiahao.baidu.com/s?id=160278735 ...

  5. 使用echarts 轻松搞定各种后台数据统计

    之前接到老大一个需求,需要将公私生态系统构建一个日志系统,统计公有云.私有云还有其他工具平台(如禅道,jenkins)的用户登录信息,并使用图标的形式动态显示,之前刚入门的时候接触过echarts 这 ...

  6. Labview学习之路(十一)日常编程技巧

    此文章用于记录自己在学习Labview过程中所用到的编程技巧,会一直更新下去. (一)移动控件 直接鼠标拖动. 按住shift键,鼠标移动,可以水平和竖直移动(取决于鼠标最开始的移动方向). 使用键盘 ...

  7. 【已学完】UGUI Schedule

    章节 内容 签到 Unity4.6 New UI(UGUI) 1.UGUI概述与Canvas画布介绍(一) 5月14日 2.Canvas画布介绍(二) 5月14日 3.Text控件 5月14日 4.I ...

  8. window.location.href跳转无效

    window.location.href跳转无效     问题情况 JS中设置window.location.href跳转无效   原因是 a标签的href跳转会执行在window.location. ...

  9. Java得到指定日期的时间

    //得到指定日期(几天前/几天后)整数往后推,负数往前移动private Date getAppointDay(int num) throws ParseException { DateFormat ...

  10. 一文解开java中字符串编码的小秘密

    目录 简介 Unicode的发展史 Unicode详解 UTF-8 UTF-16 UTF-32 Null-terminated string 和变种UTF-8 简介 在本文中你将了解到Unicode和 ...