《RPC实战与核心原理》学习笔记Day3
04 | 网络通信:RPC框架在网络通信上更倾向于哪种网络IO模型?
网络通信在RPC调用中有什么作用?
RPC是解决进程间通信的一种方式,一次RPC调用,本质就是服务消费者与服务提供者之间的一次网络信息交换的过程。服务调用者通过网络IO发送一条请求消息,服务提供者接收并解析,处理完相关的业务逻辑之后,再发送一条响应消息给服务调用者,服务调用者接收并解析响应消息,处理完相关的响应逻辑,一次RPC调用便结束了。我们可以说,网络通信是整个RPC调用流程的基础。
有哪些常见的网络IO模型?
常见的网络IO模型分为四种:同步阻塞IO(BIO)、同步非阻塞IO(NIO)、IO多路复用和异步非阻塞IO(AIO)。其中AIO是异步IO,其他三种都是同步IO。
最常用的IO模型是同步阻塞IO和IO多路复用。
阻塞IO的工作流程是怎样的?
应用进程发起IO系统调用后,应用进程被阻塞,转到内核空间处理。内核开始等待数据,等待到数据之后,再将内核中的数据拷贝到用户内存中,整个IO处理完毕后返回进程。最后应用进程解除阻塞状态,运行业务逻辑。
系统内核在处理IO操作时,主要分为两个阶段:等待数据和拷贝数据。在此期间,应用进程中进行IO操作的线程一直会处于阻塞状态。
什么是IO多路复用?
多路就是指多个通道,也就是多个网络连接的IO,复用指多个通道复用在一个复用器上。
多个网络连接的IO可以注册到一个复用器(select)上,当用户进程调用了select,整个进程会被阻塞,同时,内核会监视所有socket负责的socket,当任何一个socket中的数据准备好了,select就会返回。这时用户进程再调用read操作,将数据从内核中拷贝到用户进程。
IO多路复用的优势在于用户可以在一个线程内同时处理多个socket的IO请求,用户可以注册多个socket,然后不断地调用select读取被激活的socket,这样可以达到在同一个线程内同时处理多个IO请求的目的。
有哪些常见的框架或者工具会使用IO多路复用?
Java中的NIO、Redis、Nginx、Reactor模式等。
在高性能的网络编程框架的编写上,大多数都是基于Reactor模式做的,其中的典型就是Java的Netty框架。
RPC调用在大多数情况下,是一个高并发调用的场景,考虑到系统内核的支持、编程语言的支持以及IO模型本身的特点,在RPC框架的实现中,我们选择IO多路复用作为网络通信采用的IO模型。
什么是“零拷贝”?
在没有零拷贝之前,应用进程的每一次写操作,都会把数据写到用户空间的缓冲区内,再由CPU讲数据拷贝到系统内核的缓冲区中,之后再由DMA将这份数据拷贝到网卡中,最后由网卡发送出去,这样一次写操作数据需要拷贝两次,而数据读操作也是类似的流程。
应用进程的一次完整的写操作,都需要在用户空间和内核空间中来回拷贝,并且每一次拷贝,都需要CPU进行一次上下文切换。
网络数据读写操作示意图如下。
所谓零拷贝,就是取消用户空间与内核空间之间的数据拷贝操作,应用进程每一次的读写操作,都可以通过一种方式,让应用进程向用户空间写入或者读取数据,就如同直接向内核空间写入或者读取数据一样,之后再通过DMA将内核中的数据拷贝到网卡,或者将网卡中的数据拷贝到内核。
零拷贝的示意图如下。
零拷贝有哪些实现方式?
零拷贝有两种方式:
- mmmap+write
- sendfile
这一讲对于IO多路复用以及零拷贝讲的不是特别详细,后面可以单独针对这2个主题深入调研,整理学习笔记。