Redis小记(一)
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小记(一)的更多相关文章
- Redis 小记
最近感觉自己像是又回到了起点,知识层面上落人太多,尤其是去年早些时候几乎啥也没干成,觉得什么也不会了,只能再次从零开始,所以决定再喝两个疗程的巩固巩固. 话不多说,我们先来看看 Redis 官方是怎么 ...
- 「Nosql」Redis小记-内存解析&内存消耗篇
*博客搬家:初版发布于 2017/08/12 18:32 原博客地址:https://my.oschina.net/sunqinwen/blog/1507171 Redis内存消耗分析 注:本文 ...
- Redis小记(三)
1.复制 通过slaveof命令或设置slaveof选项,实现一个服务器去复制另一个服务器,被复制的是主服务器,执行复制的是从服务器,复制过程中主从双方数据库保持数据一致 2.8版本以前,可分为初次复 ...
- Redis小记(二)
1.redis数据库 redis数据库属于内存数据库,若不将数据存到磁盘中,服务器进程退出,数据也会消失 redis所有数据库都保存在redisServer结构的db数组中,db数组的每一项都是一个r ...
- MongoDB 小记
之前本人说过一款非关系型数据库的代表 Redis 的 < Redis 小记 >文章,觉得意犹未尽,今天就来介绍一款数据库 MongoDB ,先来看一下 MongoDB是一款基于分布式文件存 ...
- Redis Sentinel配置小记
Sentinel是一个管理多个redis实例的工具,它可以实现对redis的监控.通知.自动故障转移.sentinel不断的检测redis实例是否可以正常工作,通过API向其他程序报告redis的状态 ...
- Docker 小记 — MySQL 与 Redis 配置
前言 本篇随笔是继 "Docker Engine" 与 "Compose & Swarm" 之后的一个实例补充,初衷是记录测试环境中的一次 MySQL ...
- Redis 学习小记
由于是学习笔记,我就不来各种啰嗦,介绍这个介绍那个,也不上交给国家,或者各种对比,相信如果你真心用 redis 的话,就不会去跟 MySql,Memcached,MongoDB 等做对比了. 我原先用 ...
- 小记redis持久化的机制
刚学redis,就经常看到两种持久化机制在眼头晃,RDB和AOF,然而当时学的还知道这两东西是啥玩意,过段时间又忘了,中文记忆这两种概念总感觉有些别扭.今心血来潮翻看redis的配置文件,豁然开朗,仿 ...
随机推荐
- 【译】Introducing “Web Live Preview”
如果你开发的应用有 UI,你可能经历开发->编译->测试->修改->编译->测试的循环.根据所使用的框架或技术,有些可以改善这一流程,比如 edit-and-contin ...
- 2. Bean Validation声明式校验方法的参数、返回值
你必须非常努力,才能干起来毫不费力.本文已被 https://www.yourbatman.cn 收录,里面一并有Spring技术栈.MyBatis.JVM.中间件等小而美的专栏供以免费学习.关注公众 ...
- C#还原对图像做的修改
在C#程序中对图像进行处理,有的时候需要将处理后的图像还原,便于观察两者之间的区别,避免重新运行程序造成的麻烦.我是将之前写的Tab页中打开的图像进行还原,将原始图像数据保存在数据流中,然后从数据流中 ...
- oeasy教您玩转linux010102查看发行版
查看发行版distro 回忆上次内容 从帮助咱们可以知道 name -a 可以得到全部信息 uname -a 从中,咱们知道有ubuntu,他好像是一种发行版. 那么,什么是发行版呢? 什么是发行版?
- 分数运算(gcd)
时间限制 1000 ms 内存限制 32768 KB 代码长度限制 100 KB 判断程序 Standard (来自 小小) 题目描述 计算机中采用浮点数表示所有实数,但这意味着精度丢失.例如无法精确 ...
- 04_Python中的35个关键字
查看Python中的关键字 import keyword print(keyword.kwlist) # 返回一个包含Python关键字的列表 """执行结果 ...
- Java使用JDBC连接Oracle数据库
import java.sql.Connection; import java.sql.Driver; import java.sql.DriverManager; /** * @author liu ...
- Java中枚举的用法
public enum Week { DAY1("周一", 0.9), DAY2("周二", 0.9), DAY3("周三", 0.8), ...
- 抽象工厂模式详解 —— head first 设计模式
项目实例 假设你有一家 pizza 店,你有很多种 pizza,要在系统中显示你所有 pizza 种类.实现这个功能并不难,使用普通方式实现: public class PizzaStore { Pi ...
- 吴恩达《深度学习》-第三门课 结构化机器学习项目(Structuring Machine Learning Projects)-第一周 机器学习(ML)策略(1)(ML strategy(1))-课程笔记
第一周 机器学习(ML)策略(1)(ML strategy(1)) 1.1 为什么是 ML 策略?(Why ML Strategy?) 希望在这门课程中,可以教给一些策略,一些分析机器学习问题的方法, ...