RabbitMQのキュー遅延、遅延プッシュメッセージ


シナリオ

現在の一般的なアプリケーション・ソフトウェアは、プッシュされたメッセージの影を遅らせたことは、次のような多くのアプリケーションを、発見しました:

  • 淘宝網は7日、自動的に受信を確認します。商品の私達の受領後、物流システムが7日決済システムにメッセージを送信した後に遅らせます、決済システムが通知されます事業を呼ぶ、このプロセスは、遅延機能プッシュメッセージングミドルウェアを使用することである7日間続きました。
  • 12306チケット入金確認ページ。私たちは、チケットが、多くの場合、順序を表す、カウントダウンがあるだろうのページにジャンプするには、[OK]をクリックして選択し、30分以内に確認されていない場合、自動的に注文をキャンセルします。実際には、発券サービスシステムを注文した瞬間は、私たちは30分以内に注文を完了した場合、それはロジックコードによって判断することができ、注文システムの受注残を伝えるために30分を遅らせ、注文システムを遅らせるために、メッセージを送信しますうち、受信したメッセージを無視します。

我々は、次の2つの従来の解決策を使用する場合、上記の2つのシナリオでは、間違いなく大幅にシステムの全体の性能とスループットを低下させます。

  • 使用Redisのは、注文が完了しているかどうかがRedisの順序が決定するかどうかを決定することにより、最終的に注文する有効期限を設定し、そして。我々はRedisのがメモリに格納されている知っているので、このソリューションは、低レイテンシ性能のプッシュメッセージに比べて、我々はメモリ上の巨大な圧力を置く悪質な注文やスキャルピングに遭遇しました。
  • データベーステーブルの注文のステータスを決定するために、従来のデータベース・ポーリングを使用して、それはIOの数、非常に低いパフォーマンスが向上します。
  • DelayQueueのJVMのネイティブを使用し、それはまた、メモリを大量に消費され、そしてそこには永続化戦略はありませんか、すぐに情報が失われます注文システムを再起動します。

メッセージ遅延の実現をプッシュ

RabbitMQの3.6.xのは、我々は一般的に遅延キューを実現するためのデッドレターキュー+ TTLの有効期限を使用する前に、あなたが理解して記事を参照することができます前に、我々は、ここではあまり紹介をしない:TTL、不能キュー

RabbitMQの3.6.xのを始め、公式キュー遅延プラグインをRabbitMQを、あなたはRabbitMQののルートディレクトリに配置するプラグインをダウンロードすることができます。遅延は、プラグインのダウンロードキュー

まず、私たちは、スイッチとメッセージキューを作成し、application.propertiesは前回の記事と同じように構成されました。

import org.springframework.amqp.core.*;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;

import java.util.HashMap;
import java.util.Map;

@Configuration
public class MQConfig {

    public static final String LAZY_EXCHANGE = "Ex.LazyExchange";
    public static final String LAZY_QUEUE = "MQ.LazyQueue";
    public static final String LAZY_KEY = "lazy.#";

    @Bean
    public TopicExchange lazyExchange(){
        //Map<String, Object> pros = new HashMap<>();
        //设置交换机支持延迟消息推送
        //pros.put("x-delayed-message", "topic");
        TopicExchange exchange = new TopicExchange(LAZY_EXCHANGE, true, false, pros);
        exchange.setDelayed(true);
        return exchange;
    }

    @Bean
    public Queue lazyQueue(){
        return new Queue(LAZY_QUEUE, true);
    }

    @Bean
    public Binding lazyBinding(){
        return BindingBuilder.bind(lazyQueue()).to(lazyExchange()).with(LAZY_KEY);
    }
}

取引所の声明で私たちを設定することができますexchange.setDelayed(true)下の第1の方法は、これを達成するための方法ですので、遅延キューを開くために、あなたはまた、次のようになり、着信switch文の方法を設定することができます。

        //Map<String, Object> pros = new HashMap<>();
        //设置交换机支持延迟消息推送
        //pros.put("x-delayed-message", "topic");
        TopicExchange exchange = new TopicExchange(LAZY_EXCHANGE, true, false, pros);

我々は、遅延時間を指定する必要がメッセージを送信するとき、着信メッセージ・パラメータを送信する工程、ここで、押されnew MessagePostProcessor()得るためにMessageによって要求されるように、オブジェクトをMessageオブジェクトAPIの遅延時間が設定されています。

import com.anqi.mq.config.MQConfig;
import org.springframework.amqp.AmqpException;
import org.springframework.amqp.core.Message;
import org.springframework.amqp.core.MessageDeliveryMode;
import org.springframework.amqp.core.MessagePostProcessor;
import org.springframework.amqp.rabbit.connection.CorrelationData;
import org.springframework.amqp.rabbit.core.RabbitTemplate;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;

import java.util.Date;

@Component
public class MQSender {

    @Autowired
    private RabbitTemplate rabbitTemplate;

    //confirmCallback returnCallback 代码省略,请参照上一篇
  
    public void sendLazy(Object message){
        rabbitTemplate.setMandatory(true);
        rabbitTemplate.setConfirmCallback(confirmCallback);
        rabbitTemplate.setReturnCallback(returnCallback);
        //id + 时间戳 全局唯一
        CorrelationData correlationData = new CorrelationData("12345678909"+new Date());

        //发送消息时指定 header 延迟时间
        rabbitTemplate.convertAndSend(MQConfig.LAZY_EXCHANGE, "lazy.boot", message,
                new MessagePostProcessor() {
            @Override
            public Message postProcessMessage(Message message) throws AmqpException {
                //设置消息持久化
                message.getMessageProperties().setDeliveryMode(MessageDeliveryMode.PERSISTENT);
                //message.getMessageProperties().setHeader("x-delay", "6000");
                message.getMessageProperties().setDelay(6000);
                return message;
            }
        }, correlationData);
    }
}

我々が観察することができsetDelay(Integer i)、基礎となるコードをS-遅延のヘッダに配置されています。我々は、手動でヘッダを同等に設定します

message.getMessageProperties().setHeader("x-delay", "6000");

/**
 * Set the x-delay header.
 * @param delay the delay.
 * @since 1.6
 */
public void setDelay(Integer delay) {
    if (delay == null || delay < 0) {
        this.headers.remove(X_DELAY);
    }
    else {
        this.headers.put(X_DELAY, delay);
    }
}

消費のためのエンド・コンシューマー

import com.rabbitmq.client.Channel;
import org.springframework.amqp.rabbit.annotation.*;
import org.springframework.amqp.support.AmqpHeaders;
import org.springframework.stereotype.Component;

import java.io.IOException;
import java.util.Map;

@Component
public class MQReceiver {

    @RabbitListener(queues = "MQ.LazyQueue")
    @RabbitHandler
    public void onLazyMessage(Message msg, Channel channel) throws IOException{
        long deliveryTag = msg.getMessageProperties().getDeliveryTag();
        channel.basicAck(deliveryTag, true);
        System.out.println("lazy receive " + new String(msg.getBody()));

    }

テスト結果

import org.junit.Test;
import org.junit.runner.RunWith;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.test.context.SpringBootTest;
import org.springframework.test.context.junit4.SpringRunner;

@SpringBootTest
@RunWith(SpringRunner.class)
public class MQSenderTest {

    @Autowired
    private MQSender mqSender;

    @Test
    public void sendLazy() throws  Exception {
        String msg = "hello spring boot";

        mqSender.sendLazy(msg + ":");
    }
}

案の定、6秒のメッセージの受信後 lazy receive hello spring boot:




ありがとう、ソースを明記してください。https://www.cnblogs.com/haixiang/p/10966985.html

おすすめ

転載: www.cnblogs.com/haixiang/p/10966985.html