kafka分区----分区如何分配到broker----生产者分区策略----消费者消费策略

1.分区的一些基本概念规则

  1. 每个topic都可以被划分成一个或者多个分区(至少有一个分区),它是topic物理上的分组,在创建topic的时候指定
  2. 一个Partition只对应一个Broker,一个Broker可以管理多个Partition。
  3. 在一个分区内消息是顺序的,在不同的分区之间,kafka并不保证消息的顺序
    • 同一个主题下,不同分区所包含的内容是不同的,每个消息被添加到分区当中时,会被分配一个偏移量(offset),它是消息在分区当中的唯一编号,kafka是通过offset来确保一个分区内的消息顺序的,offset的顺序并不跨越分区。
    • 在需要严格保证消息的消费顺序的场景下,需要将partition数目设为1

2.分区下的Leader和Follower

  1. 每个分区选一个server节点作Leader,(0个或多个)server节点做Follower。
  2. 每个分区有且仅有一个Leader,Leader是负责当前数据读写的Partition;有(0个或多个)Follower跟随Leader,保持数据同步
  3. Leadre失效,会从Follower中选举一个新的Leader
  4. Follower挂掉、卡住或者同步太慢,Leader会把Follower删除,在新建个follower
  5. Leader和Follower跨节点同步,达到一种选举方式,若是在一个broker上同步没意义;每个服务器都能作为分区的一个Leader和其他分区的flowers,因此kafka是一个去中心化的集群,能被很好平衡(虽然也可以一个server上又多个leader,但是压力会大)

3.分区如何分配到broker

  1. 网上查到的分配策略如下
    • 将所有的broker和partition排序;
    • 将第i个partition分配到第(i mode n)个broker上,这个Partition的第一个Replica存在于这个分配的Broker上,并且会作为partition的优先副本
    • 将第i个partition的j个副本,放到第((i+j) mode n)个broker上
  2. 上述做法会有问题,每一个topic的分区0都会被分配在broker 0上,第1个分区都分配到broker 1上。直到partition的id超过broker的数量后开始重复在轮询,这样会导致分区更多的在前几个broker上,这样前面的机器的压力比后面的机器压力更大,反而会造成负载不均衡。同时我们也可以做实验得到证明,真实的分配方法并不是上面这样。
  3. 实际上在Kafka集群中,每一个Broker都有均等分配Partition的Leader机会,kafka是先随机挑选一个broker放置分区0,然后再按顺序放置其他分区,副本也是一样的情况。第一个放置的分区副本一般都是 Leader,其余的都是 Follow 副本。

4.Segment

  1. 由于生产者生产的消息会不断追加到log文件末尾,为防止log文件过大导致数据定位效率低下,kafka采取了分片和索引机制。将每个partition分为多个segment file,每个segment file存着message,segment由两部分(.log数据文件 .index索引文件)组成,并且一一对应
  2. 目录和file都是物理存储于磁盘,但是kafka不支持随机读写,只支持顺序读写,有效提高磁盘利用率,而且顺序读写速度超过内存读写速度,所以效率很高
  3. partion全局的第一个segment从0开始,后续每个segment文件名为上一个segment文件最后一条消息的offset值
  4. ".log"数据文件
    • offset在parition(分区)内的每条消息都有一个有序的id号,这个id号被称为偏移(offset),它可以唯一确定每条消息在parition(分区)内的位置。即offset表示partiion的第多少message
    • MessageSize表示消息内容data的大小
    • data为Message的具体内容
  5. ".index"索引文件
    • 采取稀疏索引的方式,减少了索引文件的大小,相对于稠密索引节约了存储空间,但是查找起来更费时间
    • 索引包含两个部分,分别为相对offset和position
  6. 消息的查找流程
    • 通过offset定位数据信息在哪个文件(.log,.index)
    • 找到文件后,在根据offset和文件名计算相对偏移量,可以找到index中查找到对应position????还需要试验下

5.生产者分区策略

  1. 每一条下消息ProducerRecord由主题名称、可选的分区号、可选的键和值组成
  2. 分区策略
    • 如果消息ProducerRecord中指定了有效partition字段,发送记录使用该partition
    • 如果消息ProducerRecord中没有指定partition字段
      • 但指定key,则将使用key进行hash采用MurmurHash2算法,具备高运算性能及低碰撞率)选择一个分区
      • 且没有key,则将以轮询的方式分配一个分区,常说的“round-robin”算法
    • 注意:如果key不为null,那么hash计算得到的分区号会是所有分区中的任意一个;如果key为null并且有可用分区,那么计算得到的分区号仅为可用分区中的任意一个
  3. 自己定义分区策略
    • 随机分区
      • 创建一个类,并继承partitioner,改写partition
      • 再修改配置文件partitioner.class=XXX._RandomPartitioner,启动即可
      • 或者prop.put("partition.class",XXX._RandomPartitioner.class)
      public class _RandomPartitioner implements Partitioner{
      	public int partition(String topic, Object key, byte[] keyBytes,
                           Object value, byte[] valueBytes, Cluster cluster){
      			//获取总的分区数
      			 Integer partitionNum = cluster.partitionsForTopic(topic);
      			 // 随机策略
      			 int i = random.nextInt(partitionNum)
      			 return i
      		}
      }
      
    • hash分区(个人写的话可以模拟下:hash算完取绝对值,在取模)
    • 轮询分区
    • 分组分区
提高kafka并行度,其实就是提高kafka topic分区的个数,分区个数提高了,同一时间同一消费组内可以有的消费者可以更多,消费能力增强。一般分区和消费组内的消费者保持对应
原文地址:https://www.cnblogs.com/oneLittleStar/p/13528835.html