Redis 底层结构解析

Redis 的实现原则

单线程+多路IO复用

1、常用五大数据类型 - 底层结构解析

1.1 String 类型

Redis 实现字符串的数据结构是 SDS,其是二进制安全的,意味着 Redis 的 string 可以包含任何数据。比如 jpg 图片或者序列化的对象。

二进制安全和SDS详解

1.1.1 原子性

定义:原子操作是指不会被线程调度机制打断的操作。
分两种场景分析:
1、单线程环境下,能够在单条指令中完成的操作就叫原子操作,因为中断只能发生在指令之间。
☆单条指令应该是单条机器指令,那么 incrby key 的自增+1操作是解析成单条的机器指令?还是指单条的代码指令
2、多线程环境下,不能被其他线程打断的操作就叫原子操作。

Redis 单命令的原子性主要得益于 Redis 的单线程。

原子性的应用案例:
1、java 中的 i++ 是否是原子操作?
不是。
2、i = 0;两个线程分别对 i 进行 100 次 i++,不考虑 cpu 的调度策略下,i 的理论范围是多少?
2 ~ 200。

1.2 List 类型 - 单键多值

Redis 列表是简单的字符串列表,按照插入顺序排序。你可以添加一个元素到列表的头部(左边)或者尾部(右边)。
它的底层实际是个双向链表,对两端的操作性能很高,通过索引下标的操作中间的节点性能会较差。

跳跃列表(skipList)、压缩列表(zipList)和快速列表(quicklist)
Redis 实现 List 的数据结构是快速链表 quickList。首先在列表元素较少的情况下会使用一块连续的内存存储,这个结构是 ziplist,也即是压缩列表。
它将所有的元素紧挨着一起存储,分配的是一块连续的内存。当数据量比较多的时候才会改成 quicklist。

因为普通的链表需要的附加指针空间太大,会比较浪费空间。比如这个列表里存的只是 int 类型的数据,结构上还需要两个额外的指针 prev 和
next。
在这里插入图片描述
Redis 将链表和 ziplist 结合起来组成了 quicklist。 也就是将多个 ziplist 使用双向指针串起来使用。这样既满足了快速的插入删除性能,又不会出现太大的空间冗余。

1.3 Set 类型 - 集合

Redis set 对外提供的功能与 list 类似是一个列表的功能 ,特殊之处在于 set 是可以自动去重的,当你需要存储一个列表数据,又不希望出现重复数据时,set 是一个很好的选择,并且 set 提供了判断某个成员是否在一个 set 集合内的重要接口,这个也是 list 所不能提供的。

Redis 的 Set 是 string 类型的无序集合。它底层其实是一个 value 为 null 的 hash 表,所以添加,删除,查找的复杂度都是0(1)
一个算法,随着数据的增加,执行时间的长短,如果是0(1),数据增加,查找数据的时间不变。

Redis 实现 Set 的数据结构是哈希表。Java 中 HashSet 的内部实现使用的是 HashMap,只不过所有的value都指向同一个对象。Redis 的 set 结构也是一样,它的内部也使用 hash 结构,所有的 value 都指向同一个内部值。

1.4 Hash 类型 - 哈希

Redis hash 是一个 string 类型的 field 和 value 的映射表,hash 特别适合用于存储对象。类似 Java 里面的Map<String.Object>。用户ID为查找的 key,存储的 value 用户对象包含姓名,年龄,生日等信息,如果用普通的 key/value 结构来存储。
Hash 类型对应的数据结构是两种: ziplist (压缩列表),hashtable (哈希表)。当 field-value 长度较短且个数较少时,使用 ziplist, 否则使用hashtable.。

1.5 Zset 类型

SortedSet (zset)是 Redis 提供的一个非常特别的数据结构,一方面它等价于 Java 的数据结构 Map<String,Double>,可以给每一个元素 value 赋予一个权重 score,另一方面它又类似于 TreeSet,内部的元素会按照权重 score 进行排序,可以得到每个元素的名次,还可以通过 score 的范围来获取元素的列表。

zset底层使用了两个数据结构:
1、hash:hash的作用就是关联元素 value 和权重 score,保障元素 value 的唯一性,可以通过元素 value 找到相应的 score 值。
2、跳跃表:跳跃表的目的在于给元素 value 排序,根据 score 的范围获取元素列表。

1.5.1 跳跃表(跳表)

1、简介
  有序集合在生活中比较常见,例如根据成绩对学生排名,根据得分对玩家排名等。对于有序集合的底层实现,可以用数组、平衡树、链表等。数组不便元素的插入、删除;平衡树或红黑树虽然效率高但结构复杂;链表查询需要遍历所有效率低。Redis 采用的是跳跃表。跳跃表效率堪比红黑树,实现远比红黑树简单。
2、实例
对比有序链表和跳跃表
(1)、有序链表
在这里插入图片描述
链表中查询的时间复杂度O(n)

(2)、跳跃表
在这里插入图片描述
检索步骤:
1、从第2层开始,1节点比51节点小,向后比较。
2、21节点比51节点小,继续向后比较,后面就是NULL了,所以从21节点向下到第1层
3、在第1层,41节点比51节点小,继续向后,61节点比51节点大,所以从41向下
4、在第0层,51节点为要查找的节点,节点被找到,共查找4次。
跳跃表中查询的时间复杂度O(logn)。

2、Redis 的发布和订阅

2.1.什么是发布和订阅

Redis 发布订阅 (pub/sub) 是一种消息通信模式:发送者 (pub) 发送消息,订阅者 (sub) 接收消息。

Redis 客户端可以订阅任意数量的频道。

2.2.Redis的发布和订阅

1、客户端可以订阅频道如下图
在这里插入图片描述
2、当给这个频道发布消息后,消息就会发送给订阅的客户端
在这里插入图片描述

2.3.发布订阅命令行实现

1、打开一个客户端订阅channel1
SUBSCRIBE channel1
在这里插入图片描述
2、打开另一个客户端,给channel1发布消息hello
publish channel1 hello
在这里插入图片描述
返回的1是订阅者数量
3、打开第一个客户端可以看到发送的消息
在这里插入图片描述
注:发布的消息没有持久化,如果在订阅的客户端收不到hello,只能收到订阅后发布的消息

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值