(三)Redis 线程与IO模型
1、Redis 单线程
通常说 Redis 是单线程,主要是指 Redis 的网络 IO 和键值对读写是由一个线程来完成的,其他功能,比如持久化、异步删除、集群数据同步等,是由额外的线程执行的,所以严格来说,Redis 并不是单线程。
多线程开发会不可避免的带来并发控制和资源开销的问题,如果没有良好的系统设计往往会适得其反,为了避免这些问题,Redis 直接采用了单线程模式。
Redis 单线程模型能达到每秒数十万级别的处理能力,一方面是大部分操作在内存上完成 + 高效的数据结构,例如哈希表和跳表。另一方面,就是采用了多路复用机制,使其在网络 IO 操作中能并发处理大量的客户端请求,实现高吞吐率。
在了解多路复用之前,要先明白网络操作的基本 IO 模型和潜在的阻塞点。如果单线程被阻塞了,就无法进行多路复用了。以 Get 请求为例如下图,bind/listen、accept、recv、parse 和 send 属于网络 IO 处理,get 属于键值数据操作。
这里的网络 IO 操作中,潜在的阻塞点分别是 accept() 和 recv()。当 Redis 监听到一个客户端有连接请求,但一直未能成功建立起连接时,会阻塞在 accept() 函数这里,导致其他客户端无法和 Redis 建立连接。类似的,当 Redis 通过 recv() 从一个客户端读取数据时,如果数据一直没有到达,Redis 也会一直阻塞在 recv(),这就导致 Redis 整个线程阻塞,无法处理其他客户端请求,效率很低。不过,Socket 网络模型可以设置非阻塞模式,基于此 Linux 中的 IO 多路复用机制就要登场了。
2、多路复用机制
Linux 中的 IO 多路复用机制是指一个线程处理多个 IO 流,就是我们经常听到的 select/epoll 机制。简单来说,在 Redis 只运行单线程的情况下,该机制允许内核中,同时存在多个监听套接字和已连接套接字。内核会一直监听这些套接字上的连接请求或数据请求。一旦有请求到达,就会交给 Redis 线程处理,这就实现了一个 Redis 线程处理多个 IO 流的效果。
图中的多个 FD 就是指多个套接字,Redis 网络框架调用 epoll 机制,让内核监听这些套接字。此时,Redis 线程不会阻塞在某一个特定的监听或已连接套接字上,所以,Redis 可以同时和多个客户端连接并处理请求,从而提升并发性。
为了在请求到达时能通知到 Redis 线程,select/epoll 提供了基于事件的回调机制,即针对不同事件的发生,调用相应的处理函数,select/epoll 一旦监测到 FD 上有请求到达时,就会触发相应的事件。这些事件会被放进一个事件队列,Redis 单线程对该事件队列不断进行处理。这样一来,Redis 无需一直轮询是否有请求实际发生,这就可以避免造成 CPU 资源浪费。同时,Redis 在对事件队列中的事件进行处理时,会调用相应的处理函数,这就实现了基于事件的回调。因为 Redis 一直在对事件队列进行处理,所以能及时响应客户端请求,提升 Redis 的响应性能。
3、Redis 6.0 多线程特性
Redis 6.0 之前,虽然有些命令操作可以用后台线程或子进程执行(比如数据删除、快照生成、AOF 重写),但是,从网络 IO 处理到实际的读写命令处理,都是由单个线程完成的,有时会成为 Redis 的性能瓶颈。Redis 6.0 之后采用多个 IO 线程来处理网络请求,提高网络请求处理的并行度,对于读写命令,仍然使用单线程来处理。
具体流程:
(1)主线程接收到客户端连接请求后创建连接,将 Socket 放入全局等待队列中,通过轮询分配给 IO 线程。
(2)分配后主线程就会进入阻塞状态,等待 IO 线程完成客户端请求读取和解析,多个 IO 线程在并行处理,嗖嗖嗖。
(3)IO 线程解析完请求,主线程还是会以单线程的方式执行这些命令操作。
(4)主线程执行完请求操作后,把返回结果写入缓冲区,主线程阻塞等待 IO 线程把这些结果回写到 Socket 中,并返回给客户端。
和 IO 线程读取和解析请求一样,IO 线程回写 Socket 时,也是有多个线程在并发执行,所以回写 Socket 的速度也很快。等到 IO 线程回写 Socket 完毕,主线程会清空全局队列,等待客户端的后续请求。
4、IO 多线程配置
在实际应用中,如果 Redis 实例的 CPU 开销不大,吞吐量却没有提升,可以考虑使用多线程机制提升吞吐量,redis.conf 中设置:
1. 设置 io-thread-do-reads 配置项为 yes,表示启用多线程
io-threads-do-reads yes
2. 设置线程个数要小于 Redis 实例所在机器的 CPU 核个数,例如,对于一个 8 核的机器来说,Redis 官方建议配置 6 个 IO 线程
io-threads 6
(三)Redis 线程与IO模型的更多相关文章
- Replication基础(六) 复制中的三个线程(IO/SQL/Dump)
Reference: https://blog.csdn.net/sun_ashe/article/details/82181811?utm_source=blogxgwz1 简介在MySQL复制技 ...
- {python之IO多路复用} IO模型介绍 阻塞IO(blocking IO) 非阻塞IO(non-blocking IO) 多路复用IO(IO multiplexing) 异步IO(Asynchronous I/O) IO模型比较分析 selectors模块
python之IO多路复用 阅读目录 一 IO模型介绍 二 阻塞IO(blocking IO) 三 非阻塞IO(non-blocking IO) 四 多路复用IO(IO multiplexing) 五 ...
- 15 并发编程-(IO模型)
一.IO模型介绍 1.阻塞与非阻塞指的是程序的两种运行状态 阻塞:遇到IO就发生阻塞,程序一旦遇到阻塞操作就会停在原地,并且立刻释放CPU资源 非阻塞(就绪态或运行态):没有遇到IO操作,或者通过某种 ...
- 通过实例理解Java网络IO模型
网络IO模型及分类 网络IO模型是一个经常被提到的问题,不同的书或者博客说法可能都不一样,所以没必要死抠字眼,关键在于理解. Socket连接 不管是什么模型,所使用的socket连接都是一样的. 以 ...
- Reids原理之IO模型
众所周知Redis是单进程单线程的应用,在如今多核横行的时代,我们不免有疑问,单线程的redis怎么就成了高性能的代表 当有多个线程同时调用redis的时候,那么单线程的redis是怎么处理的呢,这里 ...
- python(40)- 进程、线程、协程及IO模型
一.操作系统概念 操作系统位于底层硬件与应用软件之间的一层.工作方式:向下管理硬件,向上提供接口. 操作系统进行进程切换:1.出现IO操作:2.固定时间. 固定时间很短,人感受不到.每一个应用层运行起 ...
- 03 高性能IO模型:采用多路复用机制的“单线程”Redis
本篇重点 三个问题: "Redis真的只有单线程吗?""为什么用单线程?""单线程为什么这么快?" "Redis真的只有单线程吗? ...
- Redis线程模型的前世今生
一.概述 众所周知,Redis是一个高性能的数据存储框架,在高并发的系统设计中,Redis也是一个比较关键的组件,是我们提升系统性能的一大利器.深入去理解Redis高性能的原理显得越发重要,当然Red ...
- 详解redis网络IO模型
前言 "redis是单线程的" 这句话我们耳熟能详.但它有一定的前提,redis整个服务不可能只用到一个线程完成所有工作,它还有持久化.key过期删除.集群管理等其它模块,redi ...
- Reactor三种线程模型与Netty线程模型
文中所讲基本都是以非阻塞IO.异步IO为基础.对于阻塞式IO,下面的编程模型几乎都不适用 Reactor三种线程模型 单线程模型 单个线程以非阻塞IO或事件IO处理所有IO事件,包括连接.读.写.异常 ...
随机推荐
- Go语言打印九九乘法表,这是整洁代码范例
Go语言打印九九乘法表,这是整洁代码范例 / Go 语言输出九九乘法表 / 九九乘法表是我们学习编程时的一项基本练习,它看似简单,通过实现输出九九乘法表可以加深对 Go 语言循环结构的理解和运用. 本 ...
- DataFunTalk:阿里建设一站式实时数仓的经验分享
简介: 本文内容整理于阿里资深技术专家姜伟华在DataFunTalk上的演讲,为大家介绍阿里巴巴基于一站式实时数仓Hologres建设实时数仓的经验和解决方案. 导读:大数据计算正从规模化走向实时化, ...
- es实战-使用IK分词器进行词频统计
简介:通过IK分词器分词并生成词云. 本文主要介绍如何通过 IK 分词器进行词频统计.使用分词器对文章的词频进行统计,主要目的是实现如下图所示的词云功能,可以找到文章内的重点词汇.后续也可以对词进行 ...
- SmartNews:基于 Flink 加速 Hive 日表生产的实践
简介: 将 Flink 无缝地集成到以 Airflow 和 Hive 为主的批处理系统的技术挑战和应对方案. 本文介绍了 SmartNews 利用 Flink 加速 Hive 日表的生产,将 Flin ...
- LlamaIndex 探索视频系列
如果您喜欢通过视频学习,现在正是查看我们的"探索 LlamaIndex"系列的好时机.否则,我们建议您继续阅读"理解 LlamaIndex"教程. 自下而上开发 ...
- IIncrementalGenerator 判断程序集的引用关系
本文将告诉大家如何在 IIncrementalGenerator 增量 Source Generator 生成代码里面,在 Roslyn 分析器里面判断两个程序集是否存在引用关系 先上核心代码实现,核 ...
- 10.prometheus监控--监控进程process
一.进程监控 如果想要对主机的进程进行监控,例如chronyd,sshd等服务进程以及自定义脚本程序运行状态监控.我们使用node exporter就不能实现需求了,此时就需要使用process ex ...
- 云原生最佳实践系列 6:MSE 云原生网关使用 JWT 进行认证鉴权
01 方案概述 MSE 网关可以为后端服务提供转发路由能力,在此基础上,一些敏感的后端服务需要特定认证授权的用户才能够访问.MSE 云原生网关致力于提供给云上用户体系化的安全解决方案,其中 JWT 认 ...
- 动态修改manifest.json
点击查看代码 // h5开发环境 const h5Dev = { baseUrl: 'https://devh5.....' } // h5测试环境 const h5Test= { baseUrl: ...
- C 语言编程 — 异常处理
目录 文章目录 目录 前文列表 异常处理 perror() 和 strerror() 输出异常信息 程序退出状态 前文列表 <程序编译流程与 GCC 编译器> <C 语言编程 - 基 ...