当前位置: 首页 > 后端技术 > PHP

Redis是单线程的,但是Redis为什么这么快呢?

时间:2023-03-30 03:27:23 PHP

几乎所有Java相关的面试都会问缓存的问题。基础的会问什么是“28定律”,什么是“热数据和冷数据”,复杂的会问缓存雪崩、缓存穿透、缓存预热、缓存更新、缓存降级等。这些看似不常见的概念,都与我们的缓存服务器有关。常用的缓存服务器有Redis、Memcached等,笔者最常用的也只有Redis。如果你在之前的面试中没有遇到过面试官问你《为什么说Redis是单线程的以及Redis为什么这么快!》,那么当你看到这篇文章的时候,你应该感到很幸运吧!如果你恰好是一个高质量的面试官,你也可以带着这个问题去面试对面的“有希望”的朋友,看看他的掌握程度。好的!言归正传!我们先讨论什么是Redis,为什么Redis这么快,然后再讨论为什么Redis是单线程的?一、Redis简介Redis是一个开源的内存数据结构存储系统,可以用作:数据库、缓存和消息中间件。支持多种类型的数据结构,如字符串(String)、哈希(Hash)、列表(List)、集合(Set)、有序集合(SortedSet或ZSet)和范围查询、Bitmaps、Hyperloglogs和Geospatial索引半径查询.其中,常见的数据结构类型有:String、List、Set、Hash、ZSet。Redis内置了复制(Replication)、LUA脚本(Luascripting)、LRU驱动事件(LRUeviction)、事务(Transactions)和不同级别的磁盘持久化(Persistence),并通过Redis哨兵(Sentinel)和自动分区(集群)提供高可用性(HighAvailability)。Redis还提供了持久化选项,允许用户将自己的数据保存到磁盘中进行存储。根据实际情况,可以定时将数据集导出到磁盘(快照),或者追加到命令日志(AOF只追加文件)。执行写命令时,会将执行的写命令复制到硬盘中。.也可以关闭持久化功能,使用Redis作为高效的网络缓存数据功能。Redis不使用表,其数据库不会预先定义或强制用户关联存储在Redis中的不同数据。数据库的工作方式按存储方式可分为:硬盘数据库和内存数据库。Redis将数据存储在内存中,读写数据时,不会受到硬盘I/O速度的限制,因此速度极快。(1)硬盘数据库的工作模式:(2)内存数据库的工作模式:看了上面的介绍,你知道一些Redis相关的常见面试题吗,比如:什么是Redis,以及常见的RedisRedis的数据有哪些结构类型,Redis如何持久化等。2.Redis有多快?Redis采用基于内存的KV数据库,单进程单线程模型,C语言编写,官方数据可以达到100,000+QPS(每秒查询次数)。这个数据不比同样使用单进程多线程的基于内存的KV数据库Memcached差!横轴是连接数,纵轴是QPS。这个时候,这张图体现了一个数量级。希望大家在面试的时候能够正确的描述出来。当你的答案的数量级相差很大时不要问你!3、为什么Redis这么快?1、完全基于内存,大部分请求都是纯内存操作,速度非常快。数据存储在内存中,类似于HashMap,HashMap的优点是查找和运算的时间复杂度为O(1);2、数据结构简单,数据操作也简单。Redis中的数据结构是经过特殊设计的;3、采用单线程,避免不必要的上下文切换和竞争条件,不存在多进程或多线程切换导致的CPU消耗。无需考虑各种锁,没有释放锁的操作,没有因可能出现的死锁而导致的性能消耗;4.采用多路I/O复用模型,非阻塞IO;5、使用不同的底层模型,它们之间的底层实现方式和与客户端通信的应用协议不一样,Redis直接自己搭建了VM机制,因为一般的系统调用系统函数的话,会浪费一定的量移动和请求的时间;上面几点比较容易理解,下面我们重点介绍多通道I/O复用模型。简述:(1)多通道I/O多路复用模型多通道I/O多路复用模型是使用select、poll、epoll同时监听多个流的I/O事件的能力。阻塞当前线程,当一个或多个流有I/O事件时从阻塞状态唤醒,然后程序会轮询所有流(epoll只轮询那些真正发送事件的流),只顺序处理就绪的流,这种方法避免了很多无用的操作。这里的“多路复用”是指多个网络连接,“多路复用”是指多路复用同一个线程。多I/O多路复用技术的使用使得单个线程可以高效地处理多个连接请求(最大限度地减少网络IO的时间消耗),并且Redis在内存中操作数据的速度非常快,这意味着在内存中的操作不会变成一个影响Redis性能的瓶颈,主要是以上几点Redis的吞吐量高。4.那么Redis为什么是单线程的呢?我们首先要明白,上面的分析是为了营造一个快速的Redis氛围!根据官方FAQ,由于Redis是基于内存运行的,所以CPU不是Redis的瓶颈。Redis的瓶颈很可能是机器内存或网络带宽的大小。由于单线程容易实现,而且CPU也不会成为瓶颈,所以采用单线程方案顺理成章(毕竟多线程会带来很多麻烦!)。看到这里,你可能会气哭!本来以为会有什么重大的技术点让Redis使用单线程的速度这么快,没想到是一个官方的回答,貌似忽悠了我们!但是,我们已经可以很清楚的解释Redis为什么这么快了,因为单线程模式下已经很快了,没必要再用多线程了!但是我们使用单线程的方式是无法发挥多核CPU的性能优势的,但是我们可以通过在单机上开启多个Redis实例来提升!警告1:我们这里一直强调的单线程只是说只有一个线程来处理我们的网络请求。一个正式的RedisServer在运行时必须有多个线程。这里需要大家注意!比如Redis持久化时,会以子进程或者子线程的形式执行(具体是子线程还是子进程,有待读者深入研究);比如我查看测试服务器上的Redis进程,然后找到进程下的线程:ps命令的“-T”参数表示显示线程(Showthreads,possiblewithSPIDcolumn.)“SID”列表示线程ID,而“CMD”列显示线程名称。警告2:上图中FAQ的最后一段,表达了从Redis4.0开始支持多线程的方式,但只是对某些操作进行多线程操作!所以,本文在以后的版本中是否还是单线程的,还需要读者自己去验证!五。注1.我们知道Redis采用“单线程多路复用IO模型”来实现高性能的内存数据服务。这种机制避免了锁的使用,但是同时这种机制在执行sunion之类的耗时命令时会降低redis的并发度。因为是单线程,同一时间只有一个操作在进行。所以,耗时的命令会导致并发下降,不仅是读并发,写并发也是如此。单个线程只能使用一个CPU核心,因此可以在同一个多核服务器中启动多个实例,形成master-master或master-slave的形式,耗时的读命令可以完全在slave上执行。需要改的redis.conf项:pidfile/var/run/redis/redis_6377.pid#pidfile要加上端口号port6377#这是必须改的logfile/var/log/redis/redis_6377.log#logfile的名字也加端口号dbfilenamedump_6377.rdb#rdbfile也加端口号2,“我们不能让操作系统负载均衡,因为我们更了解自己的程序,所以我们可以手动分配CPU核数给他们而不是它会占用太多的CPU,或者用一堆其他进程来挤压我们的关键进程。”CPU是一个重要的影响因素,因为它是单线程模型,Redis更喜欢大缓存和快速CPU而不是多核。在多核CPU服务器上,Redis性能还取决于NUMA配置和处理器绑定位置。最明显的效果是redis-benchmark会随机使用CPU内核。为了获得准确的结果,您需要使用固定处理器工具(在Linux上您可以使用任务集)。最有效的方法是将客户端和服务器分离到两个不同的CPU中来使用L3缓存。六。扩展以下也是您应该知道的几种模型。祝你在面试中助一臂之力!1、单进程多线程模型:MySQL、Memcached、Oracle(Windows版);2、多进程模型:Oracle(Linux版);3、Nginx有两类进程,一类叫做Master进程(相当于管理进程),一类叫做Worker进程(实际工作进程)。有两种启动方式:(1)单进程启动:此时系统中只有一个进程,这个进程既充当Master进程又充当Worker进程。(2)多进程启动:此时系统只有一个Master进程,至少有一个Worker进程在工作。(3)Master进程主要进行一些全局的初始化工作,管理Worker的工作;事件处理在Worker中进行。