使用Message Queue处理REST请求

时间:2017-11-04 08:35:12

标签: rest spring-boot apache-storm mq

我有两个申请,如下所述:

  1. Spring启动应用程序 - 作为休息终点,将请求发布到消息队列。 (Apache Pulsar)
  2. Heron(Storm)拓扑 - 处理从消息队列(PULSAR)收到的消息,并具有所有处理逻辑。
  3. 我的要求,我需要通过Spring启动应用程序提供不同的用户查询,Spring应用程序将该查询发送到消息队列,并在spout中使用。一旦喷口和螺栓处理请求,就会再次从螺栓中发布消息。 Bolt的响应在Spring引导(消费者)处理,并回复用户请求。典型如下所示:

    enter image description here

    为了服务于同一个请求,我现在正在缓存延迟结果对象(我为每个发送到拓扑的消息设置了一个reqID,我还维护了一个密钥,值对),当消息到达时我解析请求ID并将结果设置为defferedResult(我知道这是一个糟糕的设计,如何解决这个问题?)。

    如何在这种情况下继续将响应提供回同一请求,其中从拓扑接收的消息顺序不是顺序的(因为每个请求都是进程需要自己的时间,而生成器bolt将触发响应,如同当它收到一个)。

    我有点坚持这种设计,无法继续前进。

    //Controller
    public DeferredResult<ResponseEntity<?>> process(//someinput) {
        DeferredResult<ResponseEntity<?>> result = new DeferredResult<>(config.getTimeout());
        CompletableFuture<String> serviceResponse = service.processAsync(inputSource);
        serviceResponse.whenComplete((response, exception) -> {
            if (!ObjectUtils.isEmpty(exception))
                result.setErrorResult(//error);
            else
                result.setResult(//complete);
        });
        return result;
    }
    
    //In Service
    public CompletableFuture processAsync(//input){
        producer.send(input);
        CompletableFuture result = new CompletableFuture();
        //consumer has a listener as shown below
        // **I want to avoid below line, how can I redesign this**
        map.put(id, result);
      return result;
    }
    
    //in same service, a listener is present for consumer for reading the messages
    consumerListener(Message msg){
         int reqID = msg.getRequestID();
         map.get(reqID).complete(msg.getData);
    }
    
      

    如上所示,只要收到消息,我就会获得completableFuture   对象并设置结果,它通常会调用defferred结果   对象并将响应返回给用户。

1 个答案:

答案 0 :(得分:0)

  

如何在这种情况下继续将响应提供回同一请求,其中从拓扑接收的消息顺序不是顺序的(因为每个请求都是进程需要自己的时间,而生成器bolt将触发响应,如同当它收到一个)。

听起来您正在寻找Correlation Identifier消息传递模式。大致来说,您计算/创建一个附加到发送到脉冲星的消息的标识符,并安排Heron将该标识符从它接收的请求复制到它发送的响应。

因此,当您的Spring Boot组件在步骤5中使用来自脉冲星的消息时,您将相关ID与正确的http请求相匹配,并返回结果。

据我所知,使用原始的requestId()作为您的相关标识符应该没问题。

  

为了服务于同一个请求,我现在正在缓存延迟结果对象(我为每个发送到拓扑的消息设置了一个reqID,我还维护了一个密钥,值对),当消息到达时我解析请求id并将结果设置为defferedResult(我知道这是一个糟糕的设计,如何解决这个问题?)。

最终,你可能会在某种程度上这样做;也就是说,步骤5中的消费者将使用相关ID来查找由生产者存储的某物。试图将原始请求传递到四个不同的流程边界可能会以泪流满面。

更通用的形式是在地图中存储回调而不是CompletableFuture;但在这种情况下,回调可能只是完成未来。

我想在设计中仔细检查一件事:您希望确保步骤5中的消费者在消息到达之前看到它应该使用的未来。换句话说,在某个地方应该有一个发生前的内存屏障,以确保步骤5中的地图查找不会失败。