2017-02-09 6 views
0

Ich arbeite in einer Funktion für ein LMS, um eine Reihe von ausgewählten Dateien und Ordnern in einem Zip on-the-fly herunterzuladen. Ich habe ZipOutputStream verwendet, um OutOfMemory-Probleme zu vermeiden.Die gleichzeitige Verwendung von ZipOutputStream verwendet 100% der CPU

Das Feature funktioniert schön, aber wir haben einen Stresstest durchgeführt und wenn mehrere Benutzer Reißverschlüsse zur gleichen Zeit das Herunterladen (sagen wir mal 10 Nutzern über 100 MB jeder zippen), 4 von 4 CPUs 100% Auslastung erreichen bis die Reißverschlüsse erstellt sind. Unsere Systemadministratoren denken, dass dies nicht akzeptabel ist.

Ich frage mich, ob es einen Mechanismus gibt, mit ZipOutputStream weniger Systemressourcen zu verbrauchen, egal, ob es mehr Zeit braucht, um fertig zu werden.

Mein aktueller Code:

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 
     } 
    } 
} 

Vielen Dank im Voraus.

+3

Sie können einen Semaphor verwenden, um die Anzahl gleichzeitiger Benutzer zu beschränken. – shmosel

+1

Lassen Sie nicht zu viele gleichzeitige ZIP-Prozesse gleichzeitig auftreten. Verwenden Sie einen Executor, um die Ziptask auszuführen, und Sie können die Anzahl der für sie verwendeten Threads anpassen. – Kayaman

+0

In Anbetracht der Tatsache, dass Sie Lese- und Schreibprozesse steuern, hat 'ZipOutputStream' keine Beziehung zu Ihrem Problem, stattdessen können Sie' OutputStream' platzieren und die Aufgabe wird sich nicht ändern. Im Grunde ist Ihre Frage ähnlich wie diese [http://stackoverflow.com/questions/667508/whats-a-good-rate-limiting-algorithmus]. – user3707125

Antwort

0

Ich habe es mit einem einfachen Hack von @shmosel erzählt gelöst.

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(); 

(...) 

Dies funktioniert in meinem Testserver. Aber wenn jemand irgendwelche Einwände oder zusätzliche Ratschläge hat, werde ich mich freuen zu hören.

Verwandte Themen