event-loop模型为什么在I/O密集场景中更高效

记我在知乎的回答

首先,EventLoop的原型就是Reactor模型,而Reactor模型就是一种线程模型,事实上,传统线程模型就是和阻塞IO模型一样,一个连接一个线程,你可以想象这么一个场景,当Client发起请求后,每个请求分别对应一个处理线程,该线程创建一个Handler对象,Handler对象不仅负责处理读写操作,还负责处理业务操作。
Reactor模型中最重要的两个功能就是建立连接和处理请求,Reactor对象向Accepter对象发起请求,Accepter对象调用accept方法阻塞循环等待请求的到来,Reactor对象通过IO多路复用Select方法配合事件分发Dispatch方法把Event事件分配给Handler对象,其中IO多路复用的含义便是多个连接公用一个阻塞对象,很明显,Reactor就是这个阻塞对象。
Redis中便是采用Reactor模型中的单Reactor单Handler形式,这样的优点便是足够简单,没有多线程,没有进程通信,但事实上,在Redis种,性能瓶颈常常出现在Handler这里,不仅要进行读写操作,还要进行业务处理,举个例子,业务场景下,List如果不限制大小,从一个很大的List中读取数据缓存到Redis中,便会造成Handler对象所在的线程阻塞,也就是整个Reactor线程的阻塞,在这期间,不管是建立连接还是处理请求,都不可用,所以在业务开发中,常常要限制Redis读写数据的大小。
接下来是单Reactor多Handler模型,即Handler把业务操作又交给了Worker线程,自己只负责读写操作,这种情况针对一些复杂业务计算很有效,毕竟业务处理和Reactor不在一个线程里了,达到了异步的效果,但上面我说的Redis的情况仍然会发生,因为读写操作依然和Reactor线程在一个线程里,仍有可能发生线程阻塞,导致服务不可用。
所以针对这个问题,为了保证服务的可用性 ,处理请求阻塞时仍然可对外提供连接服务 ,便有了多Reactor多Handler模型,主Reactor负责建立连接,建立连接后得句柄交给子Reactor,子Reactor负责处理请求,即监听所有事件进行处理,这样主,子Reactor在不同的线程中,职责明确,分摊压力,不会导致上述Redis的会出现的情况,Nginx,Netty包括mencached都是使用的这种模型。
至于题主所说的主线程,子线程切换时的线程开销,事实上得分场景来看,比如Redis,它的理想应用场景就是客户端有限,业务处理非常快,但是如果客户端连接激增呢?如果处于一个IO密集型的场景,那就很有可能导致整个Redis的响应变慢,可用性降低,所以,在IO密集型场景下,相比于线程切换带来的开销,保证服务得响应时长和可用性才是最重要的。

猜你喜欢

转载自www.cnblogs.com/moonyaoo/p/12908022.html