- Ignore socket.io, do pure binary websocket
- Do not serialize JSON, or use msgpack or protobuf - write your own protocol.
- Write tests for protocol, you need fast iteration. It's super easy to write tests for codec.
- Quadtrees are kinda lousy compared to r-trees.
- Measure everything with realistic load - i.e. I've found out that it's more costly to calculate world entity deltas to send to client, than to send everything in his view.
- Keep client updates under MTU payload. This is basically impossible with JSON.
- Mutability is the way to go for performance.
- Share code with backend and frontend, you'll need it for client prediction.
- Prefer fixed entity speeds.
- Don't log per-frame in production, journalctl will eat up your memory.
- Write game bots to test your load non-synthetically.
- Test on your VPS, you'll be surprised how underperforming CPUs are in most providers. Neighbours are probably serving some CRUD and are very likely not to be as noisy as you are.
Now, all this might not apply depending on exact gameplay mechanics you have, but it works for me. I have Node.js serving 200 clients and 10k entities with vision (can run at or from you) at 20 frames per second that keeps under 100MB RAM with no hiccups. I think I could use something like Golang for some more advanced physics though.
A question to all reading - I'm considering adding an option to mine Monero in my next game. It'd probably be a flip-switch between ads and mining right there on the home screen, with some intelligent throttle/thread decisions depending on the kind of device game is running on. I'd appreciate any feedback regarding the sentiment on that.