RokcetMQ之生产者消费者消息处理实例代码

首先创建springBoot项目,并引入依赖包

        <dependency>
		   <groupId>org.apache.rocketmq</groupId>
		   <artifactId>rocketmq-client</artifactId>
		   <version>4.4.0</version>
		</dependency>
		<dependency>
		    <groupId>com.alibaba</groupId>
		    <artifactId>fastjson</artifactId>
		    <version>1.2.59</version>
		</dependency>
		<dependency>
		    <groupId>org.slf4j</groupId>
		    <artifactId>slf4j-api</artifactId>
		    </dependency>
		<dependency>
		    <groupId>org.slf4j</groupId>
		    <artifactId>slf4j-nop</artifactId>
		</dependency>

生产者

发送消息的代码(同步消息及单向)


import org.apache.rocketmq.client.producer.DefaultMQProducer;
import org.apache.rocketmq.client.producer.SendResult;
import org.apache.rocketmq.client.producer.SendStatus;
import org.apache.rocketmq.common.message.Message;
import org.apache.rocketmq.remoting.common.RemotingHelper;

public class ProducerTest {

	public static void main(String[] args) throws Exception {
    	// 实例化消息生产者Producer 并确定生产者组
        DefaultMQProducer producer = new DefaultMQProducer("sayGroup");
    	// 设置NameServer的地址 多个那么server地址可以用分号; 隔开
    	producer.setNamesrvAddr("localhost:9876");
    	// 启动Producer实例
        producer.start();
    	for (int i = 0; i < 10; i++) {
    	    // 创建消息,并指定Topic,Tag和消息体
    	    Message msg = new Message();
    	    msg.setTopic("TopicTest"); /* Topic */
    	    msg.setTags("TagA");/* Tag */
    	    msg.setBody(("Hello RocketMQ " + i).getBytes(RemotingHelper.DEFAULT_CHARSET));/* Message body */
    	    msg.setKeys("123456"); // key 业务层面的唯一标识码
            // msg.setDelayTimeLevel(3); // 设置延时等级3,这个消息将在10s之后发送
        	
            SendResult sendResult = producer.send(msg);// 发送消息到一个Broker (同步消息)
            // producer.sendOneway(msg); // 单向发送消息 没有响应,只有类似于日志系统不关心相应的才可能采用
            // 通过sendResult返回消息是否成功送达   SEND_OK 发送成功;
            System.out.println(sendResult);
            SendStatus sendStatus = sendResult.getSendStatus();
            // 判断结果
            if (sendStatus == SendStatus.SEND_OK) {
                System.out.println("信息发送成功!");
            } else {
                System.out.println("信息发送失败!");
            }
    	}
    	// 如果不再发送消息,关闭Producer实例。
    	producer.shutdown();
    }
}

异步发送消息


import org.apache.rocketmq.client.producer.DefaultMQProducer;
import org.apache.rocketmq.client.producer.SendCallback;
import org.apache.rocketmq.client.producer.SendResult;
import org.apache.rocketmq.common.message.Message;
import org.apache.rocketmq.remoting.common.RemotingHelper;

public class AsyncProducer {

	public static void main(String[] args) throws Exception {
    	// 实例化消息生产者Producer
        DefaultMQProducer producer = new DefaultMQProducer("say1Group");
    	// 设置NameServer的地址
        producer.setNamesrvAddr("localhost:9876");
    	// 启动Producer实例
        producer.start();
        producer.setRetryTimesWhenSendAsyncFailed(0);
    	for (int i = 0; i < 100; i++) {
                final int index = i;
            	// 创建消息,并指定Topic,Tag和消息体
                Message msg = new Message();
        	    msg.setTopic("TopicTest"); /* Topic */
        	    msg.setTags("TagA");/* Tag */
        	    msg.setBody(("Hello RocketMQ " + i).getBytes(RemotingHelper.DEFAULT_CHARSET));/* Message body */
        	    msg.setKeys("123456"); // key 业务层面的唯一标识码
                // SendCallback接收异步返回结果的回调
                producer.send(msg, new SendCallback() {
                    @Override
                    public void onSuccess(SendResult sendResult) {
                        System.out.printf("%-10d OK %s %n", index, sendResult.getMsgId());
                    }
                    @Override
                    public void onException(Throwable e) {
      	              System.out.printf("%-10d Exception %s %n", index, e);
      	              e.printStackTrace();
                    }
            	});
    	}
    	// 如果不再发送消息,关闭Producer实例。
    	producer.shutdown();
    }
}

消费者消费

push方式

由MQ主动地将消息推送给消费者;采用Push方式,可以尽可能实时地将消息发送给消费者进行消费。但是,在消费者的处理消息的能力较弱的时候(比如,消费者端的业务系统处理一条消息的流程比较复杂,其中的调用链路比较多导致消费时间比较久。概括起来地说就是“慢消费问题”),而MQ不断地向消费者Push消息,消费者端的缓冲区可能会溢出,导致异常;


import java.util.List;

import org.apache.rocketmq.client.consumer.DefaultMQPushConsumer;
import org.apache.rocketmq.client.consumer.listener.ConsumeConcurrentlyContext;
import org.apache.rocketmq.client.consumer.listener.ConsumeConcurrentlyStatus;
import org.apache.rocketmq.client.consumer.listener.MessageListenerConcurrently;
import org.apache.rocketmq.client.exception.MQClientException;
import org.apache.rocketmq.common.message.MessageExt;

public class ConsumerPush {

	public static void main(String[] args) throws InterruptedException, MQClientException {

    	// 实例化消费者
        DefaultMQPushConsumer consumer = new DefaultMQPushConsumer("listenGroup");

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

    	// 订阅一个或者多个Topic,以及Tag来过滤需要消费的消息  过滤tag可以使用 "TagA || TagC || TagD"  方式
        consumer.subscribe("TopicTest", "*");
    	// 注册监听类  回调实现类 MessageListenerConcurrently 来处理从broker拉取回来的消息 (Push模式)
        consumer.registerMessageListener(new MessageListenerConcurrently() {
            @Override
            public ConsumeConcurrentlyStatus consumeMessage(List<MessageExt> msgs, ConsumeConcurrentlyContext context) {
                System.out.printf("%s Receive New Messages: %s %n", Thread.currentThread().getName(), msgs);
                // 标记该消息已经被成功消费
                return ConsumeConcurrentlyStatus.CONSUME_SUCCESS;
            }
        });
        // 启动消费者实例
        consumer.start();
        System.out.println("Consumer Started");
	}
}

pull

由消费者主动向MQ拉取消息;采用Pull方式,如何设置Pull消息的频率需要重点去考虑,举个例子来说,可能1分钟内连续来了1000条消息,然后2小时内没有新消息产生(概括起来说就是“消息延迟与忙等待”)。如果每次Pull的时间间隔比较久,会增加消息的延迟,即消息到达消费者的时间加长,MQ中消息的堆积量变大;若每次Pull的时间间隔较短,但是在一段时间内MQ中并没有任何消息可以消费,那么会产生很多无效的Pull请求的RPC开销,影响MQ整体的网络性能;


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

import org.apache.rocketmq.client.consumer.DefaultMQPullConsumer;
import org.apache.rocketmq.client.consumer.PullResult;
import org.apache.rocketmq.client.exception.MQClientException;
import org.apache.rocketmq.common.message.MessageQueue;

public class ConsumerPull {

	//Java缓存
    private static final Map<MessageQueue, Long> offseTable = new HashMap<MessageQueue, Long>();
    
	public static void main(String[] args) throws InterruptedException, MQClientException {

		// 消费者实例
		DefaultMQPullConsumer consumer = new DefaultMQPullConsumer("listenGroup");
        consumer.setNamesrvAddr("127.0.0.1:9876");
        consumer.setInstanceName("consumer"); // 客户端实例名称
        consumer.start();

        // 拉取订阅主题的队列,默认队列大小是4
        Set<MessageQueue> mqs = consumer.fetchSubscribeMessageQueues("TopicTest");
        System.out.println("setSize: " + mqs.size());
        for (MessageQueue mq : mqs) {
            System.out.printf("Consume from the queue: %s%n", mq);
            SINGLE_MQ: // GOTO节点
            	while (true) {
                try {
                     // 四个参数含义: mq, 从哪个队列中拉取消息;subExpression, SubscriptionData中的subString;offset, 消息拉取的offset;maxNums, 最大拉取的消息数目.
                    PullResult pullResult = consumer.pullBlockIfNotFound(mq, null, getMessageQueueOffset(mq), 32); // Consumer获取消息
                    System.out.printf("pullResult: %s%n", pullResult);
                    putMessageQueueOffset(mq, pullResult.getNextBeginOffset());
                    switch (pullResult.getPullStatus()) {
                        case FOUND: // 发现消息
                            System.out.println(pullResult.getMsgFoundList().get(0).toString());
                            break;
                        case NO_NEW_MSG: // 没有新的消息
                            break SINGLE_MQ; // GOTO 
                        case NO_MATCHED_MSG: // 没有匹配的消息???
                        	
                        case OFFSET_ILLEGAL:
                            break;
                        default:
                            break;
                    }
                } catch (Exception e) {
                }
            }
        }
        consumer.shutdown();
	}

	private static void putMessageQueueOffset(MessageQueue mq, long offset) {
        offseTable.put(mq, offset);
    }
 
	/**
	 * 获取偏移量  消费者进度控制
	 * @param mq
	 * @return
	 */
    private static long getMessageQueueOffset(MessageQueue mq) {
        Long offset = offseTable.get(mq);
        if (offset != null){
            System.out.println("offset:" + offset);
            return offset;
        }
        return 0;
    }
}

 

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值