后端服务中有用到OSS的对象存储服务,完成文件上传操作,其中有这样一个场景:
CLOSE_WAIT
就很奇怪,线程死活不关闭,然后就针对OSS相关代码做排查,一行一行把oss相关注释后,发现getFileSize()去掉后,再没有线程 CLOSE_WAIT 情况,就是这家伙惹的祸。。。。定位完毕(而时间已经是凌晨2点多了),欲哭无泪呀。OSS还有这个坑。血的教训。/**
* 获取文件大小
*
* @param fileURL 文件的url(标准oss地址)
*/
public Long getFileSize(String fileURL) {
// 解析bucketName
String bucketName = getBucketName(fileURL);
// 解析objectName
String objectName = getObjectName(bucketName, fileURL);
return s3client.getObject(bucketName, bucketName).getObjectMetadata().getInstanceLength();
}
问题就处在 s3client.getObject(bucketName, bucketName).getObjectMetadata().getInstanceLength();
这行代码。
oss SDK获取文件大小,应该调用getMetaData方法,代码里调用的getObject().getMetaData,相当于下载文件但是仅获取http头,OSS服务侧任务数据传输已完毕然后就断开连接了,本地获取到了文件流但是没有读取,此时就会导致CLOSE_WAIT,对应的tcp连接recv-q队列有值,send-q队列大小为0,表示应用已获取了数据但是还没来得及获取远程就关闭了连接,该连接不会再进入CLOSED状态,非CLOSED状态的连接不会被复用,连接一直不释放进而引发连接池打满的情况
/**
* 获取文件大小
*
* @param fileURL 文件的url(标准oss地址)
*/
public Long getFileSize(String fileURL) {
// 解析bucketName
String bucketName = getBucketName(fileURL);
// 解析objectName
String objectName = getObjectName(bucketName, fileURL);
return s3client.getObjectMetadata(bucketName, objectName).getInstanceLength();
}
后面再用三方sdk的时候,特别是这种使用到线程池先关的,一定要做好压测,针对用到的每一个方法多看看源码和底层实现,做好资源回收,做好资源回收,做好资源回收!!!