Java 面试宝典:Redis 的线程模型是怎么样的?

大家好,我是大明哥,一个专注「死磕 Java」系列创作的硬核程序员。
本文已收录到我的技术网站:https://www.skjava.com。有全网最优质的系列文章、Java 全栈技术文档以及大厂完整面经


Redis 的线程模型其实是分两块的:

  1. Redis 6.0 之前的单线程模型。其实从 4.0 开始,Redis 并不是严格意义上的单线程模型,因为 Redis 除了主线程外,也有一些后台的线程或者子进程在处理任务(例如清理脏数据、生成快照、AOF 重写),这个时候大家所说的单线程应该是 Redis 的主线程模型。
  2. Redis 6.0 之后的多线程模型。Redis 在 6.0 之后引入了一种多线程模型,用于处理网络 I/O 的任务。

所以,你的回答要涉及这两个方面。

  • Redis 的单线程是指Redis 在执行一次命令时是单线程的。其过程包括「接收客户端请求 -> 解析请求 ->数据读写等操作->返回结果给客户端」,这个过程是由一个主线程来完成的,这也是我们常说 Redis 是单线程的原因。Redis 的模型是基于单线程事件驱动模型,内部使用文件事件处理器,而这个文件事件处理是单线程的,也就决定了 Redis 是单线程的。其核心原理是:采用 IO多路复用机制同时监听多个 socket,将产生事件的 socket 压入内存队列中,事件分派器根据 socket 上的事件类型来选择对应的事件处理器进行处理。
  • 随着底层网络硬件越来越好,Redis 的性能瓶颈逐渐体现在网络 I/O 的读写上,单个线程处理网络 I/O 读写的速度跟不上底层网络硬件执行的速度。所以为了提高 Redis 的性能,在 Redis 6.0 引入多线程模型,该多线程模型只用来处理网络数据的读写和协议解析,执行读写命令的仍然是单线程。

Redis 线程模型详解

Redis 的单线程模型

Redis 的单线程是指Redis 在执行一次命令时是单线程的。Redis 客户端与服务端的模型可以简化如下图:

步骤2 执行命令为单线程,其过程包括「接收客户端请求 -> 解析请求 ->数据读写等操作->返回结果给客户端」,这个过程是由一个主线程来完成的,这也是我们常说 Redis 是单线程的原因。

从 Redis 的内部设计来说,Redis 是基于 Reactor 模式开发了自己的网络事件处理器,这个处理器称之为文件事件处理器,而这个文件事件处理器是单线程的,这就决定了 Redis 是单线程的。文件事件处理器包含 5 个部分:

  • 多个 socket:Redis 网络通信的起点,Redis 服务器为每个连接的客户端维护一个套接字,用于接收请求和发送响应。
  • IO 多路复用程序:文件事件处理器的核心。它负责监控所有套接字并确定哪些套接字准备好进行读写操作。
  • 任务队列:处理的任务的队列。
  • 文件事件分派器:当 I/O 多路复用程序确定某个套接字准备好读写时,文件事件分派器负责将这个事件分派给相应的事件处理器。
  • 事件处理器:Redis 对不同类型的文件事件定义了相应的事件处理器。当特定类型的事件发生时,对应的事件处理器会被触发以处理这些事件。

多个 socket 会产生不同的操作,每个操作对应一个不同的文件事件, IO 多路复用程序会监听多个 socket,将产生的事件放入到任务队列中排队,文件事件分派器每次从任务队列中获取一个事件,将其转发给对应的事件处理器进行处理。如下:

客户端与 Redis 服务端建立连接的过程

  • Redis sever 启动时,会把 AE_READABLE 事件与连接应答处理器关联。
  • 当客户端向 Redis 发起连接时,这是 Server Socket 会产生一个 AE_READABLE 事件,IO 多路复用程序监听到该事件后将 socket信息压入到任务队列中。
  • 文件事件分派器每次从任务队列中取一个 socket ,将其交给事件处理器,由于在 Redis 初始化时 AE_READABLE 是与连接应答处理器关联,所以就由连接应答处理器来处理该事件。
  • 连接应答处理器会创建一个与该客户端通信的 Socket(我们这里叫 socket1),并将 socket1 的 AE_READABLE 事件与命令请求处理器关联。

客户端发送请求给 Redis 服务端过程

  • 客户端发送读写请求(比如 set key value)给服务端,首先会在对应的 Socket(socket1)上面产生一个 AE_READABLE事件,IO 多路复用程序监听到该事件后将 socket信息压入到任务队列中。
  • 文件事件分派器从任务队列中取 Socket 信息转发给事件处理器,由于建立连接时 socket1 的 AE_READABLE 事件已经与命令请求处理器关联了,所以文件事件分派器将命令请求处理器。
  • 命令处理器读取该 Socket 的相关信息后执行相关命令,操作完成后,会将 socket01 的 AE_WRITABLE 事件与命令回复处理器关联。

  • 如果客户端已经准备好了接收结果,那么 socket1 会产生一个 AE_WRITABLE,IO 多路复用程序将 Socket 压入队列,然后由文件事件派发器转发给事件处理器。
  • 由于 socket1 的AE_WRITABLE 事件与命令回复处理器关联,所以由命令回复处理器处理,命令回复处理器将准备好的相应数据写入socket01(socket连接是双向的),返回给客户端,之后解除 socket01 的 AE_WRITABLE 事件与命令回复处理器的关联。

Redis 的 I/O 多线程模型

我们 Redis 是基于内存操作,内存的响应时长大约为 100 纳秒,单线程的 Redis 处理数据的极限是 80,000 到 100,000 QPS,对于绝大多数的场景来说,单线程的 Redis 其实是已经够用了。

但是,随着底层网络硬件越来越好,Redis 的性能瓶颈逐渐体现在 I/O 的读写上(CPU 从来都不是 Redis 的性能瓶颈),单个线程处理网络 I/O 读写的速度跟不上底层网络硬件执行的速度。所以,为了提高 Redis 的整体性能,在 6.0 引入多线程,注意,引入的多线程模型只⽤来处理处理网络数据的读写和协议解析,对于 Redis 的读写命令,依然是单线程处理

Redis 6.0 引入 I/O 多线程模型后,将一个命令的执行分为了两部分:

  • Socket 读写和请求解析使用多线程处理,多个 socket 读写可以并⾏化
  • 执行请求依然还是使用主线程,存内存操作,在高效的同时也保证了安全性。

主要流程如下:

  1. 主线程负责接收并建立(多个)连接请求,获取 socket 后放入全局等待处理队列;
  2. 主线程处理完这些事件之后,通过RR(Round Robin 轮询)将可读 socket 分配给这些 IO 线程;
  3. 主线程阻塞,等待 IO 线程完成命令的读取、解析;
  4. 主线程执⾏ IO 线程读取和解析出来的 Redis 请求命令,并将结果写到输出缓冲区;
  5. 主线程阻塞,等待 IO 线程将命令执⾏结果写回 socket(客户端);
  6. 主线程执行所有命令并清空整个等待队列,等待客户端后续的请求队列。

如下图:

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

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

相关文章

10个程序员可以接私活的平台和一些建议

话不多说,直接进入正题。我把我压箱底的10个程序员接私活的平台都拿出来了,看之前记得先点赞收藏~ 码市 互联网网站外包服务平台,这个平台上还有产品原型可供参考。在码市上有一系列规范的接单和发单流程答疑过程,可以很好地帮助…

XML文档节点导航与选择指南 | XPath基础知识

XPath(XML Path Language)是XSLT标准的主要组成部分。它用于在XML文档中浏览元素和属性,提供了一种强大的定位和选择节点的方式。 XPath的基本特点 代表XML路径语言: XPath是一种用于在XML文档中导航和选择节点的语言。 路径样式…

C语言---浮点数在内存中的存储

前面跟大家介绍了整数在内存中的存储,这次再向大家介绍下浮点数在内存中的存储。 我们常见的浮点数有3.14,1E10 等等,浮点数家族包括float,double,long double类型。 浮点数的表示范围在头文件 float.h 定义。 1.浮…

蓝桥杯第十四届C++C组

目录 三国游戏 填充 翻转 【单调队列优化DP】子矩阵 【快速幂、欧拉函数】互质数的个数 【tire树】异或和之差 【质因数分解】公因数匹配 子树的大小 三国游戏 题目描述 小蓝正在玩一款游戏。游戏中魏蜀吴三个国家各自拥有一定数量的士兵X, Y, Z (一开始可以认为都…

python应用-计算两个日期的时间差

学习目录 1. 安装deteutil包 2. 导入relativedelta类 3. 计算两个日期的差值 4. 计算1个日期和时间差相加后得到新的日期 之前在工作中遇到一个使用场景:需要计算两个日期之前的差值,比如相差了几年几月几日,查找资料发现deteutil包的rel…

记一次农业工程学报投稿流程与感悟

经过数段时间的实验与熬夜,终于得出一个比较满意的结果,本想着第一篇先随便发一个试试投稿流程,但是经过老师修改后非让投农业工程学报,然后在网上查了一些信息后有点害怕,大致都是在说周期长,审稿慢等等 …

《QT实用小工具·十七》密钥生成工具

1、概述 源码放在文章末尾 该项目主要用于生成密钥,下面是demo演示: 项目部分代码如下: #pragma execution_character_set("utf-8")#include "frmmain.h" #include "ui_frmmain.h" #include "qmessag…

Java实现二叉树(上)

1.树型结构 1.1树型结构的概念 树是一种 非线性 的数据结构,它是由 n ( n>0 )个有限结点组成一个具有层次关系的集合。 把它叫做树是因为它看 起来像一棵倒挂的树,也就是说它是根朝上,而叶朝下的 1.2树型结构的特点…

原型变量、原子操作、原子性、内存序

一、原子变量、原子操作 锁竞争:互斥锁、条件变量、原子变量、信号量、读写锁、自旋锁。在高性能基础组件优化的时候,为了进一步提高并发性能,可以使用原子变量。性能:原子变量 > 自旋锁 > 互斥锁。 操作临界资源的时间较长…

【leetcode】 c++ 数字全排列, test ok

1. 问题 2. 思路 3. 代码实现 #if 0 class Solution { private:vector<int> path; // 满足条件的一个结果 vector<vector<int>> res; // 结果集 void backtracking(vector<int> nums, vector<bool> used){// 若path的个数和nums个数相等&…

K8S基于containerd做容器从harbor拉取镜

实现创建pod时&#xff0c;通过指定harbor仓库里的镜像来运行pod 检查&#xff1a;K8S是不是用containerd做容器运行时&#xff0c;以及containerd的版本是不是小于1.6.22 kubectl get nodes -owide1、如果containerd小于 1.6.22&#xff0c;需要先升级containerd 先卸载旧的…

金三银四面试题(十六):MySQL面试都问什么(1)

在开发岗位面试中&#xff0c;MySQL基本是必考环节。所以接下来我们就进入MySQL八股文环节&#xff0c;看看都有哪些高频考题。 MySQL 中有哪些不同的表格&#xff1f; 在MySQL中&#xff0c;可以创建多种不同类型的表格&#xff0c;其中一些常见的类型包括&#xff1a; InnoD…