인셔셔RSS 관심 있는 블로그, 뉴스, 기술 정보를 효율적으로 추적하고 읽으세요
원문 읽기 InertiaRSS에서 열기

추천 피드

小众软件
小众软件
博客园 - 叶小钗
有赞技术团队
有赞技术团队
大猫的无限游戏
大猫的无限游戏
博客园_首页
钛媒体:引领未来商业与生活新知
钛媒体:引领未来商业与生活新知
L
LangChain Blog
Hugging Face - Blog
Hugging Face - Blog
OSCHINA 社区最新新闻
OSCHINA 社区最新新闻
aimingoo的专栏
aimingoo的专栏
Blog — PlanetScale
Blog — PlanetScale
爱范儿
爱范儿
T
Tailwind CSS Blog
Jina AI
Jina AI
量子位
Stack Overflow Blog
Stack Overflow Blog
人人都是产品经理
人人都是产品经理
J
Java Code Geeks
V
Visual Studio Blog
月光博客
月光博客

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 Common SOC 2 Failures (Real World) Stop Vibe-Checking Your AI App: A Practical Guide to Evals How to Use SonarQube and SonarScanner Locally to Level Up Your Code Quality Your Next To-Do App Is Dead — I Replaced Mine with an OpenClaw AI Sign a Nostr event in 60 lines of Python using coincurve — no nostr-sdk, no nbxplorer, no rust toolchain ITGC Audit Explained Like You’re in Big 4 Patch Tuesday abril 2026: Microsoft parcha 163 vulnerabilidades y un zero-day en SharePoint Stop scraping everything: a better way to track competitor price changes Listing on MCPize + the Official MCP Registry while routing payments OUTSIDE the marketplace — how I kept 100% of my x402 revenue Building an AI-Powered Risk Intelligence System Using Serverless Architecture Why We Ripped Function Overloading Out of Our AI Toolchain Testing AI-Generated Code: How to Actually Know If It Works SaaS Churn Is Killing Your Business. Here Is What to Do About It (Without a Support Team) The Speed of AI Is No Longer Linear - And Self-Improving Models Are Why How to Implement RBAC for MCP Tools: A Practical Guide for Engineering Teams From Standard Quote to Persuasive Proposal: AI Automation for Arborists I built a CLI that scaffolds complete multi-tenant SaaS apps Axios CVE-2025–62718: The Silent SSRF Bug That Could Be Hiding in Your Node.js App Right Now The dashboard that ended our friendship Data Pipelines Explained Simply (and How to Build Them with Python)
왜 Hytales 보물 탐색 엔진이 부하에 폭발하는가 (그리고 우리가 우리 자신을 잃지 않고 해결한 방법)
Lillian Dube · 2026-05-28 · via DEV Community

실제로 해결해야 했던 문제

Hytale 엔진은 이벤트를 간단한 pub/sub 시스템인 EventManager를 통해 트리거합니다. 하지만 Veltrix를 동시 2,500명의 플레이어로 확장했을 때, 금요일 보물 사냥은 동시 참여자 부하가 1,200명 미만으로 멈추는 현상이 발생했습니다. 증상은 눈에 띄었습니다:

  • EventManager 블락 큐가 Redis Streams에서 89%에 도달했습니다
  • 보물 스폰당시 2.4초의 지연 발생
  • 클라이언트 측 보물 활성화 시간 초과로 인한 플레이어 타임아웃, NRE-7280: 보물 상자 활성화 타임아웃—지역 53 응답 없음
  • 15분 이내에 레디스 메모리 사용량이 2.1GB에서 11.2GB로 급증하여 캐시 계층의 OOM 킬러가 트리거됨

근본 원인은 논리가 아니었다. 설정이었다: 우리는 모든 지역에 대해 하나의 글로벌 이벤트 채널, 모든 보물 유형에 대해 하나의 Redis 스트림, 그리고 백프레셔가 없었다. 이벤트 매니저는 제어된 관개 시스템이 아닌 소화기처럼 다루어지고 있었다.

먼저 시도했던 것과 그 이유 (왜 실패했는지)

우리의 첫 번째 시도는 무식한 확장이었어요: 더 많은 Redis 쇄, 더 많은 소비자, 더 빠른 하드웨어. 우리는 문제에 대해 3개의 Redis 7.2 쇄를 투입했어요, 각각 4개의 지역에 걸쳐 8개의 소비자 그룹을 가지고 있었어요. 그것은 우리에게 부하 하에서 줄이는 것이 여전히 줄을 섰을 때 40분의 안정성을 샀어요. 왜?

  • pub/sub 채널은 여전히 글로벌이었어요. Harbormere에 있는 보물이 여전히 Blightfen에 있는 것 뒤에 줄을 섰어요.
  • 소비자 이탈: 플레이어들이 지역 간에 전이하면서 소비자 그룹을 완벽하게 전환하지 못했고, 이로 인해 중복된 스폰과 환영 상자가 발생했습니다.
  • 절전기 없음. Redis 메모리가 폭발했을 때 OOM 캐너이터는 단순히 프로세스를 죽이지 않았지만, 전체 캐시 계층을 죽이며 모든 활성 플레이어 세션을 중단했습니다.
  • OpenResty를 속도 제한기로 소개했지만, 각 생성마다 추가로 400ms의 지연 시간을 발생시켜 플레이어들이 움직임에서 끊김을 보고하기 시작했습니다.

어려운 진실은? 우리는 처리량을 신호의 완결성보다 최적화했습니다. 이벤트 스트림을 명확한 경계가 있는 제한된 맥락 대신 원시 데이터 파이프라인처럼 다루었습니다.

아키텍처 결정

우리는 엄격한 지역 사회 이벤트 버스 모델로 전환했습니다:

  • 각 지역은 자신만의 고립된 Redis 스트림을 받았습니다(단일 스트림, 샤드가 아닙니다)
  • 채널 이름을 Biome ID와 일치시켜 이름을 변경했습니다: Harbormere용 EventStream_53, Blightfen용 EventStream_71
  • 보물 스폰 규칙은 지역화되었습니다: 명시적으로 허용되지 않는 한 교차 지역 스폰은 없습니다(교차 지역 유령 상자를 디버깅한 후 전적으로 비활성화했습니다)
  • Go로 작성된 가볍게 설계된 이벤트 버스 게이트웨이를 소개했습니다. 이는 2 vCPU/4GB 각각으로 독립된 k3s 노드에서 실행됩니다. 이는 분산 라우터 역할을 했으며 소비자가 아닙니다
  • 각 지역의 소비자 그룹은 Redis NACK에 지수 백오프를 적용한 최대 32개의 메시지를 동시에 처리할 수 있습니다
  • 우리는 Redis의 maxmemory-policy를 allkeys-lru로 설정하고 8GB의 하드 제한을 추가했으며, 메모리가 6GB를 넘을 때 Lua 스크립트를 추가하여 강제 GC를 수행했습니다
  • 우리는 보물 활성화 논리를 클라이언트 측에서 지역 미크로서비스 TreasureCore로 이동시켰습니다. Fly.io에서 실행되는 TreasureCore는 Postgres 16과 pgbouncer를 사용합니다. 이를 통해 REST 엔드포인트를 노출시켰습니다: POST /treasure/{biomeId}/activate, ETag 잠금을 통해 중복 생성을 방지합니다.

거래가 명확했습니다: 더 많은 운영 부담, 지역당 더 높은 비용, 그리고 지역 간 전송 시 일부 지연이 있었습니다. 하지만 우리는 편의성보다 올바름을 선택했습니다. 지역 모델은 해브머레이 트레asure 스폰이 플레이어가 이벤트 중에 전송되더라도 블라이트펜 체스트 생성을 막지 않았습니다.

숫자들이 말한 것은 뒤에

안정적인 운영 세 주 동안 후:

  • Redis 메모리는 모든 스트림에서 3.2 GB로 안정화되었습니다(구 글로벌 모델 대비 71% 감소)
  • 보물 스폰 지연 시간이 2.4초에서 180ms p99로 낮아졌습니다
  • 부하 하에서 더 이상 NRE-7280 오류가 발생하지 않습니다—활성화 실패율이 12%에서 <0.1%
  • 플레이어 경험 향상: 화면에서 가슴이 더 이상 깜빡이지 않고, 전송 유발 동기화 불량이 더 이상 발생하지 않습니다
  • 비용: Redis에 대해 $47/월(기존 $189에서 낮춤), 그리고 6개의 TreasureCore 인스턴스에 대해 $112/월 추가. 우리는 안정성을 위해 14ms의 교역 영역 지연 시간을 희생했다.

메트릭스는 우리가 이미 의심했던 것을 알려줬다: 이벤트 엔진을 글로벌 시스템으로 취급하는 것은 반패턴이었다. 지역화는 조기 최적화가 아니라 피해 통제였다.

내가 다르게 할 것들

나는 다시 단일 글로벌 채널을 갖춘 이벤트 시스템을 설계하지 않겠습니다. 하이태일용도 아니고 어떤 게임용도 아닙니다. 강력한 지역화가 있었음에도 불구하고, 플레이어들이 피크 로드 시 지역을 일괄적으로 이동할 때 이벤트 게이트웨이를 경로 업데이트로 과부하시켰습니다. 우리의 해결책은 이동 유발 지역 전환에 쿨타임을 도입하는 것이었지만, 그것은 UX를 손상시켰습니다.

다음에 이벤트 버스를 더 나눌 거야: 정적 이벤트(고정된 상자)용 스트림 하나, 동적 이벤트(몬스터, 날씨, 타이밍 스폰)용 스트림 하나. NATS JetStream을 Redis Streams 대신 사용할 수 있다면 학습 곡선을 감당할 거야—이것은 스트림 수준의 백프레셔를 기본적으로 제공해줘.

다시 클라이언트 측 활성화를 신뢰하지 않겠습니다. Hytale 클라이언트는 여전히 JavaScript와 WebGL로 구성되어 있으며, 물리적 동기화 불일치는 피할 수 없습니다. 그 논리를 서버로 옮기세요.

그 금요일에 우리는 Veltrix가 무너지는 것을 피했습니다. 더 많은 하드웨어를 문제에 던지는 것이 아니라, 우리가 실제로 구축하고 있던 시스템의 경계를 존중하는 방식으로요. 그 교훈은 여전히 유효합니다: 사건들은 단순히 기능이 아니라—theyre contracts. 계약을 깨뜨리면 시스템도 함께 무너집니다.