一、问题描述

Netty是最近非常流行的高性能异步通讯框架,相对于Java原生的NIO接口,Netty封装后的异步通讯机制要简单很多。

但是小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个服务器,你会怎么做呢?

下面这样处理怎么样呢?我们在外层加了一个for循环

for(Host host : hosts){
          //创建一个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();
}

问题很明显,如果每一个channel都对应一个NIOEventLoopGroup,那么我们实际上构建了一个connection:thread = 1:1的模型,随着连接数不断地扩大,线程膨胀的问题就会突显出来。

二、问题解决

那么如何避免线程膨胀的问题呢?很简单,我们只要稍微修改下上面的代码就可以了。

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,还远远没有结束哦,那么问题又来了。

1、如果希望每个连接能够使用不同的Handler怎么办?

2、每个连接如何能够再次复用,避免重复创建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();

三、总结

通常情况下,我们并不需要使用Netty建立连接池,common pool可以满足我们的需求,但是有些业务场景(例如:返回结果时间不确定)需要使用这种异步的连接池,在正确的业务场景下选择正确的解决方案才是王道哦。

教你正确地利用Netty建立连接池的更多相关文章

  1. python psycopg2 连接pg 建立连接池

    # -*- coding: utf-8 -*-from psycopg2.pool import ThreadedConnectionPool,SimpleConnectionPool,Persist ...

  2. ADO连接达梦7数据库,利用OLEDB建立连接

    达梦数据库本身提供多种驱动如JDBC ODBC OLEDB等等 在安装的时候可以进行勾选. 如果不安装数据库的驱动无法与达梦数据库建立连接. 达梦数据库在数据库构成或结构上与oracle极为相似,而且 ...

  3. Netty服务器连接池管理设计思路

    应用场景: 在RPC框架中,使用Netty作为高性能的网络通信框架时,每一次服务调用,都需要与Netty服务端建立连接的话,很容易导致Netty服务器资源耗尽.所以,想到连接池技术,将与同一个Nett ...

  4. ssh使两台机器建立连接

    ssh利用口令建立连接过程: 客户端--> 发送连接请求 --> 远程主机 --> 返回远程主机的公钥 --> 公钥加密客户端私钥+客户端公钥返回远程主机 --> 远程主 ...

  5. 数据库程序接口——JDBC——API解读第一篇——建立连接的核心对象

    结构图 核心对象 Driver Java通过Driver接口表示驱动,每种类型的数据库通过实现Driver接口提供自己的Driver实现类. Driver由属性,操作,事件三部分组成. 属性 公共属性 ...

  6. 走进JavaWeb技术世界3:JDBC的进化与连接池技术

    走进JavaWeb技术世界3:JDBC的进化与连接池技术 转载公众号[码农翻身] 网络访问 随着 Oracle, Sybase, SQL Server ,DB2,  Mysql 等人陆陆续续住进数据库 ...

  7. Tomcat 连接池详解

    (转) JDBC 连接池 org.apache.tomcat.jdbc.pool 是Apache-Commons DBCP连接池的一种替换或备选方案. 那究竟为何需要一个新的连接池? 原因如下: Co ...

  8. 深入理解Spring Boot数据源与连接池原理

    ​ Create by yster@foxmail.com 2018-8-2 一:开始 在使用Spring Boot数据源之前,我们一般会导入相关依赖.其中数据源核心依赖就是spring‐boot‐s ...

  9. 用Swoole4 打造高并发的PHP协程Mysql连接池

    码云代码仓库:https://gitee.com/tanjiajun/MysqlPool 代码仓库:https://github.com/asbectJ/swoole4.git 前言 在写这篇文章之前 ...

随机推荐

  1. Bottle 中文文档

    译者: smallfish (smallfish.xy@gmail.com) 更新日期: 2009-09-25 原文地址: http://bottle.paws.de/page/docs (已失效) ...

  2. 总结了关于PHP xss 和 SQL 注入的问题(转)

    漏洞无非这么几类,XSS.sql注入.命令执行.上传漏洞.本地包含.远程包含.权限绕过.信息泄露.cookie伪造.CSRF(跨站请求)等.这些漏洞不仅仅是针对PHP语言的,本文只是简单介绍PHP如何 ...

  3. Coding Your Life

    前几天看到篇文章,写的是科技让人变得陌生,balabala,总的说来就科技让邻居是男是女不知道了,朋友见面少了之类的.其实我觉得,也不能全怪科技发展的太快,而是人心都飘到网路上了,像我这一辈已经老去的 ...

  4. html移动端开发注意事项

    meta <meta charset="utf8"> <meta name="viewport" content="width=de ...

  5. poj 1988 Cube Stacking && codevs 1540 银河英雄传说(加权并茶几)

    #include<iostream> #include<cstdio> #include<cstring> #define maxn 30010 using nam ...

  6. 你真的了解 console 吗

    对于前端开发者来说,在开发过程中需要监控某些表达式或变量的值的时候,用 debugger 会显得过于笨重,取而代之则是会将值输出到控制台上方便调试.最常用的语句就是console.log(expres ...

  7. 使用linux操作系统的公司服务器有哪些品牌

    服务器硬件是什么牌子的? 操心系统有哪些?cpu是哪些?

  8. Arcgis android - Installation error: INSTALL_FAILED_INSUFFICIENT_STORAGE

    报错: Installation error: INSTALL_FAILED_INSUFFICIENT_STORAGE Please check logcat output for more deta ...

  9. SQL函数:用于将小写的数值翻译成大写的字符串

    --功能:  用于将小写的数值翻译成大写的字符串(支持到分,即小数点后两位)       --入口参数:@decNum------数字型变量    --返回:字符串    --举例:select db ...

  10. JAVA打印类(带预览)

    package tool; import java.awt.*; import java.awt.event.KeyEvent; import java.awt.event.KeyListener; ...