Topic和Partition
Topic
在kafka中,topic是一个存储消息的逻辑概念,可以认为是一个消息集合。每条消息发送到kafka集群的消息都有一个类别。物理上来说,不同的topic的消息是分开存储的,
每个topic可以有多个生产者向它发送消息,也可以有多个消费者去消费其中的消息。
Partition
每个topic可以划分多个分区(每个Topic至少有一个分区),同一topic下的不同分区包含的消息是不同的。每个消息在被添加到分区时,都会被分配一个offset(称之为偏移量),它是消息在此分区中的唯一编号,kafka通过offset保证消息在分区内的顺序,offset的顺序不跨分区,即kafka只保证在同一个分区内的消息是有序的。
下图中,对于名字为test的topic,做了3个分区,分别是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>
sh kafka-topics.sh --create --zookeeper 192.168.11.156:2181 --replication-factor 1 --partitions 3 --topic firstTopic
生产端
分区器(Partitioner)-消息分发
kafka消息分发策略
消息是kafka中最基本的数据单元,在kafka中,一条消息由key、value两部分构成,在发送一条消息时,我们可以指定这个key,那么producer会根据key和partition机制来判断当前这条消息应该发送并存储到哪个partition中。我们可以根据需要进行扩展producer的partition机制。
自定义Partitioner
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<PartitionInfo> partitionInfos = cluster.partitionsForTopic(topic);
int numofPartition = partitionInfos.size();
int partitionNum = 0;
// key没有设置
if (key == null) {
// 随机指定分区
partitionNum = random.nextInt(numofPartition);
} else {
partitionNum = Math.abs(key.hashCode()) % numofPartition;
}
System.out.println("key->" + key + ",value->" + value + "->send to partition:" + partitionNum);
return partitionNum;
}
@Override
public void close() {
}
@Override
public void configure(Map<String, ?> configs) {
// 主要用来获取配置信息及初始化数据
}
}
properties.put(ProducerConfig.PARTITIONER_CLASS_CONFIG,"com.demo.kafka.MyPa rtitioner");
消息默认的分发机制
org.apache.kafka.clients.producer.internals.DefaultPartitioner
默认分区器
public int partition(String topic, Object key, byte[] keyBytes, Object value, byte[] valueBytes, Cluster cluster) {
List<PartitionInfo> partitions = cluster.partitionsForTopic(topic);
int numPartitions = partitions.size(