教你正确地利用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 前言 在写这篇文章之前 ...
随机推荐
- Java Performance Optimization Tools and Techniques for Turbocharged Apps--reference
Java Performance Optimization by: Pierre-Hugues Charbonneau reference:http://refcardz.dzone.com/refc ...
- SVN 中trunk、tags、branches使用
简介 我们都知道SVN是管理项目源代码的软件,可以把我们开发中的各个阶段的代码记录下来,供我们以后来使用,那么SVN具体的结构你是否知道呢?下面我们来介绍一下它的基本结构 Trunk.Branches ...
- Universal-Image-Loader 基本使用
简介 https://github.com/nostra13/Android-Universal-Image-Loader 项目的结构:每一个图片的加载和显示任务都运行在独立的线程中,除非这个图片缓存 ...
- 《node.js开发指南》读书笔记(一)
在开发时如果修改了js内容,不能通过刷新浏览器直接看到效果,必须通过重启nodejs程序才能看到,这样显然不利于开发调试,supervisor可以实现这个功能,监视对代码的改动,并自动重启nodejs ...
- 【转】Mysql三种备份详解
一.备份的目的 做灾难恢复:对损坏的数据进行恢复和还原需求改变:因需求改变而需要把数据还原到改变以前测试:测试新功能是否可用 二.备份需要考虑的问题 可以容忍丢失多长时间的数据:恢复数据要在多长时间内 ...
- 安全管理:IE6安全隐患重重 为何不离不弃
安全服务商Zscaler的报告称,尽管微软IE6曾遭受一系列强势攻击并且新出的IE版本有更强的安全性能,但IE6依然受到各企业的热捧. 尽管微软一直敦促用户部署浏览器更新(截止2010年八月就将满九年 ...
- HashMap的扩容机制, ConcurrentHashMap和Hashtable主要区别
源代码查看,有三个常量, static final int DEFAULT_INITIAL_CAPACITY = 16; static final int MAXIMUM_CAPACITY = 1 & ...
- php改写session到数据库
session改写mysql 在调用 session_start();的地方改用实例化本类即可new SessionDB(); session_set_save_handler( array($thi ...
- react-redux源码解析
有理解不对的地方,欢迎大家指正!!! react为什么需要redux辅助???react是view层的单向数据流框架,数据需要一层一层往子组件传递(子组件并不会自动继承).子组件需要操作父组件的数据时 ...
- 学习OpenSeadragon之三 (覆盖层Overlayer的使用)
Overlayer(覆盖层)是一个很重要的机制,它可以在可缩放图片上显示额外的信息. 1.简单应用 以下是我做出的一个小例子: 看这小老鼠头部的红色框内的部分就是一个分离出来的overlay. 介绍一 ...