一、问题描述

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. Unix C++(boost) 线程同步和线程组

    #include <boost/thread.hpp> #include <iostream> #include <vector> #include <cst ...

  2. List 去处自定义重复对象方法

    list泛型集合去除重复项,对于单一的某个字段非常简单,但是对于一些自定义要求的还需自定义规则.例子代码: /************绑定乘客信息********/ List<RT.Model. ...

  3. AMD 规范以及如何将AMD转变为CommonJS

    原文:http://villadora.me/2014/05/23/amd-define-and-how-to-translate-amd-to-commonjs/ CommonJS和AMD的争论已经 ...

  4. ls Common Command-Line Options

    ls  Common Command-Line Options Command  Use: ls -l    Shows a long listing, which includes informat ...

  5. 12 个 CSS 高级技巧汇总

    下面这些CSS高级技巧,一般人我可不告诉他哦. 使用 :not() 在菜单上应用/取消应用边框 给body添加行高 所有一切都垂直居中 逗号分隔的列表 使用负的 nth-child 选择项目 对图标使 ...

  6. HTML5触摸屏touch事件使用介绍1

    市面上手机种类繁多,在触屏手机上运行的网页跟传统PC网页相比还是有很大差别的.由于设备的不同浏览器的事件的设计也不同.传统PC站的 click 和 onmouseover 等事件在一般触屏的手机上也可 ...

  7. Sqlserver数据库日志太大如何快速删除

    sqlserver使用在windows系统中,如果文件超上百GB了,我们还直接删除不了,这个问题我以前的apache日志就碰到过,至今还没删除呢,那么Sqlserver数据库日志太大如何快速删除呢,有 ...

  8. 粗俗易懂的SQL存储过程在.NET中的实例运用

    整理了一下存储过程在项目中的运用,防止遗忘,便记录于此!存储过程(Stored Procedure)是一组为了完成特定功能的SQL语句集,经编译后存储在数据库中.用户通过指定存储过程的名字并给出参数( ...

  9. 《CSS网站布局实录》学习笔记(六)

    第六章 CSS高级应用与技巧 6.1 id与class 6.1.1 什么是id id是XHTML元素的一个属性,用于标识对象名称.无论是class还是id,都是XHTML所支持的公共属性,并且也是其核 ...

  10. Swift - 35 - 使用闭包简化语法

    //: Playground - noun: a place where people can play import UIKit // 初始化一个整数数组 var arr = [1, 3, 5, 7 ...