You are viewing a plain text version of this content. The canonical link for it is here.
Posted to dev@phoenix.apache.org by "Alok Singh (JIRA)" <ji...@apache.org> on 2016/02/16 00:42:18 UTC

[jira] [Updated] (PHOENIX-2685) SpoolingResultIterator opening a large number of files, hitting process max open file limit

     [ https://issues.apache.org/jira/browse/PHOENIX-2685?page=com.atlassian.jira.plugin.system.issuetabpanels:all-tabpanel ]

Alok Singh updated PHOENIX-2685:
--------------------------------
    Attachment: memory_manager_aware_outputstream.patch

> SpoolingResultIterator opening a large number of files, hitting process max open file limit
> -------------------------------------------------------------------------------------------
>
>                 Key: PHOENIX-2685
>                 URL: https://issues.apache.org/jira/browse/PHOENIX-2685
>             Project: Phoenix
>          Issue Type: Bug
>    Affects Versions: 4.5.1, 4.6.0, 4.7.0
>            Reporter: Alok Singh
>              Labels: patch
>         Attachments: memory_manager_aware_outputstream.patch
>
>
> During one of out load tests, in which we execute 5-10 concurrent requests over a few hours, we have found that eventually the jvm process runs out of file handles due to 1000s of tmp files (/tmp/ResultSpoolerxxxxxx.bin). 
> Upon further investigation, it looks like that under high concurrent load, with the default 'phoenix.query.spoolThresholdBytes' value, SpoolingResultIterator will almost always run into this issue.
> {code}
> final MemoryChunk chunk = mm.allocate(0, thresholdBytes);
> long waitTime = System.currentTimeMillis() - startTime;
> GLOBAL_MEMORY_WAIT_TIME.update(waitTime);
> memoryMetrics.getMemoryWaitTimeMetric().change(waitTime);
> DeferredFileOutputStream spoolTo = null;
> try {
>     // Can't be bigger than int, since it's the max of the above allocation
>     int size = (int)chunk.getSize();
>     spoolTo = new DeferredFileOutputStream(size, "ResultSpooler",".bin", new File(spoolDirectory)) {
>         @Override
>         protected void thresholdReached() throws IOException {
>             try {
>                 super.thresholdReached();
>             } finally {
>                 chunk.close();
>             }
>         }
>     };
> {code}
> The memory chunks successfully created here will not be released until a GC cycle invokes the MemoryChunk finalizer. Since the default behavoir is to allocate the full "spoolThresholdBytes" and only resize the chunk after iterating over the scan results, if there is sufficient concurrent load the GlobablMemoryManager will run out of freememory and cause the SpoolingIterators to always spool to disk.
> {code}
> int size = (int)chunk.getSize();
> spoolTo = new DeferredFileOutputStream(size, "ResultSpooler",".bin", new File(spoolDirectory))
> {code}
> The "size" ends up being 0, causing the "thresholdReached()" method to be invoked when an attempt is made to write to the SpoolingIterator. 
> One way to mitigate this is to reduce the size of "phoenix.query.spoolThresholdBytes". We ended up reducing it to 10Mb. 
> Another would be to use a "Memory Usage" aware outputstream that has a reference to the memory manager and switches to a spooling only when allocation request to the memory manager fail. A patch with a simple MemoryManager based outputstream/SpoolingResultIterator is attached.  



--
This message was sent by Atlassian JIRA
(v6.3.4#6332)