I'm trying to compare Phoenix Channels with the new Rails ActionCable when it comes to working with WebSockets.
For some context, ActionCable uses Redis to handle PubSub when broadcasting a message to all clients. Example scenario: 1 of 3 rails processes on a separate node will be able to broadcast to clients connected on all web servers. This is done by hitting Redis which in turn publishes to all rails servers who then push to all their connected clients.
I recently read about the 2 million websocket connections achieved by Phoenix websocket connections.
Also found this gem: The Phoenix 1.0 release notes mention this regarding channels:
Even on a cluster of machines, your messages are broadcasted across the nodes automatically
How is Phoenix able to broadcast to clients across nodes? Is it using mailboxes and/or some other interprocess communication under the hood?
This is similar to question 2) in this post.
Thanks!
One channel server lightweight process is created per client, per topic. Each channel holds onto the %Phoenix.Socket {} and can maintain any state it needs within its socket.assigns. Once the connection is established, each incoming message from a client is routed, based on its topic, to the correct channel server.
The socket manages the different channels in your Phoenix application. You can connect a channel under a particular context using the built-in channel method provided by the Phoenix.Socket module. The channel method takes in two values, the context for messages and the Channel module to handle messages under that context.
Any networked device can connect to Phoenix Channels as long as it has a client library. The following libraries exist today, and new ones are always welcome. Phoenix ships with a JavaScript client that is available when generating a new Phoenix project.
Unlike stateless HTTP connections, Channels support long-lived connections, each backed by a lightweight BEAM process, working in parallel and maintaining its own state. This architecture scales well; Phoenix Channels can support millions of subscribers with reasonable latency on a single box, passing hundreds of thousands of messages per second.
Phoenix's PubSub layer is implemented solely with the standard library. The Erlang VM's concurrency model is distributed out of the box. So the mailbox/messaging model Just Works wether you are sending a message locally send(some_local_pid, :a_message)
or globally send(some_pid_on_another_machine, :a_message)
. This is one of the amazing things about Elixir and Erlang that allows Phoenix to shed dependencies like Redis. If you're curious how Phoenix's PubSub system leverages these features in its implementation, see this blog post:
http://www.zohaib.me/guts-of-phoenix-channels/?utm_campaign=elixir_radar_28&utm_medium=email&utm_source=RD+Station
tldr; we use local ETS tables to hold PubSub subscriptions for processes local to a Node, and we broadcast across nodes using a single :pg2
group that each PubSub.Local
server is a member of. When PubSub.Local
server receives a broadcast, it forwards the message to all subscribers locally by looking up the local ETS subscriptions. The actual IPC details and node<->node communication is handled entirely by the runtime.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With