Load balancing a phoenix channel clusters?

Hi i’m a new elixir user
I have a question like this, if I’m creating a phoenix cluster and allowing user to come and play game/chat via channel.

The case is: i’m load balancing those phoenix server under a single domain.
Do I need to deal with something like sticky session/ server affinity like socket.io land ?
Can I use digital ocean load balancing service ?

Thanks.

1 Like

Phoenix’s PubSub works from any node to any node in a cluster. So once a user connects and opens a websocket connection, they are able to connect to their channels, and if they have multiple connections (on same or different nodes) this is tracked as part of their overall presence. The websocket connections themselves are stateful, and if they are disconnected a new one is created.

You could also try this locally :slight_smile: Start a couple of nodes running your application, running it with something like iex --sname s1 -S mix phx.server, changing the name passed to --sname on each instance. You’ll also need to change the port number phoenix starts listening in your config before you launch each instance (4000, 4001, …). At that point you should have a nice local cluster and you can try connecting to the various running nodes and see how it works. If you really want to get “fancy” you can set up haproxy or nginx to load balance between your locally running nodes to fully emulate a load-balanced cluster.

Having local setups like this for testing is not so difficult and really useful for testing clustered deployments of applications you know will be deployed in that manner.

I don’t know anything about DO’s load balancing, so can’t say anything about that …

4 Likes

Thanks

So we dont need to care about those sticky session then ?

How do we deal with in-memory channel state between nodes ? ex: we have a poker game, we need to store which cards player has

1 Like

Presumably you would store the state for a game in a Game process in the cluster, not in the channels themselves. The clients, when they initially connect to the channels, then query for “Which games am I in?” and get a list of games that they can sync from.

What coordinates that and the games themselves are all presumably GenServers that will be registered so that any node can reach them (the easiest way to do this is just to use :global and register them with names like {PokerServer.PokerGame, poker_game_id} and any process in the cluster could then reach them by using that unique name.

Using :global will mean that things lock up heavily with regards to process registration and what not when there is a netsplit and the short version is that it prohibits you from having too many nodes in the cluster. The exact number isn’t something I’ve seen myself, but from what I’ve heard 8+ isn’t going to be the best idea.

If you do go with global, :pg2 is a great addition alongside it as it will allow you to have cluster-wide process groups out of the box, much like :global is global registration within a cluster.

2 Likes

You may store your data in the socket. But, there is a catch - it only exists until disconnect, so in case of the network issue you loose everything.

I keep the data in the browser, and send it to the server on connect, so reading is cached, but update must be done on the both client and server side.

Yeah i wanna store everything at server side. So once an user got network, he can resume later and then sync