准备重用WebSocket连接服务器与Redis / ZeroMQ后端通缉

时间:2015-11-22 13:09:46

标签: websocket redis scalability zeromq

我需要水平可扩展的WebSocket连接服务器用于聊天系统,其中连接到不同WebSocket服务器的浏览器客户端可以在单独的聊天室中交换消息

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

此处client Aclient B通过HaProxy与两个不同的WebSocket servers相关联,后者通过Redis/ZeroMQ后端交换邮件,例如thatthat个问题。

考虑构建该架构,我想知道是否已经存在开源模拟。你建议看看这样的项目是什么?

1 个答案:

答案 0 :(得分:0)

查看Plezi Ruby框架。我是作者,它内置了自动Redis可扩展性。

(您只需使用Redis网址设置ENV['PL_REDIS_URL']

至于实现这一目标的架构,它很简单......我认为。

每个服务器实例“订阅”两个频道:用于“广播”的全球频道(发送给所有用户或大型“家庭”用户的消息)和用于“单播”的唯一频道(用于特定用户的消息)连接到服务器)。

每个服务器管理其内部广播系统,以便将消息路由到特定用户,连接家庭或所有用户,与目标受众一样。

您可以找到源代码here。 Redis集成使用this codewebsocket object code处理。

使用websocket object on_broadcast callback处理Web套接字广播。 Iodine服务器使用websocket implementation处理每个服务器实例中的内部广播。

我已将内部流程架构详细信息发布为an answer to this question

我认为socket.io也有跨服务器支持。

修改(部分代码)

由于评论,我认为我会添加一些代码......如果你编辑你的问题并添加更多关于你正在寻找的功能的规范,我可以在这里编辑代码。

我正在使用术语“房间”,因为这是你提到的,虽然我没有想到Plezi只是一个“聊天”框架,但它是一个非常简单的用例来展示它的实时能力。

如果您使用的是Ruby,则可以在irb终端中运行以下命令(确保先安装Plezi):

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

你可以通过连接到:ws:// localhost:3000 / nickname / myroom

来测试它

连接到多个“房间”(你需要重新编写JSON和多房间的代码),试试:ws:// localhost:3000 / nickname / myroom,your_room

通过连接到ws:// localhost:3000 / echo

来测试回声

请注意,echo的行为方式不同,并允许您为不同的关注点设置不同的websockets - 即,使用JSON有一个连接用于更新和消息,另一个用于通过websockets使用原始二进制数据进行多个文件上载。