Kafka(基本术语,分区策略,副本策略,存储策略,ZooKeeper作用,副本同步,容灾,高吞吐原因,负载均衡)(一)

一.Kafka基础

1.Kafka核心概念

(1)术语解释

Kafka集群由不同的Broker节点组成,每个Broker都有唯一的id(如从0开始编号),应该在节点安装时指定。Broker在本地文件系统存储了所有Topic数据,不依赖外部数据库

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-5Z3YXxdc-1612516400014)(C:\Users\86188\Desktop\截图\0203\2.png)]

Topic类似一个数据库表,里面存储一条条的key-value消息。每条消息的Key及Value都有相应的序列化方式,通常是在Producer生产消息时指定相应的序列化器,而Consumer消费时使用相应的反序列化器,在实际应用时生产者与消费者应该约定统一的序列化方式。Topic又分为多个不同的分区(Partition),每一条消息都由分区策略控制该消息应该存储在哪个分区之中,并由各个分区相应的偏移量(Offset)唯一标识。

Producer负责向Kafka主题发布(生产)消息,一个Topic可以有多个Producer实例,其相互之间没有协作关系。Producer的send()方法用于发送消息,参数ProducerRecord封装了消息的内容:Topic,Partition,key,value等消息。如果发送成功,返回的RecordMetadata中记录了消息的偏移量,如果发送失败就会重试或者抛出异常。

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-uMrrLoTB-1612516400017)(C:\Users\86188\Desktop\截图\0203\3.png)]

Producer可以以同步和异步的方式发送消息。

Producer以Batch的方式推送数据可以极大的提高处理效率,Kafka Producer可以将消息在内存中累计到一定数量后作为一个Batch发送请求。Batch的数据流大小可以通过Producer的参数控制,参数值可以设置为累计的数据大小。通过增加Batch的大小,可以减少网络请求和磁盘IO的次数。

Consumer负责订阅(消费)主题并处理消息。Consumer负责维护到Broker的TCP连接以便获取数据,在一个Partition中每一个记录的Offset是该记录的唯一标识,即每一个Offset唯一标识当前Partition中的一条记录,同时Offset也可以标识Consumer在Partition中的位置(Position)。对于Consumer来说,这个位置有两种含义:current Offset 和Committed Offset。

  • Current Offset保存在Consumer客户端中,它表示Consumer希望收到的下一条消息的序号。它仅仅在poll()方法中使用,例如,Consumer第一次调用poll()方法后收到了20条消息(offset:0-19),那么Current Offset就被设置为20.这样Consumer下一次调用poll()方法时,Kafka就知道应该从序号为20的消息开始读取。这样就能够保证每次Consumer poll消息时,都能够收到不重复的消息。
  • Committed Offset保存在Broker上,它表示Consumer已经确认消费国的消息的序号。主要通过commitSync和commitAsync API来操作。

例如,如果Committed Offset为0,Consumer通过poll()方法收到20条消息后,此时Current Offset就是20,经过一系列的逻辑处理后,并没有调用consumer.commitAsync()或consumer.commitSync()来提交Committed Offset,那么此时Committed Offset依旧是0,下一次Consumer重启后调用poll()继续从0开始消费。

如果一个Consumer消费了5条消息(poll并且成功commitSync)之后宕机了,重新启动之后它仍然能够从第6条消息开始消费,因为Committed Offset已经被Kafka记录为5.

可以将多个Consumer设置为同一个Consumer Group,组内的所有Consumer协调在一起来消费订阅主题的所有分区。但每个分区只能由同一个消费组内的一个Consumer来消费。Consumer Group的作用是为了实现多个Consumer并行消费一个Topic。

(2)分区策略

一个Topic包含多个Partition,Topic是逻辑概念,而Partition则是物理上的概念。

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-N1iXGri8-1612516400018)(C:\Users\86188\Desktop\截图\0203\4.png)]

Partition将Topic进行分割,从而更好地将数据均匀分布在Kafka集群的每一个Broker中。在server.properties配置文件中可以指定一个全局的分区数设置,这是对每个主题下的分区数的默认设置,默认为1(num.partitions=1)。当然每个主题也可以自己设置分区数量,如果创建主题的时候没有指定分区数量,则会使用server.properties中的设置。

$ bin/kafka-topics.sh --zookeeper localhost:2181 
--create 
--topic my-topic 
--partitions 2
--replication-factor 1

Kafka通过一些算法尽可能将Partition分配到不同的Broker上。因此需要知道:

  • 生成数据时,生产者数据发往哪个分区?

如果给定了分区号,直接将数据发往指定的分区。

如果没有给定分区号,视消息的key值,通过key值取hashcode进行分区。

如果即没有给定分区号,也没有key值,则直接轮询分区。

也可以自定义分区类

(1)当分区按每条消息来到顺序轮询依次写入各分区时:kafka 会把收到的message 进行 load balance,均匀的分布在这个 topic 下的不同的 partition 上 ( hash(message) % [broker 数量] )。

(2)每个 partition 在内存中对应一个 index,记录每个 segment 中的第一条消息偏移。segment file 组成:由 2 大部分组成,分别为 index file 和 data file,此 2 个文件一一对应,成对出现,后缀".index"和“.log”分别表示为 segment 索引文件、数据文件。

segment 文件命名规则:partition 全局的第一个 segment 从 0 开始,后续每个segment 文件名为上一个全局 partition 的最大 offset(偏移 message 数)。数值最大为 64 位 long 大小,19 位数字字符长度,没有数字用 0 填充。

(3)一个 partition 只能被一个消费者消费(但一个消费者可以同时消费多个 partition),因此,如果设置的 partition 的数量小于 consumer 的数量,就会有消费者消费不到数据。所以,推荐 partition 的数量一定要大于同时运行的consumer 的数量。

  • 消费数据时,消费者消费哪个分区的数据?

    一个分区只能被消费组中的一个消费者消费。如果消费者组中的消费者大于等于分区数量

,则有一些消费者是多余的。但如果消费组中的消费者小于分区数量,则一个消费者将负责多个分区的消费,此时由Consumer的partition.assignment.strategy配置参数决定每个消费者可以消费哪些分区,可选策略包括:range(默认),roundrobin。

range策略

​ range策略对应的实现类是org.apache.kafka.clients.consumer.RangeAssignor.具体规则是分区顺序排序,消费者按照字母排序。partition的个数除以消费者线程的总数来决定每个消费者线程消费几个分区。如果除不尽,那么前面几个消费线程将会多消费一个分区。

roundrobin策略

roundronbin分配策略的具体实现是org.apache.kafka.clients.consumer.RoundRobinAssignor。

分区按照hashcode排序,消费者按照字母排序。

(3)副本策略

Kafka是有若干过主题,每个主题可进一步划分成若干个分区。每个分区配置有若干个副本,副本数量不能多于Broker数量。

副本分散保存在不同的Broker上,从而能够解决因为部分Broker宕机带来的数据不可用问题。

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-7bPXUwDJ-1612516400020)(C:\Users\86188\Desktop\截图\0203\5.jpg)]

分区的所有副本保存有相同的消息序列,所有副本可分为两类:Leader和Follower。每个分区在创建时选举一个Leader副本,其余副本为Follower。

Leader副本负责所有的读写请求,Follower不对外提供读写服务。当Leader所在的Broker宕机时,Kafka依赖ZooKeeper感知该故障,并立即开启新一轮的Leader选举,从所有Follower中选择新的Leader副本。当老的Leader重启后,则变成Follower。

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-bMlrwInD-1612516400021)(C:\Users\86188\Desktop\截图\0203\6.png)]

(4)存储策略

无论消息是否被消费,kafka都会保留所有消息。有两种策略可删除旧数据

  • 基于时间:log.retention.hours=168
  • 基于大小:log.retention.bytes=1073741824

因为Kafka读取特定消息的时间复杂度为O(1),即与文件大小无关,所以这里删除过期文件与提高Kafka性能无关。

2.ZooKeeper与Kafka

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-ntMZzyHq-1612516400022)(C:\Users\86188\Desktop\截图\0203\7.png)]

在Kafka中,ZooKeeper主要工作:

(1)Broker注册并监控状态

znode:/brokers/ids,保存了所有Broker id,实现对Broker的动态监控。

(2)Topic注册

znode:/brokers/topics,保存了所有Topic

(3)生产者负载均衡

由于同一个Topic消息会被分区并将其分布在多个Broker上,因此,生产者需要将消息合理地发送到这些分布式的Broker上,那么如何实现生产者的负载均衡,Kafka支持传统的四层负载均衡,也支持ZooKeeper方式实现负载均衡。

四层负载均衡,根据生产者的IP地址和端口来为其确定一个相关联的Broker。通常,一个生产者只会对应单个Broker,然后该生产者产生的消息都发往该Broker。这种方式逻辑简单,每个生产者不需要同其他系统建立额外的TCP连接,只需要和Broker维护单个Tcp连接即可。但是,其无法做到真正的负载均衡,因为实际系统中的每个生产者产生的消息量及每个Broker的消息存储量都是不一样的,如果有些生产者产生的消息远多于其他生产者的话,那么会导致不同的Broker接收到的消息总数差异巨大。同时,生产者也无法实时感知到Broker的新增和删除。

使用ZooKeeper进行负载均衡,由于每个Broker启动时,都会完成Broker注册过程,生产者会通过该节点的变化来动态的感知到Broker服务器列表的变更。这样就可以实现动态的负载均衡机制

(4)offset维护

Kafka早起版本使用ZooKeeper为每个消费者存储offset,由于ZooKeeper写入性能较差,从版本后,Kafka使用自己的内部主题维护offset。

早期版本的kafka用ZooKeeper做meta信息存储,Consumer的消费状态,group的管理以及offset的值。

3.副本同步

**Kafka引入了In-sync Replicas,也就是ISR副本集合。**ISR中的副本都是与Leader同步的副本。相反,不在ISR的追随者副本就被认为是与Leader不同步的。ISR不只是追随者副本集合,它必然包括Leader副本。甚至在某些情况下,ISR只有Leader这一个副本。设置ISR主要是为了Broker宕掉之后,重新选举Partition的Leader时从ISR列表中选择,也就是说当Leader副本发生故障时,只有在ISR集合中的Follower副本才有资格被选举为新的Leader。

ISR是一个动态调整的集合,而非静态不变的。通过Broker端replica.lag.time.max.ms参数(Follower副本能落后Leader副本的最长时间间隔,默认值10000)值来控制哪个追随者副本与Leader同步。只要一个Follower副本落后Leader副本的时间不连续超过10秒,那么Kafka就认为该Follower副本与Leader是同步的,即使此时Follower副本中保存1消息明显少于Leader副本中的消息。

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-3PnelikE-1612516400022)(C:\Users\86188\Desktop\截图\0203\8.png)]

上图中,Follower1与Follower2中的消息条数明显少于Leader,但并不一定与Leader不同步。**Follower副本唯一的工作就是不断地从Leader副本拉取消息,然后写入到自己的提交日志中。**如果这个同步过程的速度持续慢于Leader副本的消息写入速度,那么在replica.lag.time.max.ms时间后,此Follower副本就会被认为是与Leader副本不同步的。因此不能再放入ISR中。此时,Kafka会自动收缩ISR集合,将该副本“踢出”ISR。

如果该副本后面慢慢地追上了Leader进度,那么它是能够重新被加回ISR的。

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-CWztfn88-1612516400023)(C:\Users\86188\Desktop\截图\0203\9.jpg)]

4.容灾

**Kafka容灾指当Broker宕机时的恢复机制。**在Kafka集群中会有一个或者多个Broker,其中有一个Broker会被选举为控制器(Kafka Controller),它负责管理整个集群中所有分区和副本的状态。

  • 当某个分区的Leader副本出现故障时,由控制器负责为该分区选举新的Leader副本。
  • 当检测到某个分区的ISR集合发生变化时,由控制器负责同志所有Broker更新其元数据信息。
  • 当使用kafka-topic.sh脚本为某个topic增加分区数量时,同样还是由控制器负责分区的重新分配。

Kafka中的控制器选举的工作依赖于ZooKeeper,成功竞选为控制器的Broker会在ZooKeeper中创建/controller这个临时(EPHEMERAL)节点,此临时节点的内容参考如下:

{“version”:1,“brokerid”:0,“timestamp”:“1561214469054”}

brokerid 表示称为控制器的 Broker 的 id 编号,timestamp 表示竞选称为控制器时的时间戳。

Broker容灾流程:

  • Controller在ZooKeeper的/brokers/ids/[brokerId]节点注册Watcher,当Broker宕机时ZooKeeper会监听到。
  • Controller从/brokers/ids节点读取可用Broker。
  • Controller决定set_p,该集合包含宕机Broker上的所有Partition。
  • 对set_p中的每一个Partition
    • 从/brokers/topics/[topic]/partitions/[partition]/state 节点读取 ISR;
    • 决定新 Leader;
    • 将新 Leader、ISR、controller_epoch 和 leader_epoch 等信息写入 state节点。
  • 通过RPC向相关Broker发送leaderAndISRRequest命令。

5.高吞吐

kafka是如何实现高吞吐的?

(1)顺序读写

kafka的消息时不断追加到文件中的,这个特性使Kafka可以充分利用磁盘的顺序读写性能。顺序读写不需要硬盘磁头的寻道时间1,只需很少的扇区旋转时间,所以速度远快于随机读写。

(2)零拷贝

在 Linux kernel2.2 之后出现了一种叫做"零拷贝(zero-copy)"系统调用机制,就是跳过“用户缓冲区”的拷贝,建立一个磁盘空间和内存的直接映射,数据不再复制到“用户态缓冲区”。

零拷贝并不是不需要拷贝,而是减少不必要的拷贝次数。通常是说在IO读写过程中。“零拷贝技术”只用将磁盘文件的数据复制到页面缓存中一次,然后将数据从页面缓存直接发送到网络中。

(3)分区

kafka的队列topic被分为了多个区partition,每个partition又分为多个segment,所以一个队列中的消息实际上是保存在N多个片段文件中通过分段的方式,每次文件操作都是对一个小文件的操作,非常轻便,同时也增加了并行处理能力。

(4)批量发送

kafka允许进行批量发送消息,先将消息缓存在内存中,然后一次请求批量发送出去比如可以指定缓存的消息达到某个量的时候就发出去,或者缓存了固定的时间后就发送出去如100条消息就发送,或者每5秒发送一次这种策略将大大减少服务端的I/O次数。

(5)数据压缩

Kafka还支持对消息集合进行压缩,Producer可以通过GZIP或Snappy格式对消息集合进行压缩,压缩的好处就是减少传输的数据量,减轻对网络传输的压力。

(6)Consumer的负载均衡

当一个group中,有consumer加入或者离开时,会触发partitions均衡。均衡的最终目的,是提升topic的并发消费能力。

6.负载均衡

在创建一个Topic时,Kafka尽量将Partition均分在所有的Broker上,并且将Replicas也均分在不同的Broker上。

另外关于 Leader 的负载均衡也需要注意,当一个 Broker 停止时,所有本来将它作为 Leader 的分区将会把 Leader 转移到其他 Broker 上去,极端情况下,会导致同一个 Leader 管理多个分区,导致负载不均衡,同时当这个 Broker 重启时,如果这个 Broker 不再是任何分区的 Leader,Kafka 的 Client 也不会从这个 Broker来读取消息,从而导致资源的浪费。

Kafka 中有一个被称为**优先副本(preferred replicas)**的概念。如果一个分区有 3 个副本,且这 3 个副本的优先级别分别为 0,1,2,根据优先副本的概念,0会作为Leader。当0节点的Broker挂掉时,会启动1这个节点Broker当做Leader。 当 0 节点的 Broker 再次启动后,会自动恢复为此 Partition 的 Leader。不会导致负 载 不 均 衡 和 资 源 浪 费 , 这 就 是 Leader 的 均 衡 机 制 。 可 在 配 置 文 件conf/ server.properties 中配置开启(默认就是开启):

auto.leader.rebalance.enable=true

r挂掉时,会启动1这个节点Broker当做Leader。 当 0 节点的 Broker 再次启动后,会自动恢复为此 Partition 的 Leader。不会导致负 载 不 均 衡 和 资 源 浪 费 , 这 就 是 Leader 的 均 衡 机 制 。 可 在 配 置 文 件conf/ server.properties 中配置开启(默认就是开启):

auto.leader.rebalance.enable=true

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值