《Redis 核心技术与实战》课程学习笔记(二)

数据结构:快速的 Redis 有哪些慢操作

  • 数据库这么多,为啥 Redis 能有这么突出的表现呢?
    • 一方面,因为它是内存数据库,所有操作都在内存上完成,内存的访问速度本身就很快。
    • 另一方面,因为,键值对是按一定的数据结构来组织的,操作键值对最终就是对数据结构进行增删改查操作,所以高效的数据结构是 Redis 快速处理数据的基础。
  • 简单来说,底层数据结构一共有 6 种,分别是简单动态字符串、双向链表、压缩列表、哈希表、跳表和整数数组。
    在这里插入图片描述

键和值用什么结构组织?

  • 为了实现从键到值的快速访问,Redis 使用了一个哈希表来保存所有键值对。
    • 一个哈希表,其实就是一个数组,数组的每个元素称为一个哈希桶。
    • 一个哈希表是由多个哈希桶组成的,每个哈希桶中保存了键值对数据。
    • **哈希桶中的元素保存的并不是值本身,而是指向具体值的指针。**这也就是说,不管值是 String,还是集合类型,哈希桶中的元素都是指向它们的指针。
  • 哈希桶中的 entry 元素中保存了 *key 和 *value 指针,分别指向了实际的键和值,这样一来,即使值是一个集合,也可以通过 *value 指针被查找到。
    在这里插入图片描述
    • 因为这个哈希表保存了所有的键值对,所以,我也把它称为全局哈希表。
    • 哈希表的最大好处很明显,就是让我们可以用 O(1) 的时间复杂度来快速查找到键值对⸺我们只需要计算键的哈希值,就可以知道它所对应的哈希桶位置,然后就可以访问相应的 entry 元素。

为什么哈希表操作变慢了?

  • 当你往哈希表中写入更多数据时,哈希冲突是不可避免的问题。
    • 哈希冲突就是指两个 key 的哈希值和哈希桶计算对应关系时,正好落在了同一个哈希桶中。
    • Redis 解决哈希冲突的方式,就是链式哈希,即同一个哈希桶中的多个元素用一个链表来保存,它们之间依次用指针连接。
      在这里插入图片描述
  • 哈希冲突链上的元素只能通过指针逐一查找再操作。
    • 如果哈希表里写入的数据越来越多,哈希冲突可能也会越来越多,这就会导致某些哈希冲突链过长,进而导致这个链上的元素查找耗时长,效率降低。
    • 对于追求“快”的 Redis 来说,这是不太能接受的。
    • 所以,Redis 会对哈希表做 rehash 操作。
    • rehash 也就是增加现有的哈希桶数量,让逐渐增多的 entry 元素能在更多的桶之间分散保存,减少单个桶中的元素数量,从而减少单个桶中的冲突。
      • 其实,为了使 rehash 操作更高效,Redis 默认使用了两个全局哈希表:哈希表 1 和哈希表 2。
      • 一开始插入数据时,默认使用哈希表 1,此时的哈希表 2 并没有被分配空间。
      • 随着数据逐步增多,Redis开始执行 rehash,这个过程分为三步:、
        • 给哈希表 2 分配更大的空间,例如是当前哈希表 1 大小的两倍;
        • 把哈希表 1 中的数据重新映射并拷贝到哈希表 2 中;
          • Redis 采用了渐进式 rehash。
          • 每处理一个请求时,从哈希表 1 中的第一个索引位置开始,顺带着将这个索引位置上的所有 entries 拷贝到哈希表 2 中;
          • 等处理下一个请求时,再顺带拷贝哈希表 1 中的下一个索引位置的 entries。
        • 释放哈希表 1 的空间。

集合数据操作效率

  • 和 String 类型不同,一个集合类型的值,第一步是通过全局哈希表找到对应的哈希桶位置,第二步是在集合中再增删改查。
  • 集合类型的底层数据结构主要有 5 种:整数数组、双向链表、哈希表、压缩列表和跳表。
    • 压缩列表实际上类似于一个数组,数组中的每一个元素都对应保存一个数据。
      • 和数组不同的是,压缩列表在表头有三个字段 zlbytes、zltail 和 zllen,分别表示列表长度、列表尾的偏移量和列表中的 entry 个数;
      • 压缩列表在表尾还有一个 zlend,表示列表结束。
        在这里插入图片描述
      • 在压缩列表中,如果我们要查找定位第一个元素和最后一个元素,可以通过表头三个字段的长度直接定位,复杂度是 O(1)。
      • 查找其他元素时,就只能逐个查找,此时的复杂度就是 O(N)。
    • 跳表在链表的基础上,增加了多级索引,通过索引位置的几个跳转,实现数据的快速定位。
      在这里插入图片描述
      • 为了提高查找速度,我们来增加一级索引:从第一个元素开始,每两个元素选一个出来作为索引。这些索引再通过指针指向原始的链表。
      • 如果我们还想再快,可以再增加二级索引:从一级索引中,再抽取部分元素作为二级索引。
      • 可以看到,这个查找过程就是在多级索引上跳来跳去,最后定位到元素。
      • 当数据量很大时,跳表的查找复杂度就是 O(logN)。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.hqwc.cn/news/7703.html

如若内容造成侵权/违法违规/事实不符,请联系编程知识网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

spfa求负环

1.虫洞 Wormholes&#xff08;裸spfa判断负环问题&#xff09; 信息学奥赛一本通&#xff08;C版&#xff09;在线评测系统 (ssoier.cn)http://ybt.ssoier.cn:8088/problem_show.php?pid1507 #include<bits/stdc.h> using namespace std; const int N510,M5210; int d…

【Rust】安装

文章目录 1.官网下载2.安装3.安装验证4.打开本地文档5.安装插件6.HelloWorld①新建项目目录使用VSCode打开②新建rs文件③编译④运行 7.HelloCargo①新建项目目录使用VSCode打开②cargo build③cargo run④cargo check⑤为发布构建 8.更新与卸载 1.官网下载 官网地址&#xff…

基于单片机智能手环心率老人防跌倒心率体温 步数里程

功能介绍 以STM32单片机作为主控系统&#xff1b; OLED液晶显示心率体温步数等信息&#xff1b;通过按键设置心率、体温上限设置&#xff1b;当心率或者体温超过按键设置上限蜂鸣器进行声光报警提醒&#xff1b;通过wifi模块esp8266把数据发送到手机端进行显整个电路以5v供电&a…

消息中间件应用场景

提高系统性能首先考虑的是数据库的优化&#xff0c;但是数据库因为历史原因&#xff0c;横向扩展是一件非常复杂的工程&#xff0c;所有我们一般会尽量把流量都挡在数据库之前。 不管是无限的横向扩展服务器&#xff0c;还是纵向阻隔到达数据库的流量&#xff0c;都是这个思路。…

探秘高逼格艺术二维码的制作过程-AI绘画图生图

在之前的文章《AI制作艺术二维码-文生图》中&#xff0c;我介绍了一种直接通过提示词生成高逼格二维码的方法&#xff0c;但是通过提示词我们无法很好的控制生成图片的样式&#xff0c;特别是有些同学想要将自己的Logo或者头像附加到二维码中&#xff0c;要满足这类需求&#x…

Git客户端:Tower for Mac 注册版

Tower是一款Mac OS X系统上的Git客户端软件&#xff0c;它提供了丰富的功能和工具&#xff0c;帮助用户更加方便地管理和使用Git版本控制系统。以下是Tower的一些特点&#xff1a; 1. 界面友好&#xff1a;Tower的界面友好&#xff0c;使用户能够轻松地掌握软件的使用方法。 …

碳排放预测模型 | Python实现基于机器学习的碳排放预测模型——数据清理和可视化

文章目录 效果一览文章概述研究内容源码设计参考资料效果一览 文章概述 碳排放预测模型 | Python实现基于机器学习的碳排放预测模型——数据清理和可视化 研究内容 碳排放被认为是全球变暖的最主要原因之一。 该项目旨在提供各国碳排放未来趋势的概述以及未来十年的全球趋势预测…

tomcat进程注入

跟随上一篇《java进程注入》 这里使用memShell https://github.com/rebeyond/memShell 将agent.jar和inject.jar放到tomcta的web目录下 然后输入命令注入 效果&#xff1a; 注入成功后 可以看到agent.jar文件为了防止发现&#xff0c;自动清除&#xff0c;而且重启电脑之后&…

SpringBoot使用mybatis批量新增500万数据到mysql数据库Demo

SpringBoot使用mybatis批量新增500万数据到mysql数据库Demo 说明项目Demo代码地址项目目录mysql对应表建表语句pom.xmlapplication.yml配置类启动类代码OrderInfo 实体类TestController控制层接口层TestServiceTestServiceImpl实现层TestDao数据接口层dao层对应mapper.xml自定义…

leetcode 226. 翻转二叉树

2023.7.1 这题依旧可以用层序遍历的思路来做。 在层序遍历的代码上将所有节点的左右节点进行互换即可实现二叉树的反转。 下面上代码&#xff1a; class Solution { public:TreeNode* invertTree(TreeNode* root) {queue<TreeNode*> que;if(root nullptr) return{};que…

【Linux】LVS负载均衡群集 DR模式

提示&#xff1a;文章写完后&#xff0c;目录可以自动生成&#xff0c;如何生成可参考右边的帮助文档 LVS负载均衡群集 DR模式 数据包流向分析DR 模式的特点LVS-DR中的ARP问题VIP地址相同导致响应冲突返回报文时源地址使用VIP&#xff0c;导致网关设备的ARP缓存表紊乱 DR模式 L…

VUE3笔记

项目结构 模板语法&#xff08;在标签之外&#xff09; 插值语法 &#xff1a;双大括号 属性绑定&#xff08;在标签之内&#xff09; v-bind: 单属性两种写法 多属性绑定 条件渲染 列表渲染 要有key&#xff0c;降低消耗 遍历数组 遍历对象 事件处理 传递参数 事件修…