草庐IT

单线程 Redis 如此之快的四个原因

JAVA旭阳 2023-03-28 原文

​前言

作为内存中数据存储,Redis 以其速度和性能着称,通常被用作大多数后端服务的缓存解决方案。

但是,在内部,Redis 采用单线程架构。

为什么单线程设计依然会有这么高的性能?如果利用多线程并发处理请求不是更好吗?

在本文中,让我们深入探讨为什么 Redis 才有单线程架构,依然如此之快,主要从下面4个方面讲解。

  • 内存数据存储
  • 优良的数据结构
  • 单线程架构
  • 非阻塞IO
让我们一一剖析。

内存数据存储

访问 RAM 比磁盘快几个数量级

Redis 是一个基于内存存储数据,也就是上面表的RAM。

Redis 中的每个读写操作都等同于从命中 RAM(随机存取存储器)的变量中读取和写入。

访问 RAM 比直接访问磁盘快几个数量级,因此,Redis 比其他数据存储快得多。

优良的数据结构

作为内存中的数据存储,Redis 利用各种底层数据结构来高效地存储数据,而无需担心如何将它们持久化到持久存储中。

例如,Redis 列表是使用链表实现的,该链表允许在列表的头部和尾部附近进行恒定时间 O(1) 的插入和删除。

另一方面,Redis 排序集是通过跳跃列表实现的,它可以实现更快的查询和插入。

简而言之,无需担心持久化数据,Redis 中的数据可以更有效地存储,以便通过不同的数据结构进行快速检索。

单线程架构

单线程进程

Redis 的写入和读取速度极快,CPU 使用率对 Redis 来说从来都不是问题。

根据 Redis 官方文档,在普通 Linux 系统上运行时,Redis 每秒可以传递多达 100 万个请求。

然而,瓶颈主要来自网络 I/O。Redis 中的处理时间主要浪费在等待网络 I/O 上。

虽然多线程架构允许应用程序通过上下文切换并发处理任务,但 Redis 的性能提升是微乎其微的,因为大多数线程最终会在 I/O 中被阻塞。

通过采用单线程架构,Redis有下面的几个好处:

  • 最小化由于线程创建或销毁引起的 CPU 消耗
  • 最大限度地减少由于上下文切换引起的 CPU 消耗
  • 减少锁开销,因为多线程应用程序需要锁来进行线程同步,这很容易出错
  • 能够使用各种“线程不安全”命令,例如 lpush

非阻塞 I/O

为了处理传入的请求,服务器需要在套接字上调用系统调用以将数据从网络缓冲区读取到用户空间。

这通常是一个阻塞操作,线程被阻塞并且在完全接收到来自客户端的数据之前什么都不做。

为什么我们不在确定套接字中的数据已准备好读取时才调用系统调用?

这就是 I/O 多路复用发挥作用的地方。

I/O 多路复用模块同时监视多个套接字,并且只返回可读的套接字。

准备好读取的套接字被推送到单线程事件循环,并由相应的处理程序使用​​Reactor Pattern​​进行处理。

简而言之,

  • 由于其阻塞性质,网络 I/O 很慢
  • Redis内存操作速度快,Redis收到命令后可以快速执行
因此,Redis 有意识地做出以下决定:

  • 使用 I/O 多路复用来缓解缓慢的网络 I/O 问题
  • 使用单线程架构减少锁开销

总结

综上所述,单线程架构是Redis团队经过时间考验的深思熟虑的选择。尽管是单线程的,Redis 仍然是性能最高和最常用的内存数据存储之一。

有关单线程 Redis 如此之快的四个原因的更多相关文章

  1. ruby - RuntimeError(自动加载常量 Apps 多线程时检测到循环依赖 - 2

    我收到这个错误:RuntimeError(自动加载常量Apps时检测到循环依赖当我使用多线程时。下面是我的代码。为什么会这样?我尝试多线程的原因是因为我正在编写一个HTML抓取应用程序。对Nokogiri::HTML(open())的调用是一个同步阻塞调用,需要1秒才能返回,我有100,000多个页面要访问,所以我试图运行多个线程来解决这个问题。有更好的方法吗?classToolsController0)app.website=array.join(',')putsapp.websiteelseapp.website="NONE"endapp.saveapps=Apps.order("

  2. ruby - 如何让Ruby捕获线程中的语法错误 - 2

    我正在尝试使用ruby​​编写一个双线程客户端,一个线程从套接字读取数据并将其打印出来,另一个线程读取本地数据并将其发送到远程服务器。我发现的问题是Ruby似乎无法捕获线程内的错误,这是一个示例:#!/usr/bin/rubyThread.new{loop{$stdout.puts"hi"abc.putsefsleep1}}loop{sleep1}显然,如果我在线程外键入abc.putsef,代码将永远不会运行,因为Ruby将报告“undefinedvariableabc”。但是,如果它在一个线程内,则没有错误报告。我的问题是,如何让Ruby捕获这样的错误?或者至少,报告线程中的错误?

  3. ruby - 如何在 ruby​​ 中运行后台线程? - 2

    我是ruby​​的新手,我认为重新构建一个我用C#编写的简单聊天程序是个好主意。我正在使用Ruby2.0.0MRI(Matz的Ruby实现)。问题是我想在服务器运行时为简单的服务器命令提供I/O。这是从示例中获取的服务器。我添加了使用gets()获取输入的命令方法。我希望此方法在后台作为线程运行,但该线程正在阻塞另一个线程。require'socket'#Getsocketsfromstdlibserver=TCPServer.open(2000)#Sockettolistenonport2000defcommandsx=1whilex==1exitProgram=gets.chomp

  4. ruby - Rails 开发服务器、PDFKit 和多线程 - 2

    我有一个使用PDFKit呈现网页的pdf版本的Rails应用程序。我使用Thin作为开发服务器。问题是当我处于开发模式时。当我使用“bundleexecrailss”启动我的服务器并尝试呈现任何PDF时,整个过程会陷入僵局,因为当您呈现PDF时,会向服务器请求一些额外的资源,如图像和css,看起来只有一个线程.如何配置Rails开发服务器以运行多个工作线程?非常感谢。 最佳答案 我找到的最简单的解决方案是unicorn.geminstallunicorn创建一个unicorn.conf:worker_processes3然后使用它:

  5. ruby - Ruby 1.9.1 中的 native 线程,对我有什么好处? - 2

    所以,Ruby1.9.1现在是declaredstable.Rails应该与它一起工作,并且正在慢慢地将gem移植到它。它具有native线程和全局解释器锁(GIL)。自从GIL到位后,原生线程是否比1.9.1中的绿色线程有任何优势? 最佳答案 1.9中的线程是原生的,但它们被“放慢了速度”,一次只允许一个线程运行。这是因为如果线程真的并行运行,它会混淆现有代码。优点:IO现在在线程中是异步的。如果一个线程阻塞在IO上,那么另一个线程将继续执行直到IO完成。C扩展可以使用真正的线程。缺点:任何非线程安全的C扩展都可能存在使用Thre

  6. ruby - 使写入文件线程安全 - 2

    我在一个ruby​​文件中有一个函数可以像这样写入一个文件File.open("myfile",'a'){|f|f.puts("#{sometext}")}这个函数在不同的线程中被调用,使得像上面这样的文件写入不是线程安全的。有谁知道如何以最简单的方式使这个文件写入线程安全?更多信息:如果重要的话,我正在使用rspec框架。 最佳答案 您可以通过File#flock给锁File.open("myfile",'a'){|f|f.flock(File::LOCK_EX)f.puts("#{sometext}")}

  7. Ruby 线程与 Watir - 2

    我编写了几个类来控制我想如何处理多个网站,两者都使用类似的方法(即登录、刷新)。每个类都打开自己的WATIR浏览器实例。classSite1definitialize@ie=Watir::Browser.newenddeflogin@ie.goto"www.blah.com"endend无线程的main中的代码示例如下require'watir'require_relative'site1'agents=[]agents这工作正常,但在当前代理完成登录之前不会移动到下一个代理。我想合并多线程来处理这个问题,但似乎无法让它工作。require'watir'require_relative

  8. ruby - 在多个线程中引用类方法会导致自动加载循环依赖崩溃 - 2

    代码:threads=[]Thread.abort_on_exception=truebegin#throwexceptionsinthreadssowecanseethemthreadseputs"EXCEPTION:#{e.inspect}"puts"MESSAGE:#{e.message}"end崩溃:.rvm/gems/ruby-2.1.3@req/gems/activesupport-4.1.5/lib/active_support/dependencies.rb:478:inload_missing_constant':自动加载常量MyClass时检测到循环依赖稍加研究后,

  9. Ruby 多线程/多处理读物 - 2

    任何人都可以推荐任何详细介绍Ruby多线程/多处理的复杂性的好的多线程/处理书籍/网站吗?我尝试使用ruby​​线程,基本上在1.9vm上的无死锁代码中它在jruby中遇到了死锁。是的,我意识到差异很大(jruby没有GIL),但我想知道是否有用于ruby​​中多线程编程的策略或类集,我只需要继续阅读。旁注:从java到ruby​​必须定义是否需要重新输入锁,这有点奇怪。 最佳答案 如果你使用Ruby1.9,你可以试试Fiber,它是Ruby中线程的一大改进http://ruby-doc.org/core-1.9/classes/F

  10. ruby-on-rails - 出于某种原因,我无法在控制台中生成重音字符 [é、ü 等] - 2

    在MacOS更新之前,它一直运行良好。我重新安装了RVM、rails、ruby等等。到目前为止没有任何效果。在我的Mac终端中,我可以生成一个é,但是在控制台中,我可以生成字符,使用alt+character,然后当我键入字符分配给的字母,它会删除该字符。在我的~/.rvmrc中:exportruby_configure_flags="--with-readline-dir=/usr/local/Cellar/readline/6.2.4"有什么想法吗?到目前为止,我已经明确地让它工作了,包括readline-rb。我猜我的全局要求不工作。gem'rb-readline','~>0.4

随机推荐