Netty框架的 主要线程是IO线程。线程模型的好坏直接决定了系统的吞吐量、并发性和安全性。

Netty的线程模型遵循了Reactor的基础线程模型。以下我们先一起看下该模型

Reactor线程模型

Reactor 单线程模型

单线程模型中全部的IO操作都在一个NIO线程上操作:

包括接受client的请求,读取client的消息和应答。因为使用的是异步非堵塞的IO,全部的IO操作不会堵塞。理论上一个线程就能够处理全部的IO操作。

单线程模型适用小容量的应用。

由于在高并发应用 可导致下面问题

  1. 一个线程同一时候处理成百上千的链路,性能上无法支撑。

    即使IO线程cpu 100%也无法满足要求。

  2. 当NIO线层负载过重,处理速度将变慢,会导致大量的client超时,重发,会更加重NIO的负载。终于导致系统大量超时

  3. 一旦IO线程跑飞,会导致整个系统通讯模块不可用,造成节点故障

Reactor多线程模型

该模型组织了 一组线程进行IO的操作

特点:

1. 有专门的NIO线程---acceptor线程用于监听server,接受client的TCP请求

2. 网络操作的读写 由一个IO线程池负责 负责消息的读取 接收 编码和发送

3. 一个IO线程能够同一时候处理N条链路。可是一条链路 仅仅相应一个Io线程。防止并发的操作问题

适合绝大多数场景,可是对于并发百万或者server须要对client握手进行安全认证,认证很耗性能的情况,会导致性能瓶颈。

主次Reactor多线程模型

接受client的连接 不在是一个单独的IO线程,而是一个Nio线程池:

Acceptor接受client的请求并处理完毕后,将新建的socketChannel注冊到IO线程池的某个线程上,由

他负责IO的读写 接编码工作。

Acceptor线程池只负责client的登录 握手 和 安全认证,一旦链路成

功,将链路注冊到后端的线程池的线程上,有他进行兴许的Io操作。

Netty线程模型



public void bind(int port) throws Exception {

// 配置服务端的NIO线程组

EventLoopGroup bossGroup = new NioEventLoopGroup();

EventLoopGroup workerGroup = new NioEventLoopGroup();

try {

ServerBootstrap b = new ServerBootstrap();

b.group(bossGroup, workerGroup)

.channel(NioServerSocketChannel.class)

.option(ChannelOption.SO_BACKLOG, 1024)

.childHandler(new ChildChannelHandler());

// 绑定port,同步等待成功

ChannelFuture f = b.bind(port).sync()。

// 等待服务端监听port关闭

f.channel().closeFuture().sync();

} finally {

// 优雅退出,释放线程池资源

bossGroup.shutdownGracefully();

workerGroup.shutdownGracefully();

}

}

private class ChildChannelHandler extends ChannelInitializer<SocketChannel> {

@Override

protected void initChannel(SocketChannel arg0) throws Exception {

arg0.pipeline().addLast(new TimeServerHandler());

}

}

nettyserver在启动的时候,创建了两个NIOEventLoopGroup 独立的Reator线程池,一个用于接收client的TCP连接,一个用于处理IO的相关的读写操作。

Netty线程模型就是在reactor模型的基础上建立的,线程模型并非一成不变的,通过启动參数的配置,能够在三种中切换。

启动过程,bossGroup 会选择一个EventLoop 须要绑定serverSocketChannel 进行接收client连接;处理后,将准备好的socketchnanell顺利注冊到workGroup下。

netty服务端的创建过程

时序图:

Netty 屏蔽NIO通信的底层细节:

  1. 首先创建ServerBootstrap,他是Netty服务端的启动辅助类

  2. 设置并绑定Reactor线程池。

    Netty的Reactor线程池是EventLoopGroup,它实际就是EventLoop线 程的数组。

    EventLoop的职责是处理全部注冊到本线程多路复用器Selector上的Channel

  3. 设置NIOserverSocketChannel. Netty通过工厂类,利用反射创建NioServerSocketChannel对象

  4. 设置TCP參数

  5. 链路建立的时候创建并初始化ChannelPipeline.它本质就是一个负责处理网络事件的职责链,负责管理和运行ChannelHandler。

    网络事件以事件流的形式在ChannelPipeline中流转,由ChannelPipeline依据ChannelHandler的运行策略调度ChannelHandler的运行

    1. 绑定并启动监听port
    2. 绑定port,并启动。将会启动NioEventLoop负责调度和运行Selector轮询操作,选择准备就绪的Channel集合。当轮询到准备就绪的Channel之后,就由Reactor线程NioEventLoop运行ChannelPipeline的对应方法。终于调度并运行ChannelHandler。

NioEventLoop IO线程浅析

做为Netty的Reactor线程,由于要处理网络IO读写,所以聚合一个多路复用器对象,它通过open获取一个多路复用器。他的操作主要是在run方法的for循环中运行的。

  1. 做为bossGroup的线程 他须要绑定NioServerSocketChannel 来监听client的connet请求,并处理连接和校验。
  2. 作为workGroup线层组的线程。须要将连接就绪的SocketChannel绑定到线程中。所以一个client连接至相应一个线程,一个线程能够绑定多个client连接。

从调度层面看。也不存在在EventLoop线程中 再启动其他类型的线程用于异步运行其他的任务。这样就避免了多线程并发操作和锁竞争,提升了I/O线程的处理和调度性能。

NioEventLoop线程保护

IO操作是线程是的核心,一旦出现问题,导致其上面的多路复用器和多个链路无法正常工作。因此他须要特别的保护。

他在下面两个方面做了保护处理:

  1. 慎重处理异常

异常可能导致线程跑飞。会导致线程下的全部链路不可用,这时採try{}catch(Throwable) 捕获异常,防止跑飞。出现异常后,能够恢复运行。netty的原则是 某个消息的异常不会导致整个链路的不可用,某个链路的不可用。不能导致其它链路的不可用。

  1. 规避NIO BUG

Selector.select 没有任务运行时,可能触发JDK的epoll BUG。这就是著名的JDK epoll BUG,JDK1.7早期版本号 号称攻克了。可是据网上反馈,还有此BUG。

server直接表现为 IO线程的 CPU非常高,可能达到100%,可能会导致节点故障!

!!

为什么会发生epoll Bug

Netty的修复策略为:

  1. 对Selector的select的操作周期进行统计

  2. 对每完毕一次空的select操作进行一次计数

  3. 在某周期内(如100ms)连续N此空轮询, 说明触发了epoll死循环BUG

  4. 检測到死循环后,重建selector的方式让系统恢复正常

netty採用此策略,完美避免了此BUG的发生。

參考资料:netty权威指南2

Netty IO线程模型学习总结的更多相关文章

  1. Netty Reactor 线程模型笔记

    引用: https://www.cnblogs.com/TomSnail/p/6158249.html https://www.cnblogs.com/heavenhome/articles/6554 ...

  2. netty之==线程模型

    1.1 netty线程模型本质遵循了Reactor的基础线程模型,所以得先介绍Reactor模型  1.2  Reactor模型 无论是C++还是Java编写的网络框架,大多数都是基于Reactor模 ...

  3. Netty服务器线程模型概览

    一切从ServerBootstrap开始 ServerBootstrap负责初始话netty服务器,并且开始监听端口的socket请求. bootstrap bootstrap =newServerB ...

  4. 面试官:Netty的线程模型可不只是主从多Reactor这么简单

    笔者看来Netty的内核主要包括如下图三个部分: 其各个核心模块主要的职责如下: 内存管理 主要提高高效的内存管理,包含内存分配,内存回收. 网通通道 复制网络通信,例如实现对NIO.OIO等底层JA ...

  5. netty reactor线程模型分析

    netty4线程模型 ServerBootstrap http示例 // Configure the server. EventLoopGroup bossGroup = new EpollEvent ...

  6. Netty学习三:线程模型

    1 Proactor和Reactor Proactor和Reactor是两种经典的多路复用I/O模型,主要用于在高并发.高吞吐量的环境中进行I/O处理. I/O多路复用机制都依赖于一个事件分发器,事件 ...

  7. 【Netty】EventLoop和线程模型

    一.前言 在学习了ChannelHandler和ChannelPipeline的有关细节后,接着学习Netty的EventLoop和线程模型. 二.EventLoop和线程模型 2.1. 线程模型 线 ...

  8. 【Netty源码分析】Reactor线程模型

    1. 背景 1.1. Java线程模型的演进 1.1.1. 单线程 时间回到十几年前,那时主流的CPU都还是单核(除了商用高性能的小机),CPU的核心频率是机器最重要的指标之一. 在Java领域当时比 ...

  9. Netty系列之Netty线程模型

    Reference: http://www.infoq.com/cn/articles/netty-threading-model 1. 背景 1.1. Java线程模型的演进 1.1.1. 单线程 ...

随机推荐

  1. hpuoj回文串问题(manacher+kmp)

    1699: 回文串问题 时间限制: 1 Sec  内存限制: 128 MB 提交: 22  解决: 3 [提交][状态][讨论版] 题目描述 还是回文串问题,字符串是啥,大家应该都知道,就是满足 S[ ...

  2. 怎样用Eclipse正确导入开源库AndroidStaggeredGrid

    今天带给大家的是怎样正确导入开源库AndroidStaggeredGrid的代码,大家在使用github上的开源控件时,多多少少都遇到过像AndroidStaggeredGrid这样的project结 ...

  3. C#_会员管理系统:开发六(数据搜索)

    增加界面中的搜索功能 会员资料管理界面(VIPManager.cs): 详细代码如下: using System; using System.Collections.Generic; using Sy ...

  4. if else配对问题

    else语句总是与离它最近的if语句配对,所以在if语句的嵌套中一定要注意else语句与哪个if语句匹配 #include <iostream> using namespace std; ...

  5. java实现文件夹(包括其中的子文件夹、子文件)的复制——递归

    这是学校java课的一道实验题,题目如下:编程,根据指定的源和目标位置,完成指定文件或文件夹(包括其中的子文件夹.子文件)的复制. 以下是我的实现,使用了递归: package com.simon.m ...

  6. python——登陆接口设计(循环方法)

    近日重新整理了登陆接口设计程序,感觉以前的代码没有注释,让园子的其他童鞋读起来比较费劲.也没有流程图和程序运行说明. 1.流程图 2.user_file.txt&lock_file.txt文件 ...

  7. 【集训笔记】动态规划【HDOJ1159【HDOJ1003

    终于开始DP了] HDOJ_1159  Common  Subsequence 题目链接 Sample Input abcfbc abfcab programming contest abcd mnp ...

  8. SMTP邮件传输协议发送邮件和附件(转)

    1.     SMTP 常用命令简介 1). SMTP 常用命令 HELO/EHLO 向服务器标识用户身份 MAIL 初始化邮件传输 mail from: RCPT 标识单个的邮件接收人:常在MAIL ...

  9. HDU 4679 String

    String Time Limit: 2000/1000 MS (Java/Others)    Memory Limit: 65535/32768 K (Java/Others) Total Sub ...

  10. [置顶] hdu3018解题报告--也是白话几笔画学习总结

    1.题意 2.分析难点(结合图形) 1.首先说说题意吧...题意很简单...但是一开始很菜的我就很迷惑..在想啊...题目怎么就会有没有连接边的点呢....因为你每次给出一条边..就把 a,b连接啦. ...