教你正确地利用Netty建立连接池

一、问题描述

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可以满足我们的需求,但是有些业务场景(例如:返回结果时间不确定)需要使用这种异步的连接池,在正确的业务场景下选择正确的解决方案才是王道哦。

  

时间: 2024-08-09 06:33:06

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

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

达梦数据库本身提供多种驱动如JDBC ODBC OLEDB等等 在安装的时候可以进行勾选. 如果不安装数据库的驱动无法与达梦数据库建立连接. 达梦数据库在数据库构成或结构上与oracle极为相似,而且也能看到一丝MSSQLserver与MYSQL 的影子 strCon = ("Provider=DOLEDB.1;Data Source=192.168.1.16:5237;User ID=SYSDBA;Password=123456;"); 驱动为DOLEDB.1 需要数据IP .端口号

第一篇——建立连接(JDBC)

结构图 核心对象 Driver Java通过Driver接口表示驱动,每种类型的数据库通过实现Driver接口提供自己的Driver实现类. Driver由属性,操作,事件三部分组成. 属性 公共属性 版本号:版本号由两个字段主版本号(majorVersion)和副版本号(minorVersion)组成. 特殊属性: DriverPropertyInfo对象:它有四个字段,name表示属性名称,value表示属性值,required.表示是否是必要属性,description表示对属性的描述.

API解读第一篇——建立连接的核心对象(JDBC)

结构图 核心对象 Driver Java通过Driver接口表示驱动,每种类型的数据库通过实现Driver接口提供自己的Driver实现类. Driver由属性,操作,事件三部分组成. 属性 公共属性 版本号:版本号由两个字段主版本号(majorVersion)和副版本号(minorVersion)组成. 特殊属性: DriverPropertyInfo对象:它有四个字段,name表示属性名称,value表示属性值,required.表示是否是必要属性,description表示对属性的描述.

Tomcat 连接池详解

(转) JDBC 连接池 org.apache.tomcat.jdbc.pool 是Apache-Commons DBCP连接池的一种替换或备选方案. 那究竟为何需要一个新的连接池? 原因如下: Commons DBCP 1.x 是单线程.为了线程安全,在对象分配或对象返回的短期内,Commons 锁定了全部池.但注意这并不适用于 Commons DBCP 2.x. Commons DBCP 1.x 可能会变得很慢.当逻辑 CPU 数目增长,或者试图借出或归还对象的并发线程增加时,性能就会受到影

poco c++框架库应用:数据库的连接池

Poco c++中的数据库驱动部分,简洁,干净,工整,和数据库连接,封装成这样,还是比较好用的.下面是连接MySQL连接的方法. 一 需求说明 与MySQL数据库建立连接池,并在连接池中获得一个连接,实现数据库常用增删改查 二 目标说明 写出ANSI风格的代码,并输出高度结果到终端,验证程序的有效性 三 调试条件: 1.系统:ubuntu 2.qt 或 其它IDE 3.安装了mysql,有正确的访问账户和密码 四 例程说明 使用IDE:Qt Creator 项目文件:pocomysql.pro

Spring Boot的数据源与连接池

? Create by [email protected] 2018-8-2 一:依赖 使用Spring Boot的默认数据源spring.datasource只需要导入如下依赖: <dependency> <groupId>org.springframework.boot</groupId> ??????????? <artifactId>spring‐boot‐starter‐jdbc</artifactId> ??????????? <

连接池的概念和初步代码

连接池的概念  1)连接池是一个进程 多个连接是在一个进程里面存储.管理的.这个进程保存所有的连接,当我们打开连接,如果有未用连接可用,则返回该连接.如果池中的连接都用完了,则创建一个新的连接保存到连接池.而但我们关闭连接的时候,连接池里面并不关闭连接,而是返回连接池中并标记为可重用的状态,等待重新连接直到等待超时.再次打开连接的时候,我们就可以重用上次的连接.如果在这个时间内没有连接请求(打开连接),这个数据库连接将被关闭,并从连接池中移除这个连接实例.如果池中连接到达了最大连接数,请求进入等

再淡spring jdbc 连接池断开重连设置

先看一段错误日志: ### Error querying database. Cause: com.mysql.jdbc.exceptions.jdbc4.MySQLNonTransientConnectionException: No operations allowed after connection closed. ### The error may exist in file ----] ### The error may involve ..... ### The error occ

数据源与连接池的关系

今日一直在纠结数据源与连接池,这两个东西到底是什么关系呢?因为看spring中配置的明明是连接池,但是术语却叫其 数据源,而且也没有看到其配置数据源,想想肯定是有原因的,遂来总结下. 先抛开spring的配置,先来谈谈市场上常用的数据源和连接池: 数据源:JDBC数据源,JNDI数据源,ODBC数据源等(黑体比较常用): 连接池:C3P0连接池,DBCP连接池,Porxool连接池(黑体比较常用)等 那么到底他们之间是什么关系呢? 数据源是指数据的来源,比如数据库.   连接池是指这样一个"池子