首页 > 数据库 >Redis单线程速度快原理

Redis单线程速度快原理

时间:2023-11-23 11:36:09浏览次数:33  
标签:单线程 Redis 线程 内存 使用 原理 多线程

Redis单线程速度快原理

基于内存存储实现

我们都知道内存读写是比在磁盘快很多的,Redis基于内存存储实现的数据库,相对于数据存在磁盘的MySQL数据库,省去磁盘I/O的消耗。

高效的数据结构

image-20231114164525595

数据结构说明:

Redis内部采用了一些精细化的数据结构和算法,例如哈希表、跳跃表、压缩列表等,这些结构和算法能够快速完成常见的查找、插入、删除等操作,从而减少了系统的开销和运行时间。

1)SDS简单动态字符串
字符串长度处理:Redis获取字符串长度,时间复杂度为O(1),而C语言中,需要从头开始遍历,复杂度为O(N)。
空间预分配:字符串修改越频繁的话,内存分配越频繁,就会消耗性能,而SDS修改和空间扩充,会额外分配未使用的空间,减少性能损耗。
惰性空间释放:SDS缩短时,不是回收多余的内存空间,而是free记录下多余的空间,后续有变更,直接使用free中记录的空间,减少分配。
二进制安全:Redis可以存储一些二进制数据,在C语言中字符串遇到'\0'会结束,而SDS中标志字符串结束的是len属性。

2)字典
Redis作为K-V型内存数据库,所有的键值就是用字典来存储。字典就是哈希表,比如HashMap,通过key就可以直接获取到对应的value。而哈希表的特性,在O(1)时间复杂度就可以获得对应的值。

3)跳跃表
跳跃表是Redis特有的数据结构,就是在链表的基础上,增加多级索引提升查找效率。跳跃表支持平均O(logN),最坏O(N)复杂度的节点查找,还可以通过顺序性操作批量处理节点。

合理的数据编码

Redis支持多种数据数据类型,每种基本类型,可能对多种数据结构。什么时候,使用什么样数据结构,使用什么样编码,是Redis设计者总结优化的结果。
1)String:如果存储数字的话,是用int类型的编码,如果存储非数字,小于等于39字节的字符串,是embstr,大于39个字节,则是raw编码。
2)List:如果列表的元素个数小于512个,列表每个元素的值都小于64字节(默认),使用ziplist编码,否则使用linkedlist编码。
3)Hash:哈希类型元素个数小于512个,所有值小于64字节的话,使用ziplist编码,否则使用hashtable编码。
4)Set:如果集合中的元素都是整数且元素个数小于512个,使用intset编码,否则使用hashtable编码。
5)Zset:当有序集合的元素个数小于128个,每个元素的值小于64字节时,使用ziplist编码,否则使用skiplist(跳跃表)编码。

合理的线程模型

image-20231114165458289

单线程说明:

Redis基于Reactor模式开发了网络事件处理器,这个处理器被称为文件事件处理器(file event handler)。它的组成结构为4部分:多个套接字、IO多路复用程序、文件事件分派器、事件处理器。因为文件事件分派器队列的消费是单线程的,所以Redis才叫单线程模型。Redis是一个内存型键值数据库,单线程的特性对于它的高效和稳定有着关键作用。

下面是Redis单线程速度快的原理:
1)减少了上下文切换
在多线程环境下,线程的切换会需要保存当前线程的上下文信息,并加载目标线程的上下文信息,这会涉及到很多操作,例如寄存器、堆栈、内存页等。这些额外开销会降低系统运行效率。而Redis采用单线程模型,避免了多线程间的切换,从而减少了上下文切换的开销。
2)充分利用CPU缓存
在多线程环境下,CPU缓存会被不同线程频繁地读取和修改,导致缓存频繁失效和更新,影响程序性能。而单线程模型可以充分利用CPU缓存的局部性原理,将数据存储在连续的内存块中,避免了不同线程之间频繁访问同一内存地址的情况,从而提高了系统的运行效率。
3)阻塞式I/O操作
Redis采用阻塞式I/O操作,即当客户端请求发送过来时,Redis会阻塞等待完成请求的处理,不会立即返回结果,从而避免了多线程环境下的锁竞争和上下文切换。同时,Redis还采用多路复用技术,可以在等待请求处理期间同时处理其他请求,提高了系统的运行效率。
4)精细化的数据结构和算法
例如哈希表、跳跃表、压缩列表等

总结:综上所述,Redis单线程速度快的原因主要有:减少了上下文切换、充分利用CPU缓存、采用阻塞式I/O操作和精细化的数据结构和算法。这些特性使得Redis能够在高并发环境下保持高效和稳定,成为一个非常受欢迎的内存型数据库。

IO多路复用说明:
1)多路I/O复用技术可以让单个线程高效的处理多个连接请求,而Redis使用用epoll作为I/O多路复用技术的实现。并且,Redis自身的事件处理模型将epoll中的连接、读写、关闭都转换为事件,不在网络I/O上浪费过多的时间。
2)IO(网络IO)、多路(多个网络连接)、复用(复用同一个线程)
IO多路复用其实就是一种同步IO模型,它实现了一个线程可以监视多个文件句柄;一旦某个文件句柄就绪,就能够通知应用程序进行相应的读写操作;而没有文件句柄就绪时,就会阻塞应用程序,交出cpu。
3)文件事件处理器使用I/O多路复用(multiplexing)程序来同时监听多个套接字,并根据套接字目前执行的任务来为套接字关联不同的事件处理器。当被监听的套接字准备好执行连接应答(accept)、读取(read)、写入(write)、关闭(close)等操作时,与操作相对应的文件事件就会产生,这时文件事件处理器就会调用套接字之前关联好的事件处理器来处理这些事件。虽然文件事件处理器以单线程方式运行,但通过使用I/O多路复用程序来监听多个套接字,文件事件处理器既实现了高性能的网络通信模型,又可以很好地与Redis服务器中其他同样以单线程方式运行的模块进行对接,这保持了Redis内部单线程设计的简单性。

单线程模型说明:
1)Redis是单线程模型的,而单线程避免了CPU不必要的上下文切换和竞争锁的消耗。也正因为是单线程,如果某个命令执行过长(如hgetall命令),会造成阻塞。Redis是面向快速执行场景的数据库,所以要慎用如smembers和lrange、hgetall等命令。
2)Redis 6.0引入了多线程提速,它的执行命令操作内存的仍然是个单线程。

为什么Redis 6.0之后改多线程呢?
1)Redis6.0之前,Redis在处理客户端的请求时,包括读socket、解析、执行、写socket等都由一个顺序串行的主线程处理,这就是所谓的“单线程”。
2)Redis6.0之前为什么一直不使用多线程?使用Redis时,几乎不存在CPU成为瓶颈的情况,Redis主要受限于内存和网络。例如在一个普通的Linux系统上,Redis通过使用pipelining每秒可以处理100万个请求,所以如果应用程序主要使用O(N)或O(log(N))的命令,它几乎不会占用太多CPU。
3)Redis使用多线程并非是完全摒弃单线程,Redis还是使用单线程模型来处理客户端的请求,只是使用多线程来处理数据的读写和协议解析,执行命令还是使用单线程。这样做的目的是因为Redis的性能瓶颈在于网络IO而非CPU,使用多线程能提升IO读写的效率,从而整体提高Redis的性能。

虚拟内存机制

Redis直接自己构建了VM机制,不会像一般的系统会调用系统函数处理,会浪费一定的时间去移动和请求。Redis虚拟内存机制就是暂时把不经常访问的数据(冷数据)从内存交换到磁盘中,从而腾出宝贵的内存空间用于其它需要访问的数据(热数据)。通过VM功能可以实现冷热数据分离,使热数据仍在内存中、冷数据保存到磁盘。这样就可以避免因为内存不足而造成访问速度下降的问题。

标签:单线程,Redis,线程,内存,使用,原理,多线程
From: https://www.cnblogs.com/xdzy/p/17851165.html

相关文章

  • Redis命令合集
    Redis命令合集服务器相关命令说明命令启动redis服务redis-server.exeredis.windows.conf默认连接redis-cli.exe-a123456避免中文显示乱码连接redis-cli.exe-a123456--rawIP、端口、密码连接,地址:localhost、端口:6379、密码:12345如果没加密码可以不输......
  • CART算法解密:从原理到Python实现
    本文深入探讨了CART(分类与回归树)算法的核心原理、实现方法以及应用场景。文章首先介绍了决策树的基础知识,然后详细解析了CART算法的工作机制,包括特征选择和树的构建。接着,通过Python和PyTorch的实例代码展示了CART算法在实际问题中的应用。最后,文章评价了该算法的优缺点,并讨论了......
  • redis
    04-01redis一.简介1.快速了解#存储形式:key:value对#存储位置:内存#支持存储的类型:string(字符串)、list(链表)、set(集合)、zset(sortedset--有序集合)和hash(哈希类型)#支持的操作:(注意:具有原子性,要么同时成功,......
  • uniapp底层跨端原理
    uniapp底层跨端原理-代码编写:开发者使用Vue.js框架编写uniapp的代码,包括页面结构、样式和逻辑等。-编译过程:在编译过程中,uniapp会将Vue.js的代码转换为各个平台所需的代码。这一转换过程由uniapp的编译器完成。-平台特定代码生成:根据不同平台的特性和要求,uniapp的编译器......
  • 计算机组成原理(万字爆肝整理)
    第一章计算机系统概述“较简单,不做过多赘述,后面会详细学到”第一节计算机系统层次结构1.计算机系统的基本组成:硬件+软件2.计算机硬件的基本组成:运算器+存储器+控制器+输入设备+输出设备3.系统软件和应用软件系统软件操作系统、数据库管理系统、语言处理程序、分布式软......
  • select函数的用法和原理
    Linux上的select函数select函数用于检测在一组socket中是否有事件就绪。事件分为以下三类:读就绪事件在socket内核中,接收缓冲区中的字节数大于或等于低水位标记SO_RCVLOWAT,此时调用recv或read函数可以无阻塞地读该文件描述符,并且返回值大于0。TCP连接的对端......
  • synchronized 原理
    一个对象里面如果有多个synchronized方法,某一个时刻内,只要一个线程去调用其中的一个synchronized方法,其他线程都只能等待,换句话说,某一个时刻内,只能有唯一的一个线程去访问这些synchronized方,锁的是当前对象this,被锁定后,其他的线程都不能进入到当前对象的其他synchronized方法对......
  • redis中查看慢日志以及返回参数值的解释
    1、问题描述 业务反馈,出现很多连接redis的readtimedout的报错  2、问题分析及解决 由于redis是单线程处理的,所有redis接收到命令,都会进入到队列中,等待执行。 当客户端,由于等待时间过长,没有接收到server端返回的数据,就是出现超时的报错。 程序里,jedis客户端,默......
  • Beamforming 原理和背景
    转自知乎 https://zhuanlan.zhihu.com/p/110251527关于Beamforming,现在越来越多的走入了实际生活中。最先将Beamforming带入实际生产生活中的应该是802.11n,但当时还是optional,而不是critical,直接导致大部分当时的产品没有上Beamforming技术。如今,技术的发展,Beamforming已经......
  • 上拉电阻和下拉电阻 原理
    1.拉电流和灌电流电子元器件在广义上分为有源器件和无源器件。有源器件需要电源(能量)才能实现其特定的功能,比如运算放大器在有输入信号的前提下,如果不提供电源,运算放大器无法实现其放大功能。无源器件在工作时,不需要外加电源,只要输入信号就能正常工作,比如在信号线上串联33Ω的......