Skip to content

Commit df812ef

Browse files
AXIS2-6103 Correct HTTP/2 initialWindowSize guidance in transport docs
The docs recommended setting the client-side initialWindowSize to 65536 (64KB) to "align" with the server-side FlushingOutputStream 64KB flush interval. These are independent settings: the flush interval controls when serialized bytes enter the HTTP/2 framing layer (server-side, 64KB is correct), while initialWindowSize controls how much response data can be in-flight per stream before the sender pauses for a WINDOW_UPDATE (client-side, 64KB causes ~156 round-trips for a 10MB response). Changes: - Raise default initialWindowSize from 65536 to 2097152 (2MB) in basic config and parameter table - Add callout box explaining flush interval vs flow-control window - Add "Tuning for Different Workloads" section with guidance for many-small, few-large, and mixed traffic patterns - Add "Client-side vs server-side window" subsection explaining why client-side tuning matters more for large-response workloads - Fix Enterprise Big Data config: maxConcurrentStreams 50->4, initialWindowSize 128KB->8MB, maxConnPerRoute 10->32 - Update WildFly guide with correction note on window alignment - Fix simplified example initialWindowSize from 65536 to 2097152
1 parent 5271437 commit df812ef

3 files changed

Lines changed: 104 additions & 15 deletions

File tree

src/site/xdoc/docs/axis2-http2-simplified-example.xml

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -124,8 +124,8 @@
124124
maxConcurrentStreams = 100 # Memory-constrained optimization
125125
maxConnectionsTotal = 50 # Enterprise connection management
126126
maxConnectionsPerRoute = 10 # Route-specific optimization
127-
initialWindowSize = 65536 # 64KB large payload optimization
128-
streamingBufferSize = 65536 # Aligned buffer processing
127+
initialWindowSize = 2097152 # 2MB flow-control window (not related to 64KB flush interval)
128+
streamingBufferSize = 65536 # Server-side flush interval (64KB is correct here)
129129
connectionKeepAliveTime = 300000 # 5-minute balanced timeout
130130
connectionTimeout = 30000 # 30-second connection establishment
131131
responseTimeout = 300000 # 5-minute large payload tolerance

src/site/xdoc/docs/http2-transport-additions.xml

Lines changed: 85 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -110,34 +110,109 @@ within enterprise memory constraints (2GB heap).</p>
110110
&lt;transportSender name="h2" class="org.apache.axis2.transport.h2.impl.httpclient5.H2TransportSender"&gt;
111111
&lt;parameter name="PROTOCOL"&gt;HTTP/2.0&lt;/parameter&gt;
112112
&lt;parameter name="maxConcurrentStreams"&gt;100&lt;/parameter&gt;
113-
&lt;parameter name="initialWindowSize"&gt;65536&lt;/parameter&gt;
113+
&lt;parameter name="initialWindowSize"&gt;2097152&lt;/parameter&gt; &lt;!-- 2MB -- see note below --&gt;
114114
&lt;parameter name="serverPushEnabled"&gt;false&lt;/parameter&gt;
115115
&lt;parameter name="memoryOptimized"&gt;true&lt;/parameter&gt;
116116
&lt;/transportSender&gt;
117117
</pre>
118118

119+
<div style="background-color: #fff8e1; border: 1px solid #f9a825; padding: 15px; margin: 15px 0;">
120+
<h4>Flow-control window vs. streaming flush interval</h4>
121+
<p><code>initialWindowSize</code> and the <code>FlushingOutputStream</code>
122+
64 KB flush interval are <strong>independent settings that should not be
123+
"aligned"</strong> to the same value.</p>
124+
<ul>
125+
<li><strong>FlushingOutputStream flush (server-side, 64 KB)</strong> —
126+
controls when serialized bytes are pushed into the HTTP/2 framing
127+
layer. 64 KB is a good cadence: it gives early time-to-first-byte
128+
and prevents reverse proxy timeouts on long-running serializations.
129+
This value is correct and should not change.</li>
130+
<li><strong>initialWindowSize (client-side, per-stream)</strong> —
131+
controls how much data a stream may have in-flight before the
132+
sender pauses for a WINDOW_UPDATE acknowledgement from the
133+
receiver. A 10 MB response with a 64 KB window requires ~156
134+
WINDOW_UPDATE round-trips; with a 2 MB window it requires ~5.
135+
Under concurrent load, these round-trips serialize on each TCP
136+
connection, adding significant latency.</li>
137+
</ul>
138+
<p>A server flushing at 64 KB works well with a client whose
139+
window is 2 MB — the server sends 64 KB, the framing layer
140+
accumulates up to 2 MB of in-flight data, and the client
141+
acknowledges in bulk. Setting both to 64 KB forces the client to
142+
acknowledge every single flush, converting each 64 KB chunk into a
143+
synchronous round-trip.</p>
144+
</div>
145+
119146
<h3>HTTP/2 Configuration Parameters</h3>
120147

121148
<table border="1">
122149
<tr><th>Parameter</th><th>Description</th><th>Default</th><th>Range</th></tr>
123-
<tr><td>maxConcurrentStreams</td><td>Maximum concurrent streams per connection</td><td>100</td><td>1-1000</td></tr>
124-
<tr><td>initialWindowSize</td><td>Initial flow control window size (bytes)</td><td>65536</td><td>32KB-16MB</td></tr>
150+
<tr><td>maxConcurrentStreams</td><td>Maximum concurrent streams per connection. Lower values (4-8) force the connection pool to spread streams across multiple TCP connections — better for workloads with few concurrent large payloads. Higher values (50-100) maximize multiplexing efficiency for many small concurrent requests.</td><td>100</td><td>1-1000</td></tr>
151+
<tr><td>initialWindowSize</td><td>HTTP/2 per-stream flow-control window (bytes). Determines how much data can be in-flight per stream before the sender waits for a WINDOW_UPDATE. For payloads above 1 MB, use at least 1-2 MB to avoid excessive round-trips. Not related to the server-side FlushingOutputStream 64 KB flush interval.</td><td>2097152</td><td>64KB-16MB</td></tr>
125152
<tr><td>serverPushEnabled</td><td>Enable HTTP/2 server push</td><td>false</td><td>true/false</td></tr>
126153
<tr><td>memoryOptimized</td><td>Enable adaptive memory management</td><td>true</td><td>true/false</td></tr>
127154
<tr><td>largePayloadThreshold</td><td>Threshold for large payload optimization</td><td>52428800</td><td>10MB-500MB</td></tr>
128155
<tr><td>compressionEnabled</td><td>Enable intelligent compression</td><td>true</td><td>true/false</td></tr>
129156
</table>
130157

158+
<h3>Tuning for Different Workloads</h3>
159+
160+
<p>The optimal <code>maxConcurrentStreams</code> and
161+
<code>initialWindowSize</code> depend on your traffic pattern. With
162+
Apache HttpComponents 5.x, the <code>PoolingAsyncClientConnectionManager</code>
163+
only opens a new TCP connection when all existing connections have reached
164+
their <code>maxConcurrentStreams</code> limit. If this value is higher
165+
than your typical concurrency, the pool will multiplex all streams onto a
166+
single connection — which is efficient for many small requests but creates
167+
flow-control contention for concurrent large payloads.</p>
168+
169+
<table border="1">
170+
<tr><th>Workload</th><th>Example</th><th>maxConcurrentStreams</th><th>initialWindowSize</th><th>maxConnPerRoute</th></tr>
171+
<tr><td>Many small concurrent requests</td><td>Microservice mesh, API gateway</td><td>50-100</td><td>2 MB</td><td>10</td></tr>
172+
<tr><td>Few large concurrent payloads</td><td>Batch processing, ETL, report generation</td><td>4-8</td><td>8 MB</td><td>16-32</td></tr>
173+
<tr><td>Mixed traffic</td><td>General-purpose service client</td><td>8-16</td><td>2 MB</td><td>16</td></tr>
174+
</table>
175+
176+
<h4>Client-side vs. server-side window: where tuning matters</h4>
177+
178+
<p>HTTP/2 flow control is bidirectional — both client and server
179+
advertise an <code>initialWindowSize</code>. For typical Axis2
180+
deployments where the server produces large JSON responses and the
181+
client sends smaller requests (query parameters, filter criteria),
182+
the <strong>client-side window is the critical tuning point</strong>.
183+
It governs how much response data the server can push before pausing
184+
for a WINDOW_UPDATE from the client. A 64 KB client window on a
185+
10 MB response means ~156 pause-and-acknowledge cycles.</p>
186+
187+
<p>The server's inbound window (configured in the application server —
188+
e.g., WildFly's <code>http2-initial-window-size</code>, Tomcat's
189+
<code>http2InitialWindowSize</code>) controls how much
190+
<em>request</em> data the server allows in-flight. Since requests
191+
are typically small relative to responses, the server-side default
192+
(64 KB per the HTTP/2 spec) is usually adequate. Focus tuning effort
193+
on the <code>H2TransportSender</code> client-side
194+
<code>initialWindowSize</code> shown above.</p>
195+
196+
<p>If a single client consumes both small and large payload endpoints on
197+
different hosts, consider configuring separate
198+
<code>CloseableHttpAsyncClient</code> instances with per-workload tuning.
199+
The connection pool's <code>maxConnPerRoute</code> already isolates
200+
traffic by host, but <code>maxConcurrentStreams</code> and
201+
<code>initialWindowSize</code> apply to the entire client.</p>
202+
131203
<h3>Enterprise Big Data Configuration</h3>
132204

133-
<p>For enterprise applications processing large JSON datasets (50MB+), use the following optimized configuration:</p>
205+
<p>For enterprise applications processing large JSON datasets (50MB+), use the following optimized configuration.
206+
Note the lower <code>maxConcurrentStreams</code> (forces the pool to open multiple TCP connections under concurrent
207+
load) and larger <code>initialWindowSize</code> (eliminates per-stream flow-control round-trips):</p>
134208
<pre>
135209
&lt;transportSender name="h2" class="org.apache.axis2.transport.h2.impl.httpclient5.H2TransportSender"&gt;
136210
&lt;parameter name="PROTOCOL"&gt;HTTP/2.0&lt;/parameter&gt;
137211

138-
&lt;!-- Stream Management --&gt;
139-
&lt;parameter name="maxConcurrentStreams"&gt;50&lt;/parameter&gt;
140-
&lt;parameter name="initialWindowSize"&gt;131072&lt;/parameter&gt;
212+
&lt;!-- Stream Management: low stream count forces connection pooling
213+
instead of multiplexing all large payloads onto one TCP connection --&gt;
214+
&lt;parameter name="maxConcurrentStreams"&gt;4&lt;/parameter&gt;
215+
&lt;parameter name="initialWindowSize"&gt;8388608&lt;/parameter&gt; &lt;!-- 8MB -- a 50MB payload completes in ~6 window updates --&gt;
141216
&lt;parameter name="maxFrameSize"&gt;32768&lt;/parameter&gt;
142217

143218
&lt;!-- Large Payload Optimization --&gt;
@@ -150,9 +225,9 @@ within enterprise memory constraints (2GB heap).</p>
150225
&lt;parameter name="adaptiveFlowControl"&gt;true&lt;/parameter&gt;
151226
&lt;parameter name="bufferPooling"&gt;true&lt;/parameter&gt;
152227

153-
&lt;!-- Connection Management --&gt;
154-
&lt;parameter name="maxConnTotal"&gt;50&lt;/parameter&gt;
155-
&lt;parameter name="maxConnPerRoute"&gt;10&lt;/parameter&gt;
228+
&lt;!-- Connection Management: sized for concurrent large-payload fan-out --&gt;
229+
&lt;parameter name="maxConnTotal"&gt;64&lt;/parameter&gt;
230+
&lt;parameter name="maxConnPerRoute"&gt;32&lt;/parameter&gt;
156231

157232
&lt;!-- Timeouts for Large Payloads --&gt;
158233
&lt;parameter name="connectionTimeout"&gt;30000&lt;/parameter&gt;

src/site/xdoc/docs/wildfly-http2-integration-guide.xml

Lines changed: 17 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -48,15 +48,29 @@ WildFly 39 is compatible with the same configuration.</p>
4848
<h2>WildFly Server-Level HTTP/2 Configuration (RECOMMENDED)</h2>
4949

5050
<div style="background-color: #e8f5e8; border: 1px solid #4CAF50; padding: 10px; margin: 10px 0;">
51-
<strong>🎯 Key Optimizations:</strong>
51+
<strong>Key Optimizations:</strong>
5252
<ul>
53-
<li><strong>64KB Buffer Alignment</strong> - Consistent across all layers (WildFly + Enhanced Moshi/GSON H2)</li>
54-
<li><strong>128KB HTTP/2 Windows</strong> - Optimized for 50MB+ JSON payload processing</li>
53+
<li><strong>64KB Buffer/Flush Alignment</strong> - WildFly byte-buffer-pool and FlushingOutputStream flush interval are aligned at 64KB. This is a server-side serialization setting and is correct.</li>
54+
<li><strong>HTTP/2 Flow-Control Windows</strong> - Sized for payload, not aligned to flush interval. See
55+
<a href="http2-transport-additions.html#H2TransportSender">HTTP/2 Transport configuration</a>
56+
for guidance on <code>initialWindowSize</code> tuning.</li>
5557
<li><strong>Minimal Protocol Overhead</strong> - Single-layer HTTP/2 processing architecture</li>
5658
<li><strong>Enhanced Monitoring</strong> - Built-in performance tracking and access logging</li>
5759
</ul>
5860
</div>
5961

62+
<div style="background-color: #fff8e1; border: 1px solid #f9a825; padding: 10px; margin: 10px 0;">
63+
<strong>Important:</strong> The Axis2 transport's
64+
<code>initialWindowSize</code> should <strong>not</strong> be set to
65+
64KB to match the WildFly buffer pool or FlushingOutputStream flush
66+
interval. The flow-control window and the server-side flush interval are
67+
independent — a 64KB window forces ~156 WINDOW_UPDATE round-trips for a
68+
10MB response. Use at least 2MB for general traffic or 8MB for
69+
large-payload workloads. See
70+
<a href="http2-transport-additions.html#H2TransportSender">HTTP/2 Transport
71+
— Tuning for Different Workloads</a>.
72+
</div>
73+
6074
<pre>
6175
&lt;subsystem xmlns="urn:jboss:domain:undertow:14.0"
6276
default-virtual-host="default-host"

0 commit comments

Comments
 (0)