Kafka-深入

关于Topic和Partition

Topic

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

Partition

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

下图中,对于名字为test的topic,做了三个分区,分别是p0,p1,p2。

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

Topic&Partition的存储

Partition是以文件的形式存储在文件系统中,比如创建一个名为firstTopic的topic,其中有3个partition,那么在kafka的数据目录(/tmp/kafka-log)中就有3个目录,firstTopic-0~3,命名规则是<topic_name>-<partition_id> ./kafka-topic.sh --create --zookeeper 192.168.0.7:2181 --replication-factor 1 --partitions 3 --topic firstTopic

关于消息分发

kafka消息分发策略

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

消息默认的分发机制

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

消费端如何消费指定的分区

通过下面的代码,就可以消费指定该topic下的0号分区。其他分区的数据就无法接收了:

// 消费指定分区的时候,不需要再订阅
// kafkaConsumer.subscribe(Collections.singletonList(topic));
// 消费指定的分区
TopicPartition topicPartition=new TopicPartition(topic,0);
kafkaConsumer.assign(Arrays.asList(topicPartition));

消息的消费原理

kafka消息消费原理演示

在实际生产过程中,每个topic都会有多个partitions,多个partitions的好处在于,一方面能够对broker上的数据进行分片有效减少了消息的容量从而提升io性能。另外一方面,为了提高消费端的消费能力,一般会通过多个consumer去消费同一个topic,也就是消费端的负载均衡机制,也就是我们接下来要了解的,在多个partition以及多个consumer的情况下,消费者是如何消费消息的。

对于上面这种场景来说,这3个消费者会分别消费test这个topic的3个分区,也就是每个consumer消费一个partition。

什么是分区分配策略

通过上面案例演示,我们应该能猜到,同一个group中的消费者对于一个topic中的多个partition,存在一定的分区分配策略。

在kafka中,才能在两种分区分配策略,一种是Range(默认)(范围)、另一种是RoundRobin(轮询)。通过partition.assignment.strategy这个参数来设置。

Range strategy(范围分区)

Range策略是对每个主题而言的,首先对同一个主题里面的分区按照序号进行排序,并对消费者按照字母顺序进行排序。假设我们有10个分区,3个消费者,排完序的分区将会是0,1,2,3,4,5,6,7,8,9;消费者排完序将会是c1-0,c2-0,c3-0.然后将partition的个数除以消费者线程的总数来决定每个消费者线程消费几个分区。如果除不尽,那么前面几个消费者线程将会多消费一个分区。在例子中,10个分区,3个消费者线程,10/3 = 3 余 1,那么消费者线程c1-0将会多消费一个分区,所以最后分区分配的结果是这样的:

  • c1-0消费0,1,2,3分区
  • c2-0消费4,5,6分区
  • c3-0消费7,8,9分区

加入我们有2个主题(T1和T2),分别有10个分区,那么最后分区分配的结果看起来是这样的:

  • c1-0消费T1:0,1,2,3;T2:0,1,2,3分区
  • c2-0消费T1:4,5,6;T2:4,5,6分区
  • c3-0消费T1:7,8,9;T2:7,8,9分区

可以看出,c1-0消费者线程比其他消费者线程多消费了2个分区,这就是Range strategy的一个很明显的弊端

RoundRobin strategy(轮询分区)

轮询分区策略是把所有partition和所有consumer线程都列出来,然后按照hashcode进行排序。最后通过轮询算法分配partition给消费线程。如果所有consumer实例的订阅是相同的,那么partition会均匀分布。

假设按照hashCode排序完的topic-partition组依次为T1-5,T1-3,T1-0,T1-8,T1-2,T1-1,T1-4,T1-7,T1-6,T1-9;我们的消费者线程排序为c1-0,c1-1,c2-0,c2-1,最后分区分配的结果为:

  • c1-0消费T1-5,T1-2,T1-6分区
  • c1-1消费T1-3,T1-1,T1-9分区
  • c2-0消费T1-0,T1-4分区
  • c2-1消费T1-8,T1-7分区

使用轮询分区策略必须满足两个条件

  1. 每个主题的消费者实例具有相同数量的流
  2. 每个消费者订阅的主题必须是相同的

什么时候会触发这个策略呢?

当出现一下几种情况时,kafka会进行一次分区分配操作,也就是kafka consumer的rebalance

  1. 同一个consumer group内新增了消费者
  2. 消费者离开当前所属的consumer group,比如主动停机或者宕机
  3. topic新增了分区(也就是分区数量发生了变化)
  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值