当前位置: 首页 > ops >正文

Redis:常用数据结构 单线程模型

🌈 个人主页:Zfox_
🔥 系列专栏:Redis

🔥 常用数据结构

🐳 Redis 当中常用的数据结构如下所示:
在这里插入图片描述
Redis 在底层实现上述数据结构的过程中,会在源码的角度上对于上述的内容进行特定的优化,这样的优化的主要目的是为了实现出节省时间和节省空间的效果,具体的优化方法当然还是要看的是具体的内容

Redis 在外部承诺,对于哈希表来说,保证用户在进行增删查改这些操作都能保证是O(1),但是具体内部的实现来说,其实并不是一个传统意义的哈希表,在特定的实现场景下会使用其他的数据结构来实现,但是总体上来说,还是能够保证时间复杂度是满足具体的要求的

所以我们说,对于 Redis 内部的数据结构或者说是数据类型来说,这是 Redis 承诺给用户的,但是在其内部的实现中,可能会不同,具体的方式是有编码方式来进行决定的,因此换句话说,对于同一个数据结构来说,内部会有不同的实现方式,在不同的场景下会使用不同的方式,但是作为上层的使用者,其实是感知不到这样的存在的

那么下面我将会进行分析,不同的数据结构内部代表的意义是什么,以及是如何进行场景优化的

🦋 Redis 的编码方式

在这里插入图片描述

string

先说 string 类型,这个类型并不陌生,就是一个字符串类型,在内部编码的角度来讲:

  1. 如果采用的是 raw,表示的是最基本的字符串,它的底层就是一个 char 的数组
  2. 而如果采用的是 int 的编码方式,则对应的场景可能是要使用一些类似于计数的功能,那么此时作为 Value 值,其实使用传统意义的字符是没有意义的,直接使用整数int来保存是一个更好的解决方案
  3. 如果采用的是 embstr,则表示的是针对于短字符串进行的特殊优化,这里就不再过多描述

hash

  1. hash 这种数据类型,或者说是数据结构,是有两种编码方式的,第一种是 hashtable,这种实现方式就是最基本的实现方式,Redis 内部也是用这种最基本的方式来实现的,虽然这里的实现方式和前面的不太一样,但是也大体思维差不多
  2. 而对于一些元素比较少的时候,如果还使用哈希表其实是没有意义的,因此就会把对应的编码方式更换为 ziplist,它的主要目的可以进行列表的压缩,这样可以节省空间

🦋 压缩的意义?

那到此,可能会关心的问题是,为什么要进行压缩?意义在哪呢?因为 Redis 内部是有很多的 key 值的,这就意味着对于某些 key 的 Value 是一个 hash,所以当 key 值比较多的时候,对应的 hash 结构也会比较多,但是每一个 hash 的实际占用其实不大,因此就可以选择去尽量的压缩,这样压缩后就可以使得整体上的占用变的比较少了

list

对于list来说,有两种实现的方式,一种是 linkedlist,也就是传统意义上的 list,而另外一个表示的是压缩列表,但是从 Redis 3.2 开始,采用的是一个全新的方式,叫做 quicklist,它可以综合前面的两种类型,这样就针对于空间和效率折中进行实现的

set

对于 set 来说,也有两种实现,第一个是传统意义的实现,第二个表示的是 intset,如果都是使用的 int 类型的数据,那么内部就会选择这种情况

zset

  1. skipset,是跳表,每个节点上有多个指针域,可以快速定位到类型,最终使得搜索效果完成到二叉搜索树的效果,这里不再赘述,前面的内容中已经有对应的策略~
  2. ziplist:压缩
    查看方式
object encoding xxx

Redis 内部,会通过具体的实际情况来调整内部的编码方式,自动进行适应

🔥 单线程架构

Redis使⽤了单线程架构来实现⾼性能的内存数据库服务,本节⾸先通过多个客户端命令调⽤的例⼦说明Redis单线程命令处理机制,接着分析Redis单线程模型为什么性能如此之⾼,最终给出为什么理解单线程模型是使⽤和运维Redis的关键。

Redis 只使用一个线程处理所有的命令请求,不是说一个 Redis 服务器进程内部真的就只有一个线程其实也有多个线程, 多个线程是在处理 网络 IO

🦋 引出单线程模型

现在开启了三个redis-cli客户端同时执⾏命令。

127.0.0.1:6379> set counter 1

客户端2对counter做⾃增操作:

127.0.0.1:6379> incr counter

客户端3对counter做⾃增操作:

127.0.0.1:6379> incr counter

客户端1设置⼀个字符串键值对:我们已经知道从客⼾端发送的命令经历了:发送命令、执⾏命令、返回结果三个阶段,其中我们重点关注第2步。我们所谓的Redis是采⽤单线程模型执⾏命令的是指:虽然三个客⼾端看起来是同时要求Redis去执⾏命令的,但微观⻆度,这些命令还是采⽤线性⽅式去执⾏的,只是原则上命令的执⾏顺序是不确定的,但⼀定不会有两条命令被同步执⾏,如图2-3、2-4、2-5所⽰,可以想象Redis内部只有⼀个服务窗⼝,多个客⼾端按照它们达到的先后顺序被排队在窗⼝前,依次接受Redis的服务,所以两条incr命令⽆论执⾏顺序,结果⼀定 是2,不会发⽣并发问题,这个就是Redis的单线程执⾏模型。

在这里插入图片描述
在这里插入图片描述

Redis 能够使用 单线程模型 很好的工作, 原因主要在于 Redis 的核心业务逻辑,都是短平快的~~ 不太消耗 cpu 资源也就不太吃多核了!!!

弊端!!
Redis 必须要特别小心, 某个操作占用时间长, 就会阻塞其他命令的执行!

🦋 为什么单线程还能这么快

  1. 纯内存访问。Redis将所有数据放在内存中,内存的响应时⻓⼤约为100纳秒,这是Redis达到每秒万级别访问的重要基础。
  2. Redis 核心功能,比数据库的核心功能更简单,Redis 干的活少,提供的功能相比于 mysq 也是少了不少!
  3. ⾮阻塞IO。Redis使⽤epoll作为I/O多路复⽤技术的实现,再加上Redis⾃⾝的事件处理模型将epoll中的连接、读写、关闭都转换为事件,不在⽹络I/O上浪费过多的时间
  4. 单线程避免了线程切换和竞态产⽣的消耗。单线程可以简化数据结构和算法的实现,让程序模型更简单;其次单线程避免了在线程竞争同⼀份共享数据时带来的切换和等待消耗

🦋 弊端

虽然单线程给Redis带来很多好处,但还是有⼀个致命的问题:对于单个命令的执⾏时间都是有要求的。如果某个命令执⾏过⻓,会导致其他命令全部处于等待队列中,迟迟等不到响应,造成客户端的阻塞,对于Redis这种⾼性能的服务来说是⾮常严重的,所以Redis是⾯向快速执⾏场景的数据库

🔥 共勉

😋 以上就是我对 Redis:常用数据结构 & 单线程模型 的理解, 觉得这篇博客对你有帮助的,可以点赞收藏关注支持一波~ 😉
在这里插入图片描述

http://www.xdnf.cn/news/10776.html

相关文章:

  • 多线程编程中的数据竞争与内存可见性问题解析
  • [Java 基础]变量,装东西的盒子
  • 基于QwenAgent解锁Qwen3无思考高效模式:vLLM部署实战与Ollama模板定制
  • 美尔斯通携手北京康复辅具技术中心开展公益活动,科技赋能助力银龄健康管理
  • RabbitMQ在SpringBoot中的应用
  • 六步完成软件验收:从计划到终验的全面指南(二)
  • smartGit 试用突破30天
  • HCIP(BGP基础)
  • 工厂方法模式深度解析:从原理到应用实战
  • 【灵动Mini-F5265-OB】vscode+gcc工程创建、下载、调试
  • Unity——QFramework框架 内置工具
  • 强制卸载openssl-libs导致系统异常的修复方法
  • 无人机智能识别交通目标,AI视觉赋能城市交通治理新高度
  • 【OCCT+ImGUI系列】012-Geom2d_AxisPlacement
  • EPSON差分晶振X1G005331000100,SG7050VEN晶振6G无线应用
  • JVM简介
  • 二叉树(二)
  • 深入理解前端DOM:现代Web开发的基石
  • Ansys Zemax | 手机镜头设计 - 第 4 部分:用 LS-DYNA 进行冲击性能分析
  • Android Native 内存泄漏检测全解析:从原理到工具的深度实践
  • 提取 PDF 文件中的文字以及图片中的文字
  • 从 iPhone 备份照片: 保存iPhone图片的5种方法
  • 计算机基础知识(第三篇)
  • 如何监测光伏系统中的电能质量问题?分布式光伏电能质量解决方案
  • [Java 基础]运算符,将盒子套起来
  • 如何提高工作效率
  • 企业即时通讯平台,助力企业数字化转型的即时通讯工具
  • 【AI Study】第三天,Python基础 - NumPy(1)
  • 【设计模式-4.7】行为型——备忘录模式
  • 欢乐熊大话蓝牙知识14:用 STM32 或 EFR32 实现 BLE 通信模块:从0到蓝牙,你也能搞!