Nick Cabatoff created HTTPCORE-483:
--------------------------------------

             Summary: High CPU usage after enabling chunked https responses
                 Key: HTTPCORE-483
                 URL: https://issues.apache.org/jira/browse/HTTPCORE-483
             Project: HttpComponents HttpCore
          Issue Type: Bug
          Components: HttpCore NIO
    Affects Versions: 4.4.6
         Environment: Centos 7
            Reporter: Nick Cabatoff
         Attachments: fg1-initial-unchunked.svg, fg2-initial-chunked.svg, 
fg3-patched-unchunked.svg, fg4-patched-chunked.svg

I wanted persistent connections with keep-alives, and I discovered that the 
reason I wasn't getting them was because my responses didn't have a 
content-length or transfer-encoding: chunked.  So I did body.setChunked( true 
), passed that to response.setEntity(), and it worked.  But I noticed that my 
app was pegged at 100% CPU in top.  I found that the app was fine when it 
started, but after servicing a single HTTPS request with chunked responses, it 
got stuck in this 100% cpu state.  It turns out that the reactor thread was 
busy looping:  despite there being no connections open after servicing that one 
request, in AbstractIOReactor.execute() the selector.select() call continued to 
return non-zero, and processEvent() always found a key that was writable.  
Stepping through the code I noticed that SSLIOSession.updateEventMask() wasn't 
closing the session:

{noformat}
        // Graceful session termination
        if (this.status == CLOSING && this.sslEngine.isOutboundDone()
                && (this.endOfStream || this.sslEngine.isInboundDone())) {
            this.status = CLOSED;
        }
{noformat}

The status was CLOSING and endOfStream was true, but sslEngine.isOutboundDone() 
returned false.  

I looked at httpcore 5 and found that a new check had been added just above:

{noformat}
diff --git 
a/httpcore-nio/src/main/java/org/apache/http/nio/reactor/ssl/SSLIOSession.java 
b/httpcore-nio/src/main/java/org/apache/http/nio/reactor/ssl/SSLIOSession.java
--- 
a/httpcore-nio/src/main/java/org/apache/http/nio/reactor/ssl/SSLIOSession.java
+++ 
b/httpcore-nio/src/main/java/org/apache/http/nio/reactor/ssl/SSLIOSession.java
@@ -371,6 +371,11 @@
 
     private void updateEventMask() {
         // Graceful session termination
+        if (this.status == CLOSING && !this.outEncrypted.hasData()) {
+            this.sslEngine.closeOutbound();
+        }
+
+        // Graceful session termination
         if (this.status == CLOSING && this.sslEngine.isOutboundDone()
                 && (this.endOfStream || this.sslEngine.isInboundDone())) {
             this.status = CLOSED;
{noformat}

I applied this patch to my httpcore 4.4.6 and the problem went away.  Now after 
servicing a request with chunked responses the session gets closed properly and 
the reactor is properly idle. 

There's still another problem outstanding though.  Request processing now 
consumes way more CPU than it used to.  Doing one request per second without 
chunked responses, my app consumes ~20% of one core; with chunked responses 
it's closer to 100%.  

I'm attaching flame graphs (see 
[http://www.brendangregg.com/FlameGraphs/cpuflamegraphs.html]): (1) my starting 
point without chunked respones; (2) with chunked respones; (3) after applying 
the above patch, without chunked responses; (4) after applying patch, with 
chunked responses.  Note the similarity between (2) and (4): in both cases, 
much of the Java code (green) is mostly consumed with epoll calls.




--
This message was sent by Atlassian JIRA
(v6.4.14#64029)

---------------------------------------------------------------------
To unsubscribe, e-mail: [email protected]
For additional commands, e-mail: [email protected]

Reply via email to