众所周知,Redis是一个单线程架构的NoSQL数据库,但是是单线程模型的Redis为什么性能如此之高?这就是我们接下来要探究学习的内容。

1、Redis的单线程架构

1.1、Redis单线程简介

首先要明白,Redis的单线程指的是执行命令时的单线程

Redis客户端与服务端的模型可以简化成下图,每次客户端调用都经历了发送命令、执行命令、返回结果三个过程。

我们说的单线程就是在第二步执行命令,一条命令从从客户端达到服务端不会立刻被执行,而是会进入一个队列中等待,每次只会有一条指令被选中执行。

发送命令、返回结果、命令排队这些就不是那么简单了,例如Redis使用了I/O多路复用技术来解决I/O的问题。

1.2、Redis为什么要使用单线程

这是官方的解释:https://redis.io/topics/faq

官方FAQ表示,因为Redis是基于内存的操作,CPU成为Redis的瓶颈的情况很少见,Redis的瓶颈最有可能是内存的大小或者网络限制。

如果想要最大程度利用CPU,可以在一台机器上启动多个Redis实例。

值得一提的,网络上存在这样的观点:吐槽官方的解释有些敷衍,其实就是历史原因,开发者嫌多线程麻烦,后来这个CPU的利用问题就被抛给了使用者。

同时FAQ里还提到了, Redis 4.0 之后开始变成多线程,除了主线程外,它也有后台线程在处理一些较为缓慢的操作,例如清理脏数据、无用连接的释放、大 Key 的删除等等。

1.3、为什么单线程还能这么快

通常来讲,单线程处理能力要比多线程差,那么为什么Redis使用单线程模型会达到每秒万级别的处理能力呢?可以将其归结为三点:

  • 第一:纯内存访问,Redis将所有数据放在内存中,内存的响应时长大约为100纳秒,这是Redis达到每秒万级别访问的最重要的基础。

  • 第二:非阻塞I/O,Redis使用epoll作为I/O多路复用技术的实现,再加上Redis自身的事件处理模型将epoll中的连接、读写、关闭都转换为事件,不在网络I/O上浪费过多的时间

这里再扩展一下I/O多路复用:

引用知乎上一个高赞的回答来解释什么是I/O多路复用。假设你是一个老师,让30个学生解答一道题目,然后检查学生做的是否正确,你有下面几个选择:

  1. 第一种选择:按顺序逐个检查,先检查A,然后是B,之后是C、D。。。这中间如果有一个学生卡主,全班都会被耽误。这种模式就好比,你用循环挨个处理socket,根本不具有并发能力。

  2. 第二种选择:你创建30个分身,每个分身检查一个学生的答案是否正确。 这种类似于为每一个用户创建一个进程或者线程处理连接。

  3. 第三种选择,你站在讲台上等,谁解答完谁举手。这时C、D举手,表示他们解答问题完毕,你下去依次检查C、D的答案,然后继续回到讲台上等。此时E、A又举手,然后去处理E和A。

第一种就是阻塞IO模型,第三种就是I/O复用模型,Linux下的select、poll和epoll就是干这个的。将用户socket对应的fd注册进epoll,然后epoll帮你监听哪些socket上有消息到达,这样就避免了大量的无用操作。此时的socket应该采用非阻塞模式

这样,整个过程只在调用select、poll、epoll这些调用的时候才会阻塞,收发客户消息是不会阻塞的,整个进程或者线程就被充分利用起来,这就是事件驱动,所谓的reactor模式。

  • 第三:单线程避免了线程切换和竞态产生的消耗。

我们继续来看Redis单线程却很快的最后一条原因,在多线程开发中,存在线程的切换和竞争,这样一来,是有时间的消耗的。对于需要磁盘I/O的程序来讲,磁盘I/O是一个比较耗时的操作,所以对于需要进行磁盘I/O的程序,我们可以使用多线程,在某个线程进行I/O时,CPU切换到当前程序的其他线程执行,以此减少CPU的等待时间。

那么问题来了。Redis的数据存放在内存中,将内存中的数据读入CPU时,CPU不是依然需要等待吗,为什么不能在等待数据从内存读入CPU期间执行其他线程,以此提高CPU的使用率呢?这个问题的答案很简单,内存的读些速度虽然比CPU慢很多,但是也是非常快的。CPU切换线程需要花费一定的时间,而多次切换线程所花费的时间,可能比直接使用单线程执行相同的任务,花费的时间要更多,这是非常不划算的。

单线程也会有一个问题:对于每个命令的执行时间是有要求的。如果某个命令执行过长,会造成其他命令的阻塞,对于Redis这种高性能的服务来说是致命的,所以Redis是面向快速执行场景的数据库。

2、支持多线程的Redis6.0

“Redis不是单线程吗?怎么又支持多线程了?”

相信学到了这里,这已经不是一个问题了。

Redis6.0引入了多线程的特性,这个多线程是在哪里呢?——是对处理网络请求过程采用了多线程

Redis 6.0采用多个IO线程来处理网络请求,网络请求的解析可以由其他线程完成,然后把解析后的请求交由主线程进行实际的内存读写。提升网络请求处理的并行度,进而提升整体性能。

那么多并发的线程安全问题存在吗?——当然不存在。

Redis 的多 IO 线程只是用来处理网络请求的,对于命令的执行,Redis 仍然使用单线程来处理。


参考:

【1】:《Redis开发与运维》

【2】:支持多线程的Redis6.0来了

【3】:为什么 Redis 选择单线程模型

【4】:Redis 和 I/O 多路复用

【5】:I/O多路复用技术(multiplexing)是什么?

【6】:一文搞懂I/O多路复用及其技术

【7】:Redis为什么是单线程的

【Redis破障之路】三:Redis单线程架构的更多相关文章

  1. 【Redis破障之路】二:Redis安装和基本数据结构

    1.安装Redis Redis6.0在2020年已经发布,所以我们安装Redis3.0. 1.1.在Linux上安装Redis 我们在CentOS上安装Redis.常见的的有三种安装方式: yum/a ...

  2. 【Redis破障之路】四:Jedis基本使用

    在前面我们已经学习了Redis命令行客户端redis-cli的使用,接下来我们了解一下Redis基于Java编程语言的客户端. 在Java语言体系下,有三个常用的Redis客户端Jedis.Redis ...

  3. 关于redis的几件小事(三)redis的数据类型与使用场景

    1.string 这是最基本的类型了,就是普通的set和get,做简单的kv缓存. 2.hash 这个是类似map的一种结构,这个一般就是可以将结构化的数据,比如一个对象(前提是这个对象没嵌套其他的对 ...

  4. Redis单线程架构

    参考链接: http://blog.csdn.net/qqqqq1993qqqqq/article/details/77538202 单线程模型: redis中的数据结构并不全是简单的kv,还有lis ...

  5. Redis学习总结(三)--Redis持久化

    Redis 是将数据存储在内存中的,如果出现断电或系统故障的时候数据就会存在丢失的现象,Redis通过将数据持久化到硬盘中来避免这个问题的出现,我们今天就来学习下 Redis 持久化. Redis 持 ...

  6. Redis单线程架构以及工作方式

    一.单线程模型 Redis客户端对服务端的每次调用都经历了发送命令,执行命令,返回结果三个过程.其中执行命令阶段,由于Redis是单线程来处理命令的,所有每一条到达服务端的每一条到达服务端的命令都不会 ...

  7. java架构之路-(Redis专题)简单聊聊redis分布式锁

    这次我们来简单说说分布式锁,我记得过去我也过一篇JMM的内存一致性算法,就是说拿到锁的可以继续操作,没拿到的自旋等待. 思路与场景 我们在Zookeeper中提到过分布式锁,这里我们先用redis实现 ...

  8. 【进阶之路】Redis基础知识两篇就满足(一)

    导言 大家好,我是南橘,一名练习时常两年半的java练习生,这是我在博客园的第一篇文章,当然,都是要从别处搬运过来的,不过以后新的文章也会在博客园同步发布,希望大家能多多支持^_^ 这篇文章的出现,首 ...

  9. 三.redis 排序

    本篇文章介绍下redis排序命令.redis支持对list,set和sorted set元素的排序.排序命令是sort 完整的命令格式如下: SORT key [BY pattern] [LIMIT ...

随机推荐

  1. 微信小程序:页面生命周期

    小程序生命周期分为应用生命周期和页面生命周期 1.Onload:页面加载时触发,一般在onLoad中发送异步请求来初始化页面数据. 2.onShow:页面显示时触发 3.onReady:页面初次渲染完 ...

  2. 微信小程序开发小技巧:

    小技巧:输入view.tabs_content就可以生成下面的代码. 输入p10,就可以得到: 输入jc:c得到:文字水平对齐 输入d:f得到: 输入ai:c得到: 输入bb得到: currentCo ...

  3. SpringCloud Stream

    1.介绍 官网:https://www.springcloud.cc/spring-cloud-dalston.html#_spring_cloud_stream 1.1定义 是一个构建消息驱动微服务 ...

  4. Linux Cron 定时任务

    作者:丁仪 来源:https://chengxuzhixin.com/blog/post/LinuxCron-ding-shi-ren-wu.html 定时任务是经常被用到的,比如系统备份.数据导出等 ...

  5. js中数据、内存、变量的概念及三者之间的关系

    目录 数据.内存.变量的概念及三者之间的关系 什么是数据 数据的特点 什么是内存 栈内存 堆内存 JS引擎如何管理内存 什么是变量 变量是普通类型时 变量是引用类型时 数据.内存.变量的三者之间的关系 ...

  6. 女朋友看了会生气的回答 URI和URL有什么区别?

    URL是什么 URL 代表着是统一资源定位符(Uniform Resource Locator).作用是为了告诉使用者 某个资源在 Web 上的地址.这个资源可以是一个 HTML 页面,一个 CSS ...

  7. Jacobi与SOR迭代法的实现与性能比较及均匀间距与Chebyshev插值的实现、性能分析及二者生成的插值误差比较

    这篇文章给出(1)Jacobi与SOR迭代法的实现与性能比较及(2)均匀间距与Chebyshev插值的实现.性能分析及二者生成的插值误差比较,给出完整的实现代码,没有进行性能优化,仅供参考. (1)J ...

  8. [UNP] TCP 多进程服务器

    UNP Part-2: Chapter 5. TCP Client/Server Example 的读书笔记. 阅读本文前,建议先阅读多线程服务器的实现,熟悉常见的 TCP 网络通信 API 的基本使 ...

  9. 前端学习 node 快速入门 系列 —— 初步认识 node

    其他章节请看: 前端学习 node 快速入门 系列 初步认识 node node 是什么 node(或者称node.js)是 javaScript(以下简称js) 运行时的一个环境.不是一门语言. 以 ...

  10. WPF 基础 - xaml 语法总结

    Attribute 与 Property 之间的区别 Property 对应着抽象对象身上的性状: Attribute 是针对标签的特征: 往往一个标签具有的 Attribute 对于它所代表的对象的 ...