当前位置: 首页 > 科技观察

为什么Redis引入多线程?单线程不好吗?

时间:2023-03-15 16:34:38 科技观察

相信大家一定不止一次见过单线程模式下的Redis,但说实话,它只是一个老版本而已。这道题是大厂的面试题,分享给我。自己想想,之前知道redis6.0一直是单线程的,6版本才加入多线程,不是很清楚,多方查询搜索后总结出这篇文章。一、问题概述Redis6.0以后的版本放弃了单线程模型的设计。原本使用单线程运行的Redis,也开始有选择地使用多线程模型,仔细想想,这个问题其实可以拆分成两个主要问题:(1)为什么Redis当初会选择单线程模型(单线程的好处)?(2)为什么Redis在6.0之后加入了多线程(有些情况下单线程有缺点,多线程可以解决)?其实并不是作者没有逃过真香定理,而是随着时间的推移,出现的问题越来越多,原来的设计肯定是有些落伍了,所以应该做出改变。OK,带着两个问题,我们来仔细分析一下。2、为什么Redis一开始就用单线程,不管是单线程还是多线程,都是为了提高Redis的开发效率,因为Redis是一个基于内存的数据库,也需要处理大量的外部网络请求,不可避免要进行多次IO。幸运的是,Redis使用了很多优秀的机制来保证它的高效性。那么Redis为什么要设计成单线程模式呢?可以归纳如下:(1)IO多路复用我们来看看Redis的顶层设计。fd是文件描述符,表示当前文件可读、可写或异常。利用I/O多路复用机制同时监控多个文件描述符的可读可写状态。你可以理解为具有多线程的特性。一旦接收到网络请求,它将在内存中快速处理。由于大部分操作都是纯内存,所以处理速度会很快。也就是说,在单线程模式下,即使有大量的连接网络处理,因为IO多路复用,在高速内存处理中仍然可以忽略不计。(2)可维护性高多线程模型虽然在某些方面很优秀,但是引入了程序执行顺序的不确定性,带来了并发读写的一系列问题。在单线程模式下,方便调试和测试。(3)基于内存,在单线程状态下效率还是很高的。多线程可以充分利用CPU资源,但是对于Redis来说,因为基于内存的速度相当高,一秒可以处理10万个用户请求,如果每秒十万还不够,那我们可以使用Redis分片技术,交给不同的Redis服务器。这样cooking避免了在同一个Redis服务中引入大量的多线程操作。而基于内存,除非要做AOF备份,否则基本不会涉及到I/O操作。由于这些数据的读写只发生在内存中,处理速度非常快;用多线程模型处理所有外部请求可能不是一个好的解决方案。现在我们知道了,基本上可以用两句话来概括,基于内存,利用多路复用技术,单线程的速度非常快,保证了多线程的特性。因为不需要使用多线程。3、为什么要引入多线程?刚刚说了一堆使用单线程的好处,现在要说说为什么要引入多线程,大家不要习惯。多线程的引入,说明在Redis的某些方面,单线程是没有优势的。由于Redis执行过程中对网络进行读写的read/write系统调用占用了大部分的CPU时间,如果将网络读写做成多线程的方式,性能会得到很大的提升。Redis的多线程部分只是用来处理网络数据的读写和协议解析,执行命令还是单线程的。这样设计的原因是Redis不想因为多线程变得复杂,需要控制key、lua、事务、LPUSH/LPOP等的并发问题,Redis增加了一些可以处理的删除操作最新版本中被其他线程异步调用,也就是我们上面提到的UNLINK、FLUSHALLASYNC和FLUSHDBASYNC。为什么我们需要这些删除操作,为什么需要以多线程的方式通过异步处理呢?我们知道Redis可以使用del命令来删除一个元素。如果元素很大,可能会占用几十兆、几百兆,短时间内无法完成。这就需要多线程异步支持。现在删除工作可以在后台完成。4.总结Redis选择使用单线程模型来处理客户端请求主要是因为CPU不是Redis服务端的瓶颈,所以多线程模型带来的性能提升并不能抵消其带来的开发和维护成本,而系统的性能瓶颈也主要在网络I/O操作上;而Redis出于性能的考虑引入了多线程操作。对于一些大键值对的删除操作,通过多线程非阻塞的方式释放内存空间,也可以减少对Redis主线程的影响。阻塞时间提高了执行效率。一句话说完:之前用单线程是因为基于内存的速度快,多路复用的复用功能,够用了。现在引入是因为有些操作需要优化,比如删除操作,所以引入了Multithreading。