Redis的性能的影响因素
从官网的回答我们可以知道,CPU不是Redis性能的瓶颈,影响最大的是内存的大小和网络IO的问题。
最终我们可以认为Redis的性能瓶颈可以定为 :网络IO
- 主线程和IO线程是怎么协作完成请求处理的?
-
阶段一 :服务端和客户端建立Socket连接,并分配处理线程
首先,主线程负责接收建立连接的请求,当有客户端请求和实例建立Socket连接时,主线程会创建和客户端的连接,并把Socket放入全局等待队列中,紧接着,主线程通过轮询的方式把Socket连接分配给IO线程。
-
阶段二 :IO线程读取并解析请求
主线程一旦把Socket分配给IO线程,主线程就会进入阻塞状态,等待IO线程完成客户端请求读取和解析。因为有多个IO线程在并行(IO多路复用)处理,所以这个过程很快就可以完成。
-
阶段三 :主线程执行请求操作
等到IO线程解析完请求,主线程还是会以单线程的方式执行这些命令操作。
-
阶段四 :IO线程回写Socket和主线程清空全局队列
当主线程执行完请求操作后,会把需要返回的结果写入缓冲区,然后主线程会阻塞等待IO线程把这些结果回写到Socket中,并返回给客户端。和IO线程读取和解析请求一样,IO线程回写Socket时,也有多个线程在并发执行(IO多路复用),所以回写Socket的速度也很快,等到IO线程回写Socket完毕,主线程会清空全局队列,等待客户端的后续请求。
Redis—网络IO的IO多路复用模型
-
概念引入—FileDescriptor
在Linux世界中一切皆是文件,文件描述符,简称FD,即FileDescriptor,每一个线程进来Linux都会被分配一个文件描述符FD。
-
浅谈一下IO多路复用是什么
IO多路复用是一种同步的IO模型,实现一个线程监视多个FD(线程),一旦某个FD(线程)就绪,就通知到对应的应用程序进行读写的操作,没有FD(线程)就绪的时候就会阻塞应用程序,从而释放CPU资源。
-
拆分IO多路复用的概念
- I/O :网络I/O,尤其在操作系统层面,指的是数据在内核态和用户态之间的读写操作
- 多路 :多个客户端连接 (连接就是 socket 或者 channel )
- 复用 :复用一个或几个客户端线程
- IO多路复用 :也就是说,一个或一组客户端线程处理多个TCP连接,使用单进程就能够实现同时处理多个客户端连接,无需创建或者维护过多的进程/线程。
-
IO多路复用的模型
模拟一个服务器处理30个客户端socket,假如你是一个监考老师,让30个学生解答一道竞赛考题,然后负责验收学生答卷。
- select 模型 :轮询,按顺序从第一位一直验收道最后一位,这中间,但凡有一个学生卡住,后面的同学全部要等待,即阻塞IO
- poll 模型 :来一个socket,new一个线程来处理一个socket,来一个new一个,一个监考老师分身成30个监考老师一个个验收
- epoll 模型 :响应式处理,一对多服务,你在讲台上等待,谁答完题谁举手,然后监考老师下来收举手的学生的试卷
其中的epoll模型就是我们所谓的 reactor响应模式。
这就是IO多路复用原理,有请求就响应,没请求不打扰。
Redis—IO多路复用之多线程的理解
I/O 的读和写本身是堵塞的,比如当 socket 中有数据时,Redis 会通过调用先将数据从内核态空间拷贝到用户态空间,再交给 Redis 调用,而这个拷贝的过程就是阻塞的,当数据量越大时拷贝所需要的时间就越多,而这些操作都是基于单线程完成的。
从Redis6开始,就新增了多线程的功能来提高 I/O 的读写性能,他的主要实现思路是将主线程的 IO 读写任务拆分给一组独立的线程去执行,这样就可以使多个 socket 的读写可以并行化了,采用多路 I/O 复用技术可以让单个线程高效的处理多个连接请求(尽量减少网络IO的时间消耗),将最耗时的Socket的读取、请求解析、写入单独外包出去,剩下的命令执行仍然由主线程串行执行并和内存的数据交互。
结合上图可知,网络IO操作就变成多线程化了,其他核心部分仍然是线程安全的,是个不错的折中办法。