1
\$\begingroup\$

I'm building a turn-based online multiplayer game with Unity for both desktop and mobile.

Traditionally, I would build a Java socket server, host it in Google Compute Engine or similar, and have players connect to it. Since this works with sockets I can easily notify players of relevant events, such as matchmaking, chat, enemy turn, etc.

I've been curious about Serverless Functions for a while, such as Google Cloud or Amazon Lambda.

However, at first glance it doesn't seem to me like that would work for my game: because there ins't a constant connection (with sockets), I can't notify players of relevant events in realtime - or can I?

For mobile I realize I could probably use something akin to push notifications (so the serverless code may push messages to the relevant player's phone). But that doesn't seem as simple for desktop games.

Well, what if the players poll for messages? Like every second, call a Cloud function and ask them if there's anything for them.

I'd image that would work, but that seems rather overkill - with as little as a couple thousand players, calling the same function every second for prolonged times (the game's matches are long) sounds like it would easily increase expenses.

Is there something I am missing? A coding practice that would make serverless code feasible for a cross-platform online multiplayer game? I want to make it work, but it would seem like a socket server is still my only option.

\$\endgroup\$
1
\$\begingroup\$

I think the simple answer is: yes, depending on your game design.

What you touch on here is a fundamental of any server (or serverless) API design. You have to trade responsiveness off against scalability. Maintaining a connection to clients incurs overhead, and the more clients you have the more time you spend just handshaking back and forth. If all of your traffic goes through those mechanisms those nodes have to get larger and larger.

If you need clients to become aware of events within a second, or within a few render frames, the costs of polling become astronomical and wasteful, because the vast majority of the traffic is just "anything for me? No." If your clients can live with only finding out events every few seconds more more, then maintaining a continually open TCP connection when the majority of the time there's nothing to send is also wasteful, not to mention the difficulties you have maintaining and restoring those connections in the presence of poor network conditions.

That said, I think a smart architect these days would be able to leverage both solutions. Perhaps making edge nodes which your clients connect to and maintain those connections, but make them dumb, stateless and highly scalable. Effectively just brokers for message passing, like in MQTT. You send messages to the game clients when you have to, but you try to keep them short so that those nodes can cope with a lot of clients. You try to keep them disposable so that if a client loses connection or the node fails, you can shuffle those connections onto another node. Internally, your main workhorse doing game processing is not just one big monolithic service, but many little processors, working their way through their own job list, co-ordinating where they need to, sending messages to clients when something interesting happens. But you're never sending big gobs of data to the clients through the connections, you're just sending a notification, and when the clients hear about the event, they can then call the serverless API to actually pull down the data, or to do an expensive operation on the state (like querying a lot of objects around the player).

That's all purely hypothetical but you can see how it might bridge the gap between the ability to push events to disparate clients promptly while still allowing you to scale up your handling.

Back down to reality, I think the real issues with serverless probably boil down to:

  • Contention over the data store: instead of fighting over server compute resource and failing to scale because it can't cope, you get unlimited server compute, and instead the bottleneck shifts to the database that has to be shared amongst all the serverless functions to collaborate. A truly scalable database is just as hard a problem to solve, perhaps even harder, than a scalable server.
  • Unpredictable execution times: the price you pay for unlimited compute is variability in execution time. An operation on a traditional server will typically take the same amount of time every time, the startup costs are all paid when bringing the big server online. In a serverless model, you pay much smaller startup costs but have to do so every time a new context of your function spins up. Just because it's handled for you, doesn't mean it doesn't take time to do. The first execution of a function might take 500ms and the next 50 executions might only take 10ms. You don't know when or where the 500ms delay will hit, because you have no control over how fast requests are coming in for the function or how the Cloud provider will choose to scale the function up.
\$\endgroup\$

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.