前言:
  之前做个一个数据同步的定时程序. 其内部集成了某电商的SDK(简单的Apache Httpclient4.x封装)+Spring Quartz来实现. 原本以为简单轻松, 喝杯咖啡就高枕无忧的事. 没想到该程序并不买账, work时间一久, 竟频频罢工还卖萌. 我勒个过去, 套用一句流行的话说: 真是青春日了狗了.

相关文章的链接:
  第三方SDK(Rest API)和Jaskson的巧用 
  quartz和定时任务执行

现象回顾:
  最近发现数据同步迟滞了, 于是立马去check下服务进程. 发现进程活得好好的(白白胖胖那种), 稍松了口气, 看来没有OOM, 以及被误杀. 但日志没有滚动, 也就是说日志好久没更新了. 这是啥回事呢?
  难道说worker线程退出江湖了, 死锁大爷又来踢馆了, 还是说路遇张麻子(此山是我开, 此树是我栽)?
  使用jstack -l <pid>, 连续多次采样thread dump. 发现worker线程一直在read socket上等待.
  
  大概率上来讲, 进程是被堵塞了于此了.
  当然于此同时, 还发现了被动关闭, 哎呀妈呀, 问题还真不少.  
  

问题分析:
  简单解读下某电商平台的SDK代码片段:

public HttpResponse get(String method, HashMap<String,String> parames) throws Exception{
    String url = apiEntry + getParamStr(method, parames);     HttpClient client = new DefaultHttpClient();
    HttpGet request = new HttpGet(url);
    request.addHeader("User-Agent", DefaultUserAgent);
    HttpResponse response = client.execute(request);     return response;
}

  代码很简洁, 也能很好地work, 那究竟哪个环节有疏忽呢?
  由于问题都出现在Apache Httpclient 4.x上, 因此我们先看看网上是否也有类似的案例场景.
  • socket阻塞
  参考了相关文章, 基本认可博文<<Apache HttpClient 没有设置time out导致应用长时间阻塞的问题>>中的说法: socket没有设置超时选项导致.
  具体解读, 可以理解为服务端对端不回应, 或者因网络异常, 导致socket一直阻塞于读. Apache HttpClient默认设置的socket为SO_TIMEOUT为0, 既无限等待.
  结合之上的代码分析, 确实忽视了超时设定, 陷入了Apache HttpClient隐藏很深的坑中. ^_^!
  解决方案是:为对应的httpclient设置超时即可.

httpClient = new DefaultHttpClient();
httpClient.getParams().setIntParameter(CoreConnectionPNames.SO_TIMEOUT, 2000);
httpClient.getParams().setIntParameter(CoreConnectionPNames.CONNECTION_TIMEOUT, 2000);

  这样阻塞的问题就可以暂时告一段落了.
  • 句柄泄露(CLOSE_WAIT半连接关闭)
  同样参考了博文: <<HttpClient容易忽视的细节——连接关闭>>与<<HttpClient 与 Close_Wait>>.
  按apache httpclient的设计理念, 当http client 处于高并发时, 默认机制导致的CLOSE_WAIT会影响服务的可用性.
  对比之上的代码, 确实没有找到主动关闭连接的代码.
  Apache HttpClient本身变动多, 接口又杂, 以至每个版本的解决方案又有所不同, 有些让人眼花缭乱.
  比较一致的解决方式是,在处理完单个请求后, 调用如下清理代码:

httpmethod.releaseConnection();
client.getConnectionManager().shutdown();

  但不管怎么说, Apache HttpClient 4.x的关闭机制, 还是值得大书特书的, 这边显得简略, 希望以后有机会能深入研究.

总结:
  这次算是事出有因, 问题出在了第三方的SDK上. 由此可见, 对第三方的SDK的使用, 还是得留个心眼. 实际上, 很多平台的SDK, 往往是实习生所编写的, 且没有经过严苛的测试, 所以质量难免有些参差不齐.
  无论是SDK的使用者, 还是SDK的开发者, 都需要精益求精, 在质量(性能和稳定), 用户体验(易用/易理解)上做足功夫了, 这也是程序员的软实力之一.

后记:
  本文对Apache HttpClient 4.x的阻塞陷阱做了介绍, 展现了其案例表现, 以及解决方案. 但缺少对Apache HttpClient深入分析, 以及使用方式推荐. 希望自己能有机会, 好好地整理一番.

公众号&游戏站点:
  个人微信公众号: 木目的H5游戏世界
  

  个人游戏作品集站点(尚在建设中...):www.mmxfgame.com,  也可直接ip访问http://120.26.221.54/.

Apache HttpClient使用之阻塞陷阱的更多相关文章

  1. 在android 6.0(API 23)中,Google已经移除了移除了Apache HttpClient相关的类

    推荐使用HttpUrlConnection,如果要继续使用需要Apache HttpClient,需要在eclipse下libs里添加org.apache.http.legacy.jar,androi ...

  2. 论httpclient上传带参数【commons-httpclient和apache httpclient区别】

    需要做一个httpclient上传,然后啪啪啪网上找资料 1.首先以前系统中用到的了commons-httpclient上传,找了资料后一顿乱改,然后测试 PostMethod filePost = ...

  3. Android 6.0删除Apache HttpClient相关类的解决方法

    相应的官方文档如下: 上面文档的大致意思是,在Android 6.0(API 23)中,Google已经移除了Apache HttpClient相关的类,推荐使用HttpUrlConnection. ...

  4. android 中对apache httpclient及httpurlconnection的选择

    在官方blog中,android工程师谈到了如何去选择apache client和httpurlconnection的问题: 原文见http://android-developers.blogspot ...

  5. 新旧apache HttpClient 获取httpClient方法

    在apache httpclient 4.3版本中对很多旧的类进行了deprecated标注,通常比较常用的就是下面两个类了. DefaultHttpClient -> CloseableHtt ...

  6. 基于apache httpclient 调用Face++ API

    简要: 本文简要介绍使用Apache HttpClient工具调用旷世科技的Face API. 前期准备: 依赖包maven地址: <!-- https://mvnrepository.com/ ...

  7. 一个封装的使用Apache HttpClient进行Http请求(GET、POST、PUT等)的类。

    一个封装的使用Apache HttpClient进行Http请求(GET.POST.PUT等)的类. import com.qunar.payment.gateway.front.channel.mp ...

  8. RESTful Java client with Apache HttpClient / URL /Jersey client

    JSON example with Jersey + Jackson Jersey client examples RESTful Java client with RESTEasy client f ...

  9. 使用Apache HttpClient 4.x发送Json数据

    Apache HttpClient是Apache提供的一个开源组件,使用HttpClient可以很方便地进行Http请求的调用.自4.1版本开始,HttpClient的API发生了较大的改变,很多方法 ...

随机推荐

  1. CAP Confusion: Problems with ‘partition tolerance’

    by Henry Robinson, April 26, 2010 The 'CAP' theorem is a hot topic in the design of distributed data ...

  2. velocity插件 veloeclipse 支持eclipse4.4

    分享主页:http://pan.baidu.com/share/home?uk=2737650112#category/type=0 http://pan.baidu.com/s/12RSAy 感谢究 ...

  3. Redis系列-存储篇list主要操作函数小结

    在总结list之前,先要弄明白几个跟list相关的概念: 列表:一个从左到右的队列,个人理解更类似于一个栈,常规模式下,先进列表的元素,后出. 表头元素:列表最左端第一个元素. 表尾元素:列表最右端的 ...

  4. digitalocean

    sudo apt-get install sshifconfigssh 198.211.102.203sudo adduser uernameubuntu装配SSH,支持开启sftp服务 sftp 1 ...

  5. inoic是什么

    本篇只侧重框架提供的功能和能力的研究,请关注后续实际部署使用体验. 一.inoic是什么? inoic是一个可以使用Web技术以hybird方式开发移动app的前端开源框架. 二.inoic框架特点 ...

  6. 创建plist文件

    可以先在工程中直接新建一个plist文件,往里面写入自己需要的数据.但是这里的plist文件我们无法修改,是只读的,我们可以将这个plist文件复制一份到沙盒中,然后对沙盒中的文件进行操作.具体代码如 ...

  7. Apache Jmeter(1)

    Apache JMeter是Apache组织开发的基于Java的压力测试工具.用于对软件做压力测试,它最初被设计用于Web应用测试但后来扩展到其他测试领域. 它可以用于测试静态和动态资源例如静态文件. ...

  8. centos ssh 无密码登录

    在linux系统中,ssh是远程登录的默认工具,因为该工具的协议使用了RSA/DSA的加密算法.该工具做linux系统的远程管理是非常安全的.telnet,因为其不安全性,在linux系统中被搁置使用 ...

  9. STM32之RTC配置与初始化-rtc.h rtc.c

    <rtc.h> #include "stm32f10x.h" #ifndef _RTC_H #define _RTC_H typedef struct { vu8 ho ...

  10. 开源留言板 --wekan部署

    1. 安装ubuntu--server-64位系统 2. 登录ubuntu系统 3. 下载自动安装脚本 #git clone https://github.com/anselal/wekan 4. 执 ...