72 lines
3.9 KiB
Markdown
72 lines
3.9 KiB
Markdown
2
|
|
Minecraft Rust Async Networking Proxy CRIU
|
|
# Minecraft servers are HUNGRY
|
|
|
|
They hunger for your ram and your cpu. This makes it either expensive or laggy to try and host multiple servers at once.
|
|
This was something I encountered when my friend built a homeserver out of spare computer parts that was barely powerful enough to run a minecraft server.
|
|
The problem was that soon multiple people wanted a minecraft server hosted by him (which included us wanting to play modded minecraft).
|
|
|
|
It was a hassle to ssh into the server and start and stop the various servers depending on who wanted to play,
|
|
especially since a lot of people only played very rarily.
|
|
|
|
I remembered that I'd seen [a project](https://github.com/gekware/minecraft-server-hibernation) that claimed to be able to hibernate a minecraft server if nobody was playing on it.
|
|
The only issue was that it worked for a single server, and did so by starting and stopping the server process.
|
|
|
|
This meant that if we wanted to join a modded server the hundreds of mods could make us wait for several minutes before we could play.
|
|
|
|
Another issue was the fact that it could only host a single server. This meant that we would have to run multiple intances of the watcher,
|
|
and that each server would be assigned to an arbitrary port that would be needed when connecting.
|
|
|
|
# Building a reverse proxy for minecraft
|
|
|
|
Since my friends server was accessible through a domain we thought it would be cool if instead of supplying a port
|
|
you could connect to a subdomain and be sent to a specific server.
|
|
|
|
The simplest way to do this would be to create a dhcp record for each subdomain to point to a server,
|
|
but that would be slow and tedious to set up for every server.
|
|
|
|
We then tried nginx, as it seemingly could magically redirect traffic to an internal port based on the subdomain.
|
|
I quickly found out that this did *not* work for minecraft servers (who would have guessed), but after doing some research
|
|
I decided on creating my own reverse proxy that spoke the minecraft protocol instead of HTTP.
|
|
|
|
# The Minecraft protocol
|
|
|
|
Minecraft implements its own protocol consistent of packets. My first idea was to see if anybody had created a
|
|
rust library for dealing with minecraft packets.
|
|
|
|
While some did exist, most of them where unfinished or couldn't do what I wanted. [One crate](https://www.youtube.com/watch?v=E4WlUXrJgy4)
|
|
was useful for seeing how an implementation of parsing packets was done, but ultimately I had to write my own parser.
|
|
|
|
*images of minecraft protocol*
|
|
|
|
# Detecting the subdomain
|
|
|
|
Luckily for me, the Minecraft procotol sends the full address it is trying to connect to during the handshake. This meant that I simply
|
|
had to parse the handshake and extract the subdomain from the address, see if it matches any configured server, and then redirect all
|
|
traffic to the internal port that server runs on.
|
|
|
|
*code explanation*
|
|
|
|
# Why aren't my chunks loading?
|
|
|
|
Just as I thought I was finally done I encountered a problem. The chunks where loading *really* slowly. It felt like we we're back to
|
|
hosting on [aternos](aternos.org) (nothing against aternos, the **free** servers are just a little slow).
|
|
|
|
*image of chunks not loading*
|
|
|
|
I couldn't figure out why it was so slow. I thought it was because all the traffic had to flow through my program,
|
|
but the sockets are connected on the kernel level.
|
|
|
|
After hours of debugging I found the solution. `stream.set_nodelay(true)`
|
|
|
|
## ...
|
|
|
|
**All this time the problem was as simple as saying ** `if (slow) { dont(); }`!
|
|
|
|
To say I was pissed was an understatement, but at the same time I was glad it was finally working.
|
|
|
|
The reason this fixed it was because it disabled [Nagle's algorithm](https://en.wikipedia.org/wiki/Nagle%27s_algorithm), which bunches packets together
|
|
in order to (hopefully) speed up the sending of lots of smaller packets as one big packet.
|
|
|
|
For some reason this absolutely destroyed the chunk loading speed, and disabling it led to finally having the perfect Minecraft reverse proxy hibernation system thing.
|