name: Nikita
age: 23
birthday: June 23, 2003
location: Russia
role: Server Architect & Full-Stack Developer
career:
started: 2016
years_of_experience: 10
first_language: Pawn (SA-MP / MTA)
milestones:
2016: "Started game server development (Pawn/C++)"
2017: "First commercial plugins — 50+ clients"
2018: "Transitioned to PHP, built custom game frameworks"
2020: "Became top-tier PocketMine-MP developer"
2022: "Started contributing to open-source infrastructure tools"
2023: "Adopted Go & Rust for high-perf microservices"
2024: "Expanded into modern web (Nuxt, Vue, React)"
2025: "Architecting distributed systems at scale"
2026: "Went pro with Python — building a Minecraft server in it"
the_python_thing: >
Knew Python for years. Refused to ship it. Not because I couldn't read it —
because a dynamically typed language with a GIL felt like the wrong tool for
a tick loop with a 50ms budget. August 2026 I stopped arguing with the
ecosystem and started measuring instead: typed, async, uvloop, the hot path
in native code. Turns out my objection was to bad Python, not to Python.
Changed my mind. Did not change my standards.
current_focus:
- "Minecraft server core in modern Python (asyncio, strict typing, native hot paths)"
- "Distributed game server orchestration"
- "High-throughput event processing pipelines"
- "Performance engineering & zero-downtime deployments"
principles:
- "Measure first. An optimization without a benchmark is a guess."
- "p99 is the number that matters. Averages hide the outage."
- "Boring infrastructure. Interesting problems."
- "If it's not fast — it's broken."| Repositories | Private Work | Languages Shipped | Years Building |
Regenerated daily from the GitHub GraphQL API, private repositories included. Nothing in this block is typed by hand.
Language Repos Primary Reach Level
───────────────────────────────────────────────────────────────────
JavaScript 27 23 ████████░░░░░░░░░░░░ Expert
Python 13 10 ████░░░░░░░░░░░░░░░░ Advanced
PHP 12 9 ███░░░░░░░░░░░░░░░░░ Master
TypeScript 6 2 ██░░░░░░░░░░░░░░░░░░ Expert
Vue 4 4 █░░░░░░░░░░░░░░░░░░░ Advanced
Lua 1 1 ░░░░░░░░░░░░░░░░░░░░ Advanced
Ruby 1 1 ░░░░░░░░░░░░░░░░░░░░
Rust 1 0 ░░░░░░░░░░░░░░░░░░░░ Intermediate
───────────────────────────────────────────────────────────────────
across 72 repositories, 46 of them private
Repos — repositories where the language is at least 5% of the code. Primary — repositories where it is the largest language. Counted per repository rather than per byte, because byte counts measure vendored dependencies, not authorship.
PocketMine-MP is single-threaded per world. Scaling it is not a matter of adding CPU — it is a matter of deciding what a player's session is allowed to depend on. Everything below follows from that one constraint.
flowchart LR
P["Players<br/>Bedrock / RakNet"] --> LB
subgraph EDGE["Edge"]
LB["Custom balancer<br/>Go · session affinity"]
end
subgraph FLEET["Game fleet"]
direction TB
N1["Node 1<br/>PMMP · PHP"]
N2["Node 2<br/>PMMP · PHP"]
NX["Node N<br/>autoscaled"]
end
LB --> N1 & N2 & NX
subgraph STATE["Shared state"]
direction TB
R["Redis<br/>sessions · locks · presence"]
DB[("MySQL<br/>durable truth")]
end
N1 & N2 & NX <--> R
R --> DB
subgraph OBS["Telemetry"]
direction TB
K["Kafka"] --> CH[("ClickHouse")] --> G["Grafana"]
end
N1 & N2 & NX -.->|"async — never blocks the tick"| K
classDef edge fill:#1f6feb33,stroke:#58a6ff,color:#c9d1d9
classDef node fill:#777BB433,stroke:#777BB4,color:#c9d1d9
classDef state fill:#DC382D33,stroke:#DC382D,color:#c9d1d9
classDef obs fill:#F4680033,stroke:#F46800,color:#c9d1d9
class LB edge
class N1,N2,NX node
class R,DB state
class K,CH,G obs
The three rules that make it hold — and what each one costs
1. The tick loop may never wait on the network. A PMMP tick has a 50ms budget. One synchronous MySQL round trip at 4ms is 8% of that budget spent doing nothing, and it is per query, per tick, on the same thread that moves every entity in the world. Every I/O path is therefore async with a write-behind buffer, and every read the tick loop needs is already in Redis before the tick starts. Cost: the game reads slightly stale state. Acceptable, because a player's balance being 200ms old is invisible, while a 300ms tick stall is not.
2. A session belongs to exactly one node at a time. Affinity is enforced at the balancer, and the transfer handshake takes a Redis lock before it moves a player. Without the lock, a reconnect racing a transfer produces two authoritative copies of the same inventory — which is how item duplication bugs get born. Cost: a failed node drops its players instead of silently migrating them. A visible five-second reconnect beats an invisible economy corruption.
3. Telemetry is fire-and-forget or it is not telemetry. Analytics goes out over an unbuffered async producer to Kafka. If the collector is down, events are dropped on the floor. The moment observability can apply backpressure to gameplay, an outage in the least important system takes down the most important one. Cost: metrics have gaps during incidents — exactly when you want them most. The alternative is worse.
Where the tick time actually went (48ms → 11ms)
Profiling first, always. The wins were not where intuition said they would be:
| Change | Mechanism | Tick delta |
|---|---|---|
Entity lookups O(n) → spatial hash |
Chunk-local grid instead of scanning the world entity list every tick | −19ms |
| Synchronous DB writes → write-behind | Batched flush on a separate thread, Redis as the read path | −11ms |
| Packet encode moved off the main thread | Serialization is CPU-bound and order-independent per client | −5ms |
Removed per-tick array_merge in the plugin hot path |
Allocation churn, not algorithmic cost — pure GC pressure | −2ms |
The last row is the interesting one. It looked like nothing in the code review and showed up clearly in the flame graph. This is why the first rule is measure.
2026: why a Minecraft server in Python, and how it is not slow
The honest version: I avoided Python for a decade on an argument I had never actually benchmarked — GIL, dynamic dispatch, "not a systems language." Then I tested it instead of asserting it.
What the design actually looks like:
asyncio+uvloopfor the network layer. A Minecraft server is overwhelmingly I/O-bound — thousands of small packets, not heavy computation. This is the workload async was built for, and the GIL is irrelevant when the threads are waiting on sockets.- The tick loop is the only synchronous thing in the process. Same rule as
rule 1 above. Nothing in the world update path is allowed to
awaiton anything it does not already have. - Strict typing, enforced in CI.
mypy --strictand Pydantic on every protocol boundary. Most of my objection to Python was really an objection to untyped Python; that objection has a fix. - The hot path is not Python. Packet codec and chunk serialization are native extensions. Python orchestrates, native code does the byte pushing — the same split that makes NumPy fast.
- Multiprocessing per world, not threading. Worlds are already independent, so the GIL never becomes the bottleneck it is famous for being.
The result is not "Python is as fast as C++." It is that for this workload the bottleneck was never the language, and the iteration speed is worth more than the constant factor I gave up.
|
|
|
|
PRODUCTION INFRASTRUCTURE
──────────────────────────────────────────────────────────────
Servers managed 47 nodes across 3 regions
Peak concurrent users 12,847
Response time 23ms avg · 89ms p99
Uptime (12 months) 99.98%
Events processed 4.2M / day
Deployments ~18 / week, zero-downtime
Database queries 28,400 / sec at peak
Cache hit rate 97.3%
CDN bandwidth 12.4 TB / month
OPTIMIZATION HIGHLIGHTS
──────────────────────────────────────────────────────────────
▸ Game tick 48ms → 11ms spatial hash + async I/O
▸ PHP memory −340MB per instance arena allocator, tick-scoped
▸ Packet handler 3.2x throughput rewritten in Rust
▸ Spatial queries 94% faster custom B-tree index
▸ Scalability 5x horizontal monolith → services
▸ WebSocket 99.7% recovery session resume in <200ms
Self-reported from production dashboards. The GitHub numbers above this section are machine-generated; these are not.
2016 ──────── 2018 ──────── 2020 ──────── 2022 ──────── 2024 ──────── 2026
│ │ │ │ │ │
Pawn PHP PocketMine Distributed Modern web Python,
SA-MP / MTA game core systems Vue / Nuxt properly
first line frameworks contributor 12K+ CCU React this time
This page rebuilds itself every day from the GitHub API — see
.github/scripts/profile_stats.py.
If a number here is wrong, the script is wrong, and that is a bug I can fix.