总结篇:
前面三篇博客我们从运用、源码的角度分析了MINA框架的源码,这篇我们对整个MINA框架做一个小小的总结:
先要看源码分析的可以点这里:
首先来看看MINA的整个执行过程是(以服务端为例):
(1):在我们创建完NioSocketAcceptor之后,默认情况下是会为我们创建一个SimpleIoProcessorPool对象,在创建SimpleIoProcessorPool对象的时候会为我们创建一个CachedThreadPool类型的线程池,并且默认创建(CPU+1)个IoProcessor对象,NioSocketAcceptor只有一个,它里面存在一个Selector对象用于监听客户端的连接请求;每个IoProcessor里面也存在一个Selector对象,这个对象是用于监听当前IoProcessor需要处理的IoSession是否有读或者写数据的请求发出;
(2):创建完NioSocketAcceptor之后,我们调用他的bind方法,将NioSocketAcceptor与某个或者一组IP地址和端口号绑定到一起,这时候会创建一个Acceptor线程,该线程会监听是否有客户端连接到达,有的话则仅仅会为处理该连接做一些准备性的工作,即只为当前连接创建一个IoSession对象出来,在创建IoSession的时候会在他的构造方法里面创建一个IoFilter链出来,默认是存在一个HeadFilter和一个TailFilter;
(3):随后会从IoProcessor池中取出一个IoProcessor来处理当前的IoSession请求,具体某一个IoSession到底是由哪个IoProcessor来处理是根据IoSession的session id对IoProcessor池的大小进行取模运算的,既然是取模那么肯定会出现不同的IoSession会由同一个IoProcessor处理的情况了,因此在IoProcessor里面是存在一个IoSession队列的,用于顺序处理IoSession请求;
(4):接着会为每个IoProcessor创建一个Processor线程,在这个线程中会通过IoProcessor的Selector对象的select方法来不断监听是否有IoSession处于就绪状态,有的话就会通过IoFilter链来进行编码解码过程,直到到达IoFilter链的链尾IoHandler,我们具体的业务逻辑处理部分就是在IoHandler里面进行的,所以通常情况下我们必须要为NioSocketAcceptor设置IoHandler对象,否则的话会报异常;
接下来我们来看看MINA框架的责任链部分:
我们的责任链接口是IoFilter,他是在我们创建IoSession对象的时候创建的,默认情况下会创建一个链头HeadFilter和链尾TailFilter,同时会将这些IoFilter对象封装成EntryImpl对象,每个EntryImpl对象中都存在这preentry,nextentry域,这样的话就将所有的IoFilter链接成了一个链状的过滤链了,他可以用于对传输数据的处理,我们可以添加自己的过滤器也可以使用MINA自带的过滤器,这个EnterImpl链的HeadFiler前面就是我们的IoProcessor对象,TailFilter后面就是我们的IoHandler对象,也就是整个链的图形话表示是这样子的:
我们来看看读数据的责任链执行部分:
我们来看看写数据的责任链执行部分:
如果你将write和read部分的责任链连接起来你会发现整个处理过程就是从IoSession开始经过IoFilter再到IoHandler进行处理,并且整个过程中是由IoProcessor来进行处理的;
MINA中的线程模型:
MINA中默认存在着两种类型的线程,一种是Acceptor和Connector线程,一种是Processor线程;
(1):首先来说说Acceptor和Connector线程,他们可以两个线程分别会在服务端调用bind以及客户端调用connect方法之后启动起来,并且数量只能有一个,外界无法控制这两类线程的数量,他们都是用于监听连接工作的,以服务端为例,在有连接接入的时候会创建一个IoSession对象,并且选择一个IoProcessor对象来处理这个IoSession请求,注意每个IoProcessor中都会有一个Processor线程存在;
(2):接着我们说说Processor线程,它存在于IoProcessor对象中,默认情况下他的数量是(CPU+1)个,他的主要用于处理指定IoSession的读写操作及其后面的IoFilterChain和IoHandler业务逻辑,因为他可能会处理多个IoSession,所以它里面原则上是存在一个IoSession队列的,每个Processor里面都存在一个Selector对象,可以对他维护的IoSession集合进行select操作,查看哪个IoSession准备就绪了,而后对select的结果进行遍历操作,一个一个处理,具体的处理就是交给IoFilter责任链完成编解码工作,最后由IoHandler完成真正的业务逻辑操作,通过将IoSession均分到多个Processor线程中进行处理,可以充分利用多核的处理能力,减轻select操作压力,因为毕竟select是阻塞式操作;
以上是默认情况下的MINA线程模型,但是在实际中我们可以引入第三层线程来对MINA框架进行优化
(3):如果我们从单一Processor线程角度看的话,他里面对IoSession的请求处理是顺序执行的,这个顺讯处理过程中包括IoFilter和IoHandler部分,当前面的IoSession处理结束之后,才会处理下一个IoSession,如果某一个或者几个IoSession的IoFilter或者IoHandler比较耗时的话,那么就会导致Processor线程处于阻塞状态,后续的请求将得不到处理;
那么这个问题该怎么解决呢?MINA允许我们在处理链中添加线程池来解决这个问题,MINA中为我们提供了这样的一种线程池实现是ExecutorFilter,具体来讲的话是可以在IoFilterChain中添加ThreadPoolFilter的,此时的处理流程将变成Processor读取完数据之后,执行IoFilterChain的逻辑,当执行到ThreadPoolFilter的时候,该IoFilter会将后续的处理流程封装成一个Runnable对象,并交给该线程池来进行处理,而Processor线程可以立即返回处理下一个IoSession的IO请求,这样如果后续的IoFilter或者IoHandler有耗时操作的话,阻塞的只是线程池中的线程,并不会阻塞Processor线程,提高了处理速度;当然并不限于只添加一个ExecutorFilter,可以添加多个的;
引入了ExecutorFilter线程池虽然解决了可能导致的Processor线程问题,但是又带来了一个新的问题,那就是对于同一IoSession的IO请求顺序问题,引入线程池之后,同样会对同一IoSession的IO请求进行并行处理,这对于那些对IO处理顺序要求严格的IoSession来说并不适用,比如数据库服务器处理同一绘画中的connect、execute、commit过程是不能颠倒的,但是使用了线程池之后是无法保证这一点的,MINA中的ExecutorService默认使用的是OrderedThreadPoolExecutor作为内置线程池的,他并不会立即执行加进来的Runnable对象,而是先从Runnable对象中获取其关联的IoSession对象,并将Runnable对象加入到IoSession的任务列表中,OrderedThreadPoolExecutor会按任务列表中IO请求的顺序来进行任务处理的,从而保证了请求的执行顺序,如果我们已经明确知道IO请求不存在顺序问题,可以为ExecutorService指定一个自定义的Executor来替换掉默认的OrderedThreadPoolExecutor就可以了,这样同一个IoSession的IO请求便可以并行处理了;
最后附上一张MINA框架的整个原理图,以此结束对MINA的学习: