Одновременное использование ZipOutputStream использует 100% CPU

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

Эта функция работает хорошо, но мы провели стресс-тест, и когда несколько пользователей загружают архивы одновременно (скажем, 10 пользователей архивируют около 100 МБ каждый), 4 из 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
        }
    }
}

Заранее спасибо.

1 ответ

Я решил это простым взломом, рассказанным @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();

(...)

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

Другие вопросы по тегам