Redis为什么会这么快?Redis到底有多快?

这篇具有很好参考价值的文章主要介绍了Redis为什么会这么快?Redis到底有多快?。希望对大家有所帮助。如果存在错误或未考虑完全的地方,请大家不吝赐教,您也可以点击"举报违法"按钮提交疑问。

一、redis到底有多快?

官方文档:https://redis.io/docs/management/optimization/benchmarks/

我们使用redis自带的benchmark脚本测试:

D:\Redis-x64-3.2.100>redis-benchmark -t set, lpush -n 100000 -q
====== lpush -n 100000 -q ======
  100000 requests completed in 0.89 seconds
  50 parallel clients
  3 bytes payload
  keep alive: 1

99.90% <= 1 milliseconds
99.95% <= 5 milliseconds
99.96% <= 6 milliseconds
100.00% <= 6 milliseconds
111856.82 requests per second

我们发现,每秒可以执行11万多次set、lpush命令。

D:\Redis-x64-3.2.100>redis-benchmark -n 100000 -q script load "redis.call('set', 'lua','666')"
script load redis.call('set', 'lua','666'): 105485.23 requests per second

执行Lua脚本也能达到每秒10万多次,按照这个测试结果,redis的10万qps还是比较准确的,在高性能服务器上性能还能更强。

二、redis为什么这么快

总结起来主要是三点:
1、纯内存结构
2、请求处理单线程
3、多路复用机制

1、内存存储

KV结构的内存数据库,时间复杂度为O(1)。

(1)虚拟存储器(虚拟内存Virtual Memory)

计算机里面的内存我们叫做主内存,硬盘叫做辅存。

主存可看做一个很长的数组,一个字节一个单元,每个字节都有一个唯一的地址,这个地址叫做物理地址(Physical Address)。

早期的计算机中,如果CPU需要内存,使用物理寻址,直接访问主存储器。
Redis为什么会这么快?Redis到底有多快?

看起来是挺合乎情理的,但是这种方式有几个弊端:
1、一般的操作系统都是多用户多任务的,所有的进程共享主存。如果每个进程都独立占一块物理地址空间,主存很快就会被用完。我们希望在不同的时刻,不同的进程可以共用同一快物理地址空间。
2、如果所有进程都是直接访问物理内存,那么一个进程就可以修改其他进程的内存数据,导致物理地址空间被破坏,程序运行就会出现异常。

咋办呢?对于物理内存的使用,应该有一个角色来协调和指挥。
在CPU和主存之间增加一个中间层。CPU不再使用物理地址访问主存,而是访问一个虚拟地址,由这个中间层把地址转换成物理地址,最终获得数据。这个中间层叫做MMU(Memory Management Unit),内存管理单元。

具体的操作如下所示:
Redis为什么会这么快?Redis到底有多快?

我们访问MMU就跟访问物理内存一样,所以把虚拟出来的地址叫做虚拟内存(Virtual Memory)。

在每一个进程开始创建的时候,都会分配一段虚拟地址,然后通过虚拟地址和物理地址的映射来获取真实数据,这样进程就不会直接接触到物理地址,甚至不知道自己调用的哪块物理地址的数据。

目前,大多数操作系统都使用了虚拟内存,如windows系统的虚拟内存、Linux系统的交换空间等等。Windows的虚拟内存(pagefile.sys)是磁盘空间的一部分。

在32位的系统上,虚拟地址空间大小是2 ^ 32 = 4G。在64位系统上,最大虚拟地址空间理论上是2 ^ 64 = 1024 * 1024 TB,实际上没有用到64位,因为用不到那么大的空间,而且会造成很大的系统开销。Linux一般用低48位来表示虚拟地址空间,也就是2 ^ 48=256TB。

cat /proc/cpuinfo

address sizes   : 42 bits physical, 48 bits virtual

实际的物理内存可能远远小于虚拟内存的大小。

总结:引入虚拟内存的作用:

  • 1、通过把同一块物理内存映射到不同的虚拟地址空间实现内存共享
  • 2、对物理内存进行隔离,不同的进程操作互不影响
  • 3、虚拟内存可以提供更大的地址空间,并且地址空间是连续的,使得程序编写、链接更加简单。

(2)用户空间和内核空间

Linux/GNU的虚拟内存又进一步划分成了两块:一部分是内核空间(Kernel-space),一部分是用户空间(User-space)。
Redis为什么会这么快?Redis到底有多快?
在Linux系统中,虚拟地址布局如下:
Redis为什么会这么快?Redis到底有多快?
这两块空间的区别是什么呢?

进程的用户空间存放的是用户程序的代码和数据,内核空间中存放的是内核代码和数据。不管是内核空间还是用户空间,它们都处于虚拟内存空间中,都是对物理地址的映射。

当进程运行在内核空间时就处于内核态,而进程运行在用户空间时就处于用户态。

进程在内核空间可以访问受保护的内存空间,也可以访问底层硬件设备。也就是可以执行任意命令,调用系统的一切资源。在用户空间只能执行简单的运算,不能直接调用系统资源,必须通过系统接口(又称system call),才能向内核发出指令。

所以,这样划分的目的是为了避免用户进程直接操作内核,保证内核安全。

top命令:
Redis为什么会这么快?Redis到底有多快?

us表示CPU消耗在User space的时间百分比;
sy表示CPU消耗在Kernel space的时间百分比。

2、单线程

按照正常思路来讲,要实现这么高的并发性能,多线程理论上来说比单线程的性能要好很多,为什么Redis要用单线程?

这里说的单线程其实是指处理客户端的请求是单线程的,可以把它叫做主线程。从4.0版本之后,还引入了一些线程处理其他的事情,比如清理脏数据、无用连接的释放、大key的删除等等。

把处理请求的主线程设置为单线程有什么好处呢?

  • 没有创建线程、销毁线程带来的消耗
  • 避免了上下文切换导致的CPU消耗
  • 避免了线程之间带来的锁竞争问题

Redis使用单线程确实有很多好处,但是不会白白浪费了多核CPU资源吗?
官方是这样解释的:
在Redis中单线程已经够用了,CPU不是redis的瓶颈。Redis的瓶颈最有可能是机器内存或者网络带宽。既然单线程容易实现,又不需要处理线程并发的问题,那就顺理成章地采用单线程的方案了。

注意,因为请求处理是单线程的,不要在生产环境运行长命令,比如keys、flushall、flushdb,否则会导致请求被阻塞。

(1)进程切换(上下文切换)

多任务操作系统是怎么实现运行远大于CPU数量的任务个数的?当然,这些任务实际上并不是真的在同时运行,而是因为系统通过时间片分片算法,在很短的时间内,将CPU轮流分配给它们,造成多任务同时运行的错觉。

在这个交替运行的过程里面,为了控制进程的执行,内核必须有能力挂起正在CPU上运行的进程,以及恢复以前挂起的某个进程的执行。这种行为被称为进程切换。

什么叫上下文(Context)?

在每个任务运行前,CPU都需要知道任务从哪里加载、又从哪里开始运行。也就是说,需要系统事先帮它设置好CPU寄存器和程序计数器(Program Counter),这个叫做CPU的上下文。

而保存下来的上下文,会存储在系统内核中,并在任务重新调度执行时再次加载进来。这样就能保证任务原来的状态不受影响,让任务看起来还是连续运行。

在切换上下文的时候,需要完成一系列的工作,这是一个很消耗资源的操作。

(2)进程的阻塞

正在运行的进程由于提出系统服务请求(如IO操作),但因为某种原因未得到操作系统的立即响应,该进程只能把自己变成阻塞状态,等待相应的事件出现后才被唤醒。

进程在阻塞状态不占用CPU资源。

(3)文件描述符 FD

Linux系统将所有设备都当做文件来处理,而Linux用文件描述符来标识每个文件对象。

文件描述符(File Descriptor)是内核为了高效管理已被打开的文件所创建的索引,用于指向被打开的文件,所有执行IO操作的系统调用都通过文件描述符。

文件描述符是一个简单的非负整数,用以表明每个被进程打开的文件。Linux系统里面有三个标准文件描述符:0,标准输入(键盘);1,标准输出(显示器);2,标准错误输出(显示器)。

3、同步非阻塞IO

Redis使用了同步非阻塞IO,多路复用机制处理并发连接。

(1)传统IO数据拷贝

以读操作为例:
当应用程序执行read系统调用读取文件描述符(FD)的时候,如果这块数据已经存在于用户进程的页内存中,就直接从内存中读取数据。如果数据不存在,则先将数据从磁盘加载数据到内核缓冲区中,再从内核缓冲区拷贝到用户进程的页内存中。(两次拷贝,两次user和kernel的上下文切换)。

Redis为什么会这么快?Redis到底有多快?
IO阻塞到底阻塞在哪里?一目了然。

(2)Blocking IO

当使用read或write对某个文件描述符进行过读写时,如果当前FD不可读,系统就不会对其他的操作做出响应。从硬件设备复制数据到内核缓冲区是阻塞的,从内核缓冲区拷贝到用户空间,也是阻塞的,直到copy complete,内核返回结果,用户进程才解除block的状态。

Redis为什么会这么快?Redis到底有多快?
为了解决阻塞的问题,我们有几个思路:
1、在服务端创建多个线程或者使用线程池——但是在高并发的情况下需要的线程会很多,系统无法承受,而且创建和释放线程都需要消耗资源。
2、由请求方定期轮询,在数据准备完毕后再从内核缓存缓冲期复制数据到用户空间(非阻塞式IO),这种方式会存在一定的延迟。

(3)IO多路复用(IO Multiplexing)

能不能用一个线程处理多个客户端请求?答案是肯定的。

IO指的就是网络IO,多路指的多个TCP连接(Socket或Channel),复用指的是复用一个或多个线程。

它的基本原理就是不再由应用程序自己监视连接,而是由内核替应用程序监视文件描述符。

客户端在操作的时候,会产生具有不同事件类型的socket。在服务端,IO多路复用程序(IO Multiplexing Module)会把消息放入队列中,然后通过文件事件分派器(File event Dispatcher),转发到不同的事件处理器中。
Redis为什么会这么快?Redis到底有多快?
多路复用有很多的实现,以select为例,当用户进程调用了多路复用器,进程会被阻塞。内核会监视多路复用器负责的所有socket,当任何一个socket的数据准备好了,多路复用器就会返回。这时候用户进程再调用read操作,把数据从内核缓冲期拷贝到用户空间。
Redis为什么会这么快?Redis到底有多快?
所以,IO多路复用的特点是通过一种机制让一个进程能同时等待多个文件描述符,而这些文件描述符其中的任意一个进入读就绪(readable)状态,select()函数就可以返回。

多路复用需要操作系统的支持。Redis的多路复用,提供了select,epoll,evport,kqueue几种选择,在编译的时候来选择一种。源码ae.c:

#ifdef HAVE_EVPORT
#include "ae_evport.c"
#else 
	#ifdef HAVE_EPOLL
	#include "ae_epoll.c"
	#else
		#ifdef HAVE_KQUEUE
		#include "ae_kqueue.c"
		#else
		#include "ae_select.c"
		#endif
	#endif
#endif

evport是Solaris系统内核提供支持的;
epoll是Linux系统内核提供支持的;
kqueue是Mac系统提供支持的;
select是POSIX提供支持的,一般的操作系统都有支撑(保底方案);
源码:ae_evport.c、ae_epoll.c、ae_kqueue.c、ae_select.c

总结一下:
Redis抽象了一套AE事件模型,将IO事件和时间时间融入一起,同时借助多路复用机制的回调特性(Linux上用epoll),似的IO读写都是非阻塞的,实现高性能的网络处理能力。

我们一直在说的Redis新版本多线程的 特性,意思并不是服务端接收客户端请求变成多线程的了,它还是单线程的。

严格意义上来说,Redis从4.0之后就引入了多线程用来处理一些耗时长的工作和后台工作,那不然的话,如果真的只有一个线程,那些耗时的操作肯定会导致客户端请求被阻塞。我们这里说的多线程,确切的说,叫做多线程IO。

(4)多线程IO

回到多路复用的图,服务端的数据返回给客户端,需要从内核空间copy数据到用户空间,然后回写到socket(write调用),这个过程使非常耗时的。所以多线程IO指的就是把结果写到socket的这个环境是多线程的。处理请求依然是单线程的,所以不存在线程并发安全问题。

(5)select和epoll的区别

select:进程可以通过把一个或者多个 fd 传递给 select 系统调用,进程会阻塞在 select 操作上,这样 select 可以帮我们检测多个 fd 是否处于就绪状态。

这个模式有二个缺点
1.由于他能够同时监听多个文件描述符,假如说有 1000 个,这个时候如果其中一个 fd 处于就绪状态了,那么当前进程需要线性轮询所有的 fd,也就是监听的 fd 越多,性能开销越大。
2.同时,select 在单个进程中能打开的 fd 是有限制的,默认是 1024,对于那些需要支持单机上万的 TCP 连接来说确实有点少。
Redis为什么会这么快?Redis到底有多快?

epoll:linux 还提供了 epoll 的系统调用,epoll 是基于事件驱动方式来代替顺序扫描,因此性能相对来说更高,主要原理是,当被监听的 fd 中,有 fd 就绪时,会告知当前进程具体哪一个 fd 就绪,那么当前进程只需要去从指定的 fd 上读取数据即可。
另外,epoll 所能支持的 fd 上线是操作系统的最大文件句柄,这个数字要远远大于 1024。

【由于 epoll 能够通过事件告知应用进程哪个 fd 是可读的,所以我们也称这种 IO 为异步非阻塞 IO,当然它是伪异步的,因为它还需要去把数据从内核同步复制到用户空间中,真正的异步非阻塞,应该是数据已经完全准备好了,我只需要从用户空间读就行】

Redis为什么会这么快?Redis到底有多快?文章来源地址https://www.toymoban.com/news/detail-471903.html

到了这里,关于Redis为什么会这么快?Redis到底有多快?的文章就介绍完了。如果您还想了解更多内容,请在右上角搜索TOY模板网以前的文章或继续浏览下面的相关文章,希望大家以后多多支持TOY模板网!

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处: 如若内容造成侵权/违法违规/事实不符,请点击违法举报进行投诉反馈,一经查实,立即删除!

领支付宝红包 赞助服务器费用

相关文章

  • 【Redis】为什么要学 Redis

    关于为什么要学 Redis 这个问题,一个字就可以回答,那就是:快! Redis是一个将数据储存到内存中的非关系型数据库,它是以键值对的形式来组织数据的,一般可以用作内存数据库、缓存、消息队列等。 使用 Redis 的主要原因就是因为它的快,但是它的快是相对于 MySQL 等这样

    2024年02月09日
    浏览(32)
  • 快速排序到底有多快

    作者主页: paper jie的博客_CSDN博客-C语言,算法详解领域博主 本文作者: 大家好,我是paper jie,感谢你阅读本文,欢迎一建三连哦。 本文录入于 《算法详解》专栏,本专栏是针对于大学生,编程小白精心打造的。笔者用重金(时间和精力)打造,将算法基础知识一网打尽,希望

    2024年02月10日
    浏览(37)
  • Redis为什么快?

    redis是一个开源的使用ANSI C语言编写、支持网络、可基于内存亦可持久化的日志型、Key-Value数据库,并提供多种语言的API。和Memcached类似。redis支持存储的value类型相对更多,包括string(字符串)、list(链表)、set(集合)和zset(有序集合)。 它的速度快主要归功于以下几个方面: 内存

    2023年04月26日
    浏览(36)
  • redis为什么快

      内存存储:Redis 主要将数据存储在内存中,内存的读写速度远高于磁盘存储。这使得 Redis 能够快速地响应读写请求,适用于对读写性能要求较高的场景。 单线程模型:Redis 使用单线程模型来处理客户端请求,避免了多线程间的锁竞争和上下文切换开销。虽然单线程模型在

    2024年01月19日
    浏览(54)
  • 为什么要用redis

    就是把你一些复杂操作耗时查出来的结果(用了600ms),如果确定后面不咋变了,然后但是马上还有很多读请求,那么直接结果放缓存(6ms),后面直接读缓存就好了。 这样,性能就提升了100倍 说白了就是,用redis挡访问,高并发的访问,不让mysql挂了。 mysql这么重的数据库,压根

    2024年02月12日
    浏览(28)
  • Redis为什么快?(面试常问)

    Redis 是一个开源的高性能内存数据库,特点是数据存储在内存中,操作时性能更高;还支持多种数据结构,String、Hash、list、set、zset等,key还支持自动过期。 Redis的好处 是因为数据存在内存中所以性能更高,还有因为是单线程操作,所以天然具有线程安全的特性,单线程又能

    2024年02月11日
    浏览(32)
  • Redis为什么能如此之快

    Redis,一个以超高的性能和强大 的数据结构功能著称的内存数据库,在处理各种复杂数据操作时,速度却能达到惊人的水平。那么,Redis为什么能如此之快呢?今天,我们就来深入解析一下Redis的线程模型,揭开这个问题的神秘面纱。 在探讨Redis的线程模型之前,我们首先需要

    2024年02月12日
    浏览(29)
  • Redis为什么是单线程的

    首先,现在的CPU一般都是由多个核心组成,每个核心可以认为是一个独立的处理器,它们能够并行地处理任务。所以,如果我们的CPU是多核的,但是程序是单线程的,那么执行程序时,这个线程在某一个时刻只能在一个核心上运行,而其它的核心却是空闲的(如果没有其他程

    2024年02月11日
    浏览(31)
  • 你的 Redis为什么变慢了?一文讲透Redis性能优化如何做

    对 Redis 进行基准性能测试 例如,我的机器配置比较低,当延迟为 2ms 时,我就认为 Redis 变慢了,但是如果你的硬件配置比较高,那么在你的运行环境下,可能延迟是 0.5ms 时就可以认为 Redis 变慢了。 所以,你只有了解了你的 Redis 在生产环境服务器上的基准性能,才能进一步

    2024年02月02日
    浏览(42)
  • Redis为什么被设计为单线程

            redis是单线程的原因在于redis用单个CPU绑定一块内存的数据,然后针对这块内存的数据进行多次读写的时候,都是在一个CPU上完成的。redis核心就是 如果我的数据全都在内存里,我单线程的去操作就是效率最高的。所以,redis是单线程。 一、 Redis为什么那么快 1、完

    2024年02月21日
    浏览(30)

觉得文章有用就打赏一下文章作者

支付宝扫一扫打赏

博客赞助

微信扫一扫打赏

请作者喝杯咖啡吧~博客赞助

支付宝扫一扫领取红包,优惠每天领

二维码1

领取红包

二维码2

领红包