【问题标题】:Match response handler with request in VertX将响应处理程序与 VertX 中的请求匹配
【发布时间】:2016-12-20 02:33:18
【问题描述】:

假设我在 1..n 个 VertX (V) 实例前面有一个负载均衡器 (LB),每个 VertX 实例都连接到一个队列 (Q),并且我有 1..m 个后端 (BE)。

用户单击一个按钮,该按钮发出一个发布请求,甚至打开一个 Web 套接字,负载均衡器将请求转发到其中一个 VertX 实例,该实例向队列触发一个请求,其中一个后端使用该消息并发回响应;如果正确的 VertX 实例使用它,它可以查找响应处理程序并向用户写入响应,如果错误的 VertX 实例使用它,则不会有响应处理程序来写入响应,用户将无限期等待回复。

看这个草图:

或者,V2 死机并且负载平衡器将用户重新连接到 V1,这意味着即使我可以将其发送回发出请求的完全相同的用户,但不能保证在响应返回后仍然存在,但是用户可能仍在等待来自另一个 VertX 实例的响应。

我目前正在做的是为每个新连接生成一个 GUID,然后一旦 websocket 连接,将 websocket 处理程序存储在针对 GUID 的 hashmap 中,然后当 BE 想要响应时,它会进行扇出对于所有 1..n VertX 实例,当前在其哈希图中具有正确 GUID 的实例可以向用户写入响应。 以这种方式处理 POST / GET 也是如此。

伪代码:

queue.handler { q ->

  q.handler {
    val handler = someMap.get(q.guid)
    // only respond if handler exists
    if (handler != null){
        handler.writeResponse(someresponsemessagehere)
    }
  }

}

vertx.createHttpServer().websocketHandler { ws ->
  val guid = generateGUID()
  someMap.put(guid, ws)                                                                    
  ws.writeFinalTextFrame("guid=${guid}")
  ws.handler { 
    val guid = extractGuid(it)
    // send request to BE including generated GUID
    sendMessageToBE(guid, "blahblah")
  }

}.requestHandler { router.accept(it) }.listen(port)

但这确实意味着,如果我有 1000 个 VertX 应用程序正在运行,那么后端需要将其消息扇出到 1000 个前端实例,其中只有一个会使用该消息。

VertX 似乎已经很好地处理了异步操作,VertX 中有没有一种方法可以识别每个 websocket 连接,而不必维护映射到 websocket 处理程序/post 处理程序的 GUID 映射?

另外,参考图片,有没有办法让 V3 消费消息,但仍然能够向当前连接到 V2 的 websocket 处理程序写回响应?

【问题讨论】:

  • 我对 VertX 不熟悉,所以我可能会遗漏一些原本显而易见的东西,但为什么不使用 1..n 个队列(每个 VertX (V) 实例一个)或使用一个队列支持选择器以便客户端只能为它们消费消息(例如activemq.apache.org/how-do-i-consume-a-specific-message.html)?
  • 我们使用的是 RabbitMQ,我不认为 RabbitMQ 可以做到这一点 - 换句话说,专门从单个队列中消费特定消息。为了路由到 1000 个队列,您需要设置一个主题交换,如果我没记错的话,一个主题交换限制为 255 个主题。实际上,我在 2 年前就在 RabbitMQ 中寻找类似的功能:stackoverflow.com/questions/25489301/… 如果我们使用 ActiveMQ,也许这会是一个解决方案。
  • @JanVladimirMostert 作为一个附带问题,为什么您的“公式”中需要队列? Vert.x 默认情况下是异步的,并且假设您的所有操作都是非阻塞和异步的,我认为您实际上并不需要队列……而且“后端”也可以是(任何类型的)verticles。
  • @ɐuıɥɔɐɯ 这是一个多语言系统,Java、Kotlin、C#、VB、perl、Python、PHP 甚至一些 bash 脚本,并且有近 200 个应用程序坐在队列中,已经很高兴地互相聊天 -我正在将它们从 RPC 样式(阻塞)转换为异步。对于大多数应用程序,异步很容易,对于前端应用程序或集成,这很棘手,因为有一个物理连接等待响应写入它,所以它需要由保持连接打开的应用程序处理.

标签: java architecture kotlin vert.x


【解决方案1】:

您的图表中缺少的是 Vertx EventBus。

基本上你可以假设你的 V1...Vn 是相互关联的:

V1<->V2<->...<->Vn

假设 Va 收到您的出站 Q 消息(红线),该消息是针对 Vb 的。
然后它应该使用 EventBus 将其发送到 Vb:

eventBus.send("Vb UUID", "Message for Vb, also containing WebSocket UUID", ar -> {
  if (ar.succeeded()) {
    // All went well
  }
  else {
    // Vb died or has other problems. Your choice how to handle this
  }
});

【讨论】:

  • 所以根据您的建议,V1 到 V1000 启动并为自己生成一个 UUID,它们中的每一个都使用 GUID 通知其他实例它们的存在。当实例 V777 向队列发送消息时,它包含自己的 UUID,这样当实例 V367 消费响应时,它可以看到响应实际上是针对 V777 的,然后将其转发给 V777,然后 V777 完成循环。如果用户失去连接并重新连接到 V12 或 V777 死机,V367 将无法成功发送消息,V367 将从 V1 开始,nope,V2,nope ...,V12,yep 并完成循环。
  • 可以跨 Docker 容器使用 VertX Eventbus 吗?我想我只需要打开正确的端口就可以了?
  • 你明白了。关于 Docker,请查看这个(它也指原始的 Google 对话):stackoverflow.com/questions/39812848/…
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 2022-01-16
  • 1970-01-01
  • 1970-01-01
  • 2018-03-02
  • 1970-01-01
  • 2019-02-09
  • 2021-12-02
相关资源
最近更新 更多