0

我正在为 LMS 开发一项功能,以即时以 zip 格式下载一堆选定的文件和文件夹。我使用 ZipOutputStream 来防止 OutOfMemory 问题。

该功能运行良好,但我们进行了压力测试,当多个用户同时下载 zip 时(假设 10 个用户每个压缩 100 MB),4 个 CPU 中有 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
        }
    }
}

提前致谢。

4

1 回答 1

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

(...)

这在我的测试服务器上工作。但如果有人有任何异议或任何额外建议,我将很高兴听到。

于 2017-02-14T09:35:13.587 回答