我需要水平可扩展的WebSocket连接服务器来像系统一样聊天,其中连接到不同WebSocket服务器的浏览器客户端在单独的聊天室中交换消息。
Clients HaProxy WebSocket server1 WebSocket server2 Redis/ZeroMQ
| | | |
client A ----=------------>o<----------------|------------------>|
| | | |
client B ----=-------------|---------------->o<----------------->|
| | | |
在这里,client A
和client B
通过HaProxy
连接到两个不同的WebSocket servers
,它们通过后端交换消息Redis/ZeroMQ
就像那个问题一样。
想到构建这种架构,我想知道是否已经有一个开源模拟。您建议考虑哪个这样的项目?
查看 Plezi Ruby 框架。我是作者,它内置了自动 Redis 可扩展性。
(您只需使用 Redis URL 设置ENV['PL_REDIS_URL']
(
至于实现这一点的架构,它相当简单......我认为。
每个服务器实例"订阅"两个通道:一个用于"广播"的全局通道(发送给所有用户或大型"系列"用户的消息(和一个用于"单播"的唯一通道(用于连接到服务器的特定用户的消息(。
每个服务器都管理其内部广播系统,以便将消息路由到特定用户、连接系列或所有用户,作为其目标受众。
您可以在此处找到源代码。Redis 集成使用此代码和 websocket 目标代码进行处理。
Web 套接字广播使用 websocket 对象on_broadcast回调进行处理。碘服务器使用 websocket 实现处理每个服务器实例中的内部广播。
我已经发布了内部进程架构详细信息作为这个问题的答案
我认为 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 的作用不同,并允许您为不同的问题使用不同的 websocket - 即,使用JSON为更新和消息设置一个连接,为通过websockets使用原始二进制数据上传多个文件。