教你正确地利用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可以满足我们的需求,但是有些业务场景(例如:返回结果时间不确定)需要使用这种异步的连接池,在正确的业务场景下选择正确的解决方案才是王道哦。
教你正确地利用Netty建立连接池的更多相关文章
- python psycopg2 连接pg 建立连接池
# -*- coding: utf-8 -*-from psycopg2.pool import ThreadedConnectionPool,SimpleConnectionPool,Persist ...
- ADO连接达梦7数据库,利用OLEDB建立连接
达梦数据库本身提供多种驱动如JDBC ODBC OLEDB等等 在安装的时候可以进行勾选. 如果不安装数据库的驱动无法与达梦数据库建立连接. 达梦数据库在数据库构成或结构上与oracle极为相似,而且 ...
- Netty服务器连接池管理设计思路
应用场景: 在RPC框架中,使用Netty作为高性能的网络通信框架时,每一次服务调用,都需要与Netty服务端建立连接的话,很容易导致Netty服务器资源耗尽.所以,想到连接池技术,将与同一个Nett ...
- ssh使两台机器建立连接
ssh利用口令建立连接过程: 客户端--> 发送连接请求 --> 远程主机 --> 返回远程主机的公钥 --> 公钥加密客户端私钥+客户端公钥返回远程主机 --> 远程主 ...
- 数据库程序接口——JDBC——API解读第一篇——建立连接的核心对象
结构图 核心对象 Driver Java通过Driver接口表示驱动,每种类型的数据库通过实现Driver接口提供自己的Driver实现类. Driver由属性,操作,事件三部分组成. 属性 公共属性 ...
- 走进JavaWeb技术世界3:JDBC的进化与连接池技术
走进JavaWeb技术世界3:JDBC的进化与连接池技术 转载公众号[码农翻身] 网络访问 随着 Oracle, Sybase, SQL Server ,DB2, Mysql 等人陆陆续续住进数据库 ...
- Tomcat 连接池详解
(转) JDBC 连接池 org.apache.tomcat.jdbc.pool 是Apache-Commons DBCP连接池的一种替换或备选方案. 那究竟为何需要一个新的连接池? 原因如下: Co ...
- 深入理解Spring Boot数据源与连接池原理
Create by yster@foxmail.com 2018-8-2 一:开始 在使用Spring Boot数据源之前,我们一般会导入相关依赖.其中数据源核心依赖就是spring‐boot‐s ...
- 用Swoole4 打造高并发的PHP协程Mysql连接池
码云代码仓库:https://gitee.com/tanjiajun/MysqlPool 代码仓库:https://github.com/asbectJ/swoole4.git 前言 在写这篇文章之前 ...
随机推荐
- android实现界面左右滑动(GridView动态设置item,支持每个item按某个属性排序来显示在不同的界面)
效果图 : 分别是第一页.第二页.第三页,随手截的图,不整齐,勿见怪.开始走了弯路,废了不少时间. 思路如下: 1.用ViewPager实现左右分页滑动 ...
- Can a Tomcat docBase span multiple folders?--转
Question: I apologize if this is a poor question, but I'm using Windows and looking to see if there' ...
- web页面打印
在使用的两种方式打印: 第一种:js如下 function doPrint() { allhtml = window.document.body.innerHTML; starstr = " ...
- sourceTree添加git密钥步骤
给多个远程服务器比如https://github.com/wangjian2014/wjtest/blob/master/wj.txt添加public密钥 本地服务器添加private密钥 S ...
- php单例模式深入讲解
避免多次初始化数据库连接DAO 需要多次初始化数据库连接的场景 场景1: 首先PHP单例模式我觉得只是针对单次页面级请求时出现多个应用场景并需要共享同一对象资源时是非常有意义的 一个类A需要调用多个类 ...
- (转)SVN源码管理(上&下)
原文地址:http://www.cnblogs.com/IPrograming/archive/2012/12/15/SVN_1.html 使用SVN进行源码管理(上) 在原来的项目中使用的源码管理工 ...
- (转)PHP 的 __FILE__ 常量
今天碰到了PHP的常量__FILE__的问题了. 在网上查了一下.总结了以下规律. dirname(__FILE___) 函数返回的是脚本所在在的路径. 比如文件 b.php 包含如下内容: < ...
- HTML 控件和web控件 OnClientClick和OnClick OnServerClick区别
^_^ 本来对html控件,服务器控件的知识模模糊糊的.今天特地查了相关的知识. 下面是我写代码总结的. 这些事件 主要用于在客户端执行验证,然后决定是否执行服务端事件 (没接触之前就为此 ...
- 最全的ORACLE-SQL笔记
-- 首先,以超级管理员的身份登录oracle sqlplus sys/bjsxt as sysdba --然后,解除对scott用户的锁 alter user scott account unloc ...
- oracle 语句
1.查询TRENDCHART_DLT表中的30条数据,统计字段FRONT01='0',BACK12='0'的条数 select sum(case when FRONT01='0' then 1 els ...