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.mzph.cn/news/799168.shtml

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

相关文章

前端开发语言有那些?

前端开发语言有那些? 1、html 超文本标记语言:构建前端网页的基本结构,就象人的骨架一样。 2、css 层叠样式表:控制网页的样式和布局,就象人需要穿各种服式展现不同风采。 3、javascript 简称 JS 动态脚本语言&#x…

阿里面试总结

ThreadLocal 线程变量存放在当前线程变量中,线程上下文中,set将变量添加到threadLocals变量中 Thread类中定义了两个ThreadLocalMap类型变量threadLocals、inheritableThreadLocals用来存储当前操作的ThreadLocal的引用及变量对象,把当前线程…

gcc/g++:预编译阶段嵌入头文件并完成替换

预编译阶段嵌入头文件并完成替换首先需要找到需要包含头文件的位置,然后进行引入。 示例: 1)用户头文件 /*brief design and implements of demo-for-precompile.author wenxuanpeiemail 15873152445163.com(query for any question here) …

括号串(Deque)

题目 import java.util.Deque; import java.util.LinkedList; import java.util.Scanner; public class Main {public static void main(String[] args) {Scanner sc new Scanner(System.in);int n sc.nextInt();sc.nextLine();char[] c sc.nextLine().toCharArray();Deque…

Prompt提示词——常见的Prompt框架

以下是一些常见的Prompt框架,包括它们的原理、功能、使用场景、优缺点以及示例: BROKE框架: 原理:BROKE是一个结合了OKR(Objectives and Key Results)方法论的框架,通过提供背景、角色、目标、关…

柒拾贰- tushare 模拟策略交易 (三)

书接上两回 柒拾- tushare 模拟策略交易 (一) 柒拾壹- tushare 模拟策略交易 (二) 开始 终于我们可以可以来进行模拟了 复杂 的我不会,所以就写个最简单的策略吧: 买入条件 比两年前是上升的比一年前…

前端开发之el-select 设置默认值后选项无法切换

前端开发之el-select 设置默认值后选项无法切换 前言解决方案 前言 在实际使用过程中发现再给el-select设置默认值之后选项无法进行切换了 解决方案 为el-select添加 change“$forceUpdate()” 添加这个即可 <template><el-form-item label"数据类型"&g…

【题目】【信息安全管理与评估】2023年国赛信息安全管理与评估正式赛任务书-模块2

全国职业院校技能大赛高等职业教育组 信息安全管理与评估 任务书 模块二 信息安全管理与评估 网络系统管理 网络搭建与应用 云计算 软件测试 移动应用开发 竞赛任务书&#xff0c;赛题&#xff0c;解析&#xff0c;培训服务添加博主wx&#xff1a;liuliu5488233 网络安全事件…

speech to text 库FastASR交叉编译arm target的配置

FastASR是一个比较方便的SPEECH TO TEXT的AI库。开源。下面介绍下其在交叉编译到ARM target时候的交叉编译的cmake配置&#xff1a; cmake_minimum_required(VERSION 3.10)project(FastASR)SET(CMAKE_C_COMPILER "/home/xxx/buildroot/output/platform_name/host/bin/aar…

Flutter第六弹 基础列表ListView

目标&#xff1a; 1&#xff09;Flutter有哪些常用的列表组建 2&#xff09;怎么定制列表项Item&#xff1f; 一、ListView简介 使用标准的 ListView 构造方法非常适合只有少量数据的列表。我们还将使用内置的 ListTile widget 来给我们的条目提供可视化结构。ListView支持…

性能分析--内存知识

内存相关知识 计算机中与CPU进行数据交换的桥梁。内存的速度&#xff0c;比CPU的速度要慢很多。比磁盘速度要快很多。内存中存放数据&#xff0c;一旦断电就会消失。linux系统的 /proc路径下的文件&#xff0c;都是内存文件。内存大小&#xff0c;一般 是GB为单位。 现在都操作…

WebKit是什么?

WebKit是一个开源的浏览器引擎&#xff0c;它用于呈现网页内容在许多现代浏览器中&#xff0c;包括Safari浏览器、iOS内置浏览器、以及一些其他浏览器如Google Chrome的早期版本。以下是一些关于WebKit的重要信息&#xff1a; 起源和发展&#xff1a;WebKit最初是由苹果公司为其…

K8s学习四(资源调度_1)

资源调度 发现对Pod操作不方便&#xff0c;不能直接操作&#xff0c;而且不能直接编辑&#xff0c;需要对原来的配置文件进行操作&#xff0c;而且需要删除之后再创建Pod&#xff0c;不方便&#xff0c;更多是通过控制器来操作。 Label和Selector 通过设置标签和选择器来确定…

HTTP【超文本传输协议】和HTTPS【超文本传输安全协议】有什么区别?

文章目录 一、HTTP和HTTPS是什么&#xff1f;1、HTTP&#xff08;超文本传输协议&#xff09;2、HTTPS&#xff08;超文本传输安全协议&#xff09;3、HTTPS中加入的SSL/TLS层是什么&#xff1f; 二、HTTP和HTTPS的差异1、安全性2、URL表示3、端口4、证书5、性能6、浏览器显示 …

Python爬虫:为什么你爬取不到网页数据

目录 前言 一、网络请求被拒绝 二、数据是通过JavaScript加载的 三、需要进行登录 四、网站反爬虫策略 五、网站结构变更 总结 前言 作为一名开发者&#xff0c;使用Python编写爬虫程序是一项常见的任务。爬虫程序的目的是收集互联网上的数据&#xff0c;并将其保存或使…

P1616 疯狂的采药(完全背包问题)

题目&#xff1a;P1616 疯狂的采药 - 洛谷 | 计算机科学教育新生态 (luogu.com.cn) #include<iostream> #include<algorithm> using namespace std; const int maxm 10010, maxt 10000010; long long v[maxm], t[maxm], f[maxt];//开longlong&#xff01; int m…

解决IDEA 控制台中文乱码

运行某个项目时IntelliJ IDEA 控制台中文乱码&#xff0c;但其他的项目是正常的。接口文档也显示乱码&#xff1a; 一、修改 IntelliJ IDEA 全局编码、项目编码、属性文件编码 上方导航栏“File→Settings…”进入配置页面&#xff0c;在“Editor”中下滑找到“File Encodings…

LeetCode 面试题 02.07.链表相交(判断两个结点是否相同)

给你两个单链表的头节点 headA 和 headB &#xff0c;请你找出并返回两个单链表相交的起始节点。如果两个链表没有交点&#xff0c;返回 null 。 图示两个链表在节点 c1 开始相交&#xff1a; 题目数据 保证 整个链式结构中不存在环。 注意&#xff0c;函数返回结果后&#x…

Elasticsearch如何选择版本

不同版本的ES差异非常大&#xff0c;包括不局限于ES语法、架构、API、集群搭建等等。这些差异足以导致不同版本是否能满足你的业务场景以及后续开发维护成本等各种问题。 先说结论&#xff0c;以个人实践经验及综合考虑推荐使用 7.x 版本中的 7.10版本 ES版本对比 以下是通过…

内外网数据交换发展进程:安全与便捷并行

随着信息化的不断推进&#xff0c;医院、党政以及企业的内外网数据交换正成为日益关注的焦点。在保障数据安全的前提下&#xff0c;需要寻求一种既安全可靠又操作便捷的数据传输方式。本文将探讨内外网数据交换发展进程&#xff0c;分析各种传输方式的优缺点&#xff0c;以及它…