项目背景:往kafka的topic imgchk_request中produce图二中的参数,经过AI服务对图片进行质检,将结果再写入kafka topic imgchk_response中供其它系统调用。

测试范围:功能测试、性能测试

java代码kafka消费从指定时间开始消费 java kafka 消费者_kafka基础

java代码kafka消费从指定时间开始消费 java kafka 消费者_kafka_02

测试过程:用java写一段kafka生产者和消费者的代码,通过一次性生产不同数量的消息到imgchk_request,再通过消费者消费imgchk_response,监控应用服务器的资源且获取到耗时。通过CM平台也能实时查看到消息的生产和消费情况。

producer代码:

package com.test.checkimage;

import java.text.SimpleDateFormat;
import java.util.*;
import java.util.concurrent.TimeUnit;

import com.alibaba.fastjson.JSONObject;
import org.apache.kafka.clients.producer.KafkaProducer;
import org.apache.kafka.clients.producer.Producer;
import org.apache.kafka.clients.producer.ProducerRecord;
import org.apache.kafka.common.PartitionInfo;


public class TestProducer {
    public static void produce(int count){
        Properties props = new Properties();
        props.put("bootstrap.servers", "bigdata-dev-mq:9092,bigdata-dev-mq:9093,bigdata-dev-mq:9094");
        props.put("acks", "all");
        props.put("retries", 0);
        props.put("batch.size", 16384);
        props.put("linger.ms", 1);
        props.put("buffer.memory", 33554432);
        props.put("key.serializer", "org.apache.kafka.common.serialization.StringSerializer");
        props.put("value.serializer", "org.apache.kafka.common.serialization.StringSerializer");
        //生产者发送消息
        String topic = "imgchk_request";//imgchk_request
        Producer<String, String> procuder = new KafkaProducer<String,String>(props);


        for (int i = 1; i <= count; i++) {
            //生成唯一的uuid值
            UUID uuid = UUID.randomUUID();

            //准备写入topic的数据
            JSONObject params = new JSONObject();
            params.put("courier_id","12356");
            params.put("image_path","http://filesyshouse.oss-cn-beijing.aliyuncs.com/equipmentImg/2018/11/08/cb8153b7-64eb-48dd-8dc9-aaae3b97c4d7.jpg");
            params.put("storage_type","oss");
            params.put("image_class","equipment");
            params.put("task_uuid",uuid.toString());

            ProducerRecord<String, String> msg = new ProducerRecord<String,String>(topic,params.toJSONString());
            procuder.send(msg);

        }
        SimpleDateFormat df = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");//设置日期格式
        System.out.println(df.format(new Date()));// new Date()为获取当前系统时间,也可使用当前时间戳

        //列出topic的相关信息
        List<PartitionInfo> partitions = new ArrayList<PartitionInfo>() ;
        partitions = procuder.partitionsFor(topic);
        for(PartitionInfo p:partitions)
        {
            System.out.println(p);
        }

        System.out.println("send message over.");
        procuder.close(100,TimeUnit.MILLISECONDS);

    }
}

consumer代码:

package com.test.checkimage;

import org.apache.kafka.clients.consumer.ConsumerRecord;
import org.apache.kafka.clients.consumer.ConsumerRecords;
import org.apache.kafka.clients.consumer.KafkaConsumer;

import java.text.SimpleDateFormat;
import java.util.Arrays;
import java.util.Date;
import java.util.Properties;

public class TestConsumer {
    public static void consumer(){
        Properties properties = new Properties();
        properties.put("bootstrap.servers", "bigdata-dev-mq:9092,bigdata-dev-mq:9093,bigdata-dev-mq:9094");
        properties.put("group.id", "group-1");
        properties.put("enable.auto.commit", "true");
        properties.put("auto.commit.interval.ms", "1000");
        properties.put("auto.offset.reset", "earliest");
        properties.put("session.timeout.ms", "30000");
        properties.put("key.deserializer", "org.apache.kafka.common.serialization.StringDeserializer");
        properties.put("value.deserializer", "org.apache.kafka.common.serialization.StringDeserializer");

        KafkaConsumer<String, String> kafkaConsumer = new KafkaConsumer<>(properties);
        kafkaConsumer.subscribe(Arrays.asList("imgchk_response"));//imgchk_response
        while (true) {
            ConsumerRecords<String, String> records = kafkaConsumer.poll(100);
            for (ConsumerRecord<String, String> record : records) {
                //通过设置时间戳,获得消费此条消息的时间
                SimpleDateFormat df = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");//设置日期格式
                String date = df.format(new Date());// new Date()为获取当前系统时间,也可使用当前时间戳
                System.out.printf("date=%s,offset = %d, value = %s", date,record.offset(), record.value());
                System.out.println();
            }
        }


    }
}

 

 

CM平台

java代码kafka消费从指定时间开始消费 java kafka 消费者_java_03

java代码kafka消费从指定时间开始消费 java kafka 消费者_java kafka_04

附:kafka的基础知识
kafka和传统的消息系统不同于:

  • kafka是一个分布式系统,易于向外扩展
  • 它同时为发布和订阅提供高吞吐量
  • 它支持多订阅者,当失败时能自动平衡消费者
  • 消息的持久化

java代码kafka消费从指定时间开始消费 java kafka 消费者_kafka基础_05

kafka与redis作为消息列队使用的差异:
1、消息推送的可靠性 redis多用于实时性较高的消息推送,并不保证可靠。断电就会清数据,虽然也提供持久化,但多要自己去实现。kafka保证可靠有一些延迟。
2、订阅功能的分组,kafka中发布一个内容,多个订阅者可以分组,同一个组里只有一个订阅者consumer会收到该消息(topic下的每个分区只能分配给某个或多个group下的一个consumer),可用作负载均衡。group下的所有consumer都会协调在一起共同参与分配,即rebalance.

1.按照如上的算法,所以如果kafka的消费组需要增加组员,最多增加到和partition数量一致,超过的组员只会占用资源,而不起作用;
2.kafka的partition的个数一定要大于消费组组员的个数,并且partition的个数对于消费组组员取模一定要为0,不然有些消费者会占用资源却不起作用;
3.如果需要增加消费组的组员个数,那么也需要根据上面的算法,调整partition的个数

kafka架构原理

java代码kafka消费从指定时间开始消费 java kafka 消费者_kafka基础_06

在一套kafka架构中有多个producer、多个broker、多个consumer,每个producer可以对应多个topic,每个consumer只能对应一个consumer group。整个kafka架构对应一个zk集群,通过zk管理集群配置,选举leader,以及在consumer group发生变化时进行Rebalance

java代码kafka消费从指定时间开始消费 java kafka 消费者_java kafka_07