Kafka相关原理浅析

Kafka的架构

一个典型的kafka 集群包含若干 Producer (可以是应用节点产生的消息,也可以是通过Flume 收集日志产生的事件),若干个 Broker kafka 支持水平扩展)、若干个 ConsumerGroup ,以及一个 zookeeper 集群。 kafka 通过 zookeeper 管理集群配置及服务协同。Producer使用 push 模式将消息发布到 broker consumer 通过监听使用 pull 模式从broker 订阅并消费消息 。多个broker 协同工作, producer 和 consumer 部署在各个业务逻辑 中。三者通过zookeeper 管理协调请求和转发。这样就组成了一个高性能的分布式消息发布和订阅系统 。
Kafka相关原理浅析_第1张图片

producer 发送消息到broker的过程是push,而consumer从broker消费消息的过程是pull,主动去拉数据。而不是broker把数据主动发送给consumer

Topic&Partition

Topic

在kafka 中, topic 是一个存储消息的逻辑概念,可以认为是一个消息集合。每条消息发送到 kafka 集群的消息都有一个类别。物理上来说,不同的 topic 的消息是分开存储的,每个topic 可以有多个生产者向它发送消息,也可以有多个消费者去消费其中的消息。
Kafka相关原理浅析_第2张图片

partition

每个topic 可以划分多个分区(每个 Topic 至少有一个分区),同一 topic 下的不同分区包含的消息是不同的。每个消息在被添加到分区时,都会被分配一个 offset (称之为偏移量),它是消息在此分区中的唯一编号, kafka 通过 offset保证消息在分区内的顺序, offset 的顺序不跨分区,即 kafka只保证在同一个分区内的消息是有序的 。

下图中,对于名字为test 的 topic ,做了 3 个分区,分别是p 0 、 p 1 、 p 2
Kafka相关原理浅析_第3张图片

每一条消息发送到 broker 时,会根据 partition 的规则选择存储到哪一个 partition 。如果 partition 规则设置合理,那么所有的消息会均匀的分布在不同的 partition 中,这样就有点类似数据库的分库分表的概念,把数据做了分片处理。

Topic和Patition 的存储

Partition是以文件的形式存储在文件系统中,比如创建一个名为 firstTopic的 topic ,其中有 3 个 partition ,那么在kafka 的数据目录 tmp/kafka log 中就有 3 个目录,firstTopic 0~ 3 命名规则是
./kafka topics.sh create zookeeper 192 168 11 156 :2181 replication factor 1 partitions 3 topic first Topic

消息分发策略

消息是kafka 中最基本的数据单元,在 kafka 中,一条消息由 key 、 value 两部分构成,在发送一条消息时,我们可以指定这个 key ,那么 producer 会根据 key 和 partition 机制来判断当前这条消息应该发送并存储到哪个 partition 中。我们可以根据需要进行扩展 producer 的 partition 机制。

默认的消息分发策略

默认情况下,kafka 采用的是 hash 取模的分区算法。如果Key 为 null ,则会随机分配一个分区 。这个随机是在这个参数 ”metadata.max.age. 的时间范围内随机选择一 个。对于这个时间段内,如果 key 为 null ,则只会发送到唯一的分区。这个值默认情况下是 1 0 分钟更新一次。关于Metadata,简单理解就是Topic/Partition 和broker 的映射关系,每一个 topic 的每一个partition ,需要知道对应的broker列表是什么, leader是谁、 follower 是谁。这些信息都是存储在 Metadata 这个类里面。

消费端指定消费的分区

指定消费0号分区。

TopicPartition topicPartition=new TopicPartition(topic,0); 
kafkaConsumer.assign(Arrays.asList(topicPartition));

自定义分区策略:

代码实现Partitioner接口,重写partition方法。

public class MyPartitioner implements Partitioner {
    private Random random = new Random();

    @Override
    public int partition(String topic, Object key, byte[] keyBytes, Object value, byte[] valueBytes, Cluster cluster) {
        List partitions = cluster.partitionsForTopic(topic);
        if (Objects.isNull(key)) {
            return random.nextInt(partitions.size());
        }
        int partition = key.hashCode() % partitions.size();
        System.out.println("k->" + key + "value->" + value + "partition->" + partition);
        return partition;
    }

    @Override
    public void close() {

    }

    @Override
    public void configure(Map configs) {

    }
}

配置PARTITIONER_CLASS_CONFIG,配置指定到当前自定义策略的类路径

消费端分区分配

  1. 消费者可以指定消费某一个分区,一个消费者可指定消费多个分区数据
  2. 默认的消费端分配策略。

    3个分区,启动3个consumer实例,结果是3个consumer分别对应消费一个分区中的消息。启动4个consumer实例时,发现有一个无法消费到消息。启动2个consumer实例时,发现其中一个consumer实例消费了两个分区的消息。

注意:建议消费者数量正好是分区的整数倍。跨分区无法保证顺序性

  1. 增加,减少consumer、broker、partition会导致Rebalance

分区分配策略

这里所说的分区分配策略是指,同一个groupId下的不同consumer,对同一topic下的不同分区的一个分配策略。

Range

Kafka中默认的分区策略。

RoundBobin

你可能感兴趣的:(kafka)