Browse Source

New configuration parameter for HTTP2 maxFrameSize. (#1253)

Motivation:

In gRPC calls that process large payloads, the default settings of the
HTTP2 maxFrameSize (16384) within swift-nio-http2 results in significant
performance impact (for large payloads this performance impact has been
demonstrated to result in timeouts where RPCs fail to complete within
their assigned deadline).

Allowing programmatic configuration of the HTTP2 maxFrameSize when the
server is built allows the parameter to be optimised for the expected
payload sizes.

Modifications:

Added new gRPC configuration parameter for the HTTP2 parameter
maxFrameSize (which can be configured in the Server.Builder using the
new method `withHTTPMaxFrameSize()`).

Result:

The Server.Builder can be used to configure the HTTP2 maxFrameSize
parameter as:

Server.insecure(group: serverGroup).withHTTPMaxFrameSize(1024 * 1024)...
Graeme Jenkinson 4 years ago
parent
commit
b12b52f552

+ 4 - 0
Sources/GRPC/GRPCServerPipelineConfigurator.swift

@@ -90,6 +90,10 @@ final class GRPCServerPipelineConfigurator: ChannelInboundHandler, RemovableChan
           parameter: .maxHeaderListSize,
           value: HPACKDecoder.defaultMaxHeaderListSize
         ),
+        HTTP2Setting(
+          parameter: .maxFrameSize,
+          value: self.configuration.httpMaxFrameSize
+        ),
       ]
     )
   }

+ 14 - 0
Sources/GRPC/Server.swift

@@ -332,6 +332,14 @@ extension Server {
       }
     }
 
+    /// The HTTP/2 max frame size. Defaults to 16384. Value is clamped between 2^14 and 2^24-1
+    /// octets inclusive (the minimum and maximum allowable values - HTTP/2 RFC 7540 4.2).
+    public var httpMaxFrameSize: Int = 16384 {
+      didSet(httpMaxFrameSize) {
+        self.httpMaxFrameSize = httpMaxFrameSize.clamped(to: 16384 ... 16_777_215)
+      }
+    }
+
     /// The root server logger. Accepted connections will branch from this logger and RPCs on
     /// each connection will use a logger branched from the connections logger. This logger is made
     /// available to service providers via `context`. Defaults to a no-op logger.
@@ -447,3 +455,9 @@ private extension ServerBootstrapProtocol {
     }
   }
 }
+
+extension Comparable {
+  fileprivate func clamped(to range: ClosedRange<Self>) -> Self {
+    return min(max(self, range.lowerBound), range.upperBound)
+  }
+}

+ 8 - 0
Sources/GRPC/ServerBuilder.swift

@@ -168,6 +168,14 @@ extension Server.Builder {
   }
 }
 
+extension Server.Builder {
+  @discardableResult
+  public func withHTTPMaxFrameSize(_ httpMaxFrameSize: Int) -> Self {
+    self.configuration.httpMaxFrameSize = httpMaxFrameSize
+    return self
+  }
+}
+
 extension Server.Builder {
   /// Sets the root server logger. Accepted connections will branch from this logger and RPCs on
   /// each connection will use a logger branched from the connections logger. This logger is made