使用netty作为http的客户端,pool又该如何进行设计。本文将会进行详细的描述。

1. 复用类型的选型

1.1 channel 复用

多个请求可以共用一个channel

模型如下

模型

特点

  • 1:callback队列为回调队列。 不同的callback通过一个全局的id进行标识。发送的时候会把该id发到服务端,服务端在回复的时候必须把该id再返回到客户端。

  • 2:获取连接只需要随机获取一个channel即可,将callback添加到队列里面。

  • 3: 获取连接时消除了锁的竞争,性能高效。

  • 4:结构简单。

示例

  • osp(唯品会的SOA框架) client pool实现(thrift协议)

  • spray 的 akka client pool

约束

需要服务端配合支持channel复用。需要有一个全局唯一的id用于识别请求。 通常id先发给服务端,服务端还要把id会给客户端。

1.2 channel 独享

每个请求独立使用一个channel。

模型如下

模型

特点

  • 1:同一个channel同时只给一个request使用。

  • 2:连接池的设计较为复杂。

示例

  • 1:数据库连接池[druid,c3p0,dbcp,hikaricp,caelus(唯品会内部连接池)]

  • 2:netty的http pool ; apache的httpclient pool, httpasyncclient pool ; nginx的pool。

1.3 选择

由于http1.1协议原生不支持channel复用(http2是支持的),如果需要支持,则需要在header里面加入一个唯一id,所有的应用服务器均需要进行改动。为了和nginx的连接池保持一致,确定使用channel的独享方式

2. 组件选型

组件 优点 缺点
common-pool 功能完整 不支持异步连接
rxnetty pool 功能完整,支持netty 使用的为rxjava机制
netty pool netty原生实现 功能较为简单

选择netty pool作为连接池的实现。4.0.33版本有该功能,可能老版本没有pool的功能。

3. pool的设计

3.1 模型

模型

通过ip,port路由到对应的pool,每个pool之间完全独立。

3.2 主要功能点

功能点

3.3 获取连接

  • 1:通过控制最大连接数,来避免无限的创建连接。

  • 2:当超过最大连接数时,则需要等待。由于整个流程是全异步的,需要将当前信息进行任务封装注册回调。

  • 3:需要设置等待连接的个数及超时时间,避免把内存给撑爆。

  • 4:需要对获取的连接进行有效性检查。一般只需校验channel.isactive()即可。如果检验失败,需要重新获取有效连接。

3.4 资源池

  • 1:使用无锁的ConcurrentLinkedDeque 双向队列来存放所有idle的连接(jdk1.7才有该类)。

  • 2:该队列通过cas的操作来避免同步。 由于拿到连接后业务执行的速度较慢,所以这里的cas冲突应该很小。

3.5 归还连接

归还连接

归还连接主要包含两部分:正常release和异常的forceClose

  • 1:在netty中,如果收到FIN(服务端发送的正常close请求),则会通知到netty的channelInactive接口,需要在该接口处进行forceClose.

  • 2:收到RST(服务端非正常的关闭),则会通知到exceptionCaught接口,需要在该接口处进行foreclose。关于RST的问题可参考:http://blog.csdn.net/hetaohappy/article/details/51851880

  • 3:在收到正常数据后(channel的channelRead接口),需要判断header里面是否有Connection:close,如果有,则进行forceClose,否则进行release

  • 4:如果空闲超时,则关闭连接,来避免连接一直被无效的占用。只需要增加IdleStateHandler ,判断连接空闲超时,则fire一个event事件。只需要注册对该事件的监听,进行foreclose即可。

  • 5:占有超时:连接在规定的时间内未还,则进行forceClose。

6:发送请求时,发现channel已经被close掉或者其他io异常,则进行forceClose。

7:forceclose接口里面,需要通过一个状态位来控制是否操作 acquiredChannelCount(已获取连接数)。由于调用forceclose,连接可能在资源池中,如果操作该字段,会导致该字段统计不准确。

3.6 超时控制

获取连接timeout

在规定的时间内没有获取到连接,则抛异常。

  • 1:一般实现是通过ReentrantLock来设置lock的超时时间或者直接通过unsafe.park设置超时时间。该种机制会对当前线程进行block。

  • 2:由于netty是纯异步机制,如果进行block,会严重影响性能。所以这里是将当前信息进行task封装,然后schedule一个定时任务。如果在设定时间内该task没有被消费,则会抛出timeout的异常。

建立连接timeout

  • 1:在BIO中,通过设置socket的connect(SocketAddress endpoint, int timeout) 时间即可。Tips:该值不要和setSoTimeout(int timeout)混淆,sotimeout是设置调用read的超时时间。

  • 2:在NIO中,需要业务自己控制连接的超时时间。 一般是通过schedule一个定时任务来控制超时时间。(在netty中即使用的该机制)

连接空闲timeout

  • 1: 通过设置一个handler(IdleStateHandler ),在新建连接的时候schedule一个任务(时间为空闲超时时间),在调用read或者write方法的时候,进行时间的更新。如果任务运行的时候发现空闲超时,则进行event的触发。

  • 2:业务handler捕获该event,进行连接空闲超时的处理。

连接被占有timeout

避免连接泄露

  • 1:在获取连接的时候 schedule一个任务(时间为连接被占用的timeout),在归还的时候会cancel该任务。如果该任务被运行,说明在规定的时间没有归还,则进行timeout的处理。

3.7 性能优化

  • 1:资源池无锁化:ConcurrentLinkedDeque (前面已有介绍)

  • 2:acquiredChannelCount(已获取连接数)的无锁化(该字段用来控制是否达到了最大连接数,正常情况为获取连接后加1,归还连接后减1)。

连接池均会通过acquiredChannelCount来控制当前已经获取的连接个数。该参数会面临着多线程的竞争,需要进行同步或者cas的设计。如何设计让acquiredChannelCount完全不用考虑多线程竞争?

看能不能从akka的设计中找点思路: akka消除竞争的方式就是让一个actor同一时刻只能在一个线程中运行,这样actor里面所有的全局参数就不需要考虑多线程竞争,一个actor里面所有的任务都是串行执行的,完全消除竞争。

那么能不能串行操作acquiredChannelCount呢? 答案是可以的,并且在netty中实现非常简单,只需要实现如下代码即可:

if (executor.inEventLoop()) {acquiredChannelCount++;} else{executor.execute(newOneTimeTask() {@Overridepublic void run() {acquiredChannelCount++;}}
}

其中executor 就是一个固定的线程。判定当前执行的线程是否是executor这个线程,如果是则直接执行。如果不是,则放到executor线程的队列里达到串行操作的目的(类似于actor的mailbox) (netty的设计及抽象能力确实非常高)

3.8 配置参数

  • http_pool_aquire_timeout :获取连接超时时间:默认为5000ms

  • http_pool_maxConnections:连接大小:默认为1000

  • http_connection_timeout :建立连接的超时时间:默认为5000ms

  • http_pool_idle_timeout:连接空闲多久关闭:默认为:30分钟

  • http_pool_maxPending:连接池不够用,最大允许有多少个pendingRequest:默认为无限大

  • http_pool_maxHolding:拿连接的使用时间。在规定时间未还,则强制close掉。默认为5000ms。

4. 面临的问题

  • 1:所有的操作都是纯异步,导致callback嵌套的特别深(netty通过promise机制,来方便callback的使用),如果控制不好,很容易出问题。

  • 2:连接被require后,一定要保证归还,由于异步特性,很容易在某些异常下将连接漏还(笔者遇到在高并发下由于代码bug导致漏还的情况)

  • 3:如何避免在拿到连接后,同时web服务器(http的keepalive机制)将该连接给close掉了,导致执行的失败。有两种解决方案可以参考。

    • 捕获执行失败的异常,如果是特定的异常,则forceClose当前的连接,重新拿一个连接进行访问。如果超过重试次数,则抛出异常。

    • 如何确定该线程定时的时间。后端web服务器对连接的超时时间可能不一致,该定时时间一定要小于web服务器的连接超时时间。

    • 心跳执行的接口问题。需要所有的web服务器均需要实现固定的接口进行心跳检测,可行性比较差。

    • 3.1:可以参考common-pool的设计思想,在后端开启一个线程定时对所有连接进行心跳检测。问题:

      • 如何确定该线程定时的时间。后端web服务器对连接的超时时间可能不一致,该定时时间一定要小于web服务器的连接超时时间。

      • 心跳执行的接口问题。需要所有的web服务器均需要实现固定的接口进行心跳检测,可行性比较差。

    • 3.2:重试机制:

      • 捕获执行失败的异常,如果是特定的异常,则forceClose当前的连接,重新拿一个连接进行访问。如果超过重试次数,则抛出异常。

基于 Netty 如何实现高性能的 HTTP Client 的连接池相关推荐

  1. java mysql多次事务 模拟依据汇率转账,并存储转账信息 分层完成 dao层 service 层 client层 连接池使用C3p0 写入库使用DBUtils...

    Jar包使用,及层的划分 c3p0-config.xml <?xml version="1.0" encoding="UTF-8"?> <c3 ...

  2. 网络|基于Netty构建的高性能车辆网项目实现(一)

    本文主要做技术分享,如有侵权请通知作者删除 项目背景 该项目是d市的政府项目,需要从n(n>10000)台公交车中收集车上数据,包括驱动.电池.发动机.报警等共计100余种车辆信息,需要基于国标 ...

  3. 京东的Netty实践,京麦TCP网关长连接容器架构

    背景 早期京麦搭建 HTTP 和 TCP 长连接功能主要用于消息通知的推送,并未应用于 API 网关.随着逐步对 NIO 的深入学习和对 Netty 框架的了解,以及对系统通信稳定能力越来越高的要求, ...

  4. java web netty_基于Netty的非Servlet规范 JavaWeb框架及高性能 Java服务器

    Bay 一个非Servlet规范的JavaWeb框架,包括一个基于Netty的高性能服务器. ##介绍 这是一个基于Netty实现的非Servlet规范的Web服务器,由于底层设计经验不足,所以实际上 ...

  5. voyage java_GitHub - yezilong9/voyage: 采用Java实现的基于netty轻量的高性能分布式RPC服务框架...

    Voyage Overview 采用Java实现的基于netty轻量的高性能分布式RPC服务框架.实现了RPC的基本功能,开发者也可以自定义扩展,简单,易用,高效. Features 服务端支持注解配 ...

  6. 谈谈如何使用Netty开发实现高性能的RPC服务器

    RPC(Remote Procedure Call Protocol)远程过程调用协议,它是一种通过网络,从远程计算机程序上请求服务,而不必了解底层网络技术的协议.说的再直白一点,就是客户端在不必知道 ...

  7. Java编写基于netty的RPC框架

    一 简单概念RPC: ( Remote Procedure Call),远程调用过程,是通过网络调用远程计算机的进程中某个方法,从而获取到想要的数据,过程如同调用本地的方法一样.阻塞IO :当阻塞I/ ...

  8. Netty的使用:Server和Client通信

    来自:Netty的使用:Server和Client通信_宿久-CSDN博客_netty server Netty 是一款基于NIO(Nonblocking I/O,非阻塞IO)开发的网络通信框架,提供 ...

  9. Netty高并发高性能架构设计NIO空轮训BUG

    Netty高并发高性能架构设计&NIO空轮训BUG Netty高并发高性能架构设计 Netty线程模型 Netty主从Reactor模型设计的精髓 无锁串行化设计思想 零拷贝 直接内存 Net ...

最新文章

  1. 简单io应用—流水灯控制_制作简单有趣的可调速流水灯
  2. 我想自学编程技术,但是每天下班回来都很累了,没力气,怎么办?
  3. 【今日CV 计算机视觉论文速览 第134期】Fri, 21 Jun 2019
  4. php 漂亮的分页类
  5. 翁恺老师C语言学习笔记(八)数组
  6. 一对电话线传输100M带宽不再是问题
  7. 行间事件传this的问题:
  8. 纯CSS的导航下拉菜单
  9. U盘中毒后被隐藏的文件夹无法隐藏选项无法取消
  10. 去文字,如何用PS快速去除图片上的文字
  11. 【洛谷 2504】聪明的猴子
  12. 拼多多关键搜索、商品列表接口、商品详情接口
  13. C#中包含英文月份的美式日期输出格式
  14. 仅1cm厚!华硕发布全球最薄13.3英寸笔记本
  15. Python | 人脸识别系统 — 人脸比对 代码部分
  16. 透过J2Cache的吐槽,领悟代码的设计
  17. Pygame 简单打字游戏
  18. 不完整信息系统----容差关系 tolerance relation
  19. Qt窗口最大化/最小化/窗口状态判断
  20. egret引擎下,微信分包,微信登陆,微信分享例子

热门文章

  1. PHP 数组函数分类和整理
  2. 2.FastJson公司--阿里巴巴开源的速度最快的Json和对象转换工具
  3. java 线程的几种状态
  4. eclipse format的时候如何让@param后不换行
  5. 软件级负载均衡器(LVS/HAProxy/LVS)的特点简介和对比
  6. JS 获取控件的绝对位置
  7. linux epoll 模型详解
  8. C++实现RTMP协议发送H.264编码及AAC编码的音视频
  9. c++构建工具之cmake使用小结
  10. c++内存管理优化之ptmalloc,tcmalloc,jemalloc使用实例