Kafka传统定义:是一个分布式的基于发布/订阅模式的 消息队列,主要应用于大数据的实时处理领域。
发布/订阅:消息的发布者不会将消息直接发送给特定的订阅者,而是将发布的消息分为不同的类别,订阅者只接收感兴趣的消息。
最新定义:kafka是一个开源的分布式事件流平台,被数千家公司用于高性能数据管道、流分析、数据集成和关键任务应用。
消息队列应用场景—缓冲/消峰:有助于控制和优化数流经过系统的速度,解决生产消息和消费消息的处理速度不一致的情况。
解耦:允许你独立的扩展或经过修改两边的处理过程,只要确保他们遵守同样的接口约束。
异步通信:允许用户把一个消息放入队列,但并不立即处理它,然后在需要的时候再去处理他们。
消息队列的两种模式:1、点对点模式:消费者主动拉取数据,消息收到后清除消息 2、发布/订阅模式 可以有多个topic主题(浏览、点赞、收藏、评论等)消费者消费数据之后,不删除数据 每个消费者相互独立都可以消费到数据。
Kafka基础架构:1、为方便扩展,并提高吞吐量,一个topic分为多个partition 2、配合分区设计,提出消费者组的概念,组内每个消费者并行消费 3、为提高可用性,为每个partition增加若干个副本,类似NameNode HA 4、ZK中记录谁是leader,Kafka2.8.0以后也可以配置不采用ZK
kafka生产者:
发送原理:在消息发送的过程中,涉及到了两个线程——main线程和Sender线程。在main线程中创建了一个双端队列。Main线程将消息发送给RecordAccumulator,Sender线程不断从RecordAccumulator中拉取消息发送到Kafka Broker。
Kafka分区的好处:1、便于合理使用存储资源,每个Partition在一个Broker上存储,可以把海量的数据按照分区切割成一块一块数据存储在多台Broker上。合理控制分区的任务,可以实现负载均衡的效果。2、提高并行度,生产者可以以分区为单位发送数据,消费者可以以分区为单位进行消费数据。
分区原则:
Acks应答级别:0:生产者发送过来数据,不需要等数据落盘应答 1:生产者发送过来的数据,Leader收到数据后应答。-1:生产者发送过来的数据,Leader和ISR队列里面的所有节点收齐数据后应答。
Leader维护了一个动态的in-sync replica set(ISR),意为和Leader保持同步的Follow+Leader集合(leader:0,isr:0,1,2)
如果Follower长时间未向Leader发送通信请求或数据同步,则该Follower将被踢出ISR。该时间阈值默认为30S。
-1可靠性分析:如果分区副本设置为1,或者ISR里面应答的最小副本数量设置为1,和ack=1的效果是一样的,仍有丢失风险。
数据完全可靠条件=ACK级别设置为-1+分区副本大于等于2+ISR里的应答的最小副本数量大于等于2。
幂等性原理:指生产者不论向Broker发送多少次重复数据,Broker端都只会持久化一条,保证了不重复。
精确一次=幂等性+至少一次(ack=-1+分区副本数>=2+ISR最小副本数量>=2)。
重复数据的判断标准:具有<PID,Partition,SeqNumber>相同主键的消息提交时,Broker只会持久化一条。其中PID是Kafka每次重启都会分配一个新的,Partition表示分区号,Sequence Number是单调递增的。所以幂等性只能保证的是在单分区会话内不重复。
保证全区不重复:开启事务
数据乱序:1)在1.x版本之前保证数据单分区有序,条件如下:
Max.in.flight.requests.per.connection=1,(缓存队列只放一个只有前一个发完才能发第二个)不需要考虑是否开启幂等性2)在1.x及以后版本保证数据单分区有序,条件如下:1)未开启幂等性Max.in.flight.requests.per.connection需要设置为1。开启幂等性Max.in.flight.requests.per.connection需要设置小于等于5,因为kafka1.x版本后,启用幂等后,kafka服务端会缓存producer发来的最近5个request的元数据,故无论如何,都可以保证最近的5个request的数据是有序的。
在Zookeeper的服务存储的kafka相关信息:1)记录有哪些服务器2)记录谁是Leader,有哪些服务器可用3)辅助选举Leader
Follower故障处理细节:
LEO:每个副本的最后一个offset,LEO其实就是最新的offset+1
HW:所有副本中最小的LEO
- Follower故障:发生故障后会被临时踢出ISR,这个期间Leader和Follower继续接收数据,待该Follower恢复后,Follower会读取本地磁盘记录的上次的HW,并将log文件高于HW的部分截取掉,从HW开始向Leader进行同步。等该Follower的LEO大于等于该Partition的HW,即Follower追上Leader之后,就可以重新加入ISR了。
- Leader故障处理:Leader发生故障之后,会从ISR中选出一个新的Leader。为保证多个副本之间的数据一致性,其余的Follower会先将各自的log文件高于HW的部分截掉,然后从新的Leader同步数据。
注意:这只能保证副本之间的数据一致性,并不能保证数据不丢失或者不重复。
Leader Partition自动平衡:
Kafka文件存储机制:
Kafka存储日志索引是按照稀疏索引进行存储的:
文件清理策略:Kafka中默认日志保存时间为7天,可以通过调整如下参数修改保存时间
log.retention.hours, 最低优先级小时,默认7天
log.retention.minutes,分钟
log.retention.ms,最高优先级毫秒
log.retention.check.interval.ms 负责设置检查周期,默认5分钟
Kafka中提供的日志清理策略有delete和compact两种。
- delete日志删除:将过期数据删除
log.cleanup.policy =delete 所有数据启用删除策略
- 基于时间:默认打开,以segment中所有的记录中的最大时间戳作为该文件时间戳
- 基于大小:默认关闭。超过设置的所有日志总大小,删除最早的segment
log.retention.bytes,默认等于-1,表示无穷大
Compact日志压缩
高效读写数据
- kafka本身是分布式集群,可以采用分区技术,并行度高
- 读数据采用稀疏索引,可以快速定位要消费的数据
- 顺序读写磁盘 Kafka的producer生产数据要写到log文件中,写的过程是一直追加到文件末端,为顺序写。顺序写600M/s,随机100k/s跟磁盘结构有关。
- 页缓存+零拷贝技术
Kafka消费方式
Sticky以及再平衡
粘性分区定义:可以理解为分配的结果待遇“粘性的”。即在执行一次新的分配之前,考虑上一次的分配结果,尽量少的调整分配的变动,可以节省大量开销。
粘性分区首先会尽量均衡的放置分区到消费者上,在出现同一消费者组内消费者出现问题的时候,会尽量保持原有的分配的分区不变化。
Offset的默认维护位置
__consumer_offsets 主题里面采用key和value的方式存储数据。Key是group.id+topic+分区号,value就是当前offset的值。每隔一段时间,kafka内部会对这个topic进行compact,也就是每个group.id+topic+分区号就保留最新数据。
指定offset消费
Auto.offset.reset =earliest|latest|none 默认是latest
当Kafka中没有初始偏移量(消费者组第一次消费)或在服务器上不再存在当前偏移量时,
- earliest:自动将偏移量重置为最早的偏移量,--from-beginning
- latest(默认值):自动将偏移量重置为最新的偏移量
- none:如果未找到消费者组的先前偏移量,则向消费者抛出异常。
漏消费和重复消费
重复消费:已经消费了数据,但是offset没提交。
漏消费:先提交offset后消费,有可能会造成数据的漏消费
Kafka-Kraft模式
Kafka-Kraft架构:
左图为Kafka现有架构,元数据在Zookeeper中,运行时动态选举controller,由controller进行kafka集群管理。右图为Kraft模式架构,不在依赖Zookeeper集群,而是用三台controller节点代替Zookeeper,元数据保存在controller中,由controller直接进行kafka集群管理。
这样做的好处:1、kafka不再依赖外部框架,而是能够独立运行;2、controller管理集群时,不再需要从Zookeeper中先读取数据,集群性能上升3、由于不依赖Zookeeper,集群扩展时不再受到Zookeeper读写能力限制4、controller不再动态选举,而是由配置文件规定。这样我们可以有针对性的加强controller节点的配置,而不是像以前一样对随机的controller节点高负载束手无策。