kafka 名词解释及原理解析过程

一.Kafka的名词解释

  1.topic (主题)

 topic相当于传统消息系统MQ中的一个队列queue,producer端发送的message必须指定是发送到哪个topic上.在一个大型的应用系统中,可以根据功能的不同,区分不同的topic(订单的topic,登录的topic,金额的topic等等)

2. partition(分区)

一个topic下面可以有多个partition,kafka在接收到message后,会将这个message进行load blance根据(hask(message)%[broker_num])均匀的将这个message分配在不同的partition上。

partition的配置个数一般与kafka的集群数保持一致即可(即broker的数量)

3.partition replica (分区副本)

partition replica 是partition 的副本数据,是为了防止数据丢失的一种优化,partition 不会和 replica 在同一台broker上。Replica 的数量与partition数量保持一致即可做到高可用

4.broker

Kafka节点,一个Kafka节点就是一个broker,多个broker可以组成一个Kafka集群.brokerid 一般采用IP后3位表示

5. Segment

Partition 在物理结构上可以分为多个segment,每个segment 上存放着message信息

6.producer

生产message,发送到topic上

7.consumer

订阅指定的topic,消费topic上面的message信息

8.Consumer group

多个consumer 可以组成一个consumer group

二.名称的解释及原理

1.partition

kafka的message是1个key-value对的形式,或者只有topic 和value.当没有key的时候默认是null.大多数情况下都会分配1个key,这个key有2方面信息:

  1.元数据信息

  2.帮助partition分区,把这个key当成了路由,同一批数据写进一个partition上

一个message 就是一个producer record(生产记录)对象,必须包含的有topic和value这2个参数,partition和key是可以不存在的

所有的message是同一个key,将会被分配到同一个partition上

当一个key为null的时候,它将会使用默认的partition,这个partition的作用是它会随机的把这个key所对应的producer record 放到其中的1个prtition中 ,尽量的使topic上的数据分布均匀,以防止数据倾斜

如果显示的指定了一个key,那么这个partition它会根据这个key的hash值,再根据partition的数量取模,决定message存放到topic上的哪个partition中

下面我们做个测试:当存入的message有key 和无key 时数据发送到partition的位置如何?

    当存入的message有key存在时

/**
 * 
 * @des        测试kafka partition 分区信息                              
 * @author  zhao
 * @date    2019年6月27日上午12:17:55
 *
 */
public class PartitionExample {
    
    private final static  Logger LOG = LoggerFactory.getLogger(PartitionExample.class);
    
    public static void main(String[] args) throws InterruptedException, ExecutionException {
        
        Properties properties = initProp();
        KafkaProducer<String, String> producer = new KafkaProducer<String, String>(properties);
        ProducerRecord<String, String> record = new ProducerRecord<String, String>("test_partition","appointKey","hello");   //指定key时
        Future<RecordMetadata> future = producer.send(record);
        RecordMetadata recordMetadata = future.get();
        LOG.info(">>>>>>>>>>>>>>>>>> {}",recordMetadata.partition());
        
        record = new ProducerRecord<String, String>("test_partition","appointKey","world");
        future = producer.send(record); recordMetadata = future.get();
        LOG.info(">>>>>>>>>>>>>>>>>> {}",recordMetadata.partition());
         
        producer.flush();
        producer.close();
        System.out.println("====================================");
    }
    
    private static Properties initProp() {
        Properties prop = new Properties();
        prop.put("bootstrap.servers", "192.168.199.11:9092,192.168.199.12:9092,192.168.199.13:9092");
        prop.put("key.serializer", "org.apache.kafka.common.serialization.StringSerializer");
        prop.put("value.serializer", "org.apache.kafka.common.serialization.StringSerializer");
        
        return prop;
    }
}

/从日志中可以看出是随机发送到partition上的

22:21:06.231 [main] INFO com.zpb.kafka.PartitionExample - >>>>>>>>>>>>>>>>>> 1

22:21:06.258 [main] INFO com.zpb.kafka.PartitionExample - >>>>>>>>>>>>>>>>>> 0

  当存入的message无key存在时

/**
 * 
 * @des        测试kafka partition 分区信息                              
 * @author  zhao
 * @date    2019年6月27日上午12:17:55
 *
 */
public class PartitionExample {
    
    private final static  Logger LOG = LoggerFactory.getLogger(PartitionExample.class);
    
    public static void main(String[] args) throws InterruptedException, ExecutionException {
        
        Properties properties = initProp();
        KafkaProducer<String, String> producer = new KafkaProducer<String, String>(properties);
        ProducerRecord<String, String> record = new ProducerRecord<String, String>("test_partition", "hello");
        Future<RecordMetadata> future = producer.send(record);
        RecordMetadata recordMetadata = future.get();
        LOG.info(">>>>>>>>>>>>>>>>>> {}",recordMetadata.partition());
        
        record = new ProducerRecord<String, String>("test_partition","world");
        future = producer.send(record); recordMetadata = future.get();
        LOG.info(">>>>>>>>>>>>>>>>>> {}",recordMetadata.partition());
         
        producer.flush();
        producer.close();
        System.out.println("====================================");
    }
    
    private static Properties initProp() {
        Properties prop = new Properties();
        prop.put("bootstrap.servers", "192.168.199.11:9092,192.168.199.12:9092,192.168.199.13:9092");
        prop.put("key.serializer", "org.apache.kafka.common.serialization.StringSerializer");
        prop.put("value.serializer", "org.apache.kafka.common.serialization.StringSerializer");
        
        return prop;
    }
}

//从日志中可以看出发送到了同一个partition

 
 

22:29:29.963 [main] INFO com.zpb.kafka.PartitionExample - >>>>>>>>>>>>>>>>>> 2

 
 

22:29:29.969 [main] INFO com.zpb.kafka.PartitionExample - >>>>>>>>>>>>>>>>>> 2

通过以上测试得出:
  当一个key或者一批key映射同一partition时,所有的partition都要计算映射关系,不一定指的是可用的partition,因为在多个partition中,当某个partition挂掉时,也要参加到计算中,这就意味着,当你写数据时,如果是发送到了这个挂掉的partition上时,会发送失败 在一个conusmer group里面只有一个consumer client 读其中的一个partition,不可能存在多个group里面多个consumer读同一个partition

猜你喜欢

转载自www.cnblogs.com/MrRightZhao/p/11094707.html