Kafaka学习总结

1 篇文章 0 订阅
1 篇文章 0 订阅

kafka简介

kafka是一个应用比较频繁的分布式消息系统,使用scala语言开发,基于zookeeper进行协调,多分区、多副本;

它的特性是高吞吐、可持久化、可水平扩展、支持流数据处理,它具备三大功能:

  • 消息系统,在业务系统中经常用到,最常见的是解耦,当然,还具有削峰、异步通信、缓冲等功能
  • 存储系统
  • 流式处理平台

安装与基本操作

http://kafka.apache.org/quickstart#quickstart_kafkastreams

按照官网链接安装,和测试即可

kafka基本概念

  • Producer : 生产者,发送消息的一方
  • Consumer : 消费者,接收消息的一方
  • Broker : kafka节点,一个节点就是一个kafka server进程
  • Topic :主题,消息以主题来进行归类
  • Partition :分区,主题的所有消息分布在不同的区中,每个分区的消息一定是不同的,分区可以分布在不同的broker中
  • Replica : 副本机制,每个分区引入多副本,leader副本和follower副本,leader副本处理读写,follower副本负责同步leader副本的数据,出现故障时,follower副本中重新选举出新的leader副本,进行故障转移
  • ISR :TODO
  • PacificA : kafka采用的一致性协议

整体架构

在这里插入图片描述

生产者

kakaka生产者,顾名思义,为kafka消息的发送方

发送消息时,topic和消息数据是必然配置的数据,其余参数会有默认值

消息发送方法

  • Fire-forget: 发后即忘,不关心是否发成功
  • sync : 同步,发送完后需要获取是否发送成功,再发送下一条信息
  • async : 异步

生产者客户端的整体架构

在这里插入图片描述

生产者客户端的整体架构如上图所示,生产者客户端分为主线程和Sender异步线程

主线程

可以看到将消息发送到kafka broker之前,主线程会先经过拦截器,序列化器和分区器,将消息添加到消息累加器

  • 拦截器:跟大多数拦截器类似,对消息进行过滤或者进行封装处理等等
  • 序列化器: 生产者发送消息到broker,消费者从broker读取消息,都是通过字节流传输的,传输前的序列化,和获取之后的解析,就是序列化和反序列化
  • 分区器:将消息发送到哪个分区,一般默认会根据key进行算法映射到某个分区

讲过主线程的操作之后,可以确定消息发送到哪个分区,那么将消息放到RecordAccumulator中,

RecordAccumulator

RecordAccumulator对每个分区,维护了一个ProducerBatch list, 一个ProducerBatch又是一个producer message list(每个ProducrerBatch大小会有限制,跟batch.size大小有关)

Sender线程

生产者为了一个一个分区到broker节点的映射,因为sender线程只关注网络连接,即消息应该往哪个节点上发,因此会将RecordAccumulator中的map<分区,list>映射为map<node, list>,

还会再进行二次封装,将上述map放在InFilightRequests中,因为既然要向broker节点网络请求,那么必然涉及到网络连接管理,超时处理等逻辑

消费者

消费者和生产者一样,其实也是client,只不过是用于拉取消息

消费组

每一个消费者都对应一个消费组,或者说,消费组是一群消费者的组合,同一个消费组,只有一个消费者能接收到消息

kafka默认,每个消费组中,平均分配消费者到某个分区,如下图所示

在这里插入图片描述

P0-p6为分区,当消费组中的消费者改变时,每个消费者消费的分区也会发生改变

消费模式

kafka中采用主动拉取模式,消费者主动从分区拉取消息

消费位移

为了保证重启之后或者有新的消费者加入到消费组后,能够正确地继续消费某个分区,因此会有消费位移的概念,每个消费者进行消费后,都会定时提交当前消费的位移

在这里插入图片描述

消费位移可能会造成消息丢失或者重复消费的现象,重复消费是指发生异常时没有来得及提交导致重启后读取了已有的消息,消息丢失情况比较少(一般可能和业务有强关系)

也可以调用api进行手动提交位移

唯一提交或多或少存在丢失或者重复消费的问题,一般情况,应该尽量避免丢失,可以重复消费,做好幂等和防并发就行

拦截器

和生产者一样,消费者也有拦截器,在poll获取数据之前,以及位移提交之后都可以进行逻辑处理

主题与分区

在这里插入图片描述

主题和分区其实是逻辑层面的概念,真正物理意义上,是副本的Log日志

分区副本的分配

副本可以按照kafka默认的方式对主题进行副本分配,也可以设置–replica-assingnment参数设置每个分区的副本

分区

kafaka自带性能测试工具,bin/kafka-producer-perf-test.sh和bin/kafka-consumer-perf-test.sh

分区数太小整个系统的吞吐量会很小,但是太大也不好,到达一个阈值之后肯定会下降,这跟系统的资源有关,比如已经使用的文件描述符,如果过大,超过了对每个进程文件描述符的限制甚至会发生崩溃,一般可以通过未来2年内的吞吐量来设置分区

如果分区数过大,那么副本对应的分区数也会过大,那么leaderd宕机时,大量的分区进行leader角色的切换

分区数过大也会导致一些资源的耗时,比如日志

日志存储

kafka-dump-log.sh脚本用来查看日志

kafka具有日志清楚和日志压缩的功能,具体跟redis很像

kafka日志文件的形式为:每个分区对应一个文件夹,比如topicA有4个分区,那么就有4个文件夹,topicA-log-0,topicA-log-1,topicA-log-2,topicA-log-3. 每个分区的日志是一个log文和两个索引文件,为了防止log过大,会将log文件进行切割;索引文件分别为偏移量索引文件(文件后缀为.index)和时间戳索引文件(文件后缀为.timeindex)

​ — 偏移量索引文件也是和log文件的切割片段对应,偏移量的名字中数字表示log切割文件相对于整体日志的偏移量,文件每行记录是相对本日志分段的偏移量和消息所在的物理文件位置 这里物理文件位置不太懂,不知道如何从日子分段文件中找到的

​ — 时间戳索引文件是以时间为维度的,每行记录是时间戳和消息的相对偏移量

深入服务端

协议涉及

kafka有自己的协议设计,类似于grpc一样,有自己的数据基本类型和格式

在这里插入图片描述

在这里插入图片描述

时间轮

时间轮主要用于延迟任务,延迟任务因为需要针对每个任务进行特定时间触发,因此需要时间轮

时间轮可以理解为一个钟表,有多层,有多层,每一层平均划分为多个格,每个格可能根据时间存放一个任务,当时钟转到某个格时,如果刚好到时间了,就会触发该任务

控制器

控制器跟leader副本不是一个概念,集群中的某个broker会被选择为控制器,控制器用来管理集群中所有分区和副本的状态,比如某个分区leader副本出现故障,那么就由控制器重新选举leader副本

控制器的选举依赖于zookeeper, 并且会向zookeeper注册多个节点,用来监听各种状态和信息的变化

控制器的选举

首先,整个kafka集群中会有一个broker节点会被选举成为控制器,做法是所有broker节点同时向zk 创建/controller临时节点,只有一个会创建成功,并且有一个controller epoch字段,每次选举成功之后就会加1,并且创建/controller临时节点请求时也会带上这个字段,> 当前epoch值说明是有新的选举

分区leader副本的选举

每个topic的分区leader副本由全局的控制器来选择,每次初始化分区时就会有一个副本集合,即ISR集合,当有broker下线时,那么就会顺序地从AR集合中找到第一个来作为leader副本

深入客户端

分区分配策略

有多个自带的策略,RangeAssignor, RoundRobinAssignor, StickyAssignor

StickyAssignor综合来看最好,主要遵循两个条件来分配:

1、尽量均匀

2、重新分配时,尽量保留已有的分配

消费者协调器和组协调器

在服务端有一个GroupCoordinator的概念,消费者有一个ConsumerCoordinator的概念,两者之间进行通信,负责心跳、消费者再均衡的操作等等

事务

消费者消费消息时,是先处理逻辑,再提交消费位移,还是反过来,如果这两个步骤中间发生了宕机然后重启,可能会导致重复消费或者消息没有消费

幂等

幂等是针对重复消费的,当提交位移是,在broker中会保存每个分区每条已经收到的消息的序列号,如果已经提交过消费位移了,那么肯定已经保存了序列号,下次再提交时,在broker就会做对比,如果是小于或等于已有的序列号,那么就说明已经消费过了,不会再发送给消费者

事务

事务是针对发送者,保证往kafka集群中发送消息能够成功

https://zhuanlan.zhihu.com/p/163683403

可靠性探究

副本机制,日志同步机制保证了kafka的可靠性

实践篇

1、kafka bin目录下有很多工具,可以多维度查询信息,具体可以直接执行工具,查看参数

2、可以自己写个demo,发消息,然后接收消息,本人实践时,确认了以下问题:

​ 2.1、对于每个分区的消息,是顺序发送的,消费完成后才会消费下一条消息

​ 2.2、消费完如果没有提交消费位移,那么依然可以消费下一条消息,只不过如果消费客户端重启后,还是从最老的未提交消费的位置开始进行消费

kafka扩容

https://bbs.huaweicloud.com/blogs/280873
扩容:
方案1: 直接使用扩容扩分区命令,在配置文件中指定每个分区对应的副本(包括新旧分区)。
方案2: 先直接进行扩容扩分区,这样新的分区已经在原来的节点中,然后再进行迁移到新的节点中。
对于分区比较少的,用方案1, 否则用方案2

常见面试题

kafka为什么那么快

https://zhuanlan.zhihu.com/p/120967989

  • 顺序读写,对于每个分区的日志都是追加,相对于随机,非常快
  • 基于操作系统的PageCache进行读写,PageCache利用操作系统,很多场景都是基于内存的,速度很快
  • 零拷贝技术,在未使用零拷贝技术时,一般先从磁盘拷贝到内核缓冲区,再从内核缓冲区拷贝到用户进程的缓冲区,再从用户进程缓冲区拷贝到socket缓冲区,再拷贝到NIC缓冲区(网卡缓冲区)。 *而使用零拷贝技术就会直接从内核缓冲区拷贝到socket缓冲区,再到NIC缓冲区,所以节省了很多时间
  • 分区分段索引,每个topic会分多个分区,每个分区的日志文件又会分段,还有稀疏索引文件,符合分布式系统的高性能特点
  • 批量读写:producer发送消息会将消息放到一个缓冲区合并后一起发送,consumer pull时也是批量拉去
  • 批量压缩,数据发送时可以进行压缩,一般可用gzip方式和Snappy方式

kafka怎么保证顺序性

  • 每个topic的消息只会发送到一个分区,然后同一个消费组只有一个消费者能拉取这个分区的消息,并且根据topic的key可以唯一分配到某个分区
  • 消费者可以手动标记当前消息消费成功后,再去处理下一个消息
    当然,如果在一个消费者线程里用异步来做,那么可能还是会乱序

消息队列选型

业务中常用的消息队列有:kafka、rocketmq、rabbitmq
选型对比如下:https://cloud.tencent.com/developer/article/1944357
rabbitmq原理如下:https://www.cnblogs.com/frankyou/p/5283539.html
https://www.cnblogs.com/julyluo/p/6265775.html

rocketmq原理如下:https://juejin.cn/post/6844904008629354504

  • rocketmq比kafka可靠是因为rocketmq支持同步刷磁盘,但是kafka是异步刷磁盘
  • rabbit mq不支持消息的顺序性,如果要实现的话,只能在代码层面去改,比如一个queue只对应一个consumer,然后再consumer里多线程消费,需要顺序消费的再内存队列里排队
  • rabbitmq的延迟最小
  • rocketmq其实也支持消息的顺序性,做法和kafka类似,只不过是根据Selector,根据具体业务逻辑主动进行队列的选取。 而kafka只需要设置key,只要key不为null,那么就会用key进行hash,分配到固定的分区。
    在这里插入图片描述
  • 2
    点赞
  • 20
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值