2023.12.21 关于 Redis 常用数据结构 和 单线程模型

目录

各数据结构具体编码方式

查看 key 对应 value 的编码方式

Reids 单线程模型

经典面试题

IO 多路复用


Redis 常用数据结构

  • Redis 中所有的 key 均为 String 类型,而不同的是 value 的数据类型却有很多种
  • 以下介绍 5 种 value 常见的数据类型

2023.12.21 关于 Redis 常用数据结构 和 单线程模型_第1张图片

注意:

  • 上述的 有序集合 相当于是除了存储 member 之外,还需要存储一个 score
  • 而此处的 socre(分数) 相当于有序集合的 权重

各数据结构具体编码方式

  • Redis 是一种非关系型的数据库,它的底层实现了一些特定的优化,即 通过选择合适的 数据结构 和 编码方式,以便达到节省时间 和空间的效果

实例理解

  • Redis 在实现 哈希表时 可能会根据特定的场景和需求 选择使用不同的数据结构,而不仅仅是标准的哈希表
  • 但是无论使用哪种数据结构,Redis 都承诺查询、插入、删除操作的时间复杂度为 O(1)

数据结构:

  • redis 承诺给你提供使用的,也可以理解成 数据类型

编码方式:

  • redis 数据结构 内部底层的实现
  • 同一个数据结构 可能背后的编码方式是不同的,会根据特定场景优化

2023.12.21 关于 Redis 常用数据结构 和 单线程模型_第2张图片


注意:

  • redis 会自动根据当前的实际情况来选择内部编码方式,即自适应
  • 那么是否要记住 什么情况下 使用 什么编码方式 呢?
  • 只记思想,不记数字,记数字没有任何意义

原因:

  • 数字都是可自行配置的
  • 数字是怎么来的,这点需要考证清楚
  • 相比于知道数字,更重要的是知道数字是怎么得到的,就可以根据所处的实际场景,重新得到这样的数字

正确做法:

  • 根据实际的测试结果,测试出一个更合适的数值

查看 key 对应 value 的编码方式

语法:

object encoding key 

实例理解

2023.12.21 关于 Redis 常用数据结构 和 单线程模型_第3张图片

Reids 单线程模型

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

实例理解

  • 假设有多个客户端,同时操作一个 redis 服务器,且这两个客户端 并发 的发起请求

2023.12.21 关于 Redis 常用数据结构 和 单线程模型_第4张图片

  • 在多线程场景下针对类似于这样的情形
  • 即 两个线程尝试同时对同一个变量进行自增操作,虽然表面上看是自增两次,但实际上可能只自增了一次
  • 但是由图可知 我们的 redis 服务器并不会存在类似的线程安全问题

原因:

  • Redis 服务器实际上是 单线程模型
  • 即保证了 服务器收到多个请求时,并会 并发执行这多个请求,而是 串行/顺序执行

补充:

  • Redis 之所以能够使用 单线程模型 也能很好的工作,其原因主要在于 Redis 的核心业务逻辑都是短平快的
  • 短 指的是 Redis 的每个操作都很简单平 指的是 Redis 的操作都很稳定快 指的是 Redis 的操作都很快
  • 所以 Redis 不太需要消耗 CPU 资源,从而也就不太需要 利用多核来提高效率了

弊端:

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

经典面试题

  • redis 虽然是单线程模型,但为啥效率这么高呢? 速度这么快呢?

注意:

  • 此时我们的 参照物 是相对于 数据库 而言

1、redis 访问内存,而数据库访问的是硬盘

  • 内存的访问速度 要远远大于 硬盘的访问速度

2、redis 核心功能 比 数据库的核心功能更简单

  • 数据库 对于数据的插入删除查询 均支持更复杂的功能
  • 这样的功能必然需要花费更多的开销比如针对插入删除,加之数据库中的各种约束,这都会使数据库做更多额外的工作
  • redis 干的活少,因此 redis 所提供的功能相较于 mysql 也是少了很多

3、单线程模型,避免了一些不必要的线程竞争开销

  • redis 的每个操作基本都是短平快的,即简单操作一下内存数据,并不需要消耗大量的 cpu 资源
  • 所以就算搞个多线程,对效率的提升也是不大

4、处理网络 IO 的时候,使用了 epoll 这样的 IO 多路复用机制

  • IO 多路复用本质上为一个线程可以管理多个 socket

实例理解

  • 针对 TCP 来说,每当服务器要服务一个客户端时 均需要给该客户端安排一个 socket
  • 一个服务器 服务多个客户端时,便会有多个 socket

问题:

  • 这些 socket 上都是无时不刻的在传输数据吗?

具体理解:

  • 很多情况下,每个客户端和服务器之间的通信 并不会特别频繁
  • 所以多数 socket 大部分时间都是静默的,即没有数据需要进行传输

实际情况:

  • 综上所述 对于 TCP 服务器来说,大部分 socket 都是静默的,仅只有少数 socket 是活跃的,即会进行数据传输
  • 消耗大量系统资源的同时,大量的线程 占着茅坑不拉屎由此可见效率十分低下

IO 多路复用

  • 基于上述的场景,便有了 IO 多路复用机制,即一个线程来处理多个 socket
  • 这是 操作系统给程序员提供的机制
  • 同时操作系统也提供了一套 API ,其内部的功能均由操作系统内核实现的
  • Linux 上提供的 IO 多路复用,主要是三套 API (select、poll、epoll),其中 epoll 的运行效率最高

实例理解:

  • 此时我晚饭想吃三样美食,均在同一条街道上

方案一:

  • 一个一个买

2023.12.21 关于 Redis 常用数据结构 和 单线程模型_第5张图片

  • 相当于单线程串行执行,效率最低

方案二:

  • 我喊了两个好友,来帮我一起买

2023.12.21 关于 Redis 常用数据结构 和 单线程模型_第6张图片

  • 相当于多线程并行执行,效率大大提升,但是系统开销大了

方案三:

  • 我一个人来买,但是我买的时候不再干等着了

2023.12.21 关于 Redis 常用数据结构 和 单线程模型_第7张图片

  • 此时相当于一个线程同时做三件事
  • 能高效完成这三件事的前提是 这三件事的交互都不频繁,大部分时间都在等待!
  • 此处的  ' 哪样美食好了 哪个老板就喊我一声 '  相当于 epoll,即事件 通知/回调 机制

注意:

  • 如果这三件事情都是交互特别频繁的,还是需多引入几个线程,否则一个线程就容易忙不过来

补充:

  • Java 可以使用 NIO (标准库提供的一组类,底层就是封装了 epoll)

你可能感兴趣的:(Redis,redis,数据结构,哈希算法)