首页 > 数据库 >Redis--单线程

Redis--单线程

时间:2024-04-23 16:46:45浏览次数:37  
标签:调用 -- redis Redis 单线程 线程 多线程

redis是单线程的吗?

不是,redis的单线程指的是命令的执行是单线程的,如接收客户端请求->解析请求 ->进行数据读写等操作->发送数据给客户端这个过程是由一个线程(主线程)完成的。

redis程序并不是单线程,redis 在启动的时候,会启动后台线程(BIO):

  • Redis 在 2.6 版本,会启动 2 个后台线程,分别处理关闭文件、AOF 刷盘这两个任务
  • Redis 在 4.0 版本之后,新增了一个新的后台线程,用来异步释放 Redis 内存,也就是 lazyfree 线程。例如执行 unlink key / flushdb async / flushall async 等命令,会把这些删除操作交给后台线程来执行,好处是不会导致 Redis 主线程卡顿。因此,当我们要删除一个大 key 的时候,不要使用 del 命令删除,因为 del 是在主线程处理的,这样会导致 Redis 主线程卡顿,因此我们应该使用 unlink 命令来异步删除大key。
  • Redis 6.0 版本之后,也采用了多个 I/O 线程来处理网络请求,这是因为随着网络硬件的性能提升,Redis 的性能瓶颈有时会出现在网络 I/O 的处理上。

 

关闭文件、AOF 刷盘、释放内存这三个任务都有各自的任务队列:

  • BIO_CLOSE_FILE,关闭文件任务队列:当队列有任务后,后台线程会调用 close(fd) ,将文件关闭
  • BIO_AOF_FSYNC,AOF刷盘任务队列:当 AOF 日志配置成 everysec 选项后,主线程会把 AOF 写日志操作封装成一个任务,也放到队列中。当发现队列有任务后,后台线程会调用 fsync(fd),将 AOF 文件刷盘
  • BIO_LAZY_FREE,lazy free 任务队列:当队列有任务后,后台线程会 free(obj) 释放对象 / free(dict) 删除数据库所有对象 / free(skiplist) 释放跳表对象

 

redis单线程模型

Redis 6.0 版本之前的单线模式如下图:

图中的蓝色部分是一个事件循环,是由主线程负责的,可以看到网络 I/O 和命令处理都是单线程。 Redis 初始化的时候,会做下面这几件事情:

  • 首先,调用 epoll_create() 创建一个 epoll 对象和调用 socket() 创建一个服务端 socket
  • 然后,调用 bind() 绑定端口和调用 listen() 监听该 socket;
  • 然后,将调用 epoll_ctl() 将 listen socket 加入到 epoll,同时注册「连接事件」处理函数。

初始化完后,主线程就进入到一个事件循环函数,主要会做以下事情:

  • 首先,先调用处理发送队列函数,看是发送队列里是否有任务,如果有发送任务,则通过 write 函数将客户端发送缓存区里的数据发送出去,如果这一轮数据没有发送完,就会注册写事件处理函数,等待 epoll_wait 发现可写后再处理 。
  • 接着,调用 epoll_wait 函数等待事件的到来:
    • 如果是连接事件到来,则会调用连接事件处理函数,该函数会做这些事情:调用 accpet 获取已连接的 socket -> 调用 epoll_ctl 将已连接的 socket 加入到 epoll -> 注册「读事件」处理函数;
    • 如果是读事件到来,则会调用读事件处理函数,该函数会做这些事情:调用 read 获取客户端发送的数据 -> 解析命令 -> 处理命令 -> 将客户端对象添加到发送队列 -> 将执行结果写到发送缓存区等待发送;
    • 如果是写事件到来,则会调用写事件处理函数,该函数会做这些事情:通过 write 函数将客户端发送缓存区里的数据发送出去,如果这一轮数据没有发送完,就会继续注册写事件处理函数,等待 epoll_wait 发现可写后再处理 。

 

redis命令执行使用单线程为什么还那么快?

  1. 内存存储:Redis 将数据存储在内存中,这使得数据的读取和写入操作非常快速。相比于磁盘存储的数据库系统,Redis 能够通过直接从内存中读取数据来提供更高的性能。

  2. 非阻塞 I/O:Redis 采用了非阻塞 I/O 操作,通过异步地处理网络请求和数据读写操作,实现了高效的 I/O 操作。当 Redis 执行一些可能会导致阻塞的操作时,如持久化或网络请求,它会将这些操作委托给操作系统处理,同时继续处理其他请求,从而最大限度地减少了等待时间。

  3. 简单的数据结构:Redis 提供了简单而高效的数据结构,如字符串、哈希表、列表、集合和有序集合等。这些数据结构的实现经过了精心优化,能够在单线程模型下快速执行各种操作,如插入、删除、查找和排序等。

  4. 高效的网络通信:Redis 使用基于 TCP 的客户端/服务器模型,通过高效的网络通信协议与客户端进行通信。Redis 的协议非常简单且高效,减少了网络传输的开销,并且支持批量操作和管道(pipeline)操作,从而减少了网络往返的次数,提高了整体性能。

  5. 非常低的延迟:Redis 的单线程模型消除了多线程环境下的锁竞争和上下文切换开销,使得请求处理的延迟非常低。这对于需要快速响应的应用场景非常有利,如实时计数、会话存储和缓存等。

 

redis 6.0引用I/O多线程

虽然 Redis 的主要工作(网络 I/O 和执行命令)一直是单线程模型,但是在 Redis 6.0 版本之后,也采用了多个 I/O 线程来处理网络请求,这是因为随着网络硬件的性能提升,Redis 的性能瓶颈有时会出现在网络 I/O 的处理上。

所以为了提高网络 I/O 的并行度,Redis 6.0 对于网络 I/O 采用多线程来处理。但是对于命令的执行,Redis 仍然使用单线程来处理,所以大家不要误解 Redis 有多线程同时执行命令。

Redis 官方表示,Redis 6.0 版本引入的多线程 I/O 特性对性能提升至少是一倍以上。

Redis 6.0 版本支持的 I/O 多线程特性,默认情况下 I/O 多线程只针对发送响应数据(write client socket),并不会以多线程的方式处理读请求(read client socket)。要想开启多线程处理客户端读请求,就需要把 Redis.conf 配置文件中的 io-threads-do-reads 配置项设为 yes。

//读请求也使用io多线程
io-threads-do-reads yes

同时, Redis.conf 配置文件中提供了 IO 多线程个数的配置项。

// io-threads N,表示启用 N-1 个 I/O 多线程(主线程也算一个 I/O 线程)
io-threads 4

关于线程数的设置,官方的建议是如果为 4 核的 CPU,建议线程数设置为 2 或 3,如果为 8 核 CPU 建议线程数设置为 6,线程数一定要小于机器核数,线程数并不是越大越好。

因此, Redis 6.0 版本之后,Redis 在启动的时候,默认情况下会额外创建 6 个线程(这里的线程数不包括主线程):

  • Redis-server : Redis的主线程,主要负责执行命令;
  • bio_close_file、bio_aof_fsync、bio_lazy_free:三个后台线程,分别异步处理关闭文件任务、AOF刷盘任务、释放内存任务;
  • io_thd_1、io_thd_2、io_thd_3:三个 I/O 线程,io-threads 默认是 4 ,所以会启动 3(4-1)个 I/O 多线程,用来分担 Redis 网络 I/O 的压力。

 

本文转载自:https://xiaolincoding.com/redis/base/redis_interview.html#redis-%E7%BA%BF%E7%A8%8B%E6%A8%A1%E5%9E%8B

 

标签:调用,--,redis,Redis,单线程,线程,多线程
From: https://www.cnblogs.com/Xinenhui/p/18153190

相关文章

  • C++中的原子操作
    一、概述C++11提供了一个原子类型std::atomic<T>,通过这个原子类型管理的内部变量就可以称之为原子变量,我们可以给原子类型指定bool、char、int、long、指针等类型作为模板参数(不支持浮点类型和复合类型)。原子指的是一系列不可被CPU上下文交换的机器指令,这些指令组合在一起......
  • initialize方法重定向无限循环问题解决方案
    由于在initialize方法中进行重定向而造成的重定向循环。当session('?user_id')检查失败时,你的代码会尝试重定向到登录页面。如果登录页面或者处理登录的控制器也继承自同一个基类(或者有类似的initialize检查),这将导致每次尝试访问登录页面时都会再次执行重定向,从而陷入无限循......
  • MySQL企业版8.3.0 精简版
    精简版优点:占用空间小,初始总空间大小不足300MB无需安装,按需启动,双击启动MySQL.bat,即可运行。关闭即停止。3.方便移植,直接压缩并拷贝转移即可。适合开发者,学生使用。目录结构:运行状态:链接:https://pan.baidu.com/s/1boXtj-Qa50GGuLbBHhAJQg提取码:zgio说明:精简版完全......
  • c# 通过消息队列处理高并发请求实列
    网站面对高并发的情况下,除了增加硬件,优化程序提高以响应速度外,还可以通过并行改串行的思路来解决。这种思想常见的实践方式就是数据库锁和消息队列的方式。这种方式的缺点是需要排队,响应速度慢,优点是节省成本。演示一下现象创建一个在售产品表CREATETABLE[dbo].[product]([......
  • 并发编程(ReentrantLock)
    ReentrantLock是独占锁,每次只能有一个线程能获取到锁(支持重入)。其他未获取锁的线程会放入的CLH队列中,等待当前线程唤醒;主要分为公平锁和非公平锁,由内部类FairSync和NoFairSync来实现。主要的区别在于非公平锁每次都会尝试竞争,竞争不到锁才会放入到CLH队列中NonfairSync类......
  • leedcode-数字转换为十六进制数
    自己写的,先整数转二进制,再切片二进制转16进制classSolution:deftoHex(self,num:int)->str:#处理特殊情况:当num为0时,直接返回'0'ifnum==0:return'0'#定义十六进制字母的映射关系my_dict={10:......
  • 搭建SSM框架mapper.xml映射开发方式
    搭建SSM框架mapper.xml映射开发方式学习目标本节我们将学习如何搭建SSM框架映射文件开发方式,也就是将sql语句放在mapper.xml文件中进行开发,适用于频繁更新需求的项目。搭建方法pom.xml引入依赖以下依赖项为最低需求,可根据功能需要增加相关依赖。<?xmlversion="1.0"encodin......
  • 与开源数据可视化平台深度融合,进入流程办公新时代!
    进入新时代,需要有新的软件平台实现创新智造。开源数据可视化平台是流行于各中小型企业中的快速框架软件平台,够灵活、易操作、好维护、可视化操作界面等多个优势特点,在降本增效、减少成本支出、实现流程化办公等方面具有事半功倍的应用价值和效果。流辰信息作为专业的服务商,将不遗......
  • 【前端】纯JS实现文本对比高亮显示
    1.参考demo1-1、连接:http://incaseofstairs.com/jsdiff/1-2、例子:2.页面<!DOCTYPEhtml><!--savedfromurl=(0033)http://incaseofstairs.com/jsdiff/--><html><head><metahttp-equiv="Content-Type"content="text/html;chars......
  • c# 任意对象生成excel
    1publicstaticvoidExportExcel<T>(List<T>ts,stringfilename)2{3varmodel=ts.FirstOrDefault();4List<PropertyInfo>titles=model.GetType().GetProperties().ToList();5usi......