《redis》4-redis是单线程?

江湖传言,redis是单线程的,习惯了多线程高并发的高大上基数架构之后,猛然回头,发现支持三高的redis是单线程的,这个你能信?

“单线程”描述redis固然不准确,我们只能说,redis在访问存储部分的时候是单线程的。

学习过tomcat的应该清楚,tomcat跟redis的架构有些类似。

《redis》4-redis是单线程?_第1张图片

tomcat有个专门处理connector的连接器,可以同时处理N个请求,但是connector在提交请求到容器部分的时候,提交的其实是runner,tomcat的自己的线程池会持续处理提交的runner,执行结果返回给response。这也是为什么tomcat能够并发处理多请求的基础。

redis的基础模块中,

《redis》4-redis是单线程?_第2张图片

我们也总结道redis存在一个访问模块,在我们的实际环境中,

  1. redis服务处理socket请求,多台服务器同时请求redis服务,也是跟tomcat一样,使用多路复用IO模型
  2. 请求被提交到操作模块的时候,会把请求抽象成task,放入请求队列,但是只有一个线程处理task。也就是说,生产者消费者模式中,只有一个消费者。跟tomcat的线程池的多线程的区别就在这里
  3. 把请求的结果返回给response

这个时候我们其实可以关注三个点

  1. 处理访问请求的I/O模型-多路复用
  2. 生产者消费者模式
  3. 单线程和线程池的优缺点

I/O模型,就是操作系统处理I/O硬件的模型,主要有5中

  1. 同步阻塞操作模型
  2. 同步非阻塞操作模型
  3. 多路复用模型
  4. 异步模型
  5. 信号驱动模型

现在java中多使用多路复用模型,即Redis中使用的模型。他们的主要区别就是,在用户线程(redis的访问模块中的请求处理线程或者tomcat中connector中的请求处理线程),在处理socket的内容时的是否同步和是否阻塞。

简单的同步阻塞模型,比如我们需要读取socket的请求内容,这么一个简单的操作,用户线程需要等待内核线程把数据从io外部设备copy到内核,然后再从内核copy到用户线程空间,这样的速度是缓慢的,用户线程需要同步等待并阻塞,直到这一整个过程结束。

《redis》4-redis是单线程?_第3张图片

在学习tomcat的时候,李号双老师总结了一下上面的4中IO模型。我们比较关注多路复用模型。

《redis》4-redis是单线程?_第4张图片

上面是简单的多路复用模型,在用户线程中,

  1. 有一个单独的线程在循环中调用select方法,查找socket中已经做了数据准备的链接
  2. select方法查到准备好的socket,然后经过一些列操作,把socket的操作提取成task,放入队列
  3. 用户另外的线程,处理task队列中的task。

多路服用的特点就是可以处理很多socket。

上面的task列表和线程处理task列表中的task就是生产者和消费者模式

那我们在redis中的消费者,即执行task的线程只有一个线程,所以redis是单线程。tomcat却有一个线程池,线程池中有多个线程一起消费task列表。

为什么tomcat和redis选择了不同的路线呢?这跟tomcat和redis处理的业务场景有关,tomcat在启动分web服务中,很多请求需要请求数据库,文件服务器等,这些又是一些外部设备,操作时间常,cpu利用率低,所以可以多线程,增加吞吐量。

优点:但是redis是内存存储服务,只需要访问内存就能范围,而且大部分内容访问时间复杂度是O(1),所以处理访问的时间非常短,不需要线程等待太长时间,单个线程还可以避免多线程并发造成的死锁问题,还可以避免线程上下文切换造成的时间消耗。

缺点:但是单线程处理也有个问题,如果task队列中出现一个复杂访问,比如说访问时间是1s,那么队列后面的任务都要阻塞到该任务执行完。

但是redis不仅有内存访问模块一个功能,主从同步的时候,也有单独的线程。持久化的时候,也有单独的线程。这些功能性的线程也一起为redis的高可用提供的了支撑

你可能感兴趣的:(redis,redis,单线程,多路复用)