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