Skip to content

Glaze vs Boost.Beast HTTP server benchmarks and optimizations#2384

Merged
stephenberry merged 17 commits intomainfrom
glaze-benchmarks-vs-boost-beast
Mar 20, 2026
Merged

Glaze vs Boost.Beast HTTP server benchmarks and optimizations#2384
stephenberry merged 17 commits intomainfrom
glaze-benchmarks-vs-boost-beast

Conversation

@stephenberry
Copy link
Copy Markdown
Owner

@stephenberry stephenberry commented Mar 19, 2026

Glaze vs Boost.Beast HTTP Server Performance

Adds an HTTP benchmark suite comparing Glaze's HTTP server against Boost.Beast, and optimizes Glaze's server to outperform Beast on 8 of 9 benchmarks.

Benchmark Results

Benchmark Glaze Beast Delta
Plaintext (keep-alive) 39,417 37,400 Glaze +5%
JSON Small (keep-alive) 46,842 37,762 Glaze +24%
JSON Single User 45,175 37,986 Glaze +19%
JSON 100 Users 43,260 35,709 Glaze +21%
JSON 10K Users (~960KB) 7,725 7,627 Glaze +1%
POST Echo JSON 46,682 38,473 Glaze +21%
Connection-per-Request 12,955 14,316 Beast +10%
Concurrent (10 threads) 90,806 79,243 Glaze +15%
Concurrent JSON 100 89,010 77,208 Glaze +15%

HTTP Server Optimizations (http_server.hpp)

Single-pass request parser

Replaced async_read_until + asio::streambuf + separate process_request_data with async_read_until + flat std::string buffer + a single-pass parser (try_parse_request) that finds line boundaries and parses HTTP semantics simultaneously. Eliminates the streambuf overhead and redundant delimiter scan.

Direct socket and timer members

connection_state now holds socket_type socket and asio::steady_timer idle_timer as direct members instead of shared_ptrs, eliminating 2 heap allocations per connection.

Zero-copy scatter-gather response write

Response headers and body are written as two separate buffers via asio::async_write with scatter-gather I/O, avoiding the ~960KB memcpy for large response bodies. A custom completion condition removes the default 64KB-per-chunk cap in async_write.

Connection-persistent response objects

response and header_buf are members of connection_state, reusing allocated capacity across keep-alive requests instead of allocating per-request.

Response header construction

  • Pre-cached status lines for common HTTP status codes (single append instead of 5)
  • glz::to_chars replaces std::to_string for zero-allocation integer formatting
  • Bitflags track user-set headers, replacing 4 unordered_map::find() lookups
  • HTTP Date header cached with 1-second resolution via thread_local

Request parsing

  • std::from_chars replaces std::stoul for Content-Length (no exception overhead)
  • Header names lowercased in-place instead of allocating via to_lower_case()
  • Case-insensitive ci_contains for Connection/Upgrade header checks
  • Redundant method validation removed (from_string already validates)

Other

  • shutdown_send instead of shutdown_both for connection close (matches Beast)
  • Socket close via RAII instead of explicit close() call
  • Lazy remote_ip resolution (deferred from accept to handler invocation)
  • response::clear() called between keep-alive requests to prevent stale header leakage

Response struct changes (http_router.hpp)

  • Added header_flag enum and user_headers_set bitfield to response for tracking which default headers the user has overridden
  • response::header() lowercases names in-place and sets bitflags
  • response::clear() resets the bitfield
  • response::body() uses assign() for capacity reuse

Benchmark suite (http_benchmark/)

New benchmark comparing Glaze and Boost.Beast HTTP servers across:

  • Plaintext and JSON responses (various sizes) with keep-alive
  • POST request echo
  • Connection-per-request (Connection: close)
  • Concurrent multi-threaded throughput

@stephenberry stephenberry changed the title Glaze vs Boost.Beast HTTP server performance Glaze vs Boost.Beast HTTP server benchmarks and optimizations Mar 19, 2026
@stephenberry stephenberry linked an issue Mar 20, 2026 that may be closed by this pull request
@stephenberry stephenberry merged commit cac60d3 into main Mar 20, 2026
47 of 48 checks passed
@stephenberry stephenberry deleted the glaze-benchmarks-vs-boost-beast branch March 20, 2026 14:52
@VinnyVicious
Copy link
Copy Markdown

Glaze is 🔥

@GTruf
Copy link
Copy Markdown

GTruf commented Mar 29, 2026

@stephenberry, Hello! It's not entirely clear whether Glaze is faster or not. And to be honest, it would be nice to see benchmarks not against Boost.Beast, but specifically against nghttp2, cpp-httplib, and curl.

It would also be great to see a comparison of the WebSocket components, particularly the client-side ones. Of all the open-source libraries, libwebsockets is the fastest (I’m not including uWebSockets, since it doesn’t have a client-side component, but for server-side it may be fastest).

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Performance Benchmark

3 participants