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 :TODOPacificA : kafka采用的一致性协议 整体架构
生产者kakaka生产者,顾名思义,为kafka消息的发送方
发送消息时,topic和消息数据是必然配置的数据,其余参数会有默认值
消息发送方法Fire-forget: 发后即忘,不关心是否发成功sync : 同步,发送完后需要获取是否发送成功,再发送下一条信息async : 异步 生产者客户端的整体架构
生产者客户端的整体架构如上图所示,生产者客户端分为主线程和Sender异步线程
主线程可以看到将消息发送到kafka broker之前,主线程会先经过拦截器,序列化器和分区器,将消息添加到消息累加器
拦截器:跟大多数拦截器类似,对消息进行过滤或者进行封装处理等等序列化器: 生产者发送消息到broker,消费者从broker读取消息,都是通过字节流传输的,传输前的序列化,和获取之后的解析,就是序列化和反序列化分区器:将消息发送到哪个分区,一般默认会根据key进行算法映射到某个分区
讲过主线程的操作之后,可以确定消息发送到哪个分区,那么将消息放到RecordAccumulator中,
RecordAccumulatorRecordAccumulator对每个分区,维护了一个ProducerBatch list, 一个ProducerBatch又是一个producer message list(每个ProducrerBatch大小会有限制,跟batch.size大小有关)
Sender线程生产者为了一个一个分区到broker节点的映射,因为sender线程只关注网络连接,即消息应该往哪个节点上发,因此会将RecordAccumulator中的map<分区,list>映射为map
还会再进行二次封装,将上述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注册多个节点,用来监听各种状态和信息的变化
深入客户端 分区分配策略有多个自带的策略,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、消费完如果没有提交消费位移,那么依然可以消费下一条消息,只不过如果消费客户端重启后,还是从最老的未提交消费的位置开始进行消费



