大量执行OSS PutObject时卡住的问题排查

问题反馈

接到有客户反馈,在批量putobject时,发现上传到一定数量后应用卡住了,同时句柄数增加明显。
客户表示
1.使用10个worker线程进行put操作。
2.每个线程独立使用OssClient。
3.OssClient没有执行shutdown

排查过程

根据客户的描述,写了一个类似的程序来进行复现
开启五个线程,每个线程上传10000次object来测试

代码片段:

public static void main(String args[]) {
RunnableDemo R1 = new RunnableDemo( "Thread-1");
R1.start();
RunnableDemo R2 = new RunnableDemo( "Thread-2");
R2.start();
RunnableDemo R3 = new RunnableDemo( "Thread-3");
R3.start();
RunnableDemo R4 = new RunnableDemo( "Thread-4");
R4.start();
RunnableDemo R5 = new RunnableDemo( "Thread-5");
R5.start();
 }
public void run() {
          System.out.println("Running " +  threadName );
             for(int i = 0; i < 10000; i++) {
                 try {
                    System.out.println("Thread: " + threadName + ", " + i);
                    //上传部分
                    String content = new String();
                    content="12345";
                // 创建上传Object的Metadata
                ObjectMetadata meta = new ObjectMetadata();
                // 设置上传文件长度
                meta.setContentLength(content.length());
                // 设置上传MD5校验
                String md5 = BinaryUtil.toBase64String(BinaryUtil.calculateMd5(content.getBytes()));
                meta.setContentMD5(md5);
                // 设置上传内容类型
                meta.setContentType("text/plain");
                meta.setServerSideEncryption("AES256");
                // 上传文件
                PutObjectRequest putObjectRequest=new PutObjectRequest("ruide", "1.txt", new ByteArrayInputStream(content.getBytes()), meta);
                PutObjectResult por = ossclient.putObject(putObjectRequest);
                System.out.println("requestid:"+por.getRequestId());
                Thread.sleep(0);
                 }catch (Exception e) {
                     System.out.println("Thread " +  threadName + " interrupted.");
                  }
             }
          System.out.println("Thread " +  threadName + " exiting.");
       }

测试5W次上传请求正常。

而在增加callback后出现了问题

PutObjectRequest putObjectRequest=new PutObjectRequest("ruide", "1.txt", new ByteArrayInputStream(content.getBytes()), meta);
Callback callback = new Callback();
callback.setCallbackUrl("http://xx.xxx.xx.xx/Revice.ashx");
callback.setCallbackBody("bucket:${bucket},size:${size}");
putObjectRequest.setCallback(callback);
PutObjectResult por = ossclient.putObject(putObjectRequest);

大量执行OSS PutObject时卡住的问题排查

总结

看到上传确实卡住了。减少到1个线程,依然如此,看来并非是线程导致。
在putobject上传的时候,同时也会看到javaw进程的句柄数不断增加。
通过和OSS后端同学确认,在putobject时,如果没有callback是不需要句柄开销的。但如果
PutObjectResult putObjectResult = ossClient.putObject(putObjectRequest);
即使不显性的read,那么也会产生句柄开销。而目前的句柄数是1000,当句柄数用完也就无法分配新的句柄导致程序卡住。需要增加
putObjectResult.getCallbackResponseBody().close();

添加后测试,测试OK
大量执行OSS PutObject时卡住的问题排查
相关文档说明见https://help.aliyun.com/document_detail/32013.html