本文首发于 vivo互联网技术 微信公众号 
链接: https://mp.weixin.qq.com/s/8f34CaTp--Wz5pTHKA0Xeg
作者:vivo 官网商城开发团队

众所周知,Oracle JDK  是 Java 语言的绝对权威,很多时候 JDK 与 Java 语言近似一个概念。但我们始终要保持实事求是的精神,敢于质疑。本文记录了一次线上troubleshoot 实战,包含问题分析、解决并提交 Oracle JDK bug 的核心过程。

一、背景现象

总之 就是某系统上线后 CLOSE_WAIT数量随着时间增加而大量增加,持续触发多个告警。

二、分析定位过程

部署了一个节点,用来复现之前出现的问题。

Step1 问题聚焦

先查看到底是哪些IP之间的连接产生了大量CLOSE_WAIT,另外系统还会涉及调第三方,总之要确认连接建立的双方。

执行命令:

netstat -np | grep tcp|grep "CLOSE_WAIT"

结果:

(ps:xxx、yyy、zzz 均无含义,基于信息安全考虑,屏蔽掉 ip)。

tcp     3547      0 10.107.17.xxx:34602         yyy.12.230.115:443          CLOSE_WAIT  19819/java
tcp 38 0 10.107.17.xxx:59088 yyy.12.230.115:443 CLOSE_WAIT 19819/java
tcp 38 0 10.107.17.xxx:58028 yyy.12.230.115:443 CLOSE_WAIT 19819/java
tcp 38 0 10.107.17.xxx:51962 yyy.12.230.115:443 CLOSE_WAIT 19819/java
tcp 3563 0 10.107.17.xxx:46962 yyy.12.230.115:443 CLOSE_WAIT 19819/java
tcp 38 0 10.107.17.xxx:34608 yyy.12.230.115:443 CLOSE_WAIT 19819/java
tcp 38 0 10.107.17.xxx:46496 yyy.12.230.115:443 CLOSE_WAIT 19819/java tcp 38 0 10.107.17.xxx:50774 yyy.12.230.115:443 CLOSE_WAIT 19819/java
tcp 38 0 10.107.17.xxx:59904 yyy.12.230.115:443 CLOSE_WAIT 19819/java
tcp 38 0 10.107.17.xxx:40208 yyy.12.230.115:443 CLOSE_WAIT 19819/java
tcp 38 0 10.107.17.xxx:41064 yyy.12.230.115:443 CLOSE_WAIT 19819/java
tcp 38 0 10.107.17.xxx:36994 yyy.12.230.115:443 CLOSE_WAIT 19819/java tcp 3547 0 10.107.17.xxx:45080 yyy.12.230.115:443 CLOSE_WAIT 19819/java
tcp 6235 0 10.107.17.xxx:60966 yyy.12.230.115:443 CLOSE_WAIT 19819/java
tcp 38 0 10.107.17.xxx:56178 yyy.12.230.115:443 CLOSE_WAIT 19819/java
tcp 3547 0 10.107.17.xxx:39922 yyy.12.230.115:443 CLOSE_WAIT 19819/java
tcp 38 0 10.107.17.xxx:43270 yyy.12.230.115:443 CLOSE_WAIT 19819/java
tcp 38 0 10.107.17.xxx:40926 zzz.202.32.242:443 CLOSE_WAIT 19819/java
tcp 38 0 10.107.17.xxx:44472 yyy.12.230.115:443 CLOSE_WAIT 19819/java
tcp 2891 0 10.107.17.xxx:43036 zzz.202.32.241:443 CLOSE_WAIT 19819/java
........
........ tcp 38 0 10.107.17.xxx:33472 yyy.12.230.115:443 CLOSE_WAIT 19819/java
tcp 38 0 10.107.17.xxx:51976 yyy.12.230.115:443 CLOSE_WAIT 19819/java
tcp 38 0 10.107.17.xxx:57788 yyy.12.230.115:443 CLOSE_WAIT 19819/java
tcp 38 0 10.107.17.xxx:35638 yyy.12.230.115:443 CLOSE_WAIT 19819/java
tcp 38 0 10.107.17.xxx:43778 yyy.12.230.115:443 CLOSE_WAIT 19819/java
tcp 38 0 10.107.17.xxx:46418 yyy.12.230.115:443 CLOSE_WAIT 19819/java
tcp 38 0 10.107.17.xxx:49914 yyy.12.230.115:443 CLOSE_WAIT 19819/java
tcp 38 0 10.107.17.xxx:49258 yyy.12.230.115:443 CLOSE_WAIT 19819/java
tcp 38 0 10.107.17.xxx:48718 yyy.12.230.115:443 CLOSE_WAIT 19819/java
tcp 38 0 10.107.17.xxx:51480 yyy.12.230.115:443 CLOSE_WAIT 19819/java
tcp 38 0 10.107.17.xxx:59816 yyy.12.230.115:443 CLOSE_WAIT 19819/java
tcp 38 0 10.107.17.xxx:49266 yyy.12.230.115:443 CLOSE_WAIT 19819/java
tcp 38 0 10.107.17.xxx:50246 yyy.12.230.115:443 CLOSE_WAIT 19819/java
tcp 38 0 10.107.17.xxx:39324 yyy.12.230.115:443 CLOSE_WAIT 19819/java

总之:

yyy.12.230.115
zzz.202.32.241
zzz.202.32.241

这个三个IP是导火索。

Step2 问题分析

这三个IP具体是谁?具体是请求了哪个接口?

暂时无法直接获知!最直接的导火索暂时断了线索。接着从侧面开始查看更多信息,

  • JVM信息

    外部资源、线程 什么的都看了,未发现明显异常

  • 抓包

    要抓包获取更多线索了。对于很久没有碰过TCP层,有些吃力。

得到线索:发现大量的RST

那么是什么操作会导致CLOSE_WAIT呢?什么样的连接导致大量RST呢(可参考RST通常原因)?

Step3 代码分析定位

运维大佬的协助查询,得知这三个IP是图片CDN服务。

至此,可以定位到具体代码逻辑,图片CDN请求可以排查代码。

仔细分析这部分源码后,推测因为服务器 发起 URL请求,请求不存在,导致抛出异常,但是JDK中却没有地方关闭Socket。

javax.imageio.read(URL)

/**
* Returns a <code>BufferedImage</code> as the result of decoding
* a supplied <code>URL</code> with an <code>ImageReader</code>
* chosen automatically from among those currently registered. An
* <code>InputStream</code> is obtained from the <code>URL</code>,
* which is wrapped in an <code>ImageInputStream</code>. If no
* registered <code>ImageReader</code> claims to be able to read
* the resulting stream, <code>null</code> is returned.
*
* <p> The current cache settings from <code>getUseCache</code>and
* <code>getCacheDirectory</code> will be used to control caching in the
* <code>ImageInputStream</code> that is created.
*
* <p> This method does not attempt to locate
* <code>ImageReader</code>s that can read directly from a
* <code>URL</code>; that may be accomplished using
* <code>IIORegistry</code> and <code>ImageReaderSpi</code>.
*
* @param input a <code>URL</code> to read from.
*
* @return a <code>BufferedImage</code> containing the decoded
* contents of the input, or <code>null</code>.
*
* @exception IllegalArgumentException if <code>input</code> is
* <code>null</code>.
* @exception IOException if an error occurs during reading.
*/
public static BufferedImage read(URL input) throws IOException {
if (input == null) {
throw new IllegalArgumentException("input == null!");
} InputStream istream = null;
try {
//此处,建立TCP连接!并且直接获取流,因为流数据不存在,进入cache块,抛出!
istream = input.openStream();
} catch (IOException e) {
throw new IIOException("Can't get input stream from URL!", e);
}
ImageInputStream stream = createImageInputStream(istream);
BufferedImage bi;
try {
bi = read(stream);
if (bi == null) {
stream.close();
}
} finally {
istream.close();
}
return bi;
}

可以看到JDK并没有关闭 ImageIO.read(url) 代码中封装的Socket连接!CDN会请求超时关闭导致服务器处于CLOSE_WAIT?限于网络经验有限,并不能100%确认我的想法。所以模拟下吧。

Step4  复现与模拟

根据系统业务源码,快速模拟:

public static void main(String[] args) throws InterruptedException {

    ExecutorService ex = Executors.newFixedThreadPool(100);
for (int i = 0; i < 5000; i++) {
ex.execute(task());
}
} /**
* @throws IOException
* @throws MalformedURLException
*/
private static Runnable task() { return new Runnable() { @Override
public void run() {
// domain must exists,but file doesnot.
String vivofsUrl = "https://vivobbs.xx.yy.zz/wiwNWYCFW9ieGbWq/20181129/3a2adfde12cd328d81f965088890eeffff.jpg"; File file = null; BufferedImage image = null; try {
file = File.createTempFile("abc", "jpg"); URL url1 = new URL(vivofsUrl);
image = ImageIO.read(url1); } catch (Throwable e) {
e.printStackTrace();
} finally {
if (null != file) {
file.delete();
}
if (null != image) {
image.flush();
image = null;
} }
}
};
}

抓包

TCP查看

问题复现!

Step5 沟通后提报bug

report 给Oracle。

三、Oracle沟通

提单之后,Oracle跟我联系沟通。截取部分邮件内容,仅供参考。

已被采纳

四、疑点与不足

TCP状态机的流转不够熟悉透彻。导致一些问题不能从TCP状态机分析推理,知识的全面精通需要不断提高。

更多内容敬请关注 vivo 互联网技术 微信公众号

注:转载文章请先与微信号:Labs2020 联系。

Oracle JDK7 bug 发现、分析与解决实战的更多相关文章

  1. ORACLE常见错误代码的分析与解决

    (一)在使用ORACLE的过程过,我们会经常遇到一些ORACLE产生的错误,对于初学者而言,这些错误可能有点模糊,而且可能一时不知怎么去处理产生的这些错误,本人就使用中出现比较频繁的错误代码一一做出分 ...

  2. 文《左右c++与java中国的垃圾问题的分析与解决》一bug分析

    文<左右c++与java中国的垃圾问题的分析与解决>一bug分析 DionysosLai(906391500@qq.com) 2014/10/21 在前几篇一博客<关于c++与jav ...

  3. oracle执行update语句时卡住问题分析及解决办法

    转载:http://www.jb51.net/article/125754.htm 这篇文章主要介绍了oracle执行update语句时卡住问题分析及解决办法,涉及记录锁等相关知识,具有一定参考价值, ...

  4. 一个导致MGR数据混乱Bug的分析和修复

    1.背景 MGR是个好东西,因为他从本质上解决了数据不一致的问题.不光是解决了问题,而且出自名门正派(Oracle的MySQL团队),对品质和后续的维护,我们是可以期待的. 但是在调研的过程中,发现有 ...

  5. Oracle超出最大连接数问题及解决

    用过Oracle的应该都熟悉如何查看和设置Oracle数据库的最大连接数.这里就再啰嗦一遍. 查看当前的连接数,可以用select count(*) from v$process;设置的最大连接数(默 ...

  6. Oracle触发bug(cursor: mutex S),造成数据库服务器CPU接近100%

    问题现象: 项目反馈系统反应非常缓慢,数据库服务器CPU接近100%! INSERT INTO GSPAudit1712(ID,TypeID,CategoryID,DateTime,UserID,Us ...

  7. Oracle触发bug(cursor: mutex S),造成数据库服务器CPU接近100%---SQL子游标多版本问题

    问题现象: 项目反馈系统反应非常缓慢,数据库服务器CPU接近100%! INSERT INTO GSPAudit1712(ID,TypeID,CategoryID,DateTime,UserID,Us ...

  8. 改进动态设置query cache导致额外锁开销的问题分析及解决方法-mysql 5.5 以上版本

    改进动态设置query cache导致额外锁开销的问题分析及解决方法 关键字:dynamic switch for query cache,  lock overhead for query cach ...

  9. OGG-00446 分析与解决

    OGG-00446 分析与解决 Table of Contents 1. 00446 1.1. Missing filename opening checkpoint file 1.1.1. 错误信息 ...

  10. informix 数据库锁表分析和解决方法

    一.前言 在联机事务处理(OLTP)的数据库应用系统中,多用户.多任务的并发性是系统最重要的技术指标之一.为了提高并发性,目前大部分RDBMS都采用加锁技术.然而由于现实环境的复杂性,使用加锁技术又不 ...

随机推荐

  1. 聊聊分布式 SQL 数据库Doris(九)

    优化器的作用是优化查询语句的执行效率,它通过评估不同的执行计划并选择最优的执行计划来实现这一目标. CBO: 一种基于成本的优化器,它通过评估不同查询执行计划的成本来选择最优的执行计划.CBO会根据数 ...

  2. HelloJs

    JS 轻量级脚本语言,也是嵌入式语言,是一种对啊想模型语言,简称JS 想要实现复杂的效果,得依靠宿主环境提供API,最常见的是浏览器,还有服务器环境(操作系统) 语言机构+宿主环境提供的API 写js ...

  3. 我的PyCharm为什么在linux下打不开?

    PyCharm打不开解决方案 本文基于Xrdp远程连接桌面环境,Unbutu Linux OS,解决办法仅供参考.应以实际情况为准. 问题产生的原因,Xrdp下GUI绘制依赖于Xrdp的渲染,当Xrd ...

  4. 记一次 .NET 某新能源材料检测系统 崩溃分析

    一:背景 1. 讲故事 上周有位朋友找到我,说他的程序经常会偶发性崩溃,一直没找到原因,自己也抓了dump 也没分析出个所以然,让我帮忙看下怎么回事,那既然有 dump,那就开始分析呗. 二:Wind ...

  5. 使用nginx搭建creates.io镜像(稀疏索引)

    在Rust开发中,经常需要使用Cargo从crates.io下载依赖,而国内几乎没有好用的crates.io镜像,大多都只对crates.io-index和crates.io进行了镜像,而最重要的st ...

  6. 2023年度低代码平台企业TOP50榜单公布—以开源起家的JeecgBoot格外亮眼

    近日,中国科学院主管.科学出版社主办的国家级核心期刊<互联网周刊>联合eNet研究院.德本咨询评选的<2023低代码企业50强>榜单正式公布.这一榜单的公布引起了业内外的广泛关 ...

  7. python tkinter使用(五)

    python tkinter使用(五) 本篇文章讲述tkinter 中treeview的使用 Treeview是一个多列列表框,可以显示层次数据. #!/usr/bin/python3 # -*- c ...

  8. 多维数组、Arrays类、稀疏数组、冒泡排序

    多维数组 多维数组可以看成是数组的数组 比如二维数组就是一个特殊的一堆数组 其中每个元素就是一个数组. 二维数组: int a[][] = new int[2][5]; 解析:二维数组a可以看成一个两 ...

  9. vulnhub - Fawks - writeup

    信息收集 目标开放了21的ftp有匿名登录,除此之外还有常规的80,和连个ssh的端口. 80端口的是一张图片,就是哈利波特的海报图. anonymous空密码登上去有一个文件下载下来是二进制的文件 ...

  10. [VMware]ESXI下硬盘的两种直通方式

    文章来自:https://rmbz.net/archives/vmware-esxi-passthrough 最近再搞ESXI,把原来的"黑群晖"改成ESXI:因为群晖里有数据,为 ...