Netty基本介绍
Netty是一个异步的完全基于事件驱动的高性能的网络通信框架,目前大部分java生态的分布式框架的通信框架都是基于Netty构建的。比如:Dubbo、Zookeeper、Hadoop、Zuul2等。
Netty之所以能够流行除了其高性能的特性外,还得益于其简单易用的API、全异步和完全基于事件驱动的架构设计。
NIO
所谓NIO其实时相对于BIO而言的,传统的IO在网络请求场景下,从接受一个请求,到开始从内核中读取数据这段时间内一直是阻塞的,而NIO则会在读/写调用没有数据的时候立即返回。
具体的实现,其实是通过操作系统提供的API(Epoll模型,Unix:kqueue),注册一组非阻塞套接字,而操作系统会不断轮询这些套接字,一旦其中一个进入读/写就绪状态,select()函数就会返回。
//创建一个epoll的句柄,size用来告诉内核这个监听的数目一共有多大
int epoll_create(int size);
//对指定描述符fd执行op操作。epfd:是epoll_create()的返回值,op:表示op操作,fd:是需要监听的fd,epoll_event:是告诉内核需要监听什么事件
int epoll_ctl(int epfd, int op, int fd, struct epoll_event *event);
//等待epfd上的io事件,最多返回maxevents个事件。
int epoll_wait(int epfd, struct epoll_event * events, int maxevents, int timeout);
Java原生的NIO便是基于Epoll模型来实现的。而Netty则是基于JavaNIO构建的,只不过提供了统一的API且提供了更加丰富的接口和更灵活的扩展,比如它的pipeline机制,能够让我们对请求的处理做出各种定制。
Netty服务创建-ServerBoostrap
ServerBoostrap创建示例
EventLoopGroup bossGroup = new NioEventLoopGroup(1);
EventLoopGroup workerGroup = new NioEventLoopGroup();
try {
ServerBootstrap b = new ServerBootstrap();
b.group(bossGroup, workerGroup)
.channel(NioServerSocketChannel.class)
.childHandler(new ChannelInitializer<SocketChannel>() {
@Override
public void initChannel(SocketChannel ch) {
ChannelPipeline p = ch.pipeline();
p.addLast(new DiscardServerHandler());
p.addLast(new DefaultEventExecutorGroup(16), "handler", new DiscardServerHandler());
}
});
// Bind and start to accept incoming connections.
ChannelFuture f = b.bind(PORT).sync();
f.channel().closeFuture().sync();
} finally {
workerGroup.shutdownGracefully();
bossGroup.shutdownGracefully();
}
从ServerBoostrap的创建代码,可以看到,启动需要传递的一些基本参数,比如用以处理NioServerSocketChannel连接事件的bossGroup及用以处理NioSocketChannle IO事件的workerChannel,其中
需要注意的是EventExecutorGroup,它是Netty用于处理耗时任务的线程池,当我们提交一个非耗时任务时,直接通过EventLoop去提交就可以了,但是如果要执行耗时任务,就不能再EventLoop上进行处理了,因为一个EventLoop同时负责处理多个Channl的IO事件,如果当前Channel阻塞了,则会影响其他Channel的事件处理。在业务逻辑处理的时候提交任务的代码实例如下:
如何提交耗时和非耗时任务
Channel channel = ctx.channel();
//执行非耗时任务
Future future = channel.eventLoop().scheduleAtFixedRate(new Runnable() {
@Override
public void run() {
}
},6,6, TimeUnit.MINUTES);
Future future1 = ctx.executor().scheduleAtFixedRate(new Runnable() {
@Override
public void run() {
//耗时任务
}
}, 6, 6, TimeUnit.MINUTES);
channel方法:指定用于服务创建时负责处理客户端连接的class
childHandler方法:指定,当接收到请求创建Channel后,需要为创建的Channel添加的ChannelHandler
b.bind(PORT):绑定端口并启动,下文将根据对服务启动流程进行分析
网友评论