java mq 服务端_MQ任意延时消息(三)基于服务端实现

启动RocketMQ

启动nameserver

修改broker配置参数,新增

messageDelayLevel=1s 2s 4s 8s 16s 32s 64s 128s 256s 512s 1024s 2048s 4096s 8192s 16384s 32768s 65536s 131072s

org.apache.rocketmq.common.message.MessageConst新增常量

public static final String PROPERTY_MSG_REMAIN_DELAY = "MSG_REMAIN_DELAY_SERVER";

org.apache.rocketmq.store.util包下新增工具类

package org.apache.rocketmq.store.util;

/**

* 任意延时工具类

*

* @author zby

*

*/

public class ArbitrarilyDelayUtil {

/**

* 延时时间

*/

private static final long[] delayArray = new long[] { 1, 2, 4, 8, 16, 32, 64, 128, 256, 512, 1024, 2048, 4096, 8192,

16384, 32768, 65536, 131072 };

private ArbitrarilyDelayUtil() {

}

/**

* 根据延时等级获取延时时间

*

* @param delayLevel 延时等级

* @return 延时时间

*/

public static long getDelayTimeFromDelayLevel(int delayLevel) {

validDelayLevel(delayLevel);

if (delayLevel == 0) {

return 0;

}

return delayArray[delayLevel - 1];

}

/**

* 根据延时时间获取最近的延时等级

*

* @param delayTime

* @return

*/

public static int getLatestDelayLevelFromDelayTime(long delayTime) {

validDelayTime(delayTime);

if (delayTime == 0) {

return 0;

}

for (int i = 0; i < delayArray.length - 1; i++) {

if (delayTime >= delayArray[i] && delayTime < delayArray[i + 1]) {

return i + 1;

}

}

return delayArray.length;

}

/**

* 校验延时时间

*/

private static void validDelayTime(long delayTime) {

if (delayTime < 0) {

throw new IllegalArgumentException("Not supported delay time:" + delayTime);

}

}

/**

* 校验延时等级

*/

private static void validDelayLevel(int delayLevel) {

if (delayLevel < 0 || delayLevel > delayArray.length) {

throw new IllegalArgumentException("Not supported delay level:" + delayLevel);

}

}

}

org.apache.rocketmq.store.CommitLog类新增代码,根据新增代码前的代码找到新增的位置

if (tranType == MessageSysFlag.TRANSACTION_NOT_TYPE || tranType == MessageSysFlag.TRANSACTION_COMMIT_TYPE) {

// Delay Delivery

if (msg.getDelayTimeLevel() > 0) {

省略.....

}

if (msg.getUserProperty(MessageConst.PROPERTY_MSG_REMAIN_DELAY) != null

&& Long.parseLong(msg.getUserProperty(MessageConst.PROPERTY_MSG_REMAIN_DELAY)) > 0) {

long remainDelay = Long.parseLong(msg.getUserProperty(MessageConst.PROPERTY_MSG_REMAIN_DELAY));

int delayTimeLevel = ArbitrarilyDelayUtil.getLatestDelayLevelFromDelayTime(remainDelay);

msg.setDelayTimeLevel(delayTimeLevel);

msg.putUserProperty(MessageConst.PROPERTY_MSG_REMAIN_DELAY,

Long.toString(remainDelay - ArbitrarilyDelayUtil.getDelayTimeFromDelayLevel(delayTimeLevel)));

topic = ScheduleMessageService.SCHEDULE_TOPIC;

queueId = ScheduleMessageService.delayLevel2QueueId(msg.getDelayTimeLevel());

// Backup real topic, queueId

MessageAccessor.putProperty(msg, MessageConst.PROPERTY_REAL_TOPIC, msg.getTopic());

MessageAccessor.putProperty(msg, MessageConst.PROPERTY_REAL_QUEUE_ID, String.valueOf(msg.getQueueId()));

msg.setPropertiesString(MessageDecoder.messageProperties2String(msg.getProperties()));

msg.setTopic(topic);

msg.setQueueId(queueId);

}

}

启动broker

公共代码

延时等级转换工具类

package com.zby.server;

import java.util.concurrent.TimeUnit;

import org.apache.rocketmq.common.message.Message;

/**

* 消息延时工具类

*

* @author mac

*

*/

public class DelayUtil {

public static final String PROPERTY_MSG_REMAIN_DELAY = "MSG_REMAIN_DELAY_SERVER";

private DelayUtil() {

}

/**

* 消息任意延时发送

*

* @param msg 消息

* @param delayTime 延迟时间

* @param timeUnit 延迟时间单位

*/

public static void delayMsg(Message msg, long delayTime, TimeUnit timeUnit) {

msg.putUserProperty(PROPERTY_MSG_REMAIN_DELAY, Long.toString(timeUnit.toSeconds(delayTime)));

}

}

生产者

生产者示例

package com.zby.server;

import java.nio.charset.StandardCharsets;

import java.util.Date;

import java.util.concurrent.TimeUnit;

import org.apache.rocketmq.client.producer.DefaultMQProducer;

import org.apache.rocketmq.client.producer.SendResult;

import org.apache.rocketmq.common.message.Message;

public class Producer {

public static void main(String[] args) throws Exception {

DefaultMQProducer producer = new DefaultMQProducer("please_rename_unique_group_name");

producer.setNamesrvAddr("localhost:9876");

producer.start();

Message msg = new Message("TopicTest", ("消息发送时间 :" + new Date()).getBytes(StandardCharsets.UTF_8));

DelayUtil.delayMsg(msg, 27, TimeUnit.MINUTES);

SendResult sendResult = producer.send(msg);

System.out.println("消息发送结果:" + sendResult.getSendStatus());

producer.shutdown();

}

}

消费者

消费者示例

package com.zby.server;

import java.io.UnsupportedEncodingException;

import java.util.Date;

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.common.consumer.ConsumeFromWhere;

import org.apache.rocketmq.common.message.MessageExt;

import org.apache.rocketmq.remoting.common.RemotingHelper;

public class Consumer {

public static void main(String[] args) throws Exception {

DefaultMQPushConsumer consumer = new DefaultMQPushConsumer("please_rename_unique_group_name_4");

consumer.setNamesrvAddr("localhost:9876");

consumer.setConsumeFromWhere(ConsumeFromWhere.CONSUME_FROM_FIRST_OFFSET);

consumer.subscribe("TopicTest", "*");

consumer.registerMessageListener(new MessageListenerConcurrently() {

@Override

public ConsumeConcurrentlyStatus consumeMessage(List msgs, ConsumeConcurrentlyContext context) {

try {

System.out.printf("now:%s,%s Receive New Messages: %s %n", new Date(),

Thread.currentThread().getName(),

new String(msgs.get(0).getBody(), RemotingHelper.DEFAULT_CHARSET));

} catch (UnsupportedEncodingException e) {

e.printStackTrace();

}

return ConsumeConcurrentlyStatus.CONSUME_SUCCESS;

}

});

consumer.start();

System.out.printf("Consumer Started.%n");

}

}

启动测试

启动消费者

启动生产者

消费者输出结果

Consumer Started.

now:Wed Jul 22 12:42:45 CST 2020,ConsumeMessageThread_1 Receive New Messages: 消息发送时间 :Wed Jul 22 12:42:18 CST 2020

优点

客户端唯一需要的就是发送消息前调用DelayUtil.delayMsg(msg, 27, TimeUnit.MINUTES);

生产消费代码都是copy的quickstart的demo,可以看出侵入性很小

注意

改了延时等级,重试的延时间隔也会更改

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值