热门标签 | HotTags
当前位置:  开发笔记 > 编程语言 > 正文

一文看懂Redis6.0多线程IO

本文主要分享【Redis为何设计为单线程】,技术文章【一文看懂Redis6.0多线程IO】为【码农在新加坡】投稿,如果你遇到Redis相关问题,本文相关知识或能到你。Redis为何设计为单线程首

本文主要分享【Redis为何设计为单线程】,技术文章【一文看懂Redis 6.0多线程IO】为【码农在新加坡】投稿,如果你遇到Redis相关问题,本文相关知识或能到你。

Redis为何设计为单线程

首发于微信公众号:【码农在新加坡】,欢迎关注。

个人博客网站:一文看懂Redis 6.0多线程IO

Redis基础 Redis是什么

Redis是一个基于BSD开源的项目,是一个把结构化的数据放在内存中的一个存储系统。

你可以把它作为数据库,缓存和消息中间件来使用。同时支持stringslistshashessetssorted setsbitmapshyperloglogsgeospatial indexes等数据类型。

它还通过redis sentinel实现高可用,通过redis cluster实现了自动分片。以及事务,发布/订阅,自动故障转移等等。

为什么用Redis

而在后端开发的技术选型中,Redis已经成为了一个不可绕过的解决方案工具。因此Redis成为了后端开发的基本技能之一。当然,也是后端面试中必考的技术栈之一。

Redis的优点,如果只用一个字来解释,那就是:快!

Redis 有多快?官方给出的答案是读写速度 10万/秒,如果说这是在单线程情况下跑出来的成绩,你会不会惊讶?为什么单线程的 Redis 速度这么快?

Redis为什么快

主要有以下几点:

Redis 是基于内存的。 内存的读写速度非常快。当然Redis也存在持久化操作,但是是fork子进程和利用 Linux 系统的页缓存技术来完成,并不会影响Redis的读写性能。 Redis 是单线程的。 避免了不必要的上下文切换和竞争条件,也不存在多进程或者多线程导致的切换而消耗 CPU,不用去考虑各种锁的问题,不存在加锁释放锁操作,没有因为可能出现死锁而导致的性能消耗。 Redis 使用多路复用技术。 可以处理并发的连接。非阻塞 IO 部实现采用 epoll,采用了 epoll+自己实现的简单的事件框架。epoll 中的读、写、关闭、连接都转化成了事件,然后利用 epoll 的多路复用特性,绝不在 IO 上浪费一点时间。 Redis 中的数据结构是专门进行设计的。 数据结构简单。对数据操作也简单。 Redis是单线程的吗

我们经常听到,Redis是单线程的,这句话对吗?

基本上是对的,但是不准确。

而对于为什么使用单线程,官方有一句解释:

It’s not very frequent that CPU becomes your bottleneck with Redis, as usually Redis is either memory or network bound.

意思就是:
因为 Redis 是基于内存的操作,CPU 不是 Redis 的瓶颈。Redis 的瓶颈最有可能是机器内存的大小或者网络带宽。既然单线程容易实现,而且 CPU 不会成为瓶颈,那就顺理成章地采用单线程的方案了。

为什么说不准确呢?

我们需要回顾Redis的两个最重要的版本更新:

Redis 4.0 为了防止耗时的命令阻塞线程,导致无法处理后续事件。引入了多线程来处理一些非阻塞命令。有:UNLINKFLUSHALL ASYNCFLUSHDB ASYNC等。
但是整个网络模型依然是单线程的,所以我们称之为单线程。

Redis 6.0 就真正的在网络模型上加入多线程IO来解决网络IO的性能瓶颈。
此时IO读写是多线程的,执行命令依旧是单线程的。

Redis网络模型

一张图看懂Redis的单线程模型:

一文看懂Redis 6.0多线程IO

redis的网络事件处理器是基于Reactor模式,又叫做文件事件处理器。

文件事件处理器使用I/O多路复用来同时监听多个套接字,并根据套接字执行的任务关联到不同的事件处理器。
文件事件以单线程方式运行,但通过使用I/O多路复用程序来监听多个套接字,文件事件处理器实现了高性能的网络通信模型。
Redis 在处理客户端的请求时,包括接收(socket读)、解析执行发送(socket 写) 等都由一个顺序串行的主线程处理,这就是所谓的单线程

Reactor模型

Redis的单线程网络模型,这就是一个经典的Reactor的模型,其本质上是 I/O 多路复用(I/O multiplexing) + 非阻塞 I/O(non-blocking I/O)的模式。

是一种基于事件驱动模型的设计模式。

我们来看一下Reactor里面两种经典的模型。

单线程Reactor模型

Redis的单线程模型就是使用的经典的单线程Reactor模型。

我们先看看单线程的Reactor模型

一文看懂Redis 6.0多线程IO

消息处理流程:

Reactor对象通过 select/poll/epoll等IO多路复用监控连接事件,收到事件后通过 dispatcher事件分发器进行转发。如果是连接建立的事件,则由 acceptor接受连接,并创建 Handler处理后续事件。如果不是建立连接事件,则Reactor会分发调用 Handler来响应。Handler会完成 read->解析->执行->send的完整业务流程。

优点:

单线程运行,串行操作,不需要加锁,逻辑简单。

缺点:

仅用一个线程处理请求,对于多核资源机器来说是有点浪费的。当处理读写任务的线程负载比较重,将会阻塞后续的事件处理,导致整体延迟变大。

应用:

Redis网络模型。(6.0版本以前) Master-Worker Reactor模型

一文看懂Redis 6.0多线程IO

比起单线程模型,它是将Reactor分成两部分:

mainReactor 负责监听server socket,用来处理网络IO连接建立操作,将建立的socketChannel指定注册给subReactor。 (只负责监听) subReactor 主要做和建立起来的socket做数据交互和事件业务处理操作。通常,subReactor个数上可与CPU个数等同。一般是多个,这样的话,就可以充分利用多核的优势。 (负责IO读写和命令的执行)

区别于单线程Reactor模式,这种模式不再是单线程的事件循环,而是有多个线程subReactors各自维护一个独立的事件循环,由 mainReactor 负责接收新连接并分发给 subReactors 去独立处理,最后 subReactors 回写响应给客户端。

优点:

响应快,不必为单个同步时间所阻塞,虽然Reactor本身依然是同步的;可扩展性,可以方便地通过增加Reactor实例个数来充分利用CPU资源;

缺点:

如果多个线程可能操作同一份数据,就涉及到底层数据同步的问题,则必然会引入某些同步机制,比如锁。增加了代码复杂度,同时增加了同步机制的开销。

应用:

Nginx, Netty, Swoole, Memcached就是使用的这个模型 Redis 6.0的多线程网络模型

Redis 6.0版本之后,Redis 正式在核心网络模型中引入了多线程,也就是所谓的 I/O threading,至此 Redis 真正拥有了多线程模型。
但是Redis的多线程模型却并非标准的Master-Worker Reactor模型。他的多线程 只负责IO读写,不负责具体的执行。

为什么Redis 6.0 要使用多线程

之前说了,CPU不是Redis的瓶颈,Redis的瓶颈最有可能是机器内存大小和网络带宽。
从Redis自身角度来说,因为读写网络的read/write系统调用占用了Redis执行期间大部分CPU时间,瓶颈主要在于网络的 IO 消耗, 所以选择多线程IO来实现读写。主线程来执行Redis命令。

总结就是:
将主线程 IO 读写任务拆分出来给一组独立的线程处理,使得多个 socket 读写可以并行化,但是 Redis 命令还是主线程串行执行。

Redis 6.0 网络模型

一文看懂Redis 6.0多线程IO

为什么这么设计呢?

前面提到 Redis 最初选择单线程网络模型的理由是:CPU 通常不会成为性能瓶颈,瓶颈往往是内存和网络,因此单线程足够了。那么为什么现在 Redis 又要引入多线程呢?很简单,就是 Redis 的 网络 I/O 瓶颈已经越来越明显了。所以这个多线程是为了 解决IO的瓶颈的。如果多线程包括了 IO读写,解析和执行的整个过程,那么多线程需要面临线程安全的问题,Redis 6.0版本之前是没有考虑线程安全的,如果使用多线程来处理命令的执行,需要大量的改动来保证多线程的安全机制,实现更复杂。为了避免了不必要的上下文切换和竞争条件,多线程导致的切换而消耗 CPU,也不用考虑各种锁的问题,就让执行这一步只使用主线程。 Redis 6.0和Memcached多线程模型对比

相同点:

都采用了 Master-Worker 的线程的模型

不同点:

Memcached 执行主逻辑也是在 Worker 线程里,模型更加简单,实现了真正的线程隔离,通过各种锁机制来保证数据的线程安全。而 Redis 把执行逻辑交还给 Master 线程,虽然一定程度上增加了模型复杂度,但也解决了数据的线程安全问题。 总结

让我们来回顾一下 Redis 多线程网络模型的设计方案:

使用 I/O 线程实现网络 I/O 多线程化,I/O 线程只负责网络 I/O 和命令解析,不执行具体的命令。

Redis 的多线程网络模型实际上并不是一个标准的 Master-Worker Reactor 模型,Redis 的多线程方案中,I/O 线程任务仅仅是通过 socket 读取客户端请求命令并解析,却没有真正去执行命令。

所有客户端命令最后还需要回到主线程去执行,因此对多核的利用率并不算高,而且每次主线程都必须在分配完任务之后忙轮询等待所有 I/O 线程完成任务之后才能继续执行其他逻辑。

Redis 目前的多线程方案更像是一个折中的选择:既保持了原系统的兼容性,又能利用多核提升 I/O 性能,来解决网络IO的性能瓶颈。

<全文完>

欢迎关注我的微信公众号:【码农在新加坡】,有更多好的技术分享。

个人博客网站:一文看懂Redis 6.0多线程IO

本文《一文看懂Redis 6.0多线程IO》版权归码农在新加坡所有,引用一文看懂Redis 6.0多线程IO需遵循CC 4.0 BY-SA版权协议。


推荐阅读
  • Nginx使用(server参数配置)
    本文介绍了Nginx的使用,重点讲解了server参数配置,包括端口号、主机名、根目录等内容。同时,还介绍了Nginx的反向代理功能。 ... [详细]
  • 目录实现效果:实现环境实现方法一:基本思路主要代码JavaScript代码总结方法二主要代码总结方法三基本思路主要代码JavaScriptHTML总结实 ... [详细]
  • 本文讨论了一个关于cuowu类的问题,作者在使用cuowu类时遇到了错误提示和使用AdjustmentListener的问题。文章提供了16个解决方案,并给出了两个可能导致错误的原因。 ... [详细]
  • 图解redis的持久化存储机制RDB和AOF的原理和优缺点
    本文通过图解的方式介绍了redis的持久化存储机制RDB和AOF的原理和优缺点。RDB是将redis内存中的数据保存为快照文件,恢复速度较快但不支持拉链式快照。AOF是将操作日志保存到磁盘,实时存储数据但恢复速度较慢。文章详细分析了两种机制的优缺点,帮助读者更好地理解redis的持久化存储策略。 ... [详细]
  • 计算机存储系统的层次结构及其优势
    本文介绍了计算机存储系统的层次结构,包括高速缓存、主存储器和辅助存储器三个层次。通过分层存储数据可以提高程序的执行效率。计算机存储系统的层次结构将各种不同存储容量、存取速度和价格的存储器有机组合成整体,形成可寻址存储空间比主存储器空间大得多的存储整体。由于辅助存储器容量大、价格低,使得整体存储系统的平均价格降低。同时,高速缓存的存取速度可以和CPU的工作速度相匹配,进一步提高程序执行效率。 ... [详细]
  • Android工程师面试准备及设计模式使用场景
    本文介绍了Android工程师面试准备的经验,包括面试流程和重点准备内容。同时,还介绍了建造者模式的使用场景,以及在Android开发中的具体应用。 ... [详细]
  • 深入解析Linux下的I/O多路转接epoll技术
    本文深入解析了Linux下的I/O多路转接epoll技术,介绍了select和poll函数的问题,以及epoll函数的设计和优点。同时讲解了epoll函数的使用方法,包括epoll_create和epoll_ctl两个系统调用。 ... [详细]
  • Java中线程池,你真的了解会用吗
    2019独角兽企业重金招聘Python工程师标准在《深入源码分析Java线程池的实现原理》这篇文章中,我们介绍过了Java中线程池的常见用法以及基本原理。在文中 ... [详细]
  • 本文详细介绍了Spring的JdbcTemplate的使用方法,包括执行存储过程、存储函数的call()方法,执行任何SQL语句的execute()方法,单个更新和批量更新的update()和batchUpdate()方法,以及单查和列表查询的query()和queryForXXX()方法。提供了经过测试的API供使用。 ... [详细]
  • 本文介绍了在Vue项目中如何结合Element UI解决连续上传多张图片及图片编辑的问题。作者强调了在编码前要明确需求和所需要的结果,并详细描述了自己的代码实现过程。 ... [详细]
  • 前景:当UI一个查询条件为多项选择,或录入多个条件的时候,比如查询所有名称里面包含以下动态条件,需要模糊查询里面每一项时比如是这样一个数组条件:newstring[]{兴业银行, ... [详细]
  • 大厂首发!思源笔记docker
    JVMRedisJVM面试内存模型以及分区,需要详细到每个区放什么?GC的两种判定方法GC的三种收集方法:标记清除、标记整理、复制算法的 ... [详细]
  • 本文由编程笔记#小编为大家整理,主要介绍了python面试题——数据库和缓存(46题)相关的知识,希望对你有一定的参考价值。1、列举常见的关系型数据库和非关系型都有那些? ... [详细]
  • 数据库基本介绍
    1、数据库基本知识概念:数据库:database(DB),是一种存储数据的仓库数据库是根据数据结构组织、存储和 ... [详细]
  • 开发笔记:Memcached高性能内存对象缓存系统
    篇首语:本文由编程笔记#小编为大家整理,主要介绍了Memcached高性能内存对象缓存系统相关的知识,希望对你有一定的参考价值。一、Memcached概述 ... [详细]
author-avatar
迎风奔跑的狼
这个家伙很懒,什么也没留下!
PHP1.CN | 中国最专业的PHP中文社区 | DevBox开发工具箱 | json解析格式化 |PHP资讯 | PHP教程 | 数据库技术 | 服务器技术 | 前端开发技术 | PHP框架 | 开发工具 | 在线工具
Copyright © 1998 - 2020 PHP1.CN. All Rights Reserved | 京公网安备 11010802041100号 | 京ICP备19059560号-4 | PHP1.CN 第一PHP社区 版权所有