探索Redis是否为单线程的奥秘(文末送书)

news2024/12/31 4:56:52

在这里插入图片描述
🌈个人主页:聆风吟
🔥系列专栏:数据结构、网络奇遇记
🔖少年有梦不应止于心动,更要付诸行动。


文章目录

  • 📋前言
  • 一. Redis中的多线程
  • 二. I/O多线程
  • 三. Redis中的多进程
  • 四. 结论
  • 五. 书籍推荐
    • 5.1 书籍介绍
    • 5.2 作者简介
    • 5.3 粉丝福利

参与活动方式文末详见。

📋前言

很多人都遇到过这么一道面试题:Redis是单线程还是多线程?这个问题既简单又复杂。说他简单是因为大多数人都知道Redis是单线程,说复杂是因为这个答案其实并不准确。

难道Redis不是单线程?我们启动一个Redis实例,验证一下就知道了。Redis安装部署方式如下所示:

// 下载
wget https://download.redis.io/redis-stable.tar.gz
tar -xzvf redis-stable.tar.gz

// 编译安装
cd redis-stable
make

// 验证是否安装成功
./src/redis-server -v
Redis server v=7.2.4

接下来启动Redis实例,使用命令ps查看所有线程,如下所示:

// 启动Redis实例
./src/redis-server ./redis.conf

// 查看实例进程ID
ps aux | grep redis
root     385806  0.0  0.0 245472 11200 pts/2    Sl+  17:32   0:00 ./src/redis-server 127.0.0.1:6379

// 查看所有线程
ps -L -p 385806
   PID    LWP TTY          TIME CMD
385806 385806 pts/2    00:00:00 redis-server
385806 385809 pts/2    00:00:00 bio_close_file
385806 385810 pts/2    00:00:00 bio_aof
385806 385811 pts/2    00:00:00 bio_lazy_free
385806 385812 pts/2    00:00:00 jemalloc_bg_thd
385806 385813 pts/2    00:00:00 jemalloc_bg_thd

竟然有6个线程!不是说Redis是单线程吗?怎么会有这么多线程呢?

这6个线程的含义你可能不太了解,但是通过这个示例至少说明Redis并不是单线程。



一. Redis中的多线程

接下来我们逐个介绍上述6个线程的作用:

  1. redis-server:
    主线程,用于接收并处理客户端请求。

  2. jemalloc_bg_thd:
    jemalloc 是新一代的内存分配器,Redis底层使用他管理内存。

  3. bio_xxx:
    以bio前缀开始的都是异步线程,用于异步执行一些耗时任务。其中,线程bio_close_file用于异步删除文件,线程bio_aof用于异步将AOF文件刷到磁盘,线程bio_lazy_free用于异步删除数据(懒删除)。

需要说明的是,主线程是通过队列将任务分发给异步线程的,并且这一操作是需要加锁的。主线程与异步线程的关系如下图所示:
在这里插入图片描述
这里我们以懒删除为例,讲解为什么要使用异步线程。Redis是一款内存数据库,支持多种数据类型,包括字符串、列表、哈希表、集合等。思考一下,删除(DEL)列表类型数据的流程是怎样的呢?第一步从数据库字典中删除该键值对,第二步遍历并删除列表中的所有元素(释放内存)。想想如果列表中的元素数目非常多呢?这一步将非常耗时。这种删除方式称为同步删除,流程如下图所示:
在这里插入图片描述

针对上述问题,Redis提出了懒删除(异步删除),主线程在收到删除命令(UNLINK)时,首先从数据库字典中删除该键值对,随后再将删除任务分发给异步线程bio_lazy_free,由异步线程执行第二步耗时逻辑。这时候的流程如下图所示:
在这里插入图片描述



二. I/O多线程

难道Redis是多线程?那为什么我们老说Redis是单线程呢?这是因为读取客户端命令请求,执行命令以及向客户端返回结果都是在主线程完成的。不然的话,多线程同时操作内存数据库,并发问题如何解决?如果每次操作之前都加锁,那和单线程又有什么区别呢?

当然这一流程在Redis6.0版本也发生了改变,Redis官方指出,Redis是基于内存的键值对数据库,执行命令的过程是非常快的,读取客户端命令请求和向客户端返回结果(即网络I/O)通常会成为Redis的性能瓶颈。

因此,在Redis 6.0版本,作者加入了多线程I/O的能力,即可以开启多个I/O线程,并行读取客户端命令请求,并行向客户端返回结果。I/O多线程能力使得Redis性能提升至少一倍。

为了开启多线程I/O能力,需要先修改配置文件redis.conf:

io-threads-do-reads yes
io-threads 4

这两个配置含义如下:

  • io-threads-do-reads:是否开启多线程I/O能力,默认为"no";

  • io-threads:I/O线程数目,默认为1,即只使用主线程执行网络I/O,线程数最大为128;该配置应该根据CPU核数设置,作者建议,4核CPU设置2~3个I/O线程,8核CPU设置6个I/O线程。

开启多线程I/O能力之后,重新启动Redis实例,查看所有线程,结果如下:

ps -L -p 104648
   PID    LWP TTY          TIME CMD
104648 104648 pts/1    00:00:00 redis-server
104648 104654 pts/1    00:00:00 io_thd_1
104648 104655 pts/1    00:00:00 io_thd_2
104648 104656 pts/1    00:00:00 io_thd_3
……

由于我们设置了io-threads等于4,所以会创建4个线程用于执行I/O操作(包括主线程),上述结果符合预期。

当然,只有I/O阶段才使用了多线程,处理命令请求还是单线程,毕竟多线程操作内存数据存在并发问题。

最后,开启了I/O多线程之后,命令的执行流程如下图所示:
在这里插入图片描述



三. Redis中的多进程

Redis还有多进程?是的。在某些场景下,Redis也会创建多个子进程来执行一些任务。以持久化为例,Redis支持两种类型的持久化:

  • AOF(Append Only File):可以看作是命令的日志文件,Redis会将每一个写命令都追加到AOF文件。

  • RDB(Redis Database):以快照的方式存储Redis内存中的数据。命令SAVE用于手动触发RDB持久化。想想如果Redis中的数据量非常大,持久化操作必然耗时比较长,而Redis是单线程处理命令请求,那么当命令SAVE的执行时间过长时,必然会影响其他命令的执行。

命令SAVE有可能会阻塞其他请求,为此,Redis又引入了命令BGSAVE,该命令会创建一个子进程来执行持久化操作,这样就不会影响主进程执行其他请求了。

我们可以手动执行命令BGSAVE验证。首先,使用GDB跟踪Redis进程,添加断点,让子进程阻塞在持久化逻辑。如下所示:

// 查询Redis进程ID
ps aux | grep redis
root     448144  0.1  0.0 270060 11520 pts/1    tl+  17:00   0:00 ./src/redis-server 127.0.0.1:6379

// GDB跟踪进程
gdb -p 448144

// 跟踪创建的子进程(默认GDB只跟踪主进程,需手动设置)
(gdb) set follow-fork-mode child

// 函数rdbSaveDb用于持久化数据快照
(gdb) b rdbSaveDb
Breakpoint 1 at 0x541a10: file rdb.c, line 1300.
(gdb) c

设置好断点之后,使用Redis客户端发送命令BGSAVE,结果如下:

// 请求立即返回
127.0.0.1:6379> bgsave
Background saving started

// GDB输出以下信息
[New process 452541]
Breakpoint 1, rdbSaveDb (...) at rdb.c:1300

可以看到,GDB目前跟踪的是子进程,进程ID是452541。也可以通过Linux命令 ps 查看所有进程,结果如下:

ps aux | grep redis
root     448144  0.0  0.0 270060 11520 pts/1    Sl+  17:00   0:00 ./src/redis-server 127.0.0.1:6379
root     452541  0.0  0.0 270064 11412 pts/1    t+   17:19   0:00 redis-rdb-bgsave 127.0.0.1:6379

可以看到子进程的名称是redis-rdb-bgsave,也就是该进程将所有数据的快照持久化在RDB文件。

最后再思考两个问题。
问题1:为什么采用子进程而不是子线程呢?
    因为RDB是将数据快照持久化存储,如果采用子线程,主线程与子线程将会共享内存数据,主线程在持久化的同时还会修改内存数据,这有可能导致数据不一致。而主进程与子进程的内存数据是完全隔离的,不存在此问题。

问题2:假设Redis内存中存储了10GB的数据,在创建子进程执行持久化操作之后,此时子进程也需要10GB的内存吗?复制10GB的内存数据,也会比较耗时吧?另外如果系统只有15GB的内存,还能执行BGSAVE命令吗?
    这里有一个概念叫写时复制(copy on write),在使用系统调用fork创建子进程之后,主进程与子进程的内存数据暂时还是共享的,但是当主进程需要修改内存数据时,系统会自动将该内存块复制一份,以此实现内存数据的隔离。
命令BGSAVE的执行流程如下图所示:
在这里插入图片描述



四. 结论

Redis的进程模型/线程模型还是比较复杂的,这里也只是简单介绍了部分场景下的多线程以及多进程,其他场景下的多线程、多进程还有待读者自己研究。



五. 书籍推荐

5.1 书籍介绍

在这里插入图片描述
全书主要分为三部分介绍Redis。

  • 第一部分介绍Redis6中使用的数据结构,包括动态字符串、跳跃表、压缩列表、字典、整数集合和快速链表,详细介绍其基本结构及常见操作。
  • 第二部分为本书核心篇章,首先介绍了Redis6的启动流程,命令解析流程,之后对Redis6中的命令实现进行了全面的介绍,包括键命令、字符串命令、哈希表命令、列表命令、集合及有序集合命令、地理位置相关的GEO命令、统计相关的HyperLogLog命令。
  • 第三部分,主要介绍了Redis6的一些特性及使用,包括事务、持久化、主从复制以及集群等。

5.2 作者简介

李乐:好未来Golang开发专家、西安电子科技大学硕士,曾就职于滴滴,乐于钻研技术与源码,合著有《高效使用Redis:一书学透数据存储与高可用集群》《Redis5设计与源码分析》《Nginx底层设计与源码分析》。


5.3 粉丝福利

送书规则:

  • 参与方式:关注博主、点赞、收藏、评论(每人最多评论三次)

  • ⛳️本次送书1~5本【取决于阅读量,阅读量越多,送的越多】

  • 📆 活动截止时间:2024-2-27 19:00:00 | 由博主动态公布抽奖结果

🔥注:活动结束后,会私信中奖粉丝的,各位注意查看私信哦!
在这里插入图片描述

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

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

相关文章

OpenLayers水平镜像和垂直镜像

目录 1.前言2.概念介绍2.1 旋转2.2 水平镜像2.3 垂直镜像 3.要素的镜像3.1 镜像轴始终是水平的或者垂直的3.2 镜像轴是任意角度 4.图片的镜像5.总结 1.前言 最近项目中用到了要素和图片的水平镜像和垂直镜像功能。这些功能说难不难,说简单也不简单,就是稍…

【SQL注入】靶场SQLI DUMB SERIES-24通过二次注入重置用户密码

先使用已知信息admin/admin登录进去查下题,发现可以修改密码 猜测可能存在的SQL语句:UPDATE user SET password新密码 WHERE user用户名 and password旧密码 假设我们知道有个admin用户,但是不知道其密码,如何可以将其密码重置&…

[AIGC] 使用Curl进行网络请求的常见用法

使用Curl进行网络请求的常见用法 Curl是一个无比强大的工具,它可以用来获取和发送数据,支持众多的协议,包括HTTP、HTTPS、FTP、FTPS、SFTP和更多。它还支持HTTP POST,HTTP PUT,HTTPS证书,HTTP基础验证等。…

【2024软件测试面试必会技能】Postman(1): postman的介绍和安装

Postman的介绍 Postman 是一款谷歌开发的接口测试工具,使API的调试与测试更加便捷。 它提供功能强大的 Web API & HTTP 请求调试。它能够发送任何类型的HTTP 请求 (GET, HEAD, POST, PUT..),附带任何数量的参数 headers。 postman是一款支持http协议的接口调试…

流动人员人事档案主要有哪些作用

流动人员人事档案是指记录企事业单位与个人之间的雇佣关系的文件。在企事业单位中,流动人员是指临时聘用的员工、实习生、临时工等,他们的雇佣关系相对不稳定,因此需要建立相应的人事档案来管理和记录他们的基本信息、工作经历、劳动合同等重…

unity学习(34)——角色选取界面(跨场景坑多)

先把SelectMenu中的camera的audio listener去掉。 现在还是平面,直接在camera下面添加两个panel即可,应该是用不到canvas了,都是2D的UI。 加完以后问题来了,角色选择界面的按钮跑到主界面上边了,而且现在账号密码都输…

机器人内部传感器阅读笔记及心得-位置传感器-电位器式位置传感器

位置传感器 位置感觉是机器人最基本的感觉要求,可以通过多种传感器来实现。位置传感器包括位置和角度检测传感器。常用的机器人位置传感器有电位器式、光电式、电感式、电容式、霍尔元件式、磁栅式及机械式位置传感器等。机器人各关节和连杆的运动定位精度要求、重…

C语言自定义类型:结构体的使用及其内存对齐【超详细建议点赞收藏】

目录 1. 结构体类型的声明1.1 结构的声明1.2 结构体变量的创建和初始化1.3 结构的特殊声明---匿名结构体1.4 结构的自引用 2.结构体内存对齐(重点!!)2.1 对齐规则2.2 例题讲解2.3 为什么存在内存对齐?2.4 修改默认对齐…

vue3前端excel导出;组件表格,自定义表格导出;Vue3 + xlsx + xlsx-style

当画面有自定义的表格或者样式过于复杂的表格时,导出功能可以由前端实现 1. 使用的插件 : sheet.js-xlsx 文档地址:https://docs.sheetjs.com/ 中文地址:https://geekdaxue.co/read/SheetJS-docs-zh/README.md xlsx-style&#…

⭐北邮复试刷题LCR 052. 递增顺序搜索树__DFS (力扣119经典题变种挑战)

LCR 052. 递增顺序搜索树 给你一棵二叉搜索树,请 按中序遍历 将其重新排列为一棵递增顺序搜索树,使树中最左边的节点成为树的根节点,并且每个节点没有左子节点,只有一个右子节点。 示例 1: 输入:root [5,…

跨境电商消息多发脚本制作需要用到的代码!

在跨境电商的运营中,为了更有效地推广产品、提升品牌知名度并增强与消费者的互动,消息群发成为了一个重要的营销手段。 为了实现这一目的,许多跨境电商团队会选择制作消息多发脚本,通过自动化发送消息来提高效率和覆盖面&#xf…

算法沉淀——穷举、暴搜、深搜、回溯、剪枝综合练习三(leetcode真题剖析)

算法沉淀——穷举、暴搜、深搜、回溯、剪枝综合练习三 01.字母大小写全排列02.优美的排列03.N 皇后04.有效的数独 01.字母大小写全排列 题目链接:https://leetcode.cn/problems/letter-case-permutation/ 给定一个字符串 s ,通过将字符串 s 中的每个字…

获取discord上自己创建的服务器的服务器ID、频道ID以及discord的登录token(用于第三方登录)

在服务器图标上右键点击-》复制服务器ID 在频道上右键点击-》复制频道ID F12->手机模式-》application-》local storage-》填写过滤条件【token】 我开发的chatgpt网站: https://chat.xutongbao.top

铌酸锂芯片与精密划片机:科技突破引领半导体制造新潮流

在当今快速发展的半导体行业中,一种结合了铌酸锂芯片与精密划片机的创新技术正在崭露头角。这种技术不仅引领着半导体制造领域的进步,更为其他产业带来了前所未有的变革。 铌酸锂芯片是一种新型的微电子芯片,它使用铌酸锂作为基底材料&#x…

dp入门(模板题)

解法一&#xff1a; 双指针&#xff0c;没必要开数组直接边输边算&#xff0c;max至少要2个数&#xff0c;补一个数时的特判 #include <iostream> #include <vector> #include <algorithm> using namespace std; #define endl \nint main() {ios::sync_wit…

ChatGPT调教指南 | 咒语指南 | Prompts提示词教程(二)

在我们开始探索人工智能的世界时&#xff0c;了解如何与之有效沉浸交流是至关重要的。想象一下&#xff0c;你手中有一把钥匙&#xff0c;可以解锁与OpenAI的GPT模型沟通的无限可能。这把钥匙就是——正确的提示词&#xff08;prompts&#xff09;。无论你是AI领域的新手&#…

SaaS智慧校园管理平台全套源码,支持二次开发,项目使用

什么是电子班牌系统&#xff1f; 电子班牌用来显示班级信息&#xff0c;班级活动信息以及学校的通知信息。信息内容为文字、图片、视频、FLASH等&#xff0c;为学生和老师提供新颖的师生交流及校园服务平台。融合了多媒体信息发布、家校互通、物联控制、教务管理、日常办公等一…

求人脸底库匹配用时统计记录

1、 注意事项 1、预热 2、torch 异步 import torch import time torch.cuda.synchronize()device torch.device(cuda:2) data_type torch.float32t1 time.time() a torch.rand((40000000,512),dtypedata_type,devicedevice) b torch.rand((512,1),dtypedata_type,device…

Linux:Jenkins用户权限和管理

1.下载插件 由于Jenkins的默认权限管理并不是很精细所以我们安装一个插件进行权限的一个管理 插件名称为&#xff1a;Role-based Authorization Strategy 安装完插件我们再去配置一下 进入全局安全配置 选择这个Role-Based Strategy策略然后保存 2.创建角色 我们这里主要使…

Stable Diffusion 模型分享:Dark Sushi Mix 大颗寿司Mix

本文收录于《AI绘画从入门到精通》专栏,专栏总目录:点这里。 文章目录 模型介绍生成案例案例一案例二案例三案例四案例五案例六案例七案例八案例九案例十