Redis的多路复用机制

2023-11-06

Redis是单线程还是多线程?

通常我们所说的Redis 是单线程,主要是指 Redis 的网络 IO 和键值对读写是由一个线程来完成的,这也是 Redis 对外提供键值存储服务的主要流程。但 Redis 的其他功能,比如持久化、异步删除、集群数据同步等,其实是由额外的线程执行的。所以严格来说Redis并不是单线程的。

Redis为什么不用多线程处理每个命令呢?

想必大家都听过,多线程能提高系统吞吐率这个说法了,但是这个的前提是要有很好的系统设计,尤其是共享资源的并发访问控制问题,如果没有精心的设计,那么并行也会变成串行,而且,采用多线程开发一般会引入同步原语来保护共享资源的并发访问,这也会降低系统代码的易调试性和可维护性。为了避免这些问题,Redis 直接采用了单线程模式。

Redis的多路复用机制

Redis之所以这么快除了完全基于内存计算和高效的数据结构意外,还有一个重要的原因就是采用了多路复用机制,使其在网络 IO 操作中能并发处理大量的客户端请求,实现高吞吐率。

要想了解IO模型,首先我们要知道IO操作是基于什么来实现的,如果一个应用程序, 想对外提供服务, 一般都是通过建立套接字监听端口来实现, 也就是socket,IO多路复用是系统来实现的并不是Redis实现的,这个需要系统层面的支持。不要搞混哈,不过现在很多系统都实现了IO多路复用,可能只是不同的系统实现方式不同而已。

好,那下面我们先来搞一下基本的IO模型和它的阻塞点?

以 Get 请求为例,Redis为了处理一个GET请求,先要监听客户端请求(bind/listen),和客户端建立连接(accept),从 socket 中读取请求(recv),解析客户端发送请求(parse),根据请求类型读取键值数据(get),最后给客户端返回结果,即向 socket 中写回数据(send)。下图显示了这一过程,其中,bind/listen、accept、recv、parse 和 send 属于网络 IO 处理,而 get 属于键值数据操作。既然 Redis 是单线程,那么,最基本的一种实现是在一个线程中依次执行上面说的这些操作。
在这里插入图片描述
但是,在这里的网络 IO 操作中,有潜在的阻塞点,分别是 accept() 和 recv()。当 Redis 监听到一个客户端有连接请求,但一直未能成功建立起连接时,会阻塞在 accept() 函数这里,导致其他客户端无法和 Redis 建立连接。类似的,当 Redis 通过 recv() 从一个客户端读取数据时,如果数据一直没有到达,Redis 也会一直阻塞在 recv()。

这就导致 Redis 整个线程阻塞,无法处理其他客户端请求,效率很低。不过,幸运的是,socket 网络模型本身支持非阻塞模式。

非阻塞模式

非阻塞模式Socket 网络模型的非阻塞模式设置,主要体现在三个关键的函数调用上,如果想要使用 socket 非阻塞模式,就必须要了解这三个函数的调用返回类型和设置模式。接下来,我们就重点学习下它们。

在 socket 模型中,不同操作调用后会返回不同的套接字类型。socket() 方法会返回主动套接字,然后调用 listen() 方法,将主动套接字转化为监听套接字,此时,可以监听来自客户端的连接请求。最后,调用 accept() 方法接收到达的客户端连接,并返回已连接套接字。

在这里插入图片描述
针对监听套接字,我们可以设置非阻塞模式:当 Redis 调用 accept() 但一直未有连接请求到达时,Redis 线程可以返回处理其他操作,而不用一直等待。但是,你要注意的是,调用 accept() 时,已经存在监听套接字了。

虽然 Redis 线程可以不用继续等待,但是总得有机制继续在监听套接字上等待后续连接请求,并在有请求时通知 Redis。

类似的,我们也可以针对已连接套接字设置非阻塞模式:Redis 调用 recv() 后,如果已连接套接字上一直没有数据到达,Redis 线程同样可以返回处理其他操作。我们也需要有机制继续监听该已连接套接字,并在有数据达到时通知 Redis。

这样才能保证 Redis 线程,既不会像基本 IO 模型中一直在阻塞点等待,也不会导致 Redis 无法处理实际到达的连接请求或数据。

到此,Linux 中的 IO 多路复用机制就要登场了,上面说了多路复用机制是系统层面去实现的哦。

基于多路复用的高性能 I/O 模型

Linux 中的 IO 多路复用机制是指一个线程处理多个 IO 流,就是我们经常听到的 select/epoll 机制。简单来说,在 Redis 只运行单线程的情况下,该机制允许内核中,同时存在多个监听套接字和已连接套接字。内核会一直监听这些套接字上的连接请求或数据请求。一旦有请求到达,就会交给 Redis 线程处理,这就实现了一个 Redis 线程处理多个 IO 流的效果。

下图就是基于多路复用的 Redis IO 模型。图中的多个 FD 就是刚才所说的多个套接字。Redis 网络框架调用 epoll 机制,让内核监听这些套接字。此时,Redis 线程不会阻塞在某一个特定的监听或已连接套接字上,也就是说,不会阻塞在某一个特定的客户端请求处理上。正因为此,Redis 可以同时和多个客户端连接并处理请求,从而提升并发性。
在这里插入图片描述
为了在请求到达时能通知到 Redis 线程,select/epoll 提供了基于事件的回调机制,即针对不同事件的发生,调用相应的处理函数。

那么,回调机制是怎么工作的呢?其实,select/epoll 一旦监测到 FD 上有请求到达时,就会触发相应的事件,其实就是Redis会在select/epoll 机制上提前去注册Redis自己提供的回调函数。

这些事件会被放进一个事件队列,Redis 单线程对该事件队列不断进行处理。这样一来,Redis 无需一直轮询是否有请求实际发生,这就可以避免造成 CPU 资源浪费。同时,Redis 在对事件队列中的事件进行处理时,会调用相应的处理函数,这就实现了基于事件的回调。因为 Redis 一直在对事件队列进行处理,所以能及时响应客户端请求,提升 Redis 的响应性能。

为了方便你理解,我再以连接请求和读数据请求为例,具体解释一下。

这两个请求分别对应 Accept 事件和 Read 事件,Redis 分别对这两个事件注册 accept 和 get 回调函数。当 Linux 内核监听到有连接请求或读数据请求时,就会触发 Accept 事件和 Read 事件,此时,内核就会回调 Redis 相应的 accept 和 get 函数进行处理。

另外Redis在6.0推出了多线程,可以在高并发场景下利用CPU多核多线程读写客户端数据,进一步提升server性能,当然,只是针对客户端的读写是并行的,每个命令的真正操作依旧是单线程的。

本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

Redis的多路复用机制 的相关文章

  • 为什么Redis中不建议使用KEYS?

    在Redis中 建议不要使用按键命令 https redis io commands KEYS 为什么会这样呢 是因为它的时间复杂度是 O N 吗 或者是别的什么原因 我做了下面的实验来证明KEYS命令有多么危险 当带有 KEYS 的一个命
  • WSL Redis 遇到系统尚未使用 systemd 作为 init 系统(PID 1)启动。无法操作[已关闭]

    Closed 这个问题不符合堆栈溢出指南 help closed questions 目前不接受答案 我正在尝试遵循本文中讨论的 Redis 安装过程article https www digitalocean com community
  • 库存管理系统的 SQL 与 NoSQL

    我正在开发一个基于 JAVA 的网络应用程序 主要目的是拥有在多个称为渠道的网站上销售的产品的库存 我们将担任所有这些渠道的管理者 我们需要的是 用于管理每个渠道的库存更新的队列 库存表 其中包含每个通道上分配的正确快照 将会话 ID 和其
  • 如果另一个键中的计数器低于零,则从集合中原子删除一个项目?

    雷迪斯2 0 3 在我的 Redis DB 中 我有一组项目 每个项目都有一个与其关联的计数器 MULTI SADD items set foo INCRBY items foo 10000 EXEC 新项目会以随机间隔添加到集合中 当用户
  • redis-cli 重定向到 127.0.0.1

    我在PC1上启动Redis集群 然后在PC2上连接它 当需要重定向到另一个集群节点时 它会显示Redirected to slot 7785 located at 127 0 0 1 但应该显示Redirected to slot 7785
  • Redis INCRBY 有限制

    我想知道是否有一种方法可以通过我的应用程序的单次往返在 Redis 中执行此操作 对于给定的键K 其可能值V是范围内的任意整数 A B 基本上 它有上限和下限 When an INCRBY or DECRBY发出命令 例如INCRBY ke
  • 从redis中检索大数据集

    一台服务器上的应用程序查询另一台服务器上运行的 Redis 查询的结果数据集约为 250kzrangebyscore objects locations inf inf这在应用程序服务器上似乎需要 40 秒 当使用命令执行时redis cl
  • redis 阻塞直到 key 存在

    我是 Redis 新手 想知道是否有办法能够await get通过它的键来获取值 直到该键存在 最小代码 async def handler data await self fetch key async def fetch key ret
  • 如何测试我的 Redis 缓存是否正常工作?

    我已经安装了 django redis cache 和 redis py 我遵循了 Django 的缓存文档 据我所知 以下设置就是我所需要的 但我如何判断它是否正常工作 设置 py CACHES default BACKEND redis
  • 在 aws-elasticache 上使用 memcached 或 Redis

    我正在 AWS 上开发一个应用程序 并使用 AWS elasticache 进行缓存 我对使用 memcached 或 redis 感到困惑 我阅读了有关 redis 3 0 2 更新以及它现在如何等同于 memchached 的文章 ht
  • SignalR 无法连接到 SSL 上的 Azure Redis

    我目前在 Azure 上托管我的 redis 缓存服务器 并让 signalR 依赖它作为骨干 使用以下内容 GlobalHost DependencyResolver UseRedis 服务器 端口 密码 eventKey 这可以在端口
  • 使用 Redis 命令 incr 和 expire 时的竞争条件

    根据redis文档 http redis io commands incr http redis io commands incr 在段落模式 速率限制器 2 较短的版本代码 value INCR ip IF value 1 THEN EX
  • Redis Docker compose无法处理RDB格式版本10

    我无法在 docker compose 文件中启动 redis 容器 我知道docker compose文件没问题 因为我的同事可以成功启动项目 我读到有一个删除 dump rdb 文件的解决方案 但我找不到它 我使用Windows机器 任
  • 如何在Redis中从hmset()切换到hset()?

    我收到弃用警告 即 Redis hmset 已弃用 请改用 Redis hset 但是 hset 采用第三个参数 我不知道是什么name应该是 info users 10 timestamp datetime utcnow strftime
  • Redis、会话过期和反向查找

    我目前正在构建一个网络应用程序 并想使用 Redis 来存储会话 登录时 会话会使用相应的用户 ID 插入到 Redis 中 并且过期时间设置为 15 分钟 我现在想实现会话的反向查找 获取具有特定用户 ID 的会话 这里的问题是 由于我无
  • 有没有办法用Lettuce自动发现Redis集群中新的集群节点IP

    我有一个Redis集群 3主3从 运行在一个库伯内斯簇 该集群通过Kubernetes 服务 Kube 服务 我将我的应用程序服务器连接到 Redis 集群 使用Kube 服务作为 URI 通过 Redis 的 Lettuce java 客
  • 如何使redis中的“HSET”子键“过期”?

    我需要使 Redis 哈希中所有超过 1 个月的密钥过期 这不可能 https github com antirez redis issues 167 issuecomment 2559040 为了保持 Redis 简单 https git
  • StackExchange.Redis的正确使用方法

    这个想法是使用更少的连接和更好的性能 连接会随时过期吗 对于另一个问题 redis GetDatabase 打开新连接 private static ConnectionMultiplexer redis private static ID
  • 如何使 Redis 缓存中数据层次结构(树)的部分内容无效

    我有一些产品数据 需要在 Redis 缓存中存储多个版本 数据由 JSON 序列化对象组成 获取普通 基本 数据的过程很昂贵 将其定制为不同版本的过程也很昂贵 因此我想缓存所有版本以尽可能进行优化 数据结构看起来像这样 BaseProduc
  • 如何在Redis中只保存一个数据库?

    我是 Redis 新手 有一个与备份相关的问题 目前 我有一个实例在 Windows 服务器上运行 在这个实例中 我当前有一项 工作 将数据存储在一个数据库中 我不想备份这些数据 我必须创造一份新工作 我的第一个想法是将数据存储在另一个数据

随机推荐

  • Linux环境下一些配置记录

    Cmake出现The CXX Compiler not found错误 sudo apt get update sudo apt get install build essential sudo apt get install libgle
  • Flutter 使用Positioned 时异常BoxConstraints forces an infinite width.

    The following assertion was thrown during performLayout BoxConstraints forces an infinite width These invalid constraint
  • 记录实现el-table列表的无限滚动(InfiniteScroll)--使用原生Scroll

    由于接收到要求 项目由vue2切换成vue3 要前台列表使用无限滚动展示数据 我在查阅资料后发现原来官方推荐的方法是vue infinite scroll这个现在已经不在维护的插件 虽然vue infinite scroll确实挺好的 但就
  • Git 右键添加Git Bash Here

    小Z由于不知原因 右键没有了Git Bash Here 没有这个右键菜单导致获取Git仓库中的代码很不方便 所以决定通过注册表的方式将这个菜单加出来 运行regedit exe进入注册表 在HKEY CLASSES ROOT Directo
  • 用例图分析---学生成绩管理系统

    尝试画出学生成绩管理的用例图 用例有 登录 找回密码 输入 修改 保存 查询 删除成绩 参与者有教师与学生
  • JIS-CTF_VulnUpload靶机攻略

    本文中涉及到的相关漏洞已报送厂商并得到修复 本文仅限技术研究与讨论 严禁用于非法用途 否则产生的一切后果自行承担 vulnhub 是我喜爱的游乐场之一 上面的每个靶机都是很酷的一个游戏 完整找出所有 flag 只是基本任务 实现提权才是终极
  • 区块链应用 - LV的奢侈品验证平台

    领先的以太坊解决方案商ConsenSys与微软以及奢侈品牌路易威登合作开发了一个基于区块链的奢侈品验证平台 消费者可以使用该品牌验证买到的路易威登或迪奥产品 同属于LVMH 是否正品 该系统被称为 Aura 其设计目标是 服务于整个奢侈品行
  • 成长之路-- 从0开始学python(17)--Excel结合测试用例使用&数据驱动

    一般自动化测试的流程 准备测试数据 根据被测函数的参数 调用被测函数 得到实际结果 断言 这样的方法可以完成测试 但是存在不少的缺点 一个用例需要单独编写一个测试用例函数 方法 存在重复性代码 可以通过ddt解决 测试的数据都放在用例的方法
  • 对象成员的引用

    访问对象中的成员可以有3种方法 通过对象名和对象成员引用运算符 访问对象中的成员 通过指向对象的指针和指针成员引用运算符 gt 访问对象中的成员 通过对象的引用变量和对象成员引用运算符 访问对象中的成员 1 通过对象名访问对象中的成员 访问
  • 乳腺仿体breast phantom的MATLAB实现及探讨

    文献出处 2006 Development of an Analytic Breast Phantom for Quantitative Comparison of Reconstruction Algorithms for DBT I R
  • 一篇文章搞懂CMake(gcc、g++、cmake解释)

    一篇文章搞懂CMake gcc g cmake解释 这里写目录标题 一篇文章搞懂CMake gcc g cmake解释 gcc g cmake 1 CMake 流程 如何使用cmake 简单的CMake txt文件 参考 gcc gcc命令
  • C++14尝鲜:函数返回类型自动推导

    函数返回类型自动推导 函数返回类型自动推导是指C 11以及C 14中不直接给出函数返回类型 而是使用类型指示符来指示返回类型甚至彻底省略返回类型并最终由编译器来推导返回类型的语言特性 函数返回类型自动推导原则如下 当函数体内不包含任何返回值
  • 【译】Rust 中的错误处理

    Error Handling in Rust 译文 Rust 中的错误处理 原文链接 Error Handling in Rust Andrew Gallant s Blog 原文作者 Andrew Gallant 译文来自 GitHub
  • react配置之绝对路径

    绝对路径不多bb 简单的说就是 我们不再使用 之类的来表示路径位置了 直接上代码 我用的是react crate app脚手架 npm install react create app g react create app my react
  • advisor 2002的安装

    一 安装资源 http pan baidu com s 1sljurHN 二 遇到安装问题的解决方案 来源于博客 http blog csdn net qq 33565051 article details 52065063 1 在上面的网
  • 小程序首次授权拒绝后如何再次授权?(从用户的层面解决问题)

    写在前面 为了能及时的将自己踩到的前端坑 包括ionic angular react ReactNative 小程序 APICloud 分享给大家 以后会逐渐将文章转移到微信公众号 前端e家 front e family 可直接扫码关注 公
  • Java的常用日志技术(二)Logback详解

    之前我们学习了日志实现框架JUL Log4j 以及 Log4j 各种配置方式 此章我们将在 log4j 的配置文件格式的基础上 学习 logback 及相关配置 Logback简介 Logback是由log4j 创始人设计的又一个开源日志组
  • vscode 个人使用配置

    因公司绿盾加密导致使用source insight远程访问代码受限 转战vscode 把自己第一次接触以来的操作记录一下 省的哪天要重新配置还得百度半天 文章目录 1 插件安装 2 设置中文 3 设置ssh远程访问代码 3 1 安装Remo
  • 单例模式的4种写法

    单例模式是开发过程中常用的模式之一 首先了解下单例模式的四大原则 构造方法私有 以静态方法或枚举返回实例 确保实例只有一个 尤其是多线程环境 确保反射或反序列化时不会重新构建对象 饿汉模式 饿汉模式在类被初始化时就创建对象 以空间换时间 故
  • Redis的多路复用机制

    Redis是单线程还是多线程 通常我们所说的Redis 是单线程 主要是指 Redis 的网络 IO 和键值对读写是由一个线程来完成的 这也是 Redis 对外提供键值存储服务的主要流程 但 Redis 的其他功能 比如持久化 异步删除 集