(UPDATE: I now have WebRTC Datachannel handling unreliable updates in my server. A more in-depth post is to come.)
Websockets are great! They just work. They are supported by all modern browsers. There are libraries that let you easily write servers that support oodles of them. The user doesn't have to do anything to connect with your server. TLS ensures you have strong cryptography, and even that is seamless for the user. So what's not to love?
TCP stream semantics. Guaranteed delivery can be useful. Sometimes guaranteed ordering is nifty as well. But sometimes, you just want to send updates in a fire and forget style, where if you miss one update, you just take the next one. This is where websockets can be a real pain if you are a game developer. Not only will a dropped packet get you huge outliers of latency, all of the following messages behind it will also be delayed due to the ordering guarantee. This can cause a game to look stuttery or feel laggy, especially on channel-crowded wifi networks, as the stream semantics can effectively cause a momentary across the board mini-blackout/delay of all server information.
However, I did say I had a solution. It's not perfect, but it seems to work quite well in Emergence Vector. (I haven't even thought about benchmarking it yet. Perhaps I can make that a future blog post.) For frequent server updates, I simply use N websockets and round-robin them. This effectively spoils the ordering guarantee, which is what causes the across-the-board delay.
Granted, there's also WebRTC Data Channel, which would let us specify unreliable communications. However, the Go libraries don't seem as mature, and there are reasons why I would rather not have peer-to-peer. So perhaps in the future, Emergence Vector will be moving to that. In the meantime, this seems to work pretty well.