RocketMQのJavaAPI

、、 Java API

説明:

  • RocketMQサーバーのバージョンは現在最新バージョンです:4.7.0
  • Javaクライアントバージョンで採用されている現在の最新バージョン:4.7.0
  • pomは次のとおりです
<dependency>
    <groupId>org.apache.rocketmq</groupId>
    <artifactId>rocketmq-client</artifactId>
    <version>4.7.0</version>
</dependency>

1、プロデューサー

メッセージを送信するには、次の条件が必要です。

  • 実動グループの名前を指定します(デフォルトの名前は使用できません。エラーが報告されます)

  • namesrvアドレスの構成(必須)

  • トピック名を指定してください(必須)

  • タグ/キーの指定(オプション)

メッセージが正常に送信されたことを確認します。メッセージが送信された後、コンシューマーを起動して使用するか、コントロールコンソールに移動してメッセージが存在するかどうかを確認します。

1.1、送信(同期)

public class Producer {
    public static void main(String[] args) throws Exception {
        // 指定生产组名为my-producer
        DefaultMQProducer producer = new DefaultMQProducer("my-producer");
        // 配置namesrv地址
        producer.setNamesrvAddr("124.57.180.156:9876");
        // 启动Producer
        producer.start();
        // 创建消息对象,topic为:myTopic001,消息内容为:hello world
        Message msg = new Message("myTopic001", "hello world".getBytes());
        // 发送消息到mq,同步的
        SendResult result = producer.send(msg);
        System.out.println("发送消息成功!result is : " + result);
        // 关闭Producer
        producer.shutdown();
        System.out.println("生产者 shutdown!");
    }
}

出力結果:

发送消息成功!result is : SendResult [sendStatus=SEND_OK, msgId=A9FE854140F418B4AAC26F7973910000, offsetMsgId=7B39B49D00002A9F00000000000589BE, messageQueue=MessageQueue [topic=myTopic001, brokerName=broker-a, queueId=0], queueOffset=7]
生产者 shutdown!

1.2、送信(バッチ)

public class ProducerMultiMsg {
    public static void main(String[] args) throws Exception {
        // 指定生产组名为my-producer
        DefaultMQProducer producer = new DefaultMQProducer("my-producer");
        // 配置namesrv地址
        producer.setNamesrvAddr("124.57.180.156:9876");
        // 启动Producer
        producer.start();

        String topic = "myTopic001";
        // 创建消息对象,topic为:myTopic001,消息内容为:hello world1/2/3
        Message msg1 = new Message(topic, "hello world1".getBytes());
        Message msg2 = new Message(topic, "hello world2".getBytes());
        Message msg3 = new Message(topic, "hello world3".getBytes());
		// 创建消息对象的集合,用于批量发送
        List<Message> msgs = new ArrayList<>();
        msgs.add(msg1);
        msgs.add(msg2);
        msgs.add(msg3);
        // 批量发送的api的也是send(),只是他的重载方法支持List<Message>,同样是同步发送。
        SendResult result = producer.send(msgs);
        System.out.println("发送消息成功!result is : " + result);
        // 关闭Producer
        producer.shutdown();
        System.out.println("生产者 shutdown!");
    }
}

出力結果:

发送消息成功!result is : SendResult [sendStatus=SEND_OK, msgId=A9FE854139C418B4AAC26F7D13770000,A9FE854139C418B4AAC26F7D13770001,A9FE854139C418B4AAC26F7D13770002, offsetMsgId=7B39B49D00002A9F0000000000058A62,7B39B49D00002A9F0000000000058B07,7B39B49D00002A9F0000000000058BAC, messageQueue=MessageQueue [topic=myTopic001, brokerName=broker-a, queueId=0], queueOffset=8]
生产者 shutdown!

結果から、msgIdは1つしかないことがわかります。したがって、メッセージオブジェクトは3つありますが、送信されるのは1回だけであり、クライアントとサーバーのオーバーヘッドを大幅に節約できます。

エラー状態:

バッチで送信されるトピックは同じである必要があります。メッセージオブジェクトが異なるトピックを指定している場合、バッチで送信するときにエラーが報告されます。

Exception in thread "main" org.apache.rocketmq.client.exception.MQClientException: Failed to initiate the MessageBatch
For more information, please visit the url, http://rocketmq.apache.org/docs/faq/
	at org.apache.rocketmq.client.producer.DefaultMQProducer.batch(DefaultMQProducer.java:950)
	at org.apache.rocketmq.client.producer.DefaultMQProducer.send(DefaultMQProducer.java:898)
	at com.chentongwei.mq.rocketmq.ProducerMultiMsg.main(ProducerMultiMsg.java:29)
Caused by: java.lang.UnsupportedOperationException: The topic of the messages in one batch should be the same
	at org.apache.rocketmq.common.message.MessageBatch.generateFromList(MessageBatch.java:58)
	at org.apache.rocketmq.client.producer.DefaultMQProducer.batch(DefaultMQProducer.java:942)
	... 2 more

1.3、sendCallBack(非同期)

public class ProducerASync {
    public static void main(String[] args) throws Exception {
       // 指定生产组名为my-producer
        DefaultMQProducer producer = new DefaultMQProducer("my-producer");
        // 配置namesrv地址
        producer.setNamesrvAddr("124.57.180.156:9876");
        // 启动Producer
        producer.start();
        
        // 创建消息对象,topic为:myTopic001,消息内容为:hello world async
        Message msg = new Message("myTopic001", "hello world async".getBytes());
        // 进行异步发送,通过SendCallback接口来得知发送的结果
        producer.send(msg, new SendCallback() {
            // 发送成功的回调接口
            @Override
            public void onSuccess(SendResult sendResult) {
                System.out.println("发送消息成功!result is : " + sendResult);
            }
			// 发送失败的回调接口
            @Override
            public void onException(Throwable throwable) {
                throwable.printStackTrace();
                System.out.println("发送消息失败!result is : " + throwable.getMessage());
            }
        });

        producer.shutdown();
        System.out.println("生产者 shutdown!");
    }
}

出力結果:

生产者 shutdown!
java.lang.IllegalStateException: org.apache.rocketmq.remoting.exception.RemotingConnectException: connect to [124.57.180.156:9876] failed
	at org.apache.rocketmq.client.impl.factory.MQClientInstance.updateTopicRouteInfoFromNameServer(MQClientInstance.java:681)
	at org.apache.rocketmq.client.impl.factory.MQClientInstance.updateTopicRouteInfoFromNameServer(MQClientInstance.java:511)
	at org.apache.rocketmq.client.impl.producer.DefaultMQProducerImpl.tryToFindTopicPublishInfo(DefaultMQProducerImpl.java:692)
	at org.apache.rocketmq.client.impl.producer.DefaultMQProducerImpl.sendDefaultImpl(DefaultMQProducerImpl.java:556)
	at org.apache.rocketmq.client.impl.producer.DefaultMQProducerImpl.access$300(DefaultMQProducerImpl.java:97)
	at org.apache.rocketmq.client.impl.producer.DefaultMQProducerImpl$4.run(DefaultMQProducerImpl.java:510)
	at java.util.concurrent.Executors$RunnableAdapter.call(Executors.java:511)
	at java.util.concurrent.FutureTask.run(FutureTask.java:266)
	at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1142)
	at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:617)
	at java.lang.Thread.run(Thread.java:745)
Caused by: org.apache.rocketmq.remoting.exception.RemotingConnectException: connect to [124.57.180.156:9876] failed
	at org.apache.rocketmq.remoting.netty.NettyRemotingClient.getAndCreateNameserverChannel(NettyRemotingClient.java:441)
	at org.apache.rocketmq.remoting.netty.NettyRemotingClient.getAndCreateChannel(NettyRemotingClient.java:396)
	at org.apache.rocketmq.remoting.netty.NettyRemotingClient.invokeSync(NettyRemotingClient.java:365)
	at org.apache.rocketmq.client.impl.MQClientAPIImpl.getTopicRouteInfoFromNameServer(MQClientAPIImpl.java:1371)
	at org.apache.rocketmq.client.impl.MQClientAPIImpl.getTopicRouteInfoFromNameServer(MQClientAPIImpl.java:1361)
	at org.apache.rocketmq.client.impl.factory.MQClientInstance.updateTopicRouteInfoFromNameServer(MQClientInstance.java:624)
	... 10 more
发送消息失败!result is : org.apache.rocketmq.remoting.exception.RemotingConnectException: connect to [124.57.180.156:9876] failed

なぜエラーを報告したのですか?非常にシンプルです。非同期です。結果からわかります。非同期なので、まだmqに送信していないので、最初にシャットダウンする必要があります。確かにそうではないので、効果を確認するためにシャットダウンする前に1秒スリープします

public class ProducerASync {
    public static void main(String[] args) throws Exception {
       // 指定生产组名为my-producer
        DefaultMQProducer producer = new DefaultMQProducer("my-producer");
        // 配置namesrv地址
        producer.setNamesrvAddr("124.57.180.156:9876");
        // 启动Producer
        producer.start();
        
        // 创建消息对象,topic为:myTopic001,消息内容为:hello world async
        Message msg = new Message("myTopic001", "hello world async".getBytes());
        // 进行异步发送,通过SendCallback接口来得知发送的结果
        producer.send(msg, new SendCallback() {
            // 发送成功的回调接口
            @Override
            public void onSuccess(SendResult sendResult) {
                System.out.println("发送消息成功!result is : " + sendResult);
            }
			// 发送失败的回调接口
            @Override
            public void onException(Throwable throwable) {
                throwable.printStackTrace();
                System.out.println("发送消息失败!result is : " + throwable.getMessage());
            }
        });
        
        Thread.sleep(1000);

        producer.shutdown();
        System.out.println("生产者 shutdown!");
    }
}
  • 出力結果:
发送消息成功!result is : SendResult [sendStatus=SEND_OK, msgId=A9FE854106E418B4AAC26F8719B20000, offsetMsgId=7B39B49D00002A9F0000000000058CFC, messageQueue=MessageQueue [topic=myTopic001, brokerName=broker-a, queueId=1], queueOffset=2]
生产者 shutdown!

1.4、sendOneway

public class ProducerOneWay {
    public static void main(String[] args) throws Exception {
        // 指定生产组名为my-producer
        DefaultMQProducer producer = new DefaultMQProducer("my-producer");
        // 配置namesrv地址
        producer.setNamesrvAddr("124.57.180.156:9876");
        // 启动Producer
        producer.start();
        
		// 创建消息对象,topic为:myTopic001,消息内容为:hello world oneway
        Message msg = new Message("myTopic001", "hello world oneway".getBytes());
        // 效率最高,因为oneway不关心是否发送成功,我就投递一下我就不管了。所以返回是void
        producer.sendOneway(msg);
        System.out.println("投递消息成功!,注意这里是投递成功,而不是发送消息成功哦!因为我sendOneway也不知道到底成没成功,我没返回值的。");
        producer.shutdown();
        System.out.println("生产者 shutdown!");
    }
}

出力結果:

投递消息成功!,注意这里是投递成功,而不是发送消息成功哦!因为我sendOneway也不知道到底成没成功,我没返回值的。
生产者 shutdown!

1.5、効率の比較

sendOneway> sendCallBack>バッチの送信>シングルの送信

sendOnewayは結果を求めないので、納品は私が責任を負います。失敗しても成功しても、転送ステーションに相当します。来たら捨てます。私は他の処理は行いません。だから最速。

また、sendCallBackは、同期送信よりも確実に効率的です。

バッチ送信とシングル送信の効率もさまざまな状況に分けられます。送信するメッセージが1つしかない場合でも、バッチは引き続き使用され、シングル送信は直接実行されます。

2、消費者

各消費者は1つのトピックのみをフォローできます。

メッセージを送信するには、次の条件が必要です。

  • コンシューマーグループの名前を指定します(デフォルトの名前は使用できません。エラーが報告されます)

  • namesrvアドレスの構成(必須)

  • トピック名を指定してください(必須)

  • タグ/キーの指定(オプション)

2.1、クラスタリング

クラスターモード、デフォルト。

たとえば、5つのコンシューマーを開始し、プロデューサーがメッセージを生成した後、ブローカーはメッセージを消費する5つのコンシューマーの1つを選択するため、ポイントツーポイントの消費モデルに属します。

public class Consumer {
    public static void main(String[] args) throws Exception {
        // 指定消费组名为my-consumer
        DefaultMQPushConsumer consumer = new DefaultMQPushConsumer("my-consumer");
        // 配置namesrv地址
        consumer.setNamesrvAddr("124.57.180.156:9876");
        // 订阅topic:myTopic001 下的全部消息(因为是*,*指定的是tag标签,代表全部消息,不进行任何过滤)
        consumer.subscribe("myTopic001", "*");
        // 注册监听器,进行消息消息。
        consumer.registerMessageListener(new MessageListenerConcurrently() {
            @Override
            public ConsumeConcurrentlyStatus consumeMessage(List<MessageExt> msgs, ConsumeConcurrentlyContext consumeConcurrentlyContext) {
                for (MessageExt msg : msgs) {
                    String str = new String(msg.getBody());
                    // 输出消息内容
                    System.out.println(str);
                }
                // 默认情况下,这条消息只会被一个consumer消费,这叫点对点消费模式。也就是集群模式。
                // ack确认
                return ConsumeConcurrentlyStatus.CONSUME_SUCCESS;
            }
        });
        // 启动消费者
        consumer.start();
        System.out.println("Consumer start");
    }
}

2.2、放送

ブロードキャストモード。

たとえば、5つのコンシューマーを開始し、プロデューサーがメッセージを生成した後、ブローカーはメッセージを5つのコンシューマーにブロードキャストします。5つのコンシューマーは1回消費し、それぞれが1回消費します。

// 代码里只需要添加如下这句话即可:
consumer.setMessageModel(MessageModel.BROADCASTING); 

2.3.2つのモードの比較

  • クラスターはデフォルトでデフォルトであり、ブロードキャストモードは手動で構成する必要があります。
  • メッセージ:クラスターモードの複数のコンシューマーには、消費するコンシューマーが1つだけあります。ブロードキャストモードの各コンシューマーは、このメッセージを消費します。
  • ブロードキャストモードでは、メッセージを送信した後、現在ブロードキャストされているすべてのコンシューマーによって消費されますが、新しく追加されたコンシューマーはこのメッセージを消費しません。理解しやすいです。村のスピーカーが村全体に卵を集めるように叫びました。 、そして2番目のあなたの村の新しい人、その人は昨日ラウドスピーカーによって叫ばれたニュースを聞いていなかったに違いありません。

3、TAG && KEY

メッセージを送信/消費するときに、タグ/キーを指定してメッセージをフィルタリングし、ワイルドカードをサポートできます。*これは、フィルタリングせずにこのトピックの下のすべてのメッセージを消費することを意味します。

org.apache.rocketmq.common.message.Messageソースコードを見ると、メッセージを送信するときにタグとキーを指定できることがわかります。

public Message(String topic, String tags, String keys, byte[] body) {
    this(topic, tags, keys, 0, body, true);
}

といった:

public class ProducerTagsKeys {
    public static void main(String[] args) throws Exception {
        // 指定生产组名为my-producer
        DefaultMQProducer producer = new DefaultMQProducer("my-producer");
        // 配置namesrv地址
        producer.setNamesrvAddr("124.57.180.156:9876");
        // 启动Producer
        producer.start();
        // 创建消息对象,topic为:myTopic001,消息内容为:hello world,且tags为:test-tags,keys为test-keys
        Message msg = new Message("myTopic001", "test-tags", "test-keys", "hello world".getBytes());
        // 发送消息到mq,同步的
        SendResult result = producer.send(msg);
        System.out.println("发送消息成功!result is : " + result);
        // 关闭Producer
        producer.shutdown();
        System.out.println("生产者 shutdown!");
    }
}

出力結果:

发送消息成功!result is : SendResult [sendStatus=SEND_OK, msgId=A9FE854149DC18B4AAC26FA4B7200000, offsetMsgId=7B39B49D00002A9F0000000000058DA6, messageQueue=MessageQueue [topic=myTopic001, brokerName=broker-a, queueId=3], queueOffset=3]
生产者 shutdown!

コントロールコンソールを見ると、タグとキーがすでに有効になっていることがわかり
ここに画像の説明を挿入します
ます。消費時に*を指定すると、このトピックのすべてのメッセージになります。次のようなプレフィックスワイルドカードを指定できます。

// 这样就只会消费myTopic001下的tag为test-*开头的消息。
consumer.subscribe("myTopic001", "test-*");

// 代表订阅Topic为myTopic001下的tag为TagA或TagB的所有消息
consumer.subscribe("myTopic001", "TagA||TagB");

また、あまり一般的ではないSQL式フィルタリングもサポートしています。BBはもうありません。

2つのよくある間違い

1、sendDefaultImpl呼び出しタイムアウト

1.1、異常

Exception in thread "main" org.apache.rocketmq.remoting.exception.RemotingTooMuchRequestException: sendDefaultImpl call timeout
	at org.apache.rocketmq.client.impl.producer.DefaultMQProducerImpl.sendDefaultImpl(DefaultMQProducerImpl.java:666)
	at org.apache.rocketmq.client.impl.producer.DefaultMQProducerImpl.send(DefaultMQProducerImpl.java:1342)
	at org.apache.rocketmq.client.impl.producer.DefaultMQProducerImpl.send(DefaultMQProducerImpl.java:1288)
	at org.apache.rocketmq.client.producer.DefaultMQProducer.send(DefaultMQProducer.java:324)
	at com.chentongwei.mq.rocketmq.Producer.main(Producer.java:18)

1.2、解決する

1.クラウドサーバーの場合は、最初にセキュリティグループがポート9876へのアクセスを許可しているかどうか、ファイアウォールがオンになっているかどうか、オンになっている場合は9876がマップアウトされているかどうかを確認します。

2.構成ファイルを変更しbroker.conf、以下を追加します。

brokerIP1=我用的是阿里云服务器,这里是我的公网IP

namesrvとbrokerを起動するときにローカルIPを追加します(Alibaba Cloudサーバーを使用しています。これがパブリックIPです)。

./bin/mqnamesrv -n IP:9876
./bin/mqbroker -n IP:9876 -c conf/broker.conf

2、このトピックのルート情報はありません

2.1、異常

Exception in thread "main" org.apache.rocketmq.client.exception.MQClientException: No route info of this topic: myTopic001
See http://rocketmq.apache.org/docs/faq/ for further details.
	at org.apache.rocketmq.client.impl.producer.DefaultMQProducerImpl.sendDefaultImpl(DefaultMQProducerImpl.java:684)
	at org.apache.rocketmq.client.impl.producer.DefaultMQProducerImpl.send(DefaultMQProducerImpl.java:1342)
	at org.apache.rocketmq.client.impl.producer.DefaultMQProducerImpl.send(DefaultMQProducerImpl.java:1288)
	at org.apache.rocketmq.client.producer.DefaultMQProducer.send(DefaultMQProducer.java:324)
	at com.chentongwei.mq.rocketmq.Producer.main(Producer.java:18)

2.2。解決する

明らかに送信は成功しました。今はタイムアウトではありませんが、そのようなトピックはないことがわかります。毎回手動で作成することはできないため、ブローカーを起動するときにパラメーターを指定して、ブローカーが自動的に作成できるようにすることができます。次のように

./bin/mqbroker -n IP:9876 -c conf/broker.conf autoCreateTopicEnable=true
  •  

おすすめ

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