HTTP/2 is not just a faster HTTP/1.1; it’s a fundamentally different protocol that breaks many assumptions about how web traffic works, and Gatling’s support for it means you can finally load test these modern services accurately.
Let’s see Gatling put HTTP/2 through its paces. Imagine a simple scenario where we’re hitting an Nginx server configured for HTTP/2. We’ll use a basic Gatling simulation:
import io.gatling.core.Predef._
import io.gatling.http.Predef._
class Http2Simulation extends Simulation {
val httpProtocol = http
.baseUrl("https://localhost:8443") // Assuming Nginx is running on localhost:8443 with HTTP/2 enabled
.doNotTrackHeader("1")
.inferHtmlResources()
.acceptHeader(HttpHeaderNames.Accept, "text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8")
.acceptEncodingHeader(HttpHeaderNames.AcceptEncoding, "gzip, deflate")
.acceptLanguageHeader(HttpHeaderNames.AcceptLanguage, "en-US,en;q=0.5")
.userAgentHeader(HttpHeaderNames.UserAgent, "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/91.0.4472.114 Safari/537.36")
// Explicitly enable HTTP/2
val httpProtocolWithHttp2 = httpProtocol.protocols(http2)
val scn = scenario("HTTP/2 Test")
.exec(http("Homepage")
.get("/")
.check(status.is(200)))
setUp(scn.inject(atOnceUsers(10))).protocols(httpProtocolWithHttp2)
}
Here’s what’s happening under the hood:
httpProtocol.protocols(http2): This is the magic switch. By default, Gatling will try to negotiate HTTP/1.1. Adding.protocols(http2)tells Gatling to attempt an HTTP/2 upgrade during the connection handshake. If the server supports it, the connection will be upgraded.- Server Push: HTTP/2 allows servers to "push" resources to the client before the client requests them. This is a key performance advantage. Gatling’s
inferHtmlResources()combined with HTTP/2 support will automatically detect and record these pushed resources. You’ll see them listed in your Gatling reports as separate requests, even though your simulation script didn’t explicitly ask for them. - Multiplexing: Instead of opening multiple TCP connections for parallel requests like HTTP/1.1, HTTP/2 uses a single TCP connection to interleave multiple requests and responses. Gatling’s HTTP/2 implementation handles this multiplexing automatically. You don’t need to configure connection pools or anything similar; Gatling manages the streams over the single connection.
- Header Compression (HPACK): HTTP/2 uses HPACK to compress headers, significantly reducing overhead. Gatling’s HTTP/2 support includes the HPACK encoder and decoder, ensuring accurate simulation of this aspect.
The most surprising true thing about HTTP/2 is that its primary benefit isn’t just raw speed, but the reduction of latency by eliminating head-of-line blocking at the application layer and enabling efficient resource loading.
The full mental model for Gatling’s HTTP/2 support involves understanding how it leverages Netty’s HTTP/2 capabilities. Gatling acts as a client, establishing a TCP connection. It then performs a TLS handshake (if using HTTPS) and during the Application-Layer Protocol Negotiation (ALPN) extension of the TLS handshake, it advertises h2 (HTTP/2) as a supported protocol. If the server also advertises h2, the connection is established as HTTP/2. Gatling then uses Netty’s Http2FrameCodec to manage the framing, multiplexing, and flow control required by the HTTP/2 protocol. Your Simulation script defines the logical requests, and Gatling’s HTTP/2 protocol implementation translates these into the appropriate HTTP/2 frames (HEADERS, DATA, PUSH_PROMISE, etc.) over the single, multiplexed connection.
When you run this simulation, you’ll see requests for your main page, and potentially other resources like CSS or JavaScript files that the server might have "pushed" proactively, all happening over a single connection. The Gatling reports will clearly distinguish these.
The one thing most people don’t know is that even with HTTP/2, the underlying TCP connection can still suffer from head-of-line blocking. If a TCP packet is lost, all streams multiplexed over that connection must wait for that packet to be retransmitted, even if the lost packet only contained data for a completely unrelated stream. This is why protocols like QUIC (which forms the basis of HTTP/3) were developed to address this remaining bottleneck.
The next step is to explore how Gatling handles the complexities of HTTP/3, which leverages QUIC.