RocketMQ的使用

RocketMQ的使用

消费方式

<dependencies>
    <dependency>
        <groupId>org.apache.rocketmq</groupId>
        <artifactId>rocketmq-client</artifactId>
        <version>4.8.0</version>
    </dependency>
</dependencies>

生产者

/**
 * 生产者
 */
public class SenderTest {

    //演示消息同步发送
    public static void main(String[] args) throws InterruptedException, RemotingException, MQClientException, MQBrokerException {
        //生产者
        DefaultMQProducer producer = new DefaultMQProducer("hello-producerGroup");
        //设置name server地址
        producer.setNamesrvAddr("127.0.0.1:9876");
        //设置队列数量为2,有4个,根据情况设置
        producer.setDefaultTopicQueueNums(2);
        //启动
        producer.start();

//        for (int i = 0 ; i < 16 ; i++){

            Message message = new Message();
            //消息主题
            message.setTopic("hello-topic");
            //消息标签
            message.setTags("sms");
            //添加内容
            message.setBody(("我是消息").getBytes(CharsetUtil.UTF_8));
            //执行发送
            SendResult result = producer.send(message);
            //打印结果
            System.out.println(result);
//        }

        producer.shutdown();
    }
}



//消息发送者
public class ConsumerTest {

    public static void main(String[] args) {
        try {
            // 实例化消息生产者Producer
            DefaultMQPushConsumer consumer = new DefaultMQPushConsumer
                    ("hello-consumergroup");

            // 设置NameServer的地址
            consumer.setNamesrvAddr("127.0.0.1:9876");

            //设置消费模式
            //consumer.setMessageModel(MessageModel.CLUSTERING); //默认是集群
            consumer.setMessageModel(MessageModel.BROADCASTING); //默认是集群

            //从最开始的位置开始消费
            consumer.setConsumeFromWhere(ConsumeFromWhere.CONSUME_FROM_FIRST_OFFSET);

            // 订阅一个或者多个Topic,以及Tag来过滤需要消费的消息
            //和发送者保持一致才能搜到消息
            consumer.subscribe("hello-topic", "sms");

            // 注册回调实现类来处理从broker拉取回来的消息
            consumer.registerMessageListener(new MessageListenerConcurrently() {
                @Override
                public ConsumeConcurrentlyStatus consumeMessage(List<MessageExt> msgs,
                                                                ConsumeConcurrentlyContext context) {

                    msgs.forEach(message->{
                        System.out.println(message+" ; "+new String(message.getBody(), CharsetUtil.UTF_8));
                    });
                    //System.out.printf("%s 成功搜到消息: %s %n", Thread.currentThread().getName(), msgs);

                    // 标记该消息已经被成功消费 ack机制
                    return ConsumeConcurrentlyStatus.CONSUME_SUCCESS;
                }
            });
            // 启动Producer实例
            consumer.start();

        }catch (Exception e){
            e.printStackTrace();
        }
    }
}

运行两个consumer,分别测试集群和广播消费模式

1.普通消息

1.1.同步发送

同步消息是发送者发送消息,需要等待结果的返回,才能继续发送第二条消息,这是一种阻塞式模型,虽然消息可靠性高,但是阻塞导致性能低。API : SendResult result = producer.send(message); 代码示例:

发送者代码

public class Producer {

    //演示消息同步发送
    public static void main(String[] args) throws InterruptedException, RemotingException, MQClientException, MQBrokerException {
        //生产者
        DefaultMQProducer producer = new DefaultMQProducer("syn-producerGroup");
        //设置name server地址
        producer.setNamesrvAddr("127.0.0.1:9876");
//设置队列数量为2,默认为4,根据情况设置
        producer.setDefaultTopicQueueNums(2); 
        //启动
        producer.start();

        for (int i = 0 ; i < 16 ; i++){

            Message message = new Message();
            //消息主题
            message.setTopic("syn-topic");
            //消息标签
            message.setTags("sms");
            //添加内容
            message.setBody((i+"我是消息").getBytes(CharsetUtil.UTF_8));
            //执行发送
            SendResult result = producer.send(message);
            //打印结果
            System.out.println(result);
        }

        producer.shutdown();
    } }    

同步发送使用 SendResult result = producer.send(message); 方法即可,马上可以拿到返回值。SendResult 结果如下

SendResult [
sendStatus=SEND_OK, msgId=C0A8006516B018B4AAC270EF9D940000,offsetMsgId=C0A8006500002A9F0000000000008E1C, 
messageQueue=MessageQueue [topic=syn-topic, brokerName=LAPTOP-20VLGCRC, queueId=3], queueOffset=0]
  • SendStatus : 状态OK

  • msgId: 发送者生成的ID

  • OffsetMsgId : 由Broker生成的消息ID

  • MessageQueue :队列信息

1.2.异步发送

异步消息是发送者发送消息,无需等待发送结果就可以再发送第二条消息,它是通过回调的方式来获取到消息的发送结果,消息可靠性高,性能也高。API : producer.send(message,SendCallback) 示例代码:

. . . 省略. . .
producer.send(
        //创建消息对象
        new Message("asyn-topic", "sms", "我是消息".getBytes(CharsetUtil.UTF_8)),
        //添加发送回调
        new SendCallback() {

            //发送成功结果处理
            @Override
            public void onSuccess(SendResult sendResult) {
                System.out.println(sendResult);
            }
            //发送异常结果处理
            @Override
            public void onException(Throwable throwable) {
                System.out.println("发送异常:"+throwable.getMessage());
            }
        }
);

SendCallback 是消息发送结果回调。如果:sendResult.getSendStatus() == SendStatus.SEND_OK 表示成功

1.3.单向发送

这种方式指的是发送者发送消息后无需等待Broker的结果返回,Broker也不会返回结果,该方式性能最高,但是消息可靠性低。API : producer.sendOneway(message) 示例代码:

... 省略...
Message message = new Message("asyn-topic", "sms", "我是消息".getBytes(CharsetUtil.UTF_8));
producer.sendOneway(message);

sendOneway 单向发送是没有返回结果值的。

1.5.总结

下面对三种发送方式做一个对比

  • 可靠性最高: 同步发送 > 异步发送 > 单向发送

  • 性能最高:单向发送 > 异步发送 > 同步发送使用场景建议如下

  • 如果是比较重要的不可丢失的消息,且对时效性要求不高建议使用同步发送,如转账消息

  • 如果是不重要的可失败的消息,比如日志消息,建议使用单向发送

  • 如果对时效性要求比较高,且消息不能丢失,可以尝试使用异步发送

2.顺序消息

​ 在某些业务场景下是需要消息按照顺序进行消费,比如一个账户的加钱,减钱的动作必须按照时间先后去执行,否则就会发生金额不够导致操作失败。

按照发送的顺序进行消费就是顺序消息,遵循(FIFO), 默认生产者以Round Robin轮询方式把消息发送到不同的Queue分区队列;消费者从多个队列中消费消息,这种情况没法保证顺序。

2.1.全局有序

​ 全局有序是一个topic下的所有消息都要保证顺序,如果要保证消息全局顺序消费,就需要保证使用一个队列存放消息,一个消费者从这一个队列消费消息就能保证顺序,即:单线程执行,消费完了再去拉取producer.setDefaultTopicQueueNums(1);来指定队列数量。

1.发送者

可以通过代码指定创建1个队列即可

producer.setDefaultTopicQueueNums(1);
2.消费者

使用一个线程,一次只拉取一个消息 , 使用 MessageListenerOrderly 有序的消费消息。

//最大线程1个
defaultMQPushConsumer.setConsumeThreadMax(1);
defaultMQPushConsumer.setConsumeThreadMin(1);
//同时只拉取一个消息
defaultMQPushConsumer.setPullBatchSize(1);

.
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值