Uploaded image for project: 'HttpComponents HttpCore'
  1. HttpComponents HttpCore
  2. HTTPCORE-750

H2ConnPool creates too many conns under high load at initialization time

    XMLWordPrintableJSON

Details

    • Bug
    • Status: Resolved
    • Major
    • Resolution: Fixed
    • 5.2.1
    • 5.2.2
    • HttpCore
    • None
    • Linux / Ubuntu / openjdk version "1.8.0_292"

    Description

      We are using httpcore5 5.2.1 and we observed that at application startup time, httpclient5 could create more than 1 conn per endpoint and in some cases, too many connections caused OOM issue since httpclient5 creates a pair of input/output buffer per conn.

      The regression is introduced by HTTPCORE-750, which made this change:

      https://github.com/apache/httpcomponents-core/commit/14caf43eae407c544161c7f92329e8beb42a3534

       

       if (poolEntry.session != null) {
                      callback.completed(poolEntry.session);
                  } else {
                      poolEntry.requestQueue.add(callback);
                      if (poolEntry.sessionFuture != null && poolEntry.sessionFuture.isDone()) {
                          poolEntry.sessionFuture = null;
                      } 

      When poolEntry.sessionFuture.isDone() is true, the connection is already ready, but the existing logic will abandon it and create a new one, and under high load, this logic could create a lot of conns per endpoint, which consumes a lot of memory.

       

      The proposed fix:

      if (poolEntry.session != null) {
                      callback.completed(poolEntry.session);
                  } else {
                      poolEntry.requestQueue.add(callback);
                      if (poolEntry.sessionFuture != null && poolEntry.sessionFuture.isDone()) {
                          // Check whether we should recreate a new conn or not
                          try {
                              poolEntry.session = poolEntry.sessionFuture.get();
                              while (true) {
                                  final FutureCallback<IOSession> pendingCallback = poolEntry.requestQueue.poll();
                                  if (pendingCallback != null) {
                                      pendingCallback.completed(poolEntry.session);
                                  } else {
                                      break;
                                  }
                              }
                          } catch (final Exception e) {
                              poolEntry.sessionFuture = null;
                          }
                      } 

      I am planning to cut a PR for this.

       

      Attachments

        Issue Links

          Activity

            People

              Unassigned Unassigned
              Gaojie_Liu Gaojie Liu
              Votes:
              0 Vote for this issue
              Watchers:
              7 Start watching this issue

              Dates

                Created:
                Updated:
                Resolved:

                Time Tracking

                  Estimated:
                  Original Estimate - Not Specified
                  Not Specified
                  Remaining:
                  Remaining Estimate - 0h
                  0h
                  Logged:
                  Time Spent - 50m
                  50m