S3client方法使用不当导致线程大量WAIT_CLOSE

2022-09-01 16:27:25 浏览数 (2)

背景

后端服务中有用到OSS的对象存储服务,完成文件上传操作,其中有这样一个场景:

问题定位

  1. 刚开始发现这个问题以为是线程池不够用,通过调整线程池大小,发现服务能支持时间长点,但压测一段时间发现还是会卡死,线程被打满。
  2. 后端又怀疑是不是使用@Asnyc线程嵌套导致的,去掉改成同步,问题依然存在
  3. 然后就排查代码看是不是那块资源未释放(查了好几遍没发现问题,该close的资源都close了)
  4. 后面有浮现了几次后发现,每次上传1000文件,就会有1000个线程 CLOSE_WAIT 就很奇怪,线程死活不关闭,然后就针对OSS相关代码做排查,一行一行把oss相关注释后,发现getFileSize()去掉后,再没有线程 CLOSE_WAIT 情况,就是这家伙惹的祸。。。。定位完毕(而时间已经是凌晨2点多了),欲哭无泪呀。OSS还有这个坑。血的教训。
代码语言:javascript复制
/**
     * 获取文件大小
     *
     * @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状态的连接不会被复用,连接一直不释放进而引发连接池打满的情况

解决方案

代码语言:javascript复制
/**
     * 获取文件大小
     *
     * @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的时候,特别是这种使用到线程池先关的,一定要做好压测,针对用到的每一个方法多看看源码和底层实现,做好资源回收,做好资源回收,做好资源回收!!!

0 人点赞