当前位置: 首页 > 知识库问答 >
问题:

多服务器环境中的用户目标?(SpringWebSocket和RabbitMQ)

戚衡
2023-03-14

Spring WebSocket的留档状态为:

应用程序可以发送针对特定用户的消息,为此,Spring的STOMP支持识别前缀为“/user/”的目的地。例如,客户端可能订阅目的地"/user/队列/位置更新"。该目的地将由UserDestinationMessageHandler处理,并转换为用户会话独有的目的地,例如"/队列/位置-更新-用户123"。这提供了订阅通用命名目的地的便利,同时确保与订阅同一目的地的其他用户不发生冲突,以便每个用户都可以接收独特的股票头寸更新。

这应该在以RabbitMQ作为代理的多服务器环境中工作吗?

据我所知,用户的队列名称是通过附加simpSessionId来生成的。当使用推荐的客户端库时stomp.js这将导致第一个用户获得队列名称"/队列/位置-更新-用户0",下一个用户获得"/队列/位置-更新-用户1"等等。这反过来意味着第一个连接到不同服务器的用户将订阅相同的队列("/队列/位置-更新-用户0")。

我在文档中能找到的唯一参考是:

在多应用程序服务器场景中,用户目的地可能仍未解决,因为用户连接到不同的服务器。在这种情况下,您可以配置一个目标来广播未解析的消息,以便其他服务器有机会尝试。这可以通过Java配置中MessageBroker注册表的userDestinationBroadcast属性和XML中消息代理元素的user-endation-Broadcast属性来实现。

但这只能使与来自不同服务器的用户进行通信成为可能,而不是建立Web套接字的服务器。

我觉得我错过了什么?是否有配置Spring以安全使用MessagingTemplate的方法。convertAndSendToUser(principal.getName(),destination,payload)在多服务器环境中?

共有1个答案

邴宏大
2023-03-14

如果他们需要进行身份验证(我假设他们的凭据存储在数据库中),您可以始终使用他们的数据库唯一用户id进行订阅。

我所做的是,当用户登录时,他们会自动订阅两个主题,一个帐户|系统主题,用于系统范围的广播和帐户|

您可以尝试类似于通知的方法|

由于用户ID对每个用户都是唯一的,所以只要每个环境都访问相同的数据库信息,集群环境中就不应该有问题。

以下是我的发送方法:

  public static boolean send(Object msg, String topic) {
    try {
      String destination = topic;
      String payload = toJson(msg); //jsonfiy the message 
      Message<byte[]> message = MessageBuilder.withPayload(payload.getBytes("UTF-8")).build();
      template.send(destination, message);
      return true;
    } catch (Exception ex) {
      logger.error(CommService.class.getName(), ex);
      return false;
    }
  }

我的目的地是预格式化的,因此如果我想向id为的用户发送消息,目的地看起来像/topic/account | 1

我创建了一个乒乓球控制器,为连接的用户测试WebSocket,看看他们的环境是否允许WebSocket。我不知道这是否对您有帮助,但这在我的集群环境中确实有效。

/**
   * Play ping pong between the client and server to see if web sockets work
   * @param input the ping pong input
   * @return the return data to check for connectivity
   * @throws Exception exception
   */
  @MessageMapping("/ping")
  @SendToUser(value="/queue/pong", broadcast=false) // send only to the session that sent the request
  public PingPong ping(PingPong input) throws Exception {
    int receivedBytes = input.getData().length;
    int pullBytes = input.getPull();

    PingPong response = input;
    if (pullBytes == 0) {
      response.setData(new byte[0]);
    } else if (pullBytes != receivedBytes)  {
      // create random byte array
      byte[] data =  randomService.nextBytes(pullBytes);
      response.setData(data);
    }
    return response;
  }

 类似资料:
  • 我正在使用谷歌服务帐户将MySQL备份从我们的网络服务器推送到谷歌云端硬盘,使用谷歌API PHP客户端脚本设置为cron作业。 我现在想在多个网络服务器上运行相同的脚本,我不知道如何正确配置服务号,应该吗? > 是否在所有服务器上使用相同的服务帐户和服务帐户密钥/凭据? 或者使用相同的服务帐户,但为每个服务器添加服务帐户密钥/凭据? 还是为每台服务器设置单独的服务帐户?

  • 我需要为不同的环境加载属性,如DEV、QA和我为每个环境都有不同的属性文件。因此,我通过在服务器中设置environment属性并访问该值以加载相应的属性文件来解决这一问题。在谷歌搜索时,我发现spring环境配置文件提供了类似场景的解决方案。然而,即使在这里,我也必须将服务器中的active-profile变量设置为环境变量。 与本机方法相比,使用spring环境配置文件有什么好处?

  • 如何将App Engine功能与灵活环境(以前的托管VM)一起使用? 例如,我的旧应用程序使用图像API。如何在Fleixble环境中使用该API? App Engine中的功能列表:https://cloud.google.com/appengine/docs/about-the-standard-environment 图像API:https://cloud.google.com/appeng

  • 问题内容: 情况如下: 我有一个使用SP作为数据集的SSRS报告。SP创建一个临时表,在其中插入一堆数据,然后选择将其退回以供SSRS报告。挺直截了当的。 问题: 如果多个用户在选择了不同参数的情况下运行报表,SP创建的临时表是否会与tempdb冲突,并可能无法返回预期的数据集? 问题答案: 很有可能不会。如果将临时表定义为或,那么您是安全的,因为这类临时表只能由创建连接访问,并且仅在存储过程执行

  • 我为RSocket消息编写了一个小演示 问题是我无法访问endpoint,我从服务器收到以下异常: 客户端:配置: 我非常肯定这与新的函数有关,因为它接受了一个新的参数,所以我将它设置为application/json,但似乎不起作用 堆栈跟踪:

  • 我这样配置Spring Cloud Config服务器: 由于某些原因,resolvePlaceholders不适用于JSON表示,因此服务器配置客户机需要知道服务器上配置的所有ENV变量。 是否可以强制JSON表示resolvePlaceholders与纯文本(属性)表示相同?