Kafka架构深入详解

一、定义

Kafka是一个分布式的基于发布/订阅模式的消息队列(Message Queue),主要应用于大数据实时处理领域。

1.1 点对点模式

  1. 消息队列的第一种模式
  2. 一对一,消费者(Consumer)主动拉取数据,消息收到后消息清除
    在这里插入图片描述

1.2 发布/订阅模式

  1. 消息队列的第二种模式
  2. 一对多,消费者消费数据之后不会清除消息
    在这里插入图片描述

二、基础架构

  1. Producer :消息生产者,就是向kafka broker发消息的客户端;
  2. Consumer :消息消费者,向kafka broker取消息的客户端;
  3. Consumer Group (CG):消费者组,由多个consumer组成。**消费者组内每个消费者负责消费不同分区的数据,一个分区只能由一个消费者消费;消费者组之间互不影响。**所有的消费者都属于某个消费者组,即消费者组是逻辑上的一个订阅者。
  4. Broker :一台kafka服务器就是一个broker。一个集群由多个broker组成。一个broker可以容纳多个topic
  5. Topic :可以理解为一个队列,生产者和消费者面向的都是一个topic
  6. Partition:为了实现扩展性,一个非常大的topic可以分布到多个broker(即服务器)上,一个topic可以分为多个partition,每个partition是一个有序的队列;
  7. Replica:副本,为保证集群中的某个节点发生故障时,**该节点上的partition数据不丢失,**且kafka仍然能够继续工作,kafka提供了副本机制,一个topic的每个分区都有若干个副本,一个leader和若干个follower。
  8. leader:每个分区多个副本的“主”,生产者发送数据的对象,以及消费者消费数据的对象都是leader。
  9. follower:每个分区多个副本中的“从”,实时从leader中同步数据,保持和leader数据的同步。leader发生故障时,某个follower会成为新的leader。

在这里插入图片描述

三、Kafka文件存储机制

由于生产者生产的消息会不断追加到log文件末尾,为防止log文件过大导致数据定位效率低下,Kafka采取了分片和索引机制,将每个partition分为多个segment。

在这里插入图片描述

  1. 每个partition相当于一个不断被追加的文件(三个文件构成一个Partition)
  2. 一个数据文件和两个索引文件构成的(位置索引和时间索引)
  3. time_index 记录每条数据写入的信息
  4. 若文件太大了,则会生成一个新的文件(segment)
  5. 配置中log.segment.bytes=1G(默认为1G)就会生成一个新的文件(三个文件都会被切,保证配套)
  6. 存储的时间是log.retention.hours=168(一个星期)
  7. 检查的时间log.retention.chech.interval.ms=300000(5分钟),要不要被清除
  8. 存储的位置在logs下的_consumer_offsets-分区数字(内部分区),记录消费者消费
    的进度
  9. 默认只有一个partition
  10. 0000000000000000000.index ---- 数字的意思是,表示从那个消息开始存储的,如第一个文件存储了100个文件,那么第二个文件的名字为101.index
  11. 一条消息不会被分为两个文件

在这里插入图片描述

三个文件配套(数据 + 位置索引 + 时间索引)

四、Kafka生产者

4.1 分区策略

  1. **方便在集群中扩展,**每个Partition可以通过调整以适应它所在的机器,而一个topic又可以有多个Partition组成,因此整个集群就可以适应任意大小的数据了;
  2. 可以提高并发,因为可以以Partition为单位读写了。
  3. 指明 partition 的情况下,直接将指明的值直接作为 partiton 值
  4. 没有指明 partition 值但有 key 的情况下,将 key 的 hash 值与 topic 的 partition 数进行取余得到 partition 值
  5. 既没有 partition 值又没有 key 值的情况下,第一次调用时随机生成一个整数(后面每次调用在这个整数上自增),将这个值与 topic 可用的 partition 总数取余得到 partition 值,也就是常说的 round-robin 算法。

在这里插入图片描述

4.2 数据可靠性

  1. 为保证producer发送的数据,能可靠的发送到指定的topic,topic的每个partition收到producer发送的数据后,都需要向producer发送ack(acknowledgement确认收到),如果producer收到ack,就会进行下一轮的发送,否则重新发送数据。

在这里插入图片描述

  1. 在kafka有三种发送ack的方式
    2.1 收到数据直接发送ack(速度快,数据安全性低)
    2.2 leader收到数据然后发送ack(中规中矩)
    2.3 (Kafka)所有副本都写完数据然后发送ack(速度慢,安全性高,会造成数据重复)
  2. 采用第三种所有副本都写完会有问题,如果其中一个节点卡了,挂了,则永远发不回去ack,且如果在发送回去的过程中生产者挂了,则ack没成功,再次传输重复数据。
  3. 解决方法:Leader维护了一个动态的in-sync replica set (ISR),意为和leader保持同步的follower集合。当ISR中的follower完成数据的同步之后,leader就会给producer发送ack。如果follower长时间未向leader同步数据,则该follower将被踢出ISR,该时间阈值由replica.lag.time.max.ms参数设定。Leader发生故障之后,就会从ISR中选举新的leader。
  4. ISR是leader和follower组成的一个小团体,若是其中一个节点挂掉了,则把这个节点踢出团体,不影响数据的写入返回ack
  5. 后续,被踢出团体的节点怎么办呢?
  6. ISR中的分区的每个分区都有LEO是最新数据
  7. HW:ISR中最小的LEO就是HW -> consumer消费者只能看到这个值前面的数据
  8. 被踢出的节点:将HW之后的数据清除出 然后找leader同步新的HW数据,
    直到追到新的HW,重新加入团体

在这里插入图片描述

  1. follower故障:follower发生故障后会被临时踢出ISR,待该follower恢复后,follower会读取本地磁盘记录的上次的HW,并将log文件高于HW的部分截取掉,从HW开始向leader进行同步。等该follower的LEO大于等于该Partition的HW,即follower追上leader之后,就可以重新加入ISR了。
  2. leader故障:leader发生故障之后,会从ISR中选出一个新的leader,之后,为保证多个副本之间的数据一致性,其余的follower会先将各自的log文件高于HW的部分截掉,然后从新的leader同步数据。

4.3 Exactly Once语义

  1. 将服务器的ACK级别设置为-1,可以保证Producer到Server之间不会丢失数据,即At Least Once语义。相对的,将服务器ACK级别设置为0,可以保证生产者每条消息只会被发送一次,即At Most Once语义。
    At Least Once可以保证数据不丢失,但是不能保证数据不重复;相对的,At Least Once可以保证数据不重复,但是不能保证数据不丢失。但是,对于一些非常重要的信息,比如说交易数据,下游数据消费者要求数据既不重复也不丢失,即Exactly Once语义。在0.11版本以前的Kafka,对此是无能为力的,只能保证数据不丢失,再在下游消费者对数据做全局去重。对于多个下游应用的情况,每个都需要单独做全局去重,这就对性能造成了很大影响。
    0.11版本的Kafka,引入了一项重大特性:幂等性。所谓的幂等性就是指Producer不论向Server发送多少次重复数据,Server端都只会持久化一条。幂等性结合At Least Once语义,就构成了Kafka的Exactly Once语义。即:
    At Least Once + 幂等性 = Exactly Once
    要启用幂等性,只需要将Producer的参数中enable.idompotence设置为true即可。Kafka的幂等性实现其实就是将原来下游需要做的去重放在了数据上游。开启幂等性的Producer在初始化的时候会被分配一个PID,发往同一Partition的消息会附带Sequence Number。而Broker端会对<PID, Partition, SeqNumber>做缓存,当具有相同主键的消息提交时,Broker只会持久化一条。
    但是PID重启就会变化,同时不同的Partition也具有不同主键,所以幂等性无法保证跨分区跨会话的Exactly Once。
  2. 幂等性:producer生产者无论发送多少次重复数据,Server端都指挥持久化一条发送的数据没有自定义全局主键,则Kafka会自己生成一个 <PID, Partition, SeqNumber>
  3. PID:produceID
    partition:那个分区
    seqNumber:第几条消息
  4. Server会存储消息和这个全局主键
  5. 幂等性,无法保证跨分区(producer挂了再重启)

五、Kafka消费者

在这里插入图片描述

5.1 消费方式

consumer采用pull(拉)模式从broker中读取数据。
push(推)模式很难适应消费速率不同的消费者,因为消息发送速率是由broker决定的。它的目标是尽可能以最快速度传递消息,但是这样很容易造成consumer来不及处理消息,典型的表现就是拒绝服务以及网络拥塞。而pull模式则可以根据consumer的消费能力以适当的速率消费消息。
**pull模式不足之处是,如果kafka没有数据,消费者可能会陷入循环中,一直返回空数据。**针对这一点,Kafka的消费者在消费数据时会传入一个时长参数timeout,如果当前没有数据可供消费,consumer会等待一段时间之后再返回,这段时长即为timeout。

5.2 分区分配策略

  1. 一个consumer group中有多个consumer,一个 topic有多个partition,所以必然会涉及到partition的分配问题,即确定那个partition由哪个consumer来消费。
    Kafka有两种分配策略,一是roundrobin,一是range。
  2. roundrobin(轮询):斗地主 发牌
  3. range(): 不洗牌模式,分堆,然后直接发

在这里插入图片描述

5.3 offset的维护

  1. 由于consumer在消费过程中可能会出现断电宕机等故障,consumer恢复后,需要从故障前的位置的继续消费,所以consumer需要实时记录自己消费到了哪个offset,以便故障恢复后继续消费。
  2. Kafka 0.9版本之前,consumer默认将offset保存在Zookeeper中,从0.9版本开始,consumer默认将offset保存在Kafka一个内置的topic中,该topic为__consumer_offsets。
  3. 靠别人不如靠自己系列

六、Kafka高效读写数据

在这里插入图片描述

  1. 顺序写磁盘
  2. 应用Pagecache
  3. 零复制技术
    在这里插入图片描述

七、Zookeeper在Kafka中的作用

  1. Kafka集群中有一个broker会被选举为Controller,负责管理集群broker的上下线,所有topic的分区副本分配和leader选举等工作。
  2. Controller的管理工作都是依赖于Zookeeper的。

在这里插入图片描述

  1. 临时节点,谁快谁当选,启动集群后有一个broker会被选举为controller 负责管理topic的分区副本管理
  2. 在zk中注册borker controller负责监听节点信息,若leader挂了 重新选举新的leader 然后更新leader及isr

八、Kafka事务

Kafka从0.11版本开始引入了事务支持。事务可以保证Kafka在Exactly Once语义的基础上,生产和消费可以跨分区和会话,要么全部成功,要么全部失败。

8.1 Producer事务

在这里插入图片描述

  1. 为了实现跨分区跨会话的事务,需要引入一个全局唯一的Transaction ID,并将Producer获得的PID和Transaction ID绑定。这样当Producer重启后就可以通过正在进行的Transaction ID获得原来的PID。
  2. 为了管理这里是引用Transaction,Kafka引入了一个新的组件Transaction Coordinator。Producer就是通过和Transaction Coordinator交互获得Transaction ID对应的任务状态。Transaction Coordinator还负责将事务所有写入Kafka的一个内部Topic,这样即使整个服务重启,由于事务状态得到保存,进行中的事务状态可以得到恢复,从而继续进行。

8.2 Consumer事务

上述事务机制主要是从Producer方面考虑,对于Consumer而言,事务的保证就会相对较弱,尤其时无法保证Commit的信息被精确消费。这是由于Consumer可以通过offset访问任意信息,而且不同的Segment File生命周期不同,同一事务的消息可能会出现重启后被删除的情况。

九、Life

“有一种人,天天都笑嘻嘻的,好似和谁都合得来,但是从不主动联系朋友,脾气也出奇的好,好像世上没什么事情能让他们愤怒和悲伤。这一种人,懒得咒骂,懒得分享心情,也无心去写矫情的文字,你问他怎么了,他只是一笑. 只有在大着书,亦是戴着耳机,看到共鸣之处,忍住心中的一阵战栗”

在这里插入图片描述

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值