English static mirror for SEO/GEO · AI-assisted translation · Read Chinese original

Go Performance Optimization Deep Dive: VictoriaMetrics' Zero-Allocation Playbook and the Limits of Parasitic JIT

Forum topic · 小凯 · 2026-05-18

Summary

This article argues against reflexively rewriting Go projects in Rust when performance problems arise. Drawing on discussions from former Tailscale CTO David Crawshaw, VictoriaMetrics CTO Aliaksandr Valialkin, and Stewart Lynch, it presents a decision map: roughly 99% of code paths are cold, and garbage collection is a net benefit for them; only the ~1% of hot paths need manual optimization. Valialkin's three-step methodology for VictoriaMetrics—written entirely in Go yet outperforming C++/Rust time-series databases—is detailed: (1) use pprof to precisely locate hot paths, (2) fully eliminate memory allocations in those paths so the GC is never triggered, and (3) manage bulk data via pre-allocated large memory blocks, sync.Pool, and arena-style request-scoped allocation. The remaining 99% of code stays idiomatic and simple. For extreme cases where even zero-allocation Go is insufficient, a parasitic Go Tracing JIT approach (eBPF kernel-side tracing plus Wasm translation) is compared as a complementary escape hatch rather than a competitor. The piece closes with Stewart Lynch's warning that unnecessary complexity is the real enemy of good software, concluding that top engineers profile first, isolate the 1%, and keep everything else simple.

Go Performance Optimization Deep Dive: VictoriaMetrics' "Zero-Allocation" Playbook and the Ultimate Limits of Parasitic JIT

> Sources: Tony Bai's "Go Performance Optimization: No Need to Rewrite in Rust"; discussion threads on X/Twitter involving David Crawshaw (former Tailscale CTO), Aliaksandr Valialkin (VictoriaMetrics CTO), and Stewart Lynch (low-level code veteran); the Go Tracing JIT parasitic architecture proposal. > > Perspective: This is not a "Go vs Rust" tribal post, but a decision map for performance optimization — where you stand determines which tool you use.

1. Don't Rush to Rewrite in Rust

In recent years, a near-fanatic "political correctness" has swept tech communities: GC languages carry original sin, and everything should be rewritten in Rust.

Hit a performance bottleneck → first instinct: "rewrite in Rust" → the whole team struggles with the borrow checker for two months → iteration speed collapses → performance may improve, but the team is burned out.

David Crawshaw, Aliaksandr Valialkin, and Stewart Lynch sparked a discussion on X with one core conclusion:

> 99% of your code doesn't need any of this. Truly top-tier performance optimization only requires operating on the 1% of hot paths.

2. The Brutal Truth of 99% vs 1%

David Crawshaw's exact words:

> "Almost all your code paths are cold and GC is net positive. 1% of your code is performance sensitive. Don't create GC pressure there."

What is "cold code"?

  • Configuration parsing
  • Route dispatching
  • Error handling
  • Database connection initialization
  • Logging
  • In a large codebase, this code makes up 99% of the volume. It is entirely insensitive to microsecond-level latency.

    GC is a blessing for 99% of code, not a curse.

    It frees programmers' minds from mentally "compile-time planning" every line like you would in C/C++/Rust, letting you focus entirely on business logic. Forcing the whole team to fight over memory ownership in the 99% of cold code just to squeeze CPU cycles out of the 1% core logic is commercially absurd in terms of ROI.

    3. VictoriaMetrics' Three-Step "Zero-Allocation" Playbook

    VictoriaMetrics is written entirely in Go, yet in many benchmarks it beats time-series databases written in C++ and Rust.

    CTO Aliaksandr Valialkin's optimization approach can be summarized in three steps:

    3.1 Stop Guessing — Use pprof to Precisely Locate Hot Paths

    You will never find performance bottlenecks by intuition.

    First, get the program running under real traffic, then use Go's built-in pprof to precisely identify the 1% of hot paths consuming 80% of CPU and heavy memory allocations. This 1% is usually tiny in code volume — not hard to find.

    3.2 "Completely Remove" Allocations in Hot Paths

    Aliaksandr's words:

    > "This is how I optimize programs written in Go — by removing memory allocations from hot paths..."

    As long as you don't create new objects in hot paths (no malloc, no heap allocation), the garbage collector never wakes up.

    No allocation means no garbage; no garbage means no GC pressure.

    3.3 The "Escape Hatch": Pre-allocation and Arena Mechanisms

    If hot paths can't allocate new memory, what about massive data? Three techniques:

    | Technique | Mechanism | Effect | |------|------|------| | Pre-allocated large memory blocks | One-shot make([]struct{...}, 1e6) with internal sliding reuse | Appears to GC as a single contiguous pointer with minimal scan cost | | sync.Pool | Caches and reuses small objects, keeping them out of GC | Zero pressure for high-frequency create/destroy scenarios | | Arena mechanism | All allocations for a single request happen in one pre-allocated block; the whole arena is freed at request end | Near-Rust zero-overhead cleanup, but still written in Go |

    3.4 Restraint for the Other 99%

    After applying these techniques, stop immediately.

    Let the remaining 99% stay the most idiomatic, simplest, most readable Go code. Let the GC take care of it.

    The result: performance rivaling C++/Rust, plus the original high business iteration speed.

    4. Go Tracing JIT: The Parasitic Exit When "Zero Allocation" Isn't Enough

    The Tony Bai / VictoriaMetrics approach solves hot-path optimization within 99% of commercial scenarios. But what if even Zero Allocation isn't enough for your use case?

    This leads to the Go Tracing JIT (parasitic architecture) approach:

    | Dimension | VictoriaMetrics Route | Go Tracing JIT Route | |------|----------------------|---------------------| | Goal | Squeeze maximum performance within the Go runtime | Bypass the Go runtime's "control freak" constraints | | Strategy | Zero allocation + pre-allocation, coexisting peacefully with GC | eBPF kernel-side tracing + Wasm translation + trampoline entry | | Philosophy | Restraint; no added global complexity | Parasitic architecture, executing in the runtime's blind spots | | Use case | 99% of commercial projects | The extreme 1% where even Zero Allocation isn't enough | | Risk | Low — no language or architecture changes | Medium — bypasses Go runtime stack-map requirements |

    The two are not competitors, but two ends of the same rope:

  • First use the VictoriaMetrics three-step method to extract maximum performance within the Go runtime.
  • If that's still not enough, use the Tracing JIT's parasitic approach — no language change needed, just a different execution layer.
  • 5. Stewart Lynch's Warning: Complexity Is the Enemy

    Stewart Lynch's exact words:

    > "Everything that's wrong with modern software can be summed up in two words: Unnecessary Complexity."

    Programmers have a particular psychological trap: we chose this profession because we "enjoy solving complex problems." Precisely because of that, we look for chances to wrestle with complexity everywhere — even in places where simplicity should be the goal.

    That's why a simple CRUD app adopts Rust's borrow checker, and a moderately concurrent microservice gets an over-engineered service mesh.

    Complexity feels sophisticated. But complexity is the enemy of good software.

    6. The Divide Between Top Engineers and Average Coders

    | | Average Engineer | Top Engineer | |--|-----------|-----------| | Facing performance issues | "Rewrite in Rust!" | "pprof first, locate that 1%" | | Attitude toward code | Introduce complexity globally | Isolate the 1%, geek out inside the isolation zone, stay simple outside | | On GC | "GC is original sin" | "GC is a blessing for 99% of code" | | Design philosophy | Hunt for silver bullets | Restraint — design is complete when there's nothing left to take away |

    7. One-Sentence Summary

    > Don't wrap 99% dumplings just for 1% of the vinegar. > > Open pprof, reuse the temporaries in your hot paths, and head home early.

    References

  • Tony Bai, "Go Performance Optimization: No Need to Rewrite in Rust" (tonybai.com, 2026-05-18)
  • David Crawshaw, X/Twitter thread on Go GC optimization (2026-05)
  • Aliaksandr Valialkin, VictoriaMetrics performance optimization practices (X/Twitter, 2026-05)
  • Stewart Lynch, "Unnecessary Complexity" thread (X/Twitter, 2026-05)
  • Go Tracing JIT parasitic architecture proposal (internal technical record)

Tags

#go#performance-optimization#victoriametrics#zero-allocation#garbage-collection#rust#jit#software-engineering

This page is an English static mirror generated for search and AI citation. It may be a full translation or structured summary of the Chinese original. Canonical interactive discussion lives on the Chinese page: https://zhichai.net/topic/177620274