开源MMDQ测试用例

DDMQ作为典型的消息队列,现简单分析使用过程如下。
准备:
group: cg_whb_test
topic:whb_test_topic1
topic:whb_test_topic2
topic:whb_test_topic3

Producer

生产者使用比较简单,直接调用send方法即可。一般情况下,可以自行封装一层send。如:

    /**
     * 最简单的用法,只指定topic和字符串消息体(默认按UTF-8编码)。
     * @param body body
     * @param topic topic
     * @return boolean
     */
    public boolean send(String body, String topic) {
        try {
            CarreraProducer producer = this.buildCarreraProducer(topic);

            //指定iplist方式,服务发现方式不满足时,再用此方式
            //CarreraConfig config = getNoSDConfig();
            //CarreraProducer producer = new CarreraProducer(config);
            producer.start(); // 启动生产实例。这里会进行一些初始化操作。

            //0.最简单的用法,只指定topic和字符串消息体(默认按UTF-8编码)。
            Result result = producer.send(topic, body);
            //
            //--------------- 关闭生产实例 ---------------
            //
            producer.shutdown();
            if (null == result) {
                log.error("消息发送失败,body:[{}]", body);
                return false;
            }
            //强烈建议一定要在日志中打印生产的结果。
            // OK 和 CACHE_OK 两个结果都可以认为是生产成功了。
            if (result.getCode() == CarreraReturnCode.OK
                    || result.getCode() == CarreraReturnCode.CACHE_OK) {
                log.info("produce success");
                return true;
            }

            if (result.getCode() > CarreraReturnCode.CACHE_OK) {
                log.info("produce failure, body[{}], message:{}", body, result.getMsg()); // 失败的情况,根据code和msg做相应处理。
                return false;
            }
            return false;
        } catch (Exception e) {
            log.error("发送消息异常,body:{}, e:{}", body, e);
            return false;
        }
    }

Comsumer

1. 单元测试

测试代码分为3部分:

  • 配置方法:配置消费组等。
  • 消费方法:主要的消费逻辑,接收到message后的处理。
  • main主方法:用于启动消费方法。
public class CarreraConsumerExampleTest1 {
    private static final Logger LOGGER = LoggerFactory.getLogger(CarreraConsumerExampleTest1.class);

    private static final String groupName = "cg_whb_test";

    public static void simpleExample(long consumeTime) throws InterruptedException {
        //CarreraConfig config = getConfig("cg_your_groupName", "127.0.0.1:9713");
        CarreraConfig config = getSDConfig();

        final CarreraConsumer consumer = new CarreraConsumer(config);

        consumer.startConsume(new MessageProcessor() {
            @Override
            public Result process(Message message, Context context) {
                LOGGER.info("收到如下消息:{}",message.value); //收到如下消息:java.nio.HeapByteBuffer[pos=83 lim=109 cap=139]
                LOGGER.info("process key:{}, value.length:{}, offset:{}, context:{}", message.getKey(),
                        message.getValue().length, message.getOffset(), context);
                return Result.SUCCESS;
            }
        }, 5); // 每台server有2个线程,额外的一个随机分配。

        Thread.sleep(consumeTime); // consume for 10 seconds
        consumer.stop(); //1分钟便于测试,可以注释掉
    }

    public static void main(String[] args) throws TTransportException, InterruptedException {
        Runtime.getRuntime().addShutdownHook(new Thread(new Runnable() {
            @Override
            public void run() {
                LogManager.shutdown(); //shutdown log4j2.
            }
        }));

        LOGGER.info("start simpleExample...");
        simpleExample(60 * 1000);

    }

    // 不使用服务发现
    public static CarreraConfig getConfig(String groupName, String ipList) {
        CarreraConfig config = new CarreraConfig(groupName, ipList);
        config.setRetryInterval(500); // 拉取消息重试的间隔时间,单位ms。
        config.setMaxBatchSize(8);  //一次拉取的消息数量。
        return config;
    }

    // 使用服务发现
    private static CarreraConfig getSDConfig() {
        CarreraConfig config = new CarreraConfig(groupName, Env.valueOf("Test"));
        config.setRetryInterval(500); // 拉取消息重试的间隔时间,单位ms。
        config.setMaxBatchSize(8);  //一次拉取的消息数量。
        return config;
    }
}

启动main方法,并在控制台发送一条消息,看到结果:

INFO EndpointManagerSD:129 - update service completely
10:11:17,110  INFO CarreraConsumerExampleTest1:32 - 收到如下消息:java.nio.HeapByteBuffer[pos=82 lim=108 cap=138]
10:11:17,113  INFO CarreraConsumerExampleTest1:33 - process key:1nDFsGfZ0Q9jz0fo, value.length:26, offset:1, context:Context(groupId:cg_whb_test, topic:whb_test_topic1, qid:R_test_test-02_0)

2. springboot测试

在没有main方法启动消费方法的情况下,需要将消费方法发布为bean,并依靠容器来启动消费方法。

在前一节的例子中,主要是运行simpleExample方法。在spring bean注入的理念下,将该方法作为bean发布。

并且,我们注意到,消费配置中,我们仅仅配置了消费组,而没有配置topic,这意味着所有绑定该组的topic,将会被所有的startConsume随机消费。我们一般需要使用独立的方法消费指定的topic。官方例子有如下说明:

 /**
     * 如果某些topic中消息流量特别大,可以使用独立的线程消费该topic。
     *
     * @param consumeTime 消费的时间
     * @throws InterruptedException
     */
    public static void exampleWithExtraThreadsForSomeTopic(long consumeTime) throws InterruptedException {
        CarreraConfig config = getConfig("cg_your_groupName", "127.0.0.1:9713");
        final CarreraConsumer consumer = new CarreraConsumer(config);
        Map<String/*Topic*/, Integer/*该topic额外的线程数*/> extraThreads = new HashMap<String, Integer>();
        extraThreads.put("test-0", 2);
        //该配置下有6个消费线程,有4个消费test-0和test-1的消息, 另外2个线程只消费test-0.
        consumer.startConsume(new MessageProcessor() {
            @Override
            public Result process(Message message, Context context) {
                LOGGER.info("process key:{}, value.length:{}, offset:{}, context:{}", message.getKey(),
                        message.getValue().length, message.getOffset(), context);
                return Result.SUCCESS;
            }
        }, 4, extraThreads);
        Thread.sleep(consumeTime);
        consumer.stop();
    }

注意上述中 该注释对应的消费关系

//该配置下有6个消费线程,有4个消费test-0和test-1的消息, 另外2个线程只消费test-0

  • 当匿名内部类后第一个参数为0时,仅消费指定的topic;
  • 当匿名内部类后第一个参数不为0时,有其他topic时也会消费。

以下测试代码中,topic1topic2为指定方法消费;topic3由于没有指定,会随机选一个startConsume消费。

package cn.whbing.mqboot.test;

import com.xiaojukeji.carrera.consumer.thrift.Context;
import com.xiaojukeji.carrera.consumer.thrift.Message;
import com.xiaojukeji.carrera.consumer.thrift.client.CarreraConfig;
import com.xiaojukeji.carrera.consumer.thrift.client.CarreraConsumer;
import com.xiaojukeji.carrera.consumer.thrift.client.MessageProcessor;
import com.xiaojukeji.carrera.sd.Env;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.boot.SpringBootConfiguration;
import org.springframework.context.annotation.Bean;

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

@SpringBootConfiguration
public class CarreraConsumerExampleTest1 {
    private static final Logger LOGGER = LoggerFactory.getLogger(CarreraConsumerExampleTest1.class);

    private  static String groupName = "cg_whb_test";
    private  String topic1 = "whb_test_topic1";
    private  String topic2 = "whb_test_topic2";


    @Bean
    public CarreraConsumer getCarreraConsumer() {
        CarreraConfig config = getSDConfig();

        //指定iplist方式,服务发现方式不满足时,再用此方式
        //CarreraConfig config = getNoSDConfig("cg_capricornus_client", "10.95.121.43:9713;10.95.137.66:9713");
        CarreraConsumer carreraConsumer = new CarreraConsumer(config);

        //指定某topic,消费进程
        Map<String/*Topic*/, Integer/*该topic额外的线程数*/> extraThreads = new HashMap<>();
        extraThreads.put(topic1, 1);

        carreraConsumer.startConsume(new MessageProcessor() {
            @Override
            public Result process(Message message, Context context) {
                LOGGER.info("测试1收到如下消息:{}",message.value); //收到如下消息:java.nio.HeapByteBuffer[pos=83 lim=109 cap=139]
                LOGGER.info("process key:{}, value.length:{}, offset:{}, context:{}", message.getKey(),
                        message.getValue().length, message.getOffset(), context);
                return Result.SUCCESS;
            }
        }, 0,extraThreads); 

        return carreraConsumer;
    }

    @Bean
    public CarreraConsumer getCarreraConsumer2() {
        CarreraConfig config = getSDConfig();

        //指定iplist方式,服务发现方式不满足时,再用此方式
        //CarreraConfig config = getNoSDConfig("cg_capricornus_client", "10.95.121.43:9713;10.95.137.66:9713");
        CarreraConsumer carreraConsumer = new CarreraConsumer(config);

        //指定某topic,消费进程
        Map<String/*Topic*/, Integer/*该topic额外的线程数*/> extraThreads = new HashMap<>();
        extraThreads.put(topic2, 1);

        carreraConsumer.startConsume(new MessageProcessor() {
            @Override
            public Result process(Message message, Context context) {
                LOGGER.info("测试2收到如下消息:{}",message.value); //收到如下消息:java.nio.HeapByteBuffer[pos=83 lim=109 cap=139]
                LOGGER.info("process key:{}, value.length:{}, offset:{}, context:{}", message.getKey(),
                        message.getValue().length, message.getOffset(), context);
                return Result.SUCCESS;
            }
        }, 0,extraThreads); 

        return carreraConsumer;
    }
    // 使用服务发现
    private static CarreraConfig getSDConfig() {
        CarreraConfig config = new CarreraConfig(groupName, Env.valueOf("Test"));
        config.setRetryInterval(500); // 拉取消息重试的间隔时间,单位ms。
        config.setMaxBatchSize(8);  //一次拉取的消息数量。
        return config;
    }
}

其他说明:spring bean在初始化时,即@Bean的方法里,会被执行一次。

    @Bean
    public String test(){
        System.out.println("测试测试测试");
        return "返回结果";
    }

测试用例代码:https://github.com/whbing/DDMQ

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

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值