redis为什么是单线程_Redis 为什么用单线程模型?终于知道了!-程序员宅基地

技术标签: 单线程为什么cpu慢  redis线程模型  redis为什么是单线程  

d35e75b79c3468f9579cf56f45756fb5.png

Java技术栈

www.javastack.cn

关注阅读更多优质文章

Redis 作为广为人知的内存数据库,在玩具项目和复杂的工业级别项目中都看到它的身影,然而 Redis 却是使用单线程模型进行设计的,这与很多人固有的观念有所冲突,为什么单线程的程序能够抗住每秒几百万的请求量呢?

这也是我们今天要讨论的问题之一。

除此之外,Redis 4.0 之后的版本却抛弃了单线程模型这一设计,原本使用单线程运行的 Redis 也开始选择性使用多线程模型,这一看似有些矛盾的设计决策是今天需要讨论的另一个问题。

However with Redis 4.0 we started to make Redis more threaded. For now this is limited to deleting objects in the background, and to blocking commands implemented via Redis modules. For the next releases, the plan is to make Redis more and more threaded.

概述

就像在介绍中说的,这一篇文章想要讨论的两个与 Redis 有关的问题就是:

  • 为什么 Redis 在最初的版本中选择单线程模型?

  • 为什么 Redis 在 4.0 之后的版本中加入了多线程的支持?

这两个看起来有些矛盾的问题实际上并不冲突,我们会分别阐述对这个看起来完全相反的设计决策作出分析和解释,不过在具体分析它们的设计之前,我们先来看一下不同版本 Redis 顶层的设计:

8308c1b6e1bfb9626113361a976de10b.png

Redis 作为一个内存服务器,它需要处理很多来自外部的网络请求,它使用 I/O 多路复用机制同时监听多个文件描述符的可读和可写状态,一旦受到网络请求就会在内存中快速处理,由于绝大多数的操作都是纯内存的,所以处理的速度会非常地快。

在 Redis 4.0 之后的版本,情况就有了一些变动,新版的 Redis 服务在执行一些命令时就会使用『主处理线程』之外的其他线程,例如 UNLINKFLUSHALL ASYNCFLUSHDB ASYNC 等非阻塞的删除操作。

设计

无论是使用单线程模型还是多线程模型,这两个设计上的决定都是为了更好地提升 Redis 的开发效率、运行性能,想要理解两个看起来矛盾的设计决策,我们首先需要重新梳理做出决定的上下文和大前提,从下面的角度来看,使用单线程模型和多线程模型其实也并不矛盾。

虽然 Redis 在较新的版本中引入了多线程,不过是在部分命令上引入的,其中包括非阻塞的删除操作,在整体的架构设计上,主处理程序还是单线程模型的;由此看来,我们今天想要分析的两个问题可以简化成:

  • 为什么 Redis 服务使用单线程模型处理绝大多数的网络请求?

  • 为什么 Redis 服务增加了多个非阻塞的删除操作,例如:UNLINKFLUSHALL ASYNCFLUSHDB ASYNC

接下来的两个小节将从多个角度分析这两个问题。

单线程模型

Redis 从一开始就选择使用单线程模型处理来自客户端的绝大多数网络请求,这种考虑其实是多方面的,作者分析了相关的资料,发现其中最重要的几个原因如下:

  1. 使用单线程模型能带来更好的可维护性,方便开发和调试;

  2. 使用单线程模型也能并发的处理客户端的请求;

  3. Redis 服务中运行的绝大多数操作的性能瓶颈都不是 CPU;

上述三个原因中的最后一个是最终使用单线程模型的决定性因素,其他的两个原因都是使用单线程模型额外带来的好处,在这里我们会按顺序介绍上述的几个原因。

可维护性

可维护性对于一个项目来说非常重要,如果代码难以调试和测试,问题也经常难以复现,这对于任何一个项目来说都会严重地影响项目的可维护性。多线程模型虽然在某些方面表现优异,但是它却引入了程序执行顺序的不确定性,代码的执行过程不再是串行的,多个线程同时访问的变量如果没有谨慎处理就会带来诡异的问题。

271179ec01c91d4a0f8fd554accf8ea7.png

在网络上有一个调侃多线程模型的段子,就很好地展示了多线程模型带来的潜在问题:竞争条件 (race condition) —— 如果计算机中的两个进程(线程同理)同时尝试修改一个共享内存的内容,在没有并发控制的情况下,最终的结果依赖于两个进程的执行顺序和时机,如果发生了并发访问冲突,最后的结果就会是不正确的。

Some people, when confronted with a problem, think, “I know, I’ll use threads,” and then two they hav erpoblesms.

引入了多线程,我们就必须要同时引入并发控制来保证在多个线程同时访问数据时程序行为的正确性,这就需要工程师额外维护并发控制的相关代码,例如,我们会需要在可能被并发读写的变量上增加互斥锁:

var (  
    mu Mutex // cost  
    data int  
)  
  
// thread 1  
func() {  
    mu.Lock()  
    data += 1  
    mu.Unlock()  
}  
  
// thread 2  
func() {  
    mu.Lock()  
    data -= 1  
    mu.Unlock()  
}   

在访问这些变量或者内存之前也需要先对获取互斥锁,一旦忘记获取锁或者忘记释放锁就可能会导致各种诡异的问题,管理相关的并发控制机制也需要付出额外的研发成本和负担。

并发处理

使用单线程模型也并不意味着程序不能并发的处理任务,Redis 虽然使用单线程模型处理用户的请求,但是它却使用 I/O 多路复用机制并发处理来自客户端的多个连接,同时等待多个连接发送的请求。

在 I/O 多路复用模型中,最重要的函数调用就是 select 以及类似函数,该方法的能够同时监控多个文件描述符(也就是客户端的连接)的可读可写情况,当其中的某些文件描述符可读或者可写时,select 方法就会返回可读以及可写的文件描述符个数。

使用 I/O 多路复用技术能够极大地减少系统的开销,系统不再需要额外创建和维护进程和线程来监听来自客户端的大量连接,减少了服务器的开发成本和维护成本。

性能瓶颈

最后要介绍的其实就是 Redis 选择单线程模型的决定性原因 —— 多线程技术的能够帮助我们充分利用 CPU 的计算资源来并发的执行不同的任务,但是 CPU 资源往往都不是 Redis 服务器的性能瓶颈。哪怕我们在一个普通的 Linux 服务器上启动 Redis 服务,它也能在 1s 的时间内处理 1,000,000 个用户请求。

It's not very frequent that CPU becomes your bottleneck with Redis, as usually Redis is either memory or network bound. For instance, using pipelining Redis running on an average Linux system can deliver even 1 million requests per second, so if your application mainly uses O(N) or O(log(N)) commands, it is hardly going to use too much CPU.

如果这种吞吐量不能满足我们的需求,更推荐的做法是使用分片的方式将不同的请求交给不同的 Redis 服务器来处理,而不是在同一个 Redis 服务中引入大量的多线程操作。

简单总结一下,Redis 并不是 CPU 密集型的服务,如果不开启 AOF 备份,所有 Redis 的操作都会在内存中完成不会涉及任何的 I/O 操作,这些数据的读写由于只发生在内存中,所以处理速度是非常快的;整个服务的瓶颈在于网络传输带来的延迟和等待客户端的数据传输,也就是网络 I/O,所以使用多线程模型处理全部的外部请求可能不是一个好的方案。

AOF 是 Redis 的一种持久化机制,它会在每次收到来自客户端的写请求时,将其记录到日志中,每次 Redis 服务器启动时都会重放 AOF 日志构建原始的数据集,保证数据的持久性。

多线程虽然会帮助我们更充分地利用 CPU 资源,但是操作系统上线程的切换也不是免费的,线程切换其实会带来额外的开销,其中包括:

  1. 保存线程 1 的执行上下文;

  2. 加载线程 2 的执行上下文;

频繁的对线程的上下文进行切换可能还会导致性能地急剧下降,这可能会导致我们不仅没有提升请求处理的平均速度,反而进行了负优化,所以这也是为什么 Redis 对于使用多线程技术非常谨慎。

引入多线程

Redis 在最新的几个版本中加入了一些可以被其他线程异步处理的删除操作,也就是我们在上面提到的  UNLINKFLUSHALL ASYNCFLUSHDB ASYNC,我们为什么会需要这些删除操作,而它们为什么需要通过多线程的方式异步处理?

删除操作

我们可以在 Redis 在中使用 DEL 命令来删除一个键对应的值,如果待删除的键值对占用了较小的内存空间,那么哪怕是同步地删除这些键值对也不会消耗太多的时间。

但是对于 Redis 中的一些超大键值对,几十 MB 或者几百 MB 的数据并不能在几毫秒的时间内处理完,Redis 可能会需要在释放内存空间上消耗较多的时间,这些操作就会阻塞待处理的任务,影响 Redis 服务处理请求的 PCT99 和可用性。

1f684f4e1e29c2fb9e6d21b130896494.png

然而释放内存空间的工作其实可以由后台线程异步进行处理,这也就是 UNLINK 命令的实现原理,它只会将键从元数据中删除,真正的删除操作会在后台异步执行。

总结

Redis 选择使用单线程模型处理客户端的请求主要还是因为 CPU 不是 Redis 服务器的瓶颈,所以使用多线程模型带来的性能提升并不能抵消它带来的开发成本和维护成本,系统的性能瓶颈也主要在网络 I/O 操作上;而 Redis 引入多线程操作也是出于性能上的考虑,对于一些大键值对的删除操作,通过多线程非阻塞地释放内存空间也能减少对 Redis 主线程阻塞的时间,提高执行的效率。

如果对文章中的内容有疑问或者想要了解更多软件工程上一些设计决策背后的原因,可以在博客下面留言,作者会及时回复本文相关的疑问并选择其中合适的主题作为后续的内容。

Reference

  • Redis is single threaded. How can I exploit multiple CPU / cores?

  • Redis is single-threaded, then how does it do concurrent I/O?

  • Why isn't Redis designed to benefit from multi-threading?

  • Concurrency is not parallelism

  • The little-known feature of Redis 4.0 that will speed up your applications

  • Redis 和 I/O 多路复用

  • CPU Scheduling

最近热文: 1、重磅!《Java开发手册(嵩山版)》最新发布 2、打破你的认知!Java空指针居然还能这样玩 3、吊打 Tomcat ,Undertow 性能很炸!! 4、Spring Boot 太狠了,一次发布 3 个版本! 5、Spring Boot 如何快速集成 Redis? 6、盘点 6 个被淘汰的 Java 技术,曾经风光过! 7、Spring Boot Redis 实现分布式锁,真香! 8、国人开源了一款小而全的 Java 工具类库! 9、国人开源了一款超好用的 Redis 客户端!! 10、同事写了个隐藏 bug,我排查了 3 天! 扫码关注 Java技术栈 公众号阅读更多干货。

2fc5a7c159c27af747557e7ef7b182cb.png

点击「」获取面试题大全~

版权声明:本文为博主原创文章,遵循 CC 4.0 BY-SA 版权协议,转载请附上原文出处链接和本声明。
本文链接:https://blog.csdn.net/weixin_39601088/article/details/111296648

智能推荐

如何配置filezilla服务端和客户端_filezilla server for windows (32bit x86)-程序员宅基地

文章浏览阅读7.8k次,点赞3次,收藏9次。如何配置filezilla服务端和客户端百度‘filezilla server’下载最新版。注意点:下载的版本如果是32位的适用xp和win2003,百度首页的是适用于win7或更高的win系统。32和64内容无异。安装过程也是一样的。一、这里的filezilla包括服务端和客户端。我们先来用filezilla server 架设ftp服务端。看步骤。1选择标准版的就可以了。 _filezilla server for windows (32bit x86)

深度学习图像处理01:图像的本质-程序员宅基地

文章浏览阅读724次,点赞18次,收藏8次。深度学习作为一种强大的机器学习技术,已经成为图像处理领域的核心技术之一。通过模拟人脑处理信息的方式,深度学习能够从图像数据中学习到复杂的模式和特征,从而实现从简单的图像分类到复杂的场景理解等多种功能。要充分发挥深度学习在图像处理中的潜力,我们首先需要理解图像的本质。本文旨在深入探讨深度学习图像处理的基础概念,为初学者铺平通往高级理解的道路。我们将从最基础的问题开始:图像是什么?我们如何通过计算机来理解和处理图像?

数据探索阶段——对样本数据集的结构和规律进行分析_数据分析 规律集-程序员宅基地

文章浏览阅读62次。在收集到初步的样本数据之后,接下来该考虑的问题有:(1)样本数据集的数量和质量是否满足模型构建的要求。(2)是否出现从未设想过的数据状态。(3)是否有明显的规律和趋势。(4)各因素之间有什么样的关联性。解决方案:检验数据集的数据质量、绘制图表、计算某些特征量等,对样本数据集的结构和规律进行分析。从数据质量分析和数据特征分析两个角度出发。_数据分析 规律集

上传计算机桌面文件图标不见,关于桌面上图标都不见了这类问题的解决方法-程序员宅基地

文章浏览阅读8.9k次。关于桌面上图标都不见了这类问题的解决方法1、在桌面空白处右击鼠标-->排列图标-->勾选显示桌面图标。2、如果问题还没解决,那么打开任务管理器(同时按“Ctrl+Alt+Del”即可打开),点击“文件”→“新建任务”,在打开的“创建新任务”对话框中输入“explorer”,单击“确定”按钮后,稍等一下就可以见到桌面图标了。3、问题还没解决,按Windows键+R(或者点开始-->..._上传文件时候怎么找不到桌面图标

LINUX 虚拟网卡tun例子——修改_怎么设置tun的接收缓冲-程序员宅基地

文章浏览阅读1.5k次。参考:http://blog.csdn.net/zahuopuboss/article/details/9259283 #include #include #include #include #include #include #include #include #include #include #include #include _怎么设置tun的接收缓冲

UITextView 评论输入框 高度自适应-程序员宅基地

文章浏览阅读741次。创建一个inputView继承于UIView- (instancetype)initWithFrame:(CGRect)frame{ self = [superinitWithFrame:frame]; if (self) { self.backgroundColor = [UIColorcolorWithRed:0.13gre

随便推点

字符串基础面试题_java字符串相关面试题-程序员宅基地

文章浏览阅读594次。字符串面试题(2022)_java字符串相关面试题

VSCODE 实现远程GUI,显示plt.plot, 设置x11端口转发_vscode远程ssh连接服务器 python 显示plt-程序员宅基地

文章浏览阅读1.4w次,点赞12次,收藏21次。VSCODE 实现远程GUI,显示plt.plot, 设置x11端口转发问题服务器 linux ubuntu16.04本地 windows 10很多小伙伴发现VSCode不能显示figure,只有用自带的jupyter才能勉强个截图、或者转战远程桌面,这对数据分析极为不方便。在命令行键入xeyes(一个显示图像的命令)会failed,而桌面下会出现:但是Xshell能实现X11转发图像,有交互功能,但只能用Xshell输入命令plot,实在不方便。其实VScode有X11转发插件!!方法_vscode远程ssh连接服务器 python 显示plt

element-ui switch开关打开和关闭时的文字设置样式-程序员宅基地

文章浏览阅读3.3k次,点赞2次,收藏2次。element switch开关文字显示element中switch开关把on-text 和 off-text 属性改为 active-text 和 inactive-text 属性.怎么把文字描述显示在开关上?下面就是实现方法: 1 <el-table-column label="状态"> 2 <template slot-scope="scope">..._el-switch 不同状态显示不同字

HttpRequestUtil方法get、post、JsonToPost_httprequestutil.httpget-程序员宅基地

文章浏览阅读785次。java后台发起请求使用的工具类package com.cennavi.utils;import org.apache.http.Header;import org.apache.http.HttpResponse;import org.apache.http.HttpStatus;import org.apache.http.client.HttpClient;import org.apache.http.client.methods.HttpPost;import org.apach_httprequestutil.httpget

App-V轻量级应用程序虚拟化之三客户端测试-程序员宅基地

文章浏览阅读137次。在前两节我们部署了App-V Server并且序列化了相应的软件,现在可谓是万事俱备,只欠东风。在这篇博客里面主要介绍一下如何部署客户端并实现应用程序的虚拟化。在这里先简要的说一下应用虚拟化的工作原理吧!App-V Streaming 就是利用templateServer序列化出一个软件运行的虚拟环境,然后上传到app-v Server上,最后客户..._app-v 客户端

推荐文章

热门文章

相关标签