Skip to content
This repository was archived by the owner on Feb 7, 2024. It is now read-only.
This repository was archived by the owner on Feb 7, 2024. It is now read-only.

Horizontal scalability #6

Closed
Closed
@francislavoie

Description

@francislavoie

I'm just opening up this issue because this is something I've had to implement myself in my own Ratchet Websocket server implementation.

I see that you're using ChannelManager to persist connection state. This is fine for most situations, but I suggest thinking about the flexibility of it early on because I'm sure some users will hit walls with limits on vertical scaling of their WS server.

This is how I did it:

  • Require clue/redis-react to have an async Redis client
  • Use Redis as the broadcast driver instead
  • Open two Redis connections on the WS server. One for subscribing, and one for publishing. (This is because of the way Redis works, a connection which subscribes to things cannot publish or run any commands other than subscription related ones and receiving messages... so a second connection is needed to allow publishing events from the WS instance)
  • Whenever a connection comes in, subscribe to Redis on a channel like connections:$connId or whatever. This is to allow other WS server instances to trigger actions on a connection they don't own themselves. e.g. connection limit per user, so it triggers an event to kill off the oldest connection by its ID.
  • Whenever a connection subscribes to a channel, also subscribe on Redis on behalf of the connection. This way you receive Laravel Broadcasting messages via Redis.
  • Whenever a connection publishes a message, also publish to Redis to propagate to other WS instances.
  • When a connection disconnects, unsubscribe from Redis for all the channels it was listening to, but only if it's the last locally-known connection to subscribe to that channel. Also publish a message on the connections:$connId channel to tell any other instances that this one's disconnecting... then unsubscribe from that channel as well.
  • etc. (I'm sure I missed something...)

Here's a bunch of implementation details on how I did it (no full source because it was for a closed-source project) simonhamp/laravel-echo-ratchet-server#2

Obviously this would lose some compatibility with the Pusher server-side stuff due to using Redis as the broadcast driver, but all the client-side Pusher stuff should still work as-is, I think. Just need to load balance your websocket server instances (your docs mention HAProxy or Nginx to proxy, Caddy works just fine as well)

Edit: I just realized you don't necessarily need to switch to Redis for broadcasting. TriggerEventController could just publish to Redis itself. Pusher compatibility would be kept that way. You could just send those events to any of the echo server instances and they can propagate it out.

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions