• Skip to secondary menu
  • Skip to main content
  • Skip to primary sidebar
  • Home
  • Projects
  • Products
  • Themes
  • Tools
  • Request for Quote

Vengala Vinay

Having 12+ Years of Experience in Software Development

  • Home
  • WordPress
  • PHP
    • Codeigniter
  • Django
  • Magento
  • Selenium
  • Server
Home » Rust Axum vs. Go Fiber: HTTP/2 Multiplexing and Peak Connection Benchmarking

Rust Axum vs. Go Fiber: HTTP/2 Multiplexing and Peak Connection Benchmarking

HTTP/2 Multiplexing: A Foundational Performance Differentiator

When evaluating high-performance web frameworks, understanding their underlying network protocol capabilities is paramount. HTTP/2, with its multiplexing, header compression, and server push features, offers significant advantages over HTTP/1.1. For frameworks like Rust’s Axum and Go’s Fiber, the implementation and efficiency of HTTP/2 support, particularly multiplexing, directly impact their ability to handle concurrent requests and achieve peak connection throughput. Multiplexing allows multiple requests and responses to be interleaved over a single TCP connection, drastically reducing latency and improving resource utilization.

Benchmarking Methodology: Tools and Setup

To rigorously compare Axum and Fiber, we’ll employ a standardized benchmarking approach. This involves setting up identical test environments and utilizing robust load testing tools. Our primary tool will be wrk, a modern HTTP benchmarking tool capable of generating high concurrency and supporting HTTP/2. We will also use ab (ApacheBench) for baseline comparisons and k6 for more advanced scenario scripting.

The test environment will consist of:

  • A dedicated, isolated server instance (e.g., AWS EC2 m5.large or equivalent) with sufficient CPU and RAM.
  • A clean operating system installation (e.g., Ubuntu 22.04 LTS).
  • The benchmarking client (wrk, k6) running on a separate, powerful machine to avoid client-side bottlenecks.
  • Both Axum and Fiber applications compiled in release mode.
  • TLS enabled for both frameworks to simulate realistic production traffic, as HTTP/2 is typically negotiated over TLS (h2 or h2c for cleartext, though less common in production).

Axum Implementation: HTTP/2 with Tokio and Hyper

Axum, built on top of Tokio and Hyper, inherits robust HTTP/2 support. Hyper is a low-level HTTP implementation that provides excellent performance and flexibility. For Axum to serve HTTP/2, we need to configure the underlying Tokio runtime and Hyper server to use TLS and enable HTTP/2. This typically involves generating or obtaining SSL certificates and configuring the listener.

Axum Server Setup (HTTP/2 with TLS)

Here’s a minimal Axum application demonstrating HTTP/2 setup. We’ll use self-signed certificates for this example. In production, you would use certificates from a trusted Certificate Authority.

Generating Self-Signed Certificates

First, generate a self-signed certificate and private key:

openssl req -x509 -newkey rsa:4096 -nodes -keyout key.pem -out cert.pem -days 365 -subj '/CN=localhost'

Axum Application Code

The Rust code will load these certificates and configure the Axum service.

use axum::{routing::get, Router};
use tokio_rustls::{
    rustls::{Certificate, PrivateKey, ServerConfig},
    TlsAcceptor,
};
use std::sync::Arc;
use std::fs;
use std::io;
use std::net::SocketAddr;

async fn root() -> &'static str {
    "Hello, Axum!"
}

#[tokio::main]
async fn main() -> io::Result<()> {
    // Load certificate and private key
    let cert_file = fs::File::open("cert.pem")?;
    let mut reader = io::BufReader::new(cert_file);
    let certs = rustls_pemfile::certs(&mut reader)?
        .into_iter()
        .map(rustls::Certificate)
        .collect();

    let key_file = fs::File::open("key.pem")?;
    let mut reader = io::BufReader::new(key_file);
    let keys = rustls_pemfile::pkcs8_private_keys(&mut reader)?
        .into_iter()
        .map(rustls::PrivateKey)
        .collect::>();

    if keys.is_empty() {
        panic!("No private keys found");
    }
    let key = keys[0].clone();

    // Build the TLS configuration
    let tls_config = ServerConfig::builder()
        .with_safe_defaults()
        .with_no_client_auth()
        .with_single_cert(certs, key)
        .map_err(|e| io::Error::new(io::ErrorKind::Other, e))?;

    let tls_acceptor = TlsAcceptor::from(Arc::new(tls_config));

    // Build the Axum router
    let app = Router::new().route("/", get(root));

    // Create a TCP listener
    let listener = tokio::net::TcpListener::bind("0.0.0.0:3000").await?;

    // Create the Tokio runtime and run the server
    let server_handle = tokio::spawn(async move {
        loop {
            let (socket, _) = listener.accept().await.unwrap();
            let tls_acceptor = tls_acceptor.clone();
            let app = app.clone(); // Clone the app for each connection

            tokio::spawn(async move {
                if let Ok(stream) = tls_acceptor.accept_with(socket).await {
                    // Hyper server configuration for HTTP/2
                    let mut builder = hyper::server::conn::Http::new();
                    builder.http2_only(true); // Explicitly enable HTTP/2

                    let service = hyper::service::service_fn(move |req| {
                        // Axum's service implementation
                        app.call(req)
                    });

                    if let Err(err) = builder.serve_connection(stream, service).await {
                        eprintln!("Error serving connection: {:?}", err);
                    }
                }
            });
        }
    });

    server_handle.await?;
    Ok(())
}

Note the explicit builder.http2_only(true); which ensures Hyper attempts to negotiate HTTP/2. Tokio’s TLS integration with Hyper handles the ALPN negotiation for HTTP/2.

Fiber Implementation: HTTP/2 with Fasthttp

Go Fiber is a web framework built on top of Fasthttp, known for its exceptional performance. Fasthttp itself is highly optimized for speed and low-level network operations. While Fasthttp primarily focuses on HTTP/1.1 performance, it has experimental support for HTTP/2. Enabling HTTP/2 in Fiber requires careful configuration of the underlying Fasthttp server, particularly regarding TLS and the HTTP/2 protocol.

Fiber Server Setup (HTTP/2 with TLS)

Similar to Axum, we’ll use self-signed certificates. Fiber’s configuration for HTTP/2 is more direct via its server options.

Generating Self-Signed Certificates (Go)

Use the same openssl command as for Axum:

openssl req -x509 -newkey rsa:4096 -nodes -keyout key.pem -out cert.pem -days 365 -subj '/CN=localhost'

Fiber Application Code

The Go code will configure Fiber to use TLS and enable HTTP/2.

package main

import (
	"log"

	"github.com/gofiber/fiber/v2"
	"github.com/gofiber/fiber/v2/middleware/logger"
)

func main() {
	// Create a new Fiber app
	app := fiber.New(fiber.Config{
		DisableStartupMessage: true,
		// Enable HTTP/2 by setting TLSConfig
		// Fasthttp automatically enables HTTP/2 when TLSConfig is provided
		// and the client negotiates it.
		TLSConfig: &tls.Config{
			Certificates: []*tls.Certificate{
				// Load certificate and key
				&tls.Certificate{
					Certificate: [][]byte{certPEM}, // Replace with actual cert PEM bytes
					PrivateKey:  privateKeyPEM,    // Replace with actual private key PEM bytes
				},
			},
			// Optional: Set NextProtos for explicit ALPN negotiation
			NextProtos: []string{"h2", "http/1.1"},
		},
	})

	// Middleware
	app.Use(logger.New())

	// Routes
	app.Get("/", func(c *fiber.Ctx) error {
		return c.SendString("Hello, Fiber!")
	})

	// Start server on port 3000 with TLS
	log.Fatal(app.ListenTLS(":3000", "cert.pem", "key.pem"))
}

// Placeholder for certificate and key bytes. In a real app, load from files.
var certPEM []byte
var privateKeyPEM []byte

func init() {
	// Load certificate and private key from files
	certPEMBytes, err := ioutil.ReadFile("cert.pem")
	if err != nil {
		log.Fatalf("Failed to read certificate file: %v", err)
	}
	privateKeyPEMBytes, err := ioutil.ReadFile("key.pem")
	if err != nil {
		log.Fatalf("Failed to read private key file: %v", err)
	}
	certPEM = certPEMBytes
	privateKeyPEM = privateKeyPEMBytes
}

Fiber’s ListenTLS function, when provided with certificate and key files, implicitly configures Fasthttp to support HTTP/2 if the client negotiates it via ALPN. The NextProtos field in tls.Config is crucial for explicit ALPN negotiation.

Benchmarking with wrk

We will use wrk to simulate concurrent users and measure the throughput and latency of both applications. The key is to enable HTTP/2 support in wrk.

wrk Setup for HTTP/2

Ensure you have a recent version of wrk compiled with HTTP/2 support. You can typically enable this during compilation or by using a pre-built binary that includes it. The command-line flag --http2 is used.

Benchmarking Axum

Run the Axum server, then execute the wrk command:

# On the server where Axum is running
cargo run --release

# On the client machine
wrk -t8 -c1000 --http2 -d30s --latency https://your_server_ip:3000/

Explanation of flags:

  • -t8: Use 8 threads.
  • -c1000: Maintain 1000 concurrent connections.
  • --http2: Enable HTTP/2 protocol.
  • -d30s: Run the benchmark for 30 seconds.
  • --latency: Record latency statistics.
  • https://your_server_ip:3000/: The target URL.

Benchmarking Fiber

Run the Fiber server, then execute the wrk command:

# On the server where Fiber is running
go run main.go

# On the client machine
wrk -t8 -c1000 --http2 -d30s --latency https://your_server_ip:3000/

The wrk command remains identical, allowing for a direct comparison.

Interpreting Results: Multiplexing and Throughput

When analyzing the wrk output, pay close attention to:

  • Requests/sec: Higher is better, indicating more requests processed.
  • Latency (Avg, Min, Max, 99%): Lower latency is crucial for user experience. HTTP/2’s multiplexing should ideally reduce tail latencies under high load.
  • Transfer/sec: Indicates data throughput.
  • Socket errors: Any errors suggest connection instability or resource exhaustion.

Expected Observations Regarding HTTP/2 Multiplexing:

  • Under high concurrency (e.g., 1000+ connections), both frameworks should demonstrate significantly better performance with HTTP/2 compared to HTTP/1.1. This is due to multiplexing reducing the overhead of establishing multiple TCP connections and the head-of-line blocking inherent in HTTP/1.1.
  • The framework that more efficiently manages its internal event loops and I/O operations will likely show higher requests/sec and lower latency. Rust’s asynchronous model with Tokio and Hyper is generally very performant, while Go’s goroutines and efficient scheduler also provide excellent concurrency.
  • Differences might emerge in how gracefully each framework handles connection churn, error conditions, and resource contention at extreme loads.

Advanced Benchmarking: Connection Limits and Resource Saturation

To truly stress-test the HTTP/2 implementation and multiplexing capabilities, we need to push beyond typical load. This involves increasing the number of concurrent connections significantly and observing how each framework behaves as it approaches its resource limits (CPU, memory, file descriptors).

Pushing Connection Limits with wrk

Gradually increase the -c (connections) parameter in wrk, starting from 1000 and incrementing by 500 or 1000. Monitor server-side resource utilization (CPU, memory, network I/O, open file descriptors) using tools like htop, vmstat, and lsof.

# Example: Pushing connections for Axum
wrk -t16 -c5000 --http2 -d60s --latency https://your_server_ip:3000/

# Example: Pushing connections for Fiber
wrk -t16 -c5000 --http2 -d60s --latency https://your_server_ip:3000/

Server-Side Monitoring and Tuning

On the server, use the following to monitor:

# Monitor CPU and Memory
htop

# Monitor network and I/O
vmstat 1

# Monitor open file descriptors
sudo lsof -p <PID_of_your_app> | wc -l
sudo sysctl fs.file-max
sudo sysctl fs.nr_open

If you encounter Too many open files errors, you may need to increase the system’s file descriptor limits. This is a common bottleneck for high-concurrency servers.

# Temporarily increase limits (for current session)
ulimit -n 65536

# Permanently increase limits (edit /etc/security/limits.conf)
# * soft nofile 65536
# * hard nofile 65536

# Apply system-wide limits (edit /etc/sysctl.conf)
# fs.file-max = 2097152
# fs.nr_open = 1048576

Performance Analysis: Axum vs. Fiber HTTP/2

The results from these benchmarks will highlight key differences:

  • Raw Throughput (Requests/sec): Which framework sustains higher request rates at peak load? This often comes down to the efficiency of the underlying HTTP implementation and the runtime’s concurrency model.
  • Latency Under Load: How does latency (especially tail latency) degrade as connection counts increase? Effective multiplexing should minimize this degradation.
  • Resource Utilization (CPU/Memory): Which framework is more memory-efficient per connection? Which utilizes CPU more effectively?
  • Stability and Error Handling: At extreme loads, which framework is more resilient to errors and connection failures?

Rust Axum (Tokio/Hyper): Generally offers very fine-grained control and predictable performance due to its explicit async model and mature ecosystem. Hyper is a highly optimized HTTP library. Performance can be exceptional, but requires careful management of async tasks and resources.

Go Fiber (Fasthttp): Leverages Go’s efficient goroutine scheduler and Fasthttp’s low-level optimizations. Often simpler to achieve high concurrency with less explicit code. Performance is typically excellent, though Fasthttp’s HTTP/2 support might be less mature or performant than Hyper’s in certain edge cases.

Conclusion: Choosing the Right Tool for HTTP/2 Demands

Both Axum and Fiber are capable of high-performance HTTP/2 serving. The choice between them for demanding, high-concurrency applications hinges on specific workload characteristics, team expertise, and the nuances revealed by rigorous benchmarking. Axum, with its foundation in Tokio and Hyper, offers a robust and highly tunable HTTP/2 implementation. Fiber, leveraging Fasthttp and Go’s concurrency primitives, provides a compelling, often simpler, path to high throughput. For scenarios where absolute maximum performance and fine-grained control over network I/O are critical, Axum might have an edge. For rapid development and excellent out-of-the-box performance, Fiber is a strong contender. Always validate with your specific use case and load patterns.

Primary Sidebar

A little about the Author

Having 12+ Years of Experience in Software Development, Vinay is a principal software architect, senior systems engineer, and elite technical consultant. He specializes in bespoke PHP/WordPress development, high-performance Magento 2 & Shopify architectures, custom plugin/theme development from scratch, and legacy code modernization (including VB6, VB.NET, PyQt, and Crystal Reports). Known for solving complex database bottlenecks, speed optimization (Core Web Vitals), and advanced security code auditing, Vinay engineers production-ready systems designed to scale under heavy concurrent load conditions.



Chat on WhatsApp

Recent Posts

  • Go Goroutines vs. Node.js Event Loop: Scaling I/O-Bound Microservices Under High Load
  • Elixir Phoenix vs. Go Gin: Concurrency Models and Fault Tolerance Under Peak Request Volume
  • Python Celery vs. Go Channels: Distributed Task Queue Overhead and Memory Reliability
  • Scala Pekko vs. Go Goroutines: Actor Model vs. CSP for Event-Driven Reactive Systems
  • Java Loom Virtual Threads vs. Go Goroutines: Under-the-Hood Scheduler and Thread Overhead Comparison

Categories

  • apache (1)
  • Business & Monetization (390)
  • Centos (4)
  • Comparisons & Decision Making (55)
  • Debian (2)
  • Debugging & Troubleshooting (584)
  • Desktop Applications (14)
  • DevOps (7)
  • DevOps & Cloud Scaling (962)
  • Django (1)
  • Laravel (4)
  • Migration & Architecture (192)
  • Mobile Applications (24)
  • MySQL (1)
  • Performance & Optimization (806)
  • PHP (5)
  • PHP Development (21)
  • Plugins & Themes (244)
  • Programming Languages (9)
  • Python (19)
  • Ruby on Rails (1)
  • Security & Compliance (543)
  • SEO & Growth (491)
  • Server (23)
  • Ubuntu (9)
  • VB6 & VB.NET (8)
  • Web Applications & Frontend (19)
  • Web Assembly (Wasm) (2)
  • WordPress (22)
  • WordPress Plugin Development (7)
  • WordPress Theme Development (357)

Recent Posts

  • Go Goroutines vs. Node.js Event Loop: Scaling I/O-Bound Microservices Under High Load
  • Elixir Phoenix vs. Go Gin: Concurrency Models and Fault Tolerance Under Peak Request Volume
  • Python Celery vs. Go Channels: Distributed Task Queue Overhead and Memory Reliability

Top Categories

  • DevOps & Cloud Scaling (962)
  • Performance & Optimization (806)
  • Debugging & Troubleshooting (584)
  • Security & Compliance (543)
  • SEO & Growth (491)
  • Business & Monetization (390)

Our Products

  • ERP & LMS Systems (4)
  • Directories & Marketplaces (4)
  • Healthcare Portals (3)
  • Point of Sale (POS) (2)
  • E-Commerce Engines (2)

Our Services

  • E-Commerce Development (10)
  • WordPress Development (8)
  • Python & Desktop GUI (7)
  • General Consulting (7)
  • Legacy Modernization (5)
  • Mobile App Development (4)

Copyright © 2026 · Vinay Vengala