2

I need horizontally scalable WebSocket connection server for chat like system, where browser clients connected to different WebSocket servers coould exchange messages within separate chat rooms.

Clients    HaProxy  WebSocket server1   WebSocket server2    Redis/ZeroMQ
             |             |                 |                   |
client A ----=------------>o<----------------|------------------>|
             |             |                 |                   |
client B ----=-------------|---------------->o<----------------->|
             |             |                 |                   |

Here client A and client B are connected through HaProxy to two different WebSocket servers, which exchange messages through Redis/ZeroMQ backend, like in that and that questions.

Thinking of building that architecture I wonder if already there is an opensource analog. What such a project would you suggest to look at?

Community
  • 1
  • 1
zuba
  • 1,488
  • 1
  • 17
  • 50

1 Answers1

0

Look into the Plezi Ruby framework. I'm the author and it has automatic Redis scalability built in.

(you just setup the ENV['PL_REDIS_URL'] with the Redis URL)

As for the architecture to achieve this, it's fairly simple... I think.

Each server instance "subscribes" to two channels: a global channel for "broadcasting" (messages sent to all users or a large "family" of users) and a unique channel for "unicasting" (messages intended for a specific user connected to the server).

Each server manages it's internal broadcasting system, so that messages are either routed to a specific user, to a family of connections or all users, as par their target audience.

You can find the source code here. The Redis integration is handled using this code together with the websocket object code.

Web socket broadcasts are handled using both the websocket object on_broadcast callback. The Iodine server handles the inner broadcasting within each server instance using the websocket implementation.

I already posted the inner process architecture details as an answer to this question

I think socket.io has cross server support as well.

Edit (some code)

Due to the comment, I thought I'd put in some code... if you edit your question and add more specifications about the feature you're looking for, I can edit the code here.

I'm using the term "room" since this is what you referred to, although I didn't envision Plezi as just a "chat" framework, it is a very simple use case to demonstrate it's real-time abilities.

If you're using Ruby, you can run the following in the irb terminal (make sure to install Plezi first):

require 'plezi'
class MultiRoom
    def on_open
        return close unless params[:room] && params[:name]
        @name = params[:name]
        puts "connected to room #{params[:room]}"
        # # if you use JSON to get room data,
        # # you can use room arrays like so:
        # params[:room] = params[:room].split(',') unless params[:room].is_a?(Array)
    end
    def on_message data
        to_room = params[:room]
        # # if you use JSON you can try:
        # to_room = JSON.parse(data)['room'] rescue nil
        # # we can use class `broadcast`, to broadcast also to self
        MultiRoom.broadcast :got_msg, to_room, data, @name if to_room
    end
    protected
    def got_msg room, data, from
        write ::ERB::Util.html_escape("#{from}: #{data}") if params[:room] == room
        # # OR, on JSON, with room arrays, try something like:
        # write data if params[:room].include?(room)
    end
end
class EchoConnection
    def on_message data
        write data
        MultiRoom.broadcast "myroom", "Echo?", "system" if data == /^test/i
    end
end
route '/echo', EchoConnection
route '/:name/(:room)', MultiRoom
# # add Redis auto-scaling with:
# ENV['PL_REDIS_URL'] = "redis://:password@my.host:6389/0"
exit # if running in terminal, using irb

You can test it out by connecting to: ws://localhost:3000/nickname/myroom

to connect to multiple "rooms" (you need to re-write the code for JSON and multi-room), try: ws://localhost:3000/nickname/myroom,your_room

test the echo by connecting to ws://localhost:3000/echo

Notice that the echo acts differently and allows you to have different websockets for different concerns - i.e., having one connection for updates and messages using JSON and another for multiple file uploading using raw binary data over websockets.

Community
  • 1
  • 1
Myst
  • 18,516
  • 2
  • 45
  • 67
  • It looks like yet another broadcasting chat. Seems I need something else, or maybe I don't get how to manage separate rooms – zuba Nov 23 '15 at 08:02
  • 1
    You can use different connection routes, with different controllers, to manage "rooms". These "rooms" can communicate with each other, either sending messages to everyone in a room or targeting specific connections (or a single connection) disregarding which "room" they connected to. – Myst Nov 23 '15 at 08:08
  • My pleasure, @zuba :) – Myst Nov 24 '15 at 07:05