系统学习消息队列分享(十) 如何实现高性能的异步网络传输?

异步与同步模型最大的区别是,同步模型会阻塞线程等待资源,而异步模型不会阻塞线程,它是等资源准备好后,再通知业务代码来完成后续的资源处理逻 辑。这种异步设计的方法,可以很好地解决IO等待的问题。

我们开发的绝大多数业务系统,它都是IO密集型系统。跟IO密集型系统相对的另一种系统叫计算密集型系 统。通过这两种系统的名字,估计你也能大概猜出来IO密集型系统是什么意思。

IO密集型系统大部分时间都在执行IO操作,这个IO操作主要包括网络IO和磁盘IO,以及与计算机连接的一 些外围设备的访问。与之相对的计算密集型系统,大部分时间都是在使用CPU执行计算操作。我们开发的业 务系统,很少有非常耗时的计算,更多的是网络收发数据,读写磁盘和数据库这些IO操作。这样的系统基本 上都是IO密集型系统,特别适合使用异步的设计来提升系统性能。

应用程序最常使用的IO资源,主要包括磁盘IO和网络IO。由于现在的SSD的速度越来越快,对于本地磁盘的 读写,异步的意义越来越小。所以,使用异步设计的方法来提升IO性能,我们更加需要关注的问题是,如何 来实现高性能的异步网络传输。

理想的异步网络框架应该是什么样的?

    在我们开发的程序中,如果要实现通过网络来传输数据,需要用到开发语言提供的网络通信类库。大部分语 言提供的网络通信基础类库都是同步的。一个TCP连接建立后,用戶代码会获得一个用于收发数据的通道。 每个通道会在内存中开辟两片区域用于收发数据的缓存。

发送数据的过程比较简单,我们直接往这个通道里面来写入数据就可以了。用戶代码在发送时写入的数据会 暂存在缓存中,然后操作系统会通过网卡,把发送缓存中的数据传输到对端的服务器上。

只要这个缓存不满,或者说,我们发送数据的速度没有超过网卡传输速度的上限,那这个发送数据的操作耗 时,只不过是一次内存写入的时间,这个时间是非常快的。所以,发送数据的时候同步发送就可以了,没有 必要异步。

     比较麻烦的是接收数据。对于数据的接收方来说,它并不知道什么时候会收到数据。那我们能直接想到的方 法就是,用一个线程阻塞在那儿等着数据,当有数据到来的时候,操作系统会先把数据写入接收缓存,然后 给接收数据的线程发一个通知,线程收到通知后结束等待,开始读取数据。处理完这一批数据后,继续阻塞 等待下一批数据到来,这样周而复始地处理收到的数据。

 

系统学习消息队列分享(十) 如何实现高性能的异步网络传输?

 

 

这就是同步网络IO的模型。同步网络IO模型在处理少量连接的时候,是没有问题的。但是如果要同时处理非 常多的连接,同步的网络IO模型就有点儿力不从心了。

因为,每个连接都需要阻塞一个线程来等待数据,大量的连接数就会需要相同数量的数据接收线程。当这些 TCP连接都在进行数据收发的时候,会导致什么情况呢?对,会有大量的线程来抢占CPU时间,造成频繁的 CPU上下文切换,导致CPU的负载升高,整个系统的性能就会比较慢。

所以,我们需要使用异步的模型来解决网络IO问题。怎么解决呢?

你可以先抛开你知道的各种语言的异步类库和各种异步的网络IO框架,想一想,对于业务开发者来说,一个 好的异步网络框架,它的API应该是什么样的呢?

我们希望达到的效果,无非就是,只用少量的线程就能处理大量的连接,有数据到来的时候能第一时间处理 就可以了。

 

系统学习消息队列分享(十) 如何实现高性能的异步网络传输?

 

 

对于开发者来说,最简单的方式就是,事先定义好收到数据后的处理逻辑,把这个处理逻辑作为一个回调方 法,在连接建立前就通过框架提供的API设置好。当收到数据的时候,由框架自动来执行这个回调方法就好了