Redis----数据结构

一.认识Redis

什么是Redis

一款基于内存的非关系型数据库,对数据的读写操作都是在内存中完成的,具有高性能 高并发的特点,可以用来作为缓存降低mysql数据库的压力,还可以用来做分布式锁 以及轻量级消息队列等

与Memcached的区别

具备许多Memcached不具备的功能,多种可满足不同需求的数据类型,数据持久化,原生集群

为什么用 Redis 作为 MySQL 的缓存

Redis具有高性能与高并发的特性 可以提前将部分MySql中存储的数据存储到 Redis中 进行数据访问时直接访问Redis即可 即使在高并发的场景下也可以做到较 快的响应速度 避免大量请求直接访问MySql导致服务宕机

二.Redis中的数据结构

Redis具有哪些基础数据结构

Redis具有七种基础数据结构,其中六种基本数据结构以及RedisObject,Redis中的所有数据类型都封装在RedisObject中

SDS动态字符串

Redis是利用C语言开发的 由于c语言原生的字符串具有非二进制安全,不可修改等缺点,构建了全新的字符串结构 SDS动态字符串

SDS实际是C语言中的结构体 分为Header与 字符串数组两部分 实际数据保存在字 符数组中Header中保存 字符串已经占用的字节数 申请的总字节数 SDS类型(控 制可保存数据的上限) 通过头信息可以可以直接得知数组长度无需再受'\0'的影响 还具有 动态扩容的能力 解决了c语言原生字符串 不可修改 二进制安全等问题

动态扩容: 当SDS申请的空间不足以容纳要添加的新字符串时则会申请新的内存空间 根据 新字符串的大小还会有不同的申请方式(小于1M 新字符串长度2倍+1 大于1M 新字符串长度+1M+1)

IntSet 整数数组

InSet结构体 encoding编码方式决定存放整数大小范围 length记录存放元素个数 contents指针 指向实际数组起始地址 长度可变 有序

编码升级:当即将添加的元素超过了当前编码方式每个元素可表示的范围,就会发生编码升级,每个元素占用的字节数会改变,按新的编码方式进行数组扩容,倒序将数组中的旧元素拷贝到正确位置(正序拷贝会覆盖原数据),将待添加的元素添加到末尾 最后更改结构体中的encoding(编码方式) 以及length

Inset的元素是唯一有序的,具备升级机制,当元素小时采用占用内存空间小的编码方式元素过大时才会升级编码节省内存空间,底层采用二分查找查询元素,不适合存储大量数据,数据量大查询效率低 且InSet申请的是连续内存空间 数据量大时不便申请较大的连续内存空间

Dict字典(数组+单向链表)

Dict内部维护了一个指向哈希表数组的指针,实际数据都存储在哈希表数组的元素DictEntry中,每个节点都包含key value next(哈希冲突时 升级成链表),内部有两张哈希表,一张用于存储现有数据另一张用于rehash

Rehash:当负载因子(哈希数组长度/已存储元素) >=1,表示hash数组已存满,再存储数据必然会出现哈希冲突升级为链表,避免链表出现,链表过长影响存储性能,则需要进行rehash;rehash的时机: Redis本身没有进行需要消耗算力资源的后台进程例 如 BGSAVE(异步RDB持久化) BGREWRITEAOF(AOF重写)或负载因子大于5 直接扩容;当删除元素时,检查负载因子,负载因子<0.1时 哈希表收缩

渐进式rehash: 当哈希表负载因子超过阈值时,会分配一个更大的新哈希表 ht[1],并设置 rehashidx=0标记迁移起点;随后在每次数据访问时,Redis 会顺带将 ht[0]rehashidx 位置的键值对迁移到 ht[1],并递增rehashidx,同时新数据直接写入 ht[1](如果有数据写入操作);当所有数据迁移完成后,释放 ht[0] 并将 ht[1] 设为新的主表,完成平滑扩容或缩容。避免因扩容造成阻塞,Redis对底层数据结构优化的代表性实例。

Dict字典,底层利用hash表存储数据,精确查询性能好,但会产生内存碎片,且内部维护了较多指针,指针本身会占据较多内存空间

ZipList压缩链表

便于首尾操作:每个元素占用空间不定需要多少占多少节省内存,连续内存空间 头部维护了几个变量分别记录了当前ZipList占用的总内存空间,尾偏移量记录尾节点距离其实地址有多少字节,可以确定尾节点地址;由于头部变量占用的字节数固定,且记录了链表总占用内存空间,以及尾偏移量记录了起始到最后一个起点起始之间的空间,所以可以方便的得出第一个元素与最后一 个元素的地址,便于头尾操作

Entry内部结构: previous 记录前一个节点的总长度 encoding编码属性 记录 contents的数据类型(字符串或整数) 以及contents的长度 contents 节点保存的数据;既不满足数组遍历规律也不满足链表遍历规律,通过记录每个节点的长度遍历

缺点: 连续内存空间不便于存储大量数据,随机读取性能差,存在连锁更新问题

连锁更新: 若一个ZipList中保存了N个连续的长度为250~253字节的entry其长度,刚好不超过254 则每个entry只需要1字节记录上一个entry的长度,假如此时在第一个entry前插入了一个,长度大于等于254字节的元素,那么此时该entry的长度用1字节就无法表示,需要用5 字节表示,那么下一个entry的pre就由1字节变更为5字节,那么其本身的长度也会增大,表示其长度也需要5字节,就导致了联锁反应,之后的每个entry都需要改变其占用的内存空间,导致频繁的产生内存的申请销毁数据迁移

QuickList(双端链表,每个节点都是一个ZipList)

解决ZipList无法保存大量数据的问题,数据分片思想

ZipList虽然节省内存,但其申请的内存必须是连续空间,若其需要存储较大的数据量,则需要一大块连续的内存空间,而内存往往是分散、碎片化的,申请大块连续内存的效率很低

双端链表,QuickList每个节点都是一个ZipList,将数据分片储存在单个ZipList当中,解决了ZipList难以存储大量数据的缺点

QuickList: 节省内存,但每个节点占用的内存空间无法确定,无法随机访问只能顺序遍历或倒序遍历,不具备随机读取的能力;QuickList可以对节点ZipList进行压缩由于首位访问需求大,首位不压缩,压缩中间部分进一步节省内存

SkipList跳表

建立多级指针,指针跨度不同 牺牲存储空间 换取随机读写能力

SkipList首先是链表,但与传统链表不同,建立了多层指针,不同层指针跨度不同,通过建立多级指针,以牺牲部分存储空间为代价,换取随机读写能力较大的提升

RedisObject

Redis中所有数据类型都被封装在RedisObject中,也叫Redis对象

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值