惯性聚合 高效追踪和阅读你感兴趣的博客、新闻、科技资讯
阅读原文 在惯性聚合中打开

推荐订阅源

博客园 - Franky
U
Unit 42
MyScale Blog
MyScale Blog
B
Blog
阮一峰的网络日志
阮一峰的网络日志
量子位
IT之家
IT之家
The GitHub Blog
The GitHub Blog
F
Fortinet All Blogs
Recent Announcements
Recent Announcements
V
Visual Studio Blog
G
Google Developers Blog
Last Week in AI
Last Week in AI
雷峰网
雷峰网
博客园 - 聂微东
博客园 - 叶小钗
OSCHINA 社区最新新闻
OSCHINA 社区最新新闻
让小产品的独立变现更简单 - ezindie.com
让小产品的独立变现更简单 - ezindie.com
J
Java Code Geeks
博客园 - 司徒正美
Y
Y Combinator Blog
T
The Blog of Author Tim Ferriss
月光博客
月光博客
aimingoo的专栏
aimingoo的专栏

DEV Community

Authentication Security Deep Dive: From Brute Force to Salted Hashing (With Java Examples) Why AI Systems Don’t Fail — They Drift Spilling beans for how i learn for exam😁"Reinforcement Learning Cheat Sheet" I Replaced Chrome with Safari for AI Browser Automation. Here's What Broke (and What Finally Worked) How Python Borrows Other People's Work The $40 Architecture: Processing 1 Billion API Requests with 99.99% Uptime Vibe Coding: A Workflow Guide (From Zero to SaaS) Most webhook security guides protect the wrong side. The scary part is delivery. Headless CMS for TanStack Start: Build a Blog with Cosmic EU Age Verification App "Hacked in 2 Minutes" — What Actually Happened Comfy Cloud’s delete function does not actually remove files Running AI Models on GPU Cloud Servers: A Beginner Guide Event-driven media intelligence with AWS Step Functions and Bedrock I scored 500 AI prompts across 8 quality dimensions — here's what broke How to Call Google Gemini API from Next.js (Free Tier, No Backend Needed) The Portal Protocol: Reclaiming Human Connection in the Age of AI How to Fix Your Team's Scattered Knowledge Problem With a Self-Hosted Forum Intro to tc Cloud Functors: A Graph-First Mental Model for the Modern Cloud Designing Multi-Tenant Backends With Both Ownership and Team Access I Built a Neumorphic CSS Library with 77+ Components — Here's What I Learned PostgreSQL Performance Optimization: Why Connection Pooling Is Critical at Scale Cómo construí un SaaS multi-rubro para gestionar expensas en Argentina con FastAPI + Vue 3 🚀 I Built an Ethical Hacking Scanner Tool – Open Source Project I Replaced /usage and /context in Claude Code With a Single Statusline A Pythonic Way to Handle Emails (IMAP/SMTP) with Auto-Discovery and AI-Ready Design I Collected 8.9 Million Polymarket Price Points — Here's What I Found About How Markets Really Move EcoTrack AI — Carbon Footprint Tracker & Dashboard Everyone's Using AI. No One Agrees How. 5 self-hosted ebook managers worth trying in 2026 Building Your First AI Agent with LangChain: From Chatbot to Autonomous Assistant
Hytale Servers and the Lies We Told Ourselves About Treas...
pretty ncube · 2026-05-27 · via DEV Community

The Problem We Were Actually Solving

The Veltrix public cluster runs up to 1,200 concurrent worlds, each with an in-memory treasure-hunt engine that must atomically pick, lock, and drop loot within 20 ticks (400 ms) or the spawn rules break and loot float freely. Our first implementation offloaded pickup detection to a Lua sandbox per world, then queued loot drops to a single global allocator. At 400 worlds the allocator saturated, resulting in runtime: out of memory with 1.8 GB RSS per pod. We watched pprof flame graphs show 32 % of CPU time lost in mutexes around sync.Map shards, not the lock-heavy treasure math. The real problem was allocation rate, not the algorithm.

What We Tried First (And Why It Failed)

We rewrote the engine in Go 1.20 and adopted a staged pipeline: arena allocator per tick, garbage-free state machines, and go:embed for static loot tables. Latency dropped—until GC jitter arrived. Running go tool trace -c 1000 during a global drop revealed 4.2 ms mark-sweep pauses every 70 ms, coincident with 95th-percentile tooltips flickering. We tried GOGC=off, which pushed RSS to 3 GB and triggered OOM killer. We tried runtime.SetGCPercent(5), which stabilized at 200 ms p99 but broke deterministic seeding: the global PRNG state became racy under GC compaction.

The Architecture Decision

After a week of flame graphs and allocator benchmarks, we accepted that Gos GC was the wrong fundamental constraint. We moved the engine to a Rust crate compiled as a C-extension (cdylib) and loaded via Lua FFI in the same world process. The Rust crate used bumpalo arena with no_std + libc_alloc for zero-copy loot tables. We disabled GC on the Go side, relying on arena pools for tick-local allocations. The FFI boundary added 12 ns per call, but the cost was dwarfed by the previous GC pauses. We also switched the PRNG to fastrand with per-world seeds, guaranteeing deterministic spawns even under arena reuse.

What The Numbers Said After

After one sprint of Rust migration, the median treasure-hunt apex dropped from 30 ms to 1.8 ms on the same hardware. P99 latency fell from 280 ms to 42 ms. The allocation rate went from 142 MB/s per world to 8 MB/s. Heap snapshots from jemalloc profiler showed zero GC pressure and 128 KB RSS per world instance instead of 1.8 GB. The only regression was build time: a clean Rust crate took 45 s to compile with mold, versus 3 s for Go. In production, we pre-built shared objects and hot-patched via dlopen during blue-green deploys, hiding the penalty.

What I Would Do Differently

I would have modeled the PRNG seed lock earlier. The first Rust version serialized all per-world seeds through a single mutex, creating a latency spike at global loot drops. Once we switched to 64-bit XOR-shift with world-id mixing, the hot path became lock-free and the p99 latency halved again. I would also have profiled memory bandwidth on the host node before blaming the language; the Go allocator fragmentation caused 28 % cache misses during spawn bursts. In hindsight, the language change bought us headroom; but without understanding the memory subsystem, the fix would have missed the mark.