2017-02-09 44 views
0

Я работаю над функцией LMS для загрузки множества выбранных файлов и папок в zip на лету. Я использовал ZipOutputStream для предотвращения проблем с OutOfMemory.Одновременное использование ZipOutputStream использует 100% CPU

Эта функция работает хорошо, но мы провели стресс-тест, и когда несколько пользователей загружают ZIP-файлы в одно и то же время (скажем, 10 пользователей сбрасывают около 100 МБ каждый), 4 из 4 процессоров достигают 100% нагрузки пока не будут созданы zip-файлы. Наши администраторы системы считают, что это неприемлемо.

Интересно, есть ли какой-то механизм для работы с 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

Не допускать одновременного одновременного прохождения одновременно нескольких процессов. Используйте исполнитель для выполнения 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(); 

(...) 

Это работает на моем тестовом сервере. Но если у кого-нибудь есть какие-либо возражения или какие-либо дополнительные советы, я буду рад услышать.