2017-02-09 72 views
0

我正在爲一個LMS功能工作,以便即時下載一堆選定的文件和文件夾。我使用ZipOutputStream來防止OutOfMemory問題。ZipOutputStream的併發使用使用100%的CPU

該功能很好,但我們做了壓力測試,當幾個用戶同時下載zip文件(可以說10個用戶每個壓縮大約100MB),4個CPU中有4個達到100%的負載直到拉鍊被創建。我們的系統管理員認爲這是不可接受的。

我不知道是否有一些機制可以做ZipOutputStream使用較少的系統資源,無論是否需要更多時間才能完成。

我當前的代碼:

protected void compressResource(ZipOutputStream zipOut, String collectionId, String rootFolderName, String resourceId) throws Exception 
{ 
    if (ContentHostingService.isCollection(resourceId)) 
    { 
     try 
     { 
      ContentCollection collection = ContentHostingService.getCollection(resourceId); 
      List<String> children = collection.getMembers(); 
      if(children != null) 
      { 
       for(int i = children.size() - 1; i >= 0; i--) 
       { 
        String child = children.get(i); 
        compressResource(zipOut,collectionId,rootFolderName,child); 
       } 
      } 
     } 
     catch (PermissionException e) 
     { 
      //Ignore 
     } 
    } 
    else 
    { 
     try 
     { 
      ContentResource resource = ContentHostingService.getResource(resourceId); 
      String displayName = isolateName(resource.getId()); 
      displayName = escapeInvalidCharsEntry(displayName); 

      InputStream content = resource.streamContent(); 
      byte data[] = new byte[1024 * 10]; 
      BufferedInputStream bContent = null; 

      try 
      { 
       bContent = new BufferedInputStream(content, data.length); 

       String entryName = (resource.getContainingCollection().getId() + displayName); 
       entryName=entryName.replace(collectionId,rootFolderName+"/"); 
       entryName = escapeInvalidCharsEntry(entryName); 

       ZipEntry resourceEntry = new ZipEntry(entryName); 
       zipOut.putNextEntry(resourceEntry); //A duplicate entry throw ZipException here. 
       int bCount = -1; 
       while ((bCount = bContent.read(data, 0, data.length)) != -1) 
       { 
        zipOut.write(data, 0, bCount); 
       } 

       try 
       { 
        zipOut.closeEntry(); 
       } 
       catch (IOException ioException) 
       { 
        logger.error("IOException when closing zip file entry",ioException); 
       } 
      } 
      catch (IllegalArgumentException iException) 
      { 
       logger.error("IllegalArgumentException while creating zip file",iException); 
      } 
      catch (java.util.zip.ZipException e) 
      { 
       //Duplicate entry: ignore and continue. 
       try 
       { 
        zipOut.closeEntry(); 
       } 
       catch (IOException ioException) 
       { 
        logger.error("IOException when closing zip file entry",ioException); 
       } 
      } 
      finally 
      { 
       if (bContent != null) 
       { 
        try 
        { 
         bContent.close(); 
        } 
        catch (IOException ioException) 
        { 
         logger.error("IOException when closing zip file",ioException); 
        } 
       } 
      } 
     } 
     catch (PermissionException e) 
     { 
      //Ignore 
     } 
    } 
} 

在此先感謝。

+3

您可以使用信號量來限制併發用戶的數量。 – shmosel

+1

不允許同時發生這麼多的併發zip進程。使用執行程序執行ziptask,並且可以調整用於它們的線程數量。 – Kayaman

+0

考慮到您同時控制了讀取和寫入過程,'ZipOutputStream'與您的問題沒有關係,您可以改爲放置'OutputStream',任務不會改變。基本上你的問題類似於[這一個](http://stackoverflow.com/questions/667508/whats-a-good-rate-limiting-algorithm)。 – user3707125

回答

0

我用@shmosel告訴我一個簡單的黑客解決了它。

private static Semaphore mySemaphore= new Semaphore(ServerConfigurationService.getInt("content.zip.download.maxconcurrentdownloads",5),true); 

(...) 

ZipOutputStream zipOut = null; 
    try 
    { 
     mySemaphore.acquire(); 
     ContentCollection collection = ContentHostingService.getCollection(collectionId); 

(...) 

zipOut.flush(); 
zipOut.close(); 
mySemaphore.release(); 

(...) 

這是在我的測試服務器上工作。但如果有人有任何異議或任何額外的建議,我會很樂意聽到。