1、问题描述java
Netty是最近很是流行的高性能异步通信框架,相对于Java原生的NIO接口,Netty封装后的异步通信机制要简单不少。bootstrap
可是小K最近发现并非全部开发人员在使用的过程当中都了解其内部实现机制,而是照着葫芦画瓢。服务器
网上简单搜索下,在客户端使用Netty创建链接池的文章也是比较少。今天小K给你们简单介绍下使用Netty创建链接池的方法。框架
首先咱们来看下Netty官方给出的客户端sample实例:异步
//建立一个EventLoopGroup,能够简单认为是Netty框架下的线程池,默认最大线程数量是处理器数量的2倍 EventLoopGroup group = new NioEventLoopGroup(); try { //Netty创建链接的辅助类 Bootstrap b = new Bootstrap(); //配置属性,向pipeline添加handler b.group(group) .channel(NioSocketChannel.class) .option(ChannelOption.TCP_NODELAY, true) .handler(new ChannelInitializer<SocketChannel>() { @Override public void initChannel(SocketChannel ch) throws Exception { ChannelPipeline p = ch.pipeline(); if (sslCtx != null) { p.addLast(sslCtx.newHandler(ch.alloc(), HOST, PORT)); } //p.addLast(new LoggingHandler(LogLevel.INFO)); p.addLast(new EchoClientHandler()); } }); //启动创建链接 ChannelFuture f = b.connect(HOST, PORT).sync(); //block直到链接被关闭 f.channel().closeFuture().sync();
很简单?没错,确实如此。那么如今问题来了,若是你如今须要链接100个服务器,你会怎么作呢?ide
下面这样处理怎么样呢?咱们在外层加了一个for循环oop
for(Host host : hosts){ //建立一个EventLoopGroup,能够简单认为是Netty框架下的线程池,默认线程数量是处理器数量的2倍 EventLoopGroup group = new NioEventLoopGroup(1); try { //Netty创建链接的辅助类 Bootstrap b = new Bootstrap(); //配置属性,向pipeline添加handler b.group(group) .channel(NioSocketChannel.class) .option(ChannelOption.TCP_NODELAY, true) .handler(new ChannelInitializer<SocketChannel>() { @Override public void initChannel(SocketChannel ch) throws Exception { ChannelPipeline p = ch.pipeline(); if (sslCtx != null) { p.addLast(sslCtx.newHandler(ch.alloc(), HOST, PORT)); } //p.addLast(new LoggingHandler(LogLevel.INFO)); p.addLast(new EchoClientHandler()); } }); //启动创建链接 ChannelFuture f = b.connect(HOST, PORT).sync(); //block直到链接被关闭 f.channel().closeFuture().sync(); }
问题很明显,若是每个channel都对应一个NIOEventLoopGroup,那么咱们实际上构建了一个connection:thread = 1:1的模型,随着链接数不断地扩大,线程膨胀的问题就会突显出来。性能
1、问题解决ui
那么如何避免线程膨胀的问题呢?很简单,咱们只要稍微修改下上面的代码就能够了。spa
NioEventLoopGroup group = new NioEventLoopGroup(); Bootstrap b = new Bootstrap(); try { b.group(group) .channel(NioSocketChannel.class) .option(ChannelOption.TCP_NODELAY, true) .handler(new ChannelInitializer<SocketChannel>() { @Override public void initChannel(SocketChannel ch) throws Exception { ChannelPipeline p = ch.pipeline(); if (sslCtx != null) { p.addLast(sslCtx.newHandler(ch.alloc(), HOST, PORT)); } //p.addLast(new LoggingHandler(LogLevel.INFO)); p.addLast(new EchoClientHandler()); } }); for(Host HOST : Hosts){ ChannelFuture f = b.connect(HOST, PORT).sync(); }
在上面的代码中,咱们使用同一个bootstrap建立了多个链接,从而使链接共享了一个NioEventLoopGroup,避免了线程膨胀的问题。
问题就这样解决了吗?NO,还远远没有结束哦,那么问题又来了。
一、若是但愿每一个链接可以使用不一样的Handler怎么办?
二、每一个链接如何可以再次复用,避免重复建立channel?
为了可以建立异步操做的链接池咱们须要实现以下的模型。
为了可以方便地创建一个异步操做的链接池,咱们会使用到FixedChannelPool(不了解的同窗麻烦Google一下吧,(⌒_⌒))
其伪代码以下(具体的代码实现结构仍是留给读者本身思考吧):
Bootstrap b = new Bootstrap().channel(NioSocketChannel.class).group( new NioEventLoopGroup()); //自定义的channelpoolhandler ChannelPoolHandler handler = new ChannelPoolHandler(); //建立一个FixedChannelPool FixedChannelPool pool = new FixedChannelPool(bootstrap, handler); //从channelpool中获取链接或者建立新的链接,并添加listener pool.acquire.addlistener();
3、总结:
一般状况下,咱们并不须要使用Netty创建链接池,common pool能够知足咱们的需求,可是有些业务场景(例如:返回结果时间不肯定)须要使用这种异步的链接池,在正确的业务场景下选择正确的解决方案才是王道哦。