记录使用过程中偶然发现的一些关键逻辑。先做记录,以后netty知识有一定体系再做整理
childGroup
服务器中有俩group,一个是parentGroup,负责处理链接请求,一个是childGroup,负责业务逻辑。
channelActive是在childGroup中触发的。
新建立链接后会触发channelActive这个事件,parent会将此事件打包成任务放到child的taskqueue中
offerTask:353, SingleThreadEventExecutor (io.netty.util.concurrent)
addTask:344, SingleThreadEventExecutor (io.netty.util.concurrent)
execute:836, SingleThreadEventExecutor (io.netty.util.concurrent)
execute0:827, SingleThreadEventExecutor (io.netty.util.concurrent)
execute:817, SingleThreadEventExecutor (io.netty.util.concurrent)
register:483, AbstractChannel$AbstractUnsafe (io.netty.channel)
register:89, SingleThreadEventLoop (io.netty.channel)
register:83, SingleThreadEventLoop (io.netty.channel)
register:86, MultithreadEventLoopGroup (io.netty.channel)
channelRead:215, ServerBootstrap$ServerBootstrapAcceptor (io.netty.bootstrap)
invokeChannelRead:444, AbstractChannelHandlerContext (io.netty.channel)
invokeChannelRead:420, AbstractChannelHandlerContext (io.netty.channel)
fireChannelRead:412, AbstractChannelHandlerContext (io.netty.channel)
channelRead:1410, DefaultChannelPipeline$HeadContext (io.netty.channel)
invokeChannelRead:440, AbstractChannelHandlerContext (io.netty.channel)
invokeChannelRead:420, AbstractChannelHandlerContext (io.netty.channel)
fireChannelRead:919, DefaultChannelPipeline (io.netty.channel)
read:97, AbstractNioMessageChannel$NioMessageUnsafe (io.netty.channel.nio)
processSelectedKey:788, NioEventLoop (io.netty.channel.nio)
processSelectedKeysOptimized:724, NioEventLoop (io.netty.channel.nio)
processSelectedKeys:650, NioEventLoop (io.netty.channel.nio)
run:562, NioEventLoop (io.netty.channel.nio)
run:997, SingleThreadEventExecutor$4 (io.netty.util.concurrent)
run:74, ThreadExecutorMap$2 (io.netty.util.internal)
run:30, FastThreadLocalRunnable (io.netty.util.concurrent)
run:842, Thread (java.lang)
child执行任务
channelActive:41, NettyHandler (com.example.demo.demos.service)
invokeChannelActive:262, AbstractChannelHandlerContext (io.netty.channel)
invokeChannelActive:238, AbstractChannelHandlerContext (io.netty.channel)
fireChannelActive:231, AbstractChannelHandlerContext (io.netty.channel)
channelActive:1398, DefaultChannelPipeline$HeadContext (io.netty.channel)
invokeChannelActive:258, AbstractChannelHandlerContext (io.netty.channel)
invokeChannelActive:238, AbstractChannelHandlerContext (io.netty.channel)
fireChannelActive:895, DefaultChannelPipeline (io.netty.channel)
register0:522, AbstractChannel$AbstractUnsafe (io.netty.channel)
access$200:429, AbstractChannel$AbstractUnsafe (io.netty.channel)
run:486, AbstractChannel$AbstractUnsafe$1 (io.netty.channel)
runTask:174, AbstractEventExecutor (io.netty.util.concurrent)
safeExecute:167, AbstractEventExecutor (io.netty.util.concurrent)
runAllTasks:470, SingleThreadEventExecutor (io.netty.util.concurrent)
run:569, NioEventLoop (io.netty.channel.nio)
run:997, SingleThreadEventExecutor$4 (io.netty.util.concurrent)
run:74, ThreadExecutorMap$2 (io.netty.util.internal)
run:30, FastThreadLocalRunnable (io.netty.util.concurrent)
run:842, Thread (java.lang)
从哪获取child?
ServerBootstrapAcceptor中会存储childGroup,通过这个childGroup以轮询这种负载均衡算法将任务设置到group中的一个loop里
ServerBootstrapAcceptor.childGroup何时何地设置?
<init>:186, ServerBootstrap$ServerBootstrapAcceptor (io.netty.bootstrap)
run:154, ServerBootstrap$1$1 (io.netty.bootstrap)
runTask:174, AbstractEventExecutor (io.netty.util.concurrent)
safeExecute:167, AbstractEventExecutor (io.netty.util.concurrent)
runAllTasks:470, SingleThreadEventExecutor (io.netty.util.concurrent)
run:569, NioEventLoop (io.netty.channel.nio)
run:997, SingleThreadEventExecutor$4 (io.netty.util.concurrent)
run:74, ThreadExecutorMap$2 (io.netty.util.internal)
run:30, FastThreadLocalRunnable (io.netty.util.concurrent)
run:842, Thread (java.lang)
child和parent为一个loop时,如何更换pipeline?
pipeline跟channel绑定,而不是与loop绑定
bossGroup设置为1就行了?
貌似只有一个channel在处理accept请求(如果服务端只开了一个端口监听服务),bossGroup设置多了也只会用一个loop。
这个观点还有待进一步验证
WEPollSelectorImpl
Selector
使用"轮询+同步阻塞"的方式处理channel中发生的事件
同步阻塞
底层使用微软的一套API阻塞线程,直到有新的事件到达
doSelect:111, WEPollSelectorImpl (sun.nio.ch)
lockAndDoSelect:129, SelectorImpl (sun.nio.ch)
select:146, SelectorImpl (sun.nio.ch)
select:68, SelectedSelectionKeySetSelector (io.netty.channel.nio)
select:879, NioEventLoop (io.netty.channel.nio)
run:526, NioEventLoop (io.netty.channel.nio)
run:997, SingleThreadEventExecutor$4 (io.netty.util.concurrent)
run:74, ThreadExecutorMap$2 (io.netty.util.internal)
run:30, FastThreadLocalRunnable (io.netty.util.concurrent)
run:842, Thread (java.lang)
阻塞状态结束后,io.netty.channel.nio.NioEventLoop#processSelectedKeysOptimized中会遍历io.netty.channel.nio.NioEventLoop#selectedKeys获取需要处理的事件
从NioEventLoop#selectedKeys取出的key的channel是netty中的类?
阻塞结束后用fd找到相应的channel然后进行处理?
parent在哪里将channel移交给child的selector?
设置att
netty的管道将以att的形式注册到selector
attach:458, SelectionKey (java.nio.channels)
register:212, SelectorImpl (sun.nio.ch)
register:236, AbstractSelectableChannel (java.nio.channels.spi)
doRegister:380, AbstractNioChannel (io.netty.channel.nio)
register0:508, AbstractChannel$AbstractUnsafe (io.netty.channel)
access$200:429, AbstractChannel$AbstractUnsafe (io.netty.channel)
run:486, AbstractChannel$AbstractUnsafe$1 (io.netty.channel)
runTask:174, AbstractEventExecutor (io.netty.util.concurrent)
safeExecute:167, AbstractEventExecutor (io.netty.util.concurrent)
runAllTasks:470, SingleThreadEventExecutor (io.netty.util.concurrent)
run:569, NioEventLoop (io.netty.channel.nio)
run:997, SingleThreadEventExecutor$4 (io.netty.util.concurrent)
run:74, ThreadExecutorMap$2 (io.netty.util.internal)
run:30, FastThreadLocalRunnable (io.netty.util.concurrent)
run:842, Thread (java.lang)
上个截图中使用javaChannel获取到java自带的channel,然后用这个自带的channel生成了一个key。其中有几点需要注意。
1、原生channel(this)+监听的事件(ops)+nettyChannel(att)+selector(sel)=key,同时这个key也会反过来注册到当前的原生channel上(addKey(k)
)
2、若当前原生channel已经注册到selector中,就不要重复生成了。findKey
中会遍历当前原生channel的keys
这也间接说明一个channel可以绑定在多个selector上,但是同一个selector上不能绑定多个相同的channel,即使ops不同也不行。
fdToKey
processUpdateQueue:131, WEPollSelectorImpl (sun.nio.ch)
doSelect:107, WEPollSelectorImpl (sun.nio.ch)
lockAndDoSelect:129, SelectorImpl (sun.nio.ch)
select:146, SelectorImpl (sun.nio.ch)
select:68, SelectedSelectionKeySetSelector (io.netty.channel.nio)
select:879, NioEventLoop (io.netty.channel.nio)
run:526, NioEventLoop (io.netty.channel.nio)
run:997, SingleThreadEventExecutor$4 (io.netty.util.concurrent)
run:74, ThreadExecutorMap$2 (io.netty.util.internal)
run:30, FastThreadLocalRunnable (io.netty.util.concurrent)
run:842, Thread (java.lang)
fd
生成文件描述符
<init>:130, ServerSocketChannelImpl (sun.nio.ch)
<init>:109, ServerSocketChannelImpl (sun.nio.ch)
openServerSocketChannel:72, SelectorProviderImpl (sun.nio.ch)
newChannel:63, NioServerSocketChannel (io.netty.channel.socket.nio)
<init>:89, NioServerSocketChannel (io.netty.channel.socket.nio)
<init>:82, NioServerSocketChannel (io.netty.channel.socket.nio)
<init>:75, NioServerSocketChannel (io.netty.channel.socket.nio)
newInstance0:-1, NativeConstructorAccessorImpl (jdk.internal.reflect)
newInstance:77, NativeConstructorAccessorImpl (jdk.internal.reflect)
newInstance:45, DelegatingConstructorAccessorImpl (jdk.internal.reflect)
newInstanceWithCaller:499, Constructor (java.lang.reflect)
newInstance:480, Constructor (java.lang.reflect)
newChannel:44, ReflectiveChannelFactory (io.netty.channel)
initAndRegister:310, AbstractBootstrap (io.netty.bootstrap)
doBind:272, AbstractBootstrap (io.netty.bootstrap)
bind:268, AbstractBootstrap (io.netty.bootstrap)
bind:253, AbstractBootstrap (io.netty.bootstrap)
init:58, DemoApplicationTests2 (com.example.demo)
main:33, DemoApplicationTests2 (com.example.demo)
设置selectedKeys
io.netty.channel.nio.NioEventLoop#selectedKeys与WEPollSelectorImpl中的selectedKeys是同一个对象。netty中会通过反射的方式将io.netty.channel.nio.NioEventLoop#selectedKeys设置到WEPollSelectorImpl中的selectedKeys。
run:228, NioEventLoop$4 (io.netty.channel.nio)
executePrivileged:776, AccessController (java.security)
doPrivileged:318, AccessController (java.security)
openSelector:213, NioEventLoop (io.netty.channel.nio)
<init>:146, NioEventLoop (io.netty.channel.nio)
newChild:183, NioEventLoopGroup (io.netty.channel.nio)
newChild:38, NioEventLoopGroup (io.netty.channel.nio)
<init>:84, MultithreadEventExecutorGroup (io.netty.util.concurrent)
<init>:60, MultithreadEventExecutorGroup (io.netty.util.concurrent)
<init>:52, MultithreadEventLoopGroup (io.netty.channel)
<init>:97, NioEventLoopGroup (io.netty.channel.nio)
<init>:92, NioEventLoopGroup (io.netty.channel.nio)
<init>:73, NioEventLoopGroup (io.netty.channel.nio)
<init>:53, NioEventLoopGroup (io.netty.channel.nio)
init:39, DemoApplicationTests2 (com.example.demo)
main:33, DemoApplicationTests2 (com.example.demo)
因为io.netty.channel.nio.NioEventLoop#selectedKeys与WEPollSelectorImpl中的selectedKeys是同一个对象,所以loop阻塞结束后,可以直接使用io.netty.channel.nio.NioEventLoop#selectedKeys获取WEPollSelectorImpl的结果
channel注册到selector