RocketMQシーケンシャルメッセージの原理とコードを紹介します

1つは、シーケンスメッセージの解釈

1。概要

RocketMQメッセージはトピックキューに格納され、キュー自体はFIFO(First Int First Out)キューです。したがって、単一のキューで順序を保証できます。ただし、問題は、トピックにN個のキューがあることです。作成者の設計の利点も明らかです。クラスタリングと負荷分散の特性を自然にサポートし、各キューに大量のデータを均等に分散します。10個のメッセージをに送信します。同じトピック。、これらの10個のメッセージは、トピックの下のすべてのキューに自動的に分散されるため、消費するときに、どのキューが最初に消費され、どのキューが後で消費されるかは必ずしも必要ではなく、無秩序な消費につながります。

2.グラフィック

ここに画像の説明を挿入します

3.再度分析します

プロデューサーは、4つのメッセージm1、m2、m3、およびm4をトピックに送信します。トピックには4つのキューがあります。独自の負荷分散戦略により、4つのキューのそれぞれに1つのメッセージが格納されます。キュー1に格納されたm1、キュー2に格納されたm2、キュー3に格納されたm3、およびキュー4に格納されたm4。コンシューマはマルチスレッド消費を消費するため、送信の順序など、どのキューまたはメッセージが最初に消費されるかを保証できません。 m1、m2、m3、m4ですが、コンシューマーはコンシューマー内の複数のスレッドによって消費されるため、最初にqueue4キューのm4を消費し、次にm1を消費する可能性があります。これは無秩序につながります。

二、解決策

1.オプション1

簡単に言うと、問題の鍵は、複数のキューにメッセージがあることです。消費すると、どのキューのメッセージが最新かわかりません。メッセージを送信するときに秩序を確保したい場合は、メッセージをキューに送信してから、消費するときに送信します。そのキューだけにメッセージがあり、キューはFIFOであるため、先入れ先出しなので、通常の消費です。終わった。非常に完璧な。また、RocketMQは、メッセージの送信時にキューを選択するためのAPI(MessageQueueSelector)も提供します。コードに直接移動します。

2.コード1

2.1。プロデューサー

import java.util.List;
import org.apache.rocketmq.client.producer.DefaultMQProducer;
import org.apache.rocketmq.client.producer.MessageQueueSelector;
import org.apache.rocketmq.common.message.Message;
import org.apache.rocketmq.common.message.MessageQueue;

/**
 * 消息发送者
 */
public class Producer5 {
	public static void main(String[] args)throws Exception {
		DefaultMQProducer producer = new DefaultMQProducer("my-order-producer");
		producer.setNamesrvAddr("124.57.180.156:9876");		
		producer.start();
		for (int i = 0; i < 5; i++) {
			Message message = new Message("orderTopic", ("hello!" + i).getBytes());
			producer.send(
					// 要发的那条消息
					message,
					// queue 选择器 ,向 topic中的哪个queue去写消息
					new MessageQueueSelector() {
						// 手动 选择一个queue
                        @Override
						public MessageQueue select(
								// 当前topic 里面包含的所有queue
								List<MessageQueue> mqs, 
								// 具体要发的那条消息
								Message msg,
								// 对应到 send() 里的 args,也就是2000前面的那个0
                            	// 实际业务中可以把0换成实际业务系统的主键,比如订单号啥的,然后这里做hash进行选择queue等。能做的事情很多,我这里做演示就用第一个queue,所以不用arg。
								Object arg) {
							// 向固定的一个queue里写消息,比如这里就是向第一个queue里写消息
							MessageQueue queue = mqs.get(0);
							// 选好的queue
							return queue;
						}
					},
					// 自定义参数:0
                    // 2000代表2000毫秒超时时间
					0, 2000);
		}
	}
}

2.2。消費者

import org.apache.rocketmq.client.consumer.DefaultMQPushConsumer;
import org.apache.rocketmq.client.consumer.listener.*;
import org.apache.rocketmq.common.message.MessageExt;

import java.util.List;

/**
 * Description:
 *
 * @author TongWei.Chen 2020-06-22 11:17:47
 */
public class ConsumerOrder {
    public static void main(String[] args) throws Exception {
        DefaultMQPushConsumer consumer = new DefaultMQPushConsumer("my-consumer");
        consumer.setNamesrvAddr("124.57.180.156:9876");
        consumer.subscribe("orderTopic", "*");
        consumer.registerMessageListener(new MessageListenerOrderly() {
            @Override
            public ConsumeOrderlyStatus consumeMessage(List<MessageExt> msgs, ConsumeOrderlyContext context) {
                for (MessageExt msg : msgs) {
                    System.out.println(new String(msg.getBody()) + " Thread:" + Thread.currentThread().getName() + " queueid:" + msg.getQueueId());
                }
                return ConsumeOrderlyStatus.SUCCESS;
            }
        });

        consumer.start();
        System.out.println("Consumer start...");
    }
}

2.3、出力結果

Consumer start...
hello!0 Thread:ConsumeMessageThread_1 queueid:0
hello!1 Thread:ConsumeMessageThread_1 queueid:0
hello!2 Thread:ConsumeMessageThread_1 queueid:0
hello!3 Thread:ConsumeMessageThread_1 queueid:0
hello!4 Thread:ConsumeMessageThread_1 queueid:0

非常に完璧で整然とした出力!

3.状況2

たとえば、新しい要件:すべての未払いの注文をqueue1に入れ、有料の注文をqueue2に入れ、異常な支払いの注文をqueue3に入れます。次に、消費するときに各キューが正しいことを確認する必要があります。、queue1を消費できず、直接queue2。キューを1つずつ消費する必要があります。

現時点では、メッセージを送信するときにカスタムパラメータargを使用することをお勧めします。メッセージ本文には支払いステータスが含まれている必要があります。未払いと判断された場合は、queue1などを選択します。これにより、各キューに同じ状態のメッセージのみが含まれるようになります。そのため、現在、コンシューマーは複数のスレッドによって消費されていますが、これは故障している必要があります。3つのキューがランダムに消費されます。解決策はより単純で、コンシューマー側のスレッド数を直接1に変更して、キューがFIFOになり、コンシューマー側が1つずつ消費するようにします。RocketMQは、次の2つの文でそのようなAPIも提供します。

// 最大线程数1
consumer.setConsumeThreadMax(1);
// 最小线程数
consumer.setConsumeThreadMin(1);
  •  

おすすめ

転載: blog.csdn.net/qq_33762302/article/details/114784066