简体   繁体   English

发送方如何知道接收方在使用 Spring 引导的 JMS 中不可用?

[英]How do the Sender know that the Receiver isn't available in JMS using Spring Boot?

I have a Spring Boot app, there are 2 microservices and these microservices communicate asynchronous using JMS and ActiveMq.我有一个 Spring 启动应用程序,有 2 个微服务,这些微服务使用 JMS 和 ActiveMq 进行异步通信。 So the Sender (ms1) sends a message to the Receiver (ms2), the Sender will put the message on the queue and if the Receiver isn't available, the message will stay on the queue until the Receiver is available.因此,Sender (ms1) 向 Receiver (ms2) 发送消息,Sender 会将消息放入队列,如果 Receiver 不可用,则消息将保留在队列中,直到 Receiver 可用。

I want to ask you how could the Sender knows if the Receiver is available or not?我想问您,Sender 怎么知道 Receiver 是否可用? I want to know that because I want to use Hystrix and if the Receiver is available the Sender will show a message like this: "Transaction successfully completed,", but if the Receiver isn't available the Sender will show other message: something like this, "The Receiver service isn't currently availble. the message is added to the queue and will be sended to the Receiver when it'll be available".我想知道,因为我想使用 Hystrix,如果接收器可用,发件人将显示如下消息:“交易成功完成”,但如果接收器不可用,发件人将显示其他消息:类似这个,“接收器服务当前不可用。消息被添加到队列中,当它可用时将被发送到接收器”。

This code is from the Sender service:此代码来自发件人服务:

    @HystrixCommand(fallbackMethod="sendMessageToProducerFail")
    private ResponseEntity sendMessageToProducer(String jsonStr) {
        jmsTemplate.convertAndSend(queue, jsonStr);
        return new ResponseEntity("Transaction successfully completed!", HttpStatus.CREATED);
    }

    private ResponseEntity sendMessageToProducerFail(String jsonStr) {
//        "The Receiver service isn't currently availble, the message is added to the queue..."
    }

There's no simple way to achieve this.没有简单的方法可以实现这一目标。 Identifying whether the consumer is up or not bring some of the design choices.确定消费者是否起床会带来一些设计选择。 Also, there's no out of box solution for your problem.此外,您的问题没有现成的解决方案。 You can use the concept of a heartbeat to notify producers about consumer state.您可以使用心跳的概念来通知生产者有关消费者 state 的信息。

+----------+               +-------------+              +--------+
|          |<--Heartbeat---|             |---Message--->|        |
| Producer |               | AMQP Server |              |Consumer|
|          |----Message--->|             |<--Heartbeat--|        |  
+----------+               +-------------+              +--------+

Your setup would look somewhat like this, In this producer( ms1 ) will send messages to AMQP server and will consume Heartbeat events from the consumer(s), to identify whether the consumer(s) is/are alive.你的设置看起来有点像这样,在这个生产者中( ms1 )将向 AMQP 服务器发送消息,并将使用来自消费者的 Heartbeat 事件,以确定消费者是否还活着。 This will become more tricky when you have more than one producer/consumer for the same topic.当同一主题有多个生产者/消费者时,这将变得更加棘手。

Once you have more than once consumers, multiple heartbeats would be sent on the same topic/queue.一旦你有多个消费者,就会在同一个主题/队列上发送多个心跳。 You need to identify which one of them is alive, you need to also consider consumers going down/up.您需要确定其中哪一个还活着,您还需要考虑消费者的下降/上升。

Each heartbeat can have timestamp when it was generated so that you can make a consumer alive decision at a more granular level.每个心跳都可以在生成时具有时间戳,以便您可以在更细粒度的级别上做出消费者存活的决定。 The next question would be when to send a heartbeat?下一个问题是何时发送心跳? As you're using Spring boot you will not have the flexibility of sending heartbeat outside of the message listener.当您使用 Spring 启动时,您将无法灵活地在消息侦听器之外发送心跳。 If you're using the MessageListener interface then do something like this.如果您正在使用MessageListener接口,请执行以下操作。

Create a heartbeat publisher class创建心跳发布器 class

@Component
class HeartBeatPublisher {
   public void registerMessageListener( String listenerName,
                                        String topicOrQueueName,
                                        Long intervals) {
   // store this detail in a map 
   // do lazy init of threads to send heartbeat 
   }
}

Your message listener class would like您的消息监听器 class 想要

@Component
class MyMessageListener implements MessageListener {
   @Autowired HeartBitPublisher heartBeatPublisher;
   @PostConstruct
   public void init(){
      // 30 seconds interval
      heartBeatPublisher.registerMessageListener("MyMessageListener", 
                                                 "MyMessageListener",
                                                 30*1000 );
   }
   void onMessage(Message message){
     // consume message here
   }
}

In case you're not using MessageListener still you can send heartbeats, in that case, I would recommend adding one listener per component.如果您不使用MessageListener仍然可以发送心跳,在这种情况下,我建议为每个组件添加一个侦听器。

@Component
class MyMessageListener{
   @Autowired HeartBeatPublisher heartBeatPublisher;
   @PostConstruct
   public void init(){
     // 30 seconds interval
     heartBeatPublisher.registerMessageListener("MyMessageListener", 
                                                "MyMessageListener",
                                                30*1000 );
   }

   @RabbitListener(queues="myQueue")
   public void onMessage(Object message) {
    // Consume message
   }
}  

On the producer side, you need to add a listener(s) to check which consumer(s) is/are active using a heartbeat.在生产者方面,您需要添加一个侦听器以使用心跳检查哪些消费者处于活动状态。 Once you know which consumer(s) is/are active you can use that to restrict message publish.一旦您知道哪些消费者处于活动状态,您就可以使用它来限制消息发布。

@Component
class HeartBeatListener {
  private List<String> queues;
   @PostConstruct 
   public void init(){
      // initialize queue and consumer status to inactive
      // at certain intervals checks for missing heartbeat 
      // if you find heartbeats are not being sent that means either 
      // that consumer has died or there's a delay in heart bit 
      // publish in that case mark that consumer/topic/queue inactive
   }
  
   @RabbitListener(queues="myQueue-HeartBeat")
   public void onMessage(Object message) {
     // update consumer status 
     // Record heart beat for a given consumer/topic
   }
}  

Instead of doing all this, you can use Consul , Zookeeper , or Etcd to move some of the works to these systems.您可以使用ConsulZookeeperEtcd将一些工作转移到这些系统上,而不是执行所有这些操作。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM