教你正确地利用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 前言 在写这篇文章之前 ...
随机推荐
- SVN经常使用命令说明
SVN版本号:1.5 及更新版本号 名词说明: WC:Working Copy 你的工作区 Versioned:受控的:受版本号控制的 SVN是什么? SVN是开源的版本号控制系统. 比CVS很多其它 ...
- Java 编程的动态性,第 7 部分: 用 BCEL 设计字节码--转载
在本系列的最后三篇文章中,我展示了如何用 Javassist 框架操作类.这次我将用一种很不同的方法操纵字节码——使用 Apache Byte Code Engineering Library (BC ...
- PHP 单链表
<?php class Hero { public $no; public $name; public $nickname; public $next=null; public function ...
- HTTP状态码(HTTP Status codes)简介
HTTP可能大家都熟悉,就是超文本传输协议.浏览器通过HTTP与WEB Server通讯(也有一些其它软件比如IM使用HTTP协议传递数据),把我们的请求(HTTP Request)传递给服务器,服务 ...
- maven发布时在不同的环境使用不同的配置文件
在开发时,不同的环境总会使用到不同的配置.如本地,测试,预发布,发布等环境,像数据库这些都要使用到不同的配置.如果手动改的话肯定会十分的麻烦. 还好maven提供的功能能够帮我们解决这个问题. 我们通 ...
- iOS判断UIScrollView的滚动方向
- (void) scrollViewDidScroll:(UIScrollView *)scrollView { CGFloat newY = scrollView.contentOffset.y; ...
- windows下安装php笔记
为了更深入的理解下服务端的配置 ,上篇文章讲了如何在windows下安装apache , 接下来再研究下在windows下安装php并且结合apache运行php环境, 纯属学习用 ^^ ,如果嫌麻烦 ...
- 搭建ngrok服务器(ubuntu 14)-- 微信 80端口和IPC备案限制解决方案
概述: ngrok其实这东西,我也不是很懂,所以也直接跟大家说,这就是个类似花生壳的东西. 简单来说,它就好像把我们内网自己使用的电脑和服务器用vpn连接起来,然后你的电脑就可以从互联网来访问了,有个 ...
- oracle单行函数之日期函数
在日期上加上或减去一个数字结果仍为日期. 两个日期相减返回日期之间相差的天数. 可以用数字除24来向日期中加上或减去小时. SQL from dual; SYSDATE SYSDATE ------- ...
- log4j的配置及使用
用日志的好处: 可以长久的保存日志信息. 日志可以保存到:网络.文件.数据库 设置日志的级别. OFF Fatal – System.exit(0); - JVM, ERROR – 错误,模块错误. ...