RocketMQ - API

2、Consumer

每个consumer只能关注一个topic。

发消息肯定要必备如下几个条件:

  • 指定消费组名(不能用默认的,会报错)

  • 配置namesrv地址(必须)

  • 指定topic name(必须)

  • 指定tag/key(可选)

2.1、CLUSTERING

集群模式,默认。

比如启动五个Consumer,Producer生产一条消息后,Broker会选择五个Consumer中的其中一个进行消费这条消息,所以他属于点对点消费模式。

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、BROADCASTING

广播模式。

比如启动五个Consumer,Producer生产一条消息后,Broker会把这条消息广播到五个Consumer中,这五个Consumer分别消费一次,每个都消费一次。

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

2.3、两种模式对比

  • 集群默认是默认的,广播模式是需要手动配置。

  • 一条消息:集群模式下的多个Consumer只会有一个Consumer消费。广播模式下的每一个Consumer都会消费这条消息。

  • 广播模式下,发送一条消息后,会被当前被广播的所有Consumer消费,但是后面新加入的Consumer不会消费这条消息,很好理解:村里面大喇叭喊了全村来领鸡蛋,第二天你们村新来个人,那个人肯定听不到昨天大喇叭喊的消息呀。

3、TAG&&KEY

发送/消费 消息的时候可以指定tag/key来进行过滤消息,支持通配符。*代表消费此topic下的全部消息,不进行过滤。

看下org.apache.rocketmq.common.message.Message源码可以发现发消息的时候可以指定tag和keys:

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!

查看管控台,可以发现tags和keys已经生效了:

 

消费的时候如果指定*那就是此topic下的全部消息,我们可以指定前缀通配符,比如:

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

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

还支持SQL表达式过滤,不是很常用。不BB了。

4、常见错误

4.1、sendDefaultImpl call timeout

4.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)

4.1.2、解决

1.如果你是云服务器,首先检查安全组是否允许9876这个端口访问,是否开启了防火墙,如果开启了的话是否将9876映射了出去。

2.修改配置文件broker.conf,加上:

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

启动namesrv和broker的时候加上本机IP(我用的是阿里云服务器,这里是我的公网IP):

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

4.2、No route info of this topic

4.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)

4.2.2、解决

很明显发送成功了,不再是刚才的超时了,但是告诉我们没有这个topic。那不能每次都手动创建呀,所以启动broker的时候可以指定参数让broker为我们自动创建。如下

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

END

猜你喜欢

转载自blog.csdn.net/My_SweetXue/article/details/107381324