转载自ph0ly:http://www.ph0ly.com
一、概念
SelectorManager是选择器管理器,它主要完成连接接入时的Selector选择,以及控制ManagedSelector完成一系列的操作(例如EndPoint和Connection的创建,以及读写事件的注册)
二、继承体系
通常我们用的是ServerConnectorManager,ServerConnectorManager会完成一些简单的操作,大部分核心逻辑还是在SelectorManager。可以看到SelectorManager是具有生命周期的
三、总体架构
四、源码剖析
1. 构造函数
可以看到SelectorManager第一个构造函数会用当前JVM可用处理器数/2,+1的目的是防止为0,也就是最少保证1个,正常是可用处理器数/2,作为selector的数量
Executor、Scheduler使用的是ServerConnector传入的(ServerConnector文章有讲解)
2. 启动
按照之前分配的selector数量,创建ManagedSelector,并将其他们放到容器托管,并启动容器中的所有对象(super.doStart),包括ManagedSelector
newSelector会直接创建ManagedSelector,并将当前执行任务策略工厂传入(稍后EPC会专门讲解这部分知识)
3. 接受连接
首选选择一个Selector,然后在新的线程执行连接接受,接受逻辑将会在ManagedSelector文章中介绍
4. 选择Selector
这个方法是SelectorManager选择ManagedSelector核心的方法
默认情况,SocketChannel不是null,因此会根据当前ip地址的最后一个值来对选择器数量取模,选出一个candidate1,作为预选择的ManagedSelector,而candidate2则是直接轮询选一个
通常我们希望同一个客户端的连接尽量就在同一个selector上面,防止多核数据污染(这里大家可以思考下为什么?)
但是有些客户端是一个代理,可能会将很多客户端的请求转发过来,那其实拿到的ip地址是同一个,这个时候我们还将同一个ip的落到同一个Selector上面,那这个Selector压力就很大了,所以这里会看这个candidate1选出来的ManagedSelector是否注册过过多的Channel(超过candidate2的两倍),那就会使用轮询选择出来的candidate2作为选择器,这其实是一种优化
另外值得注意的是,当candidate1为null的时候,直接返回candidate2,这种情况是使用Selector来接受连接的场景,用户使用ServerConnector的时候配置的
4. 创建EndPoint、Connection
创建accepted其实就是上面实际调用的连接接受,最终调到了ServerConnector,由ServerConnector配置完成后触发SelectorManager分发逻辑
newEndPoint创建一个SelectChannelEndPoint
newConnection会使用当前容器中的工厂来创建连接,默认是HttpConnectionFactory,将会创建一个HttpConnection
endPointOpened会触发SelectChannelEndPoint.onOpen
onEndPointOpened会将当前创建的EndPoint加入到ServerConnector的_endpoints列表中
endPointClosed逻辑相似,这里不在赘述
五、总结
SelectorManager是一个管理器,逻辑相对还是比较简单,不过对于实现来说,还是有点小绕,读者如果还想更加细节的理解,还是需要下来追下代码,这里只是把总体核心的思路理清楚了。后面的文章会带领大家来看下ManagedSelector如何实现数据的读写,以及EPC在这里发挥的作用,请持续关注~