什么是Kafka呢?
在刚接触的时候我们可以浅浅的当作一个消息队列,
这也是传统定义
( Kafka是一个分布式的基于发布/订阅模式的消息队列(Message Queue),主要应用于大数据实时处理领域。)
随着技术提升Kafka也来到了一个新的高度,在现在定义Kafka已是一个 分布式事件平台了 被应用于高性能数据管道、流分析、数据集成和关键任务应用。
那从定义能引出 那什么是消息队列(Message Queue)呢?
消息队列,一般我们会简称它为MQ(Message Queue),也叫消息中间件,是分布式系统中重要的组件,主要解决应用解耦,异步消息,流量削峰等问题,目前使用较多的消息队列有ActiveMQ,RabbitMQ,ZeroMQ,Kafka,MetaMQ,RocketMQ。
传统的消息队列的主要应用场景包括:缓存/消峰、解耦和异步通信。
看完这个图,Kafka全貌也就差不多出来了,
而接下来的就是将这个图抽丝剥茧,主要划分为3+ 1 的 4个部分
(1)Producer:消息生产者,就是向 Kafka broker 发消息的客户端, 也就是图中的左边
。
(2)Kafka cluster: Kafka集群
(2.1)Broker:一台 Kafka 服务器就是一个 broker.一个集群由多个 broker 组成.一个 broker 可以容纳多个 topic.
(2.2)Topic:可以理解为一个队列,生产者和消费者面向的都是一个 topic
(2.3) Partition:为了实现扩展性,一个非常大的 topic 可以分布到多个 broker即(服务器)上,一个 topic 可以分为多个 partition,每个partition 是一个有序的队列。
(2.4)Replica:副本。一个 topic 的每个分区都有若干个副本,一个 Leader(“主”) 和若干个Follower(“从”)。
(3)Consumer:消息消费者,向 Kafka broker 取消息的客户端
Consumer Group(CG):消费者组,由多个 consumer 组成。
下面从左至右来将这张图 :
第一个 生产者 --> 到第二个 Kafka Cluster 的过程 涉及到了两个线程——main 线程和 Sender 线程
。在 main线程中创建了一个双端队列 RecordAccumulator。main 线程将消息发送给 RecordAccumulator, Sender 线程不断从 RecordAccumulator 中拉取消息发送到 Kafka Broker。
(4)Zookeeper Cluster:Zookeeper 集群 不重点介绍
第二个图中
还有一个内存池的细节:双端队列中来到一批次数据会向内存池中去取内存,然后发送到kafka集群完再释放会内存池
图中细节 :
①RecordAccumulator 缓冲区总大小,默认 32m。
②batch.size 缓冲区一批数据最大值,默认 16k。`适当增加该值,可 以提高吞吐量,但是如果该值设置太大,会导致数据 传输延迟增加。
③如果数据迟迟未达到 batch.size,sender 等待 linger.time之后就会发送数据。
④允许最多没有返回 ack 的次数,默认为 5,开启幂等性 要保证该值是 1-5 的数字。
⑤retries 当消息发送出现错误的时候,系统会重发消息。retries 表示重试次数。默认是 int 最大值 2147483647。
要是保存有序,得开启相关参数,将允许最多没有返回 ack 的次数等于1,brock默认缓存5个请求 ,两次重试之间的时间间隔,默认是 100ms。
应答ack 0是接收到就应答 ,1 是leader 保存就应答 ,-1 是 leader 和所有备份节点 保存 就应答
(1)指明partition的情况下,直 接将指明的值作为partition值 , 例如partition=0,所有数据写入分区0;
(2)没有指明partition值但有key的情况下,将key的hash值与topic的 partition数进行取余得到partition值;例如:key1的hash值=5, key2的hash值=6 ,topic的partition数=2,那 么key1 对应的value1写入1号分区,key2对应的value2写入0号分区。
(3)既没有partition值又没有key值的情况下,Kafka采用Sticky Partition(黏性分区器),会随机选择一个分区,并尽可能一直 使用该分区,待该分区的batch已满或者已完成,Kafka再随机一个分区进行使用(和上一次的分区不同)。 例如:第一次随机选择0号分区,等0号分区当前批次满了(默认16k)或者linger.ms设置的时间到, Kafka再随机一个分区进 行使用(如果还是0会继续随机)。
数据完全可靠条件 = ACK级别设置为-1 + 分区副本大于等于2 + ISR里应答的最小副本数量大于等于2
可靠性总结:
acks=0,生产者发送过来数据就不管了,可靠性差,效率高;
acks=1,生产者发送过来数据Leader应答,可靠性中等,效率中等;
acks=-1,生产者发送过来数据Leader和ISR队列里面所有Follwer应答,可靠性高,效率低;
在生产环境中,acks=0很少使用;acks=1,一般用于传输普通日志,允许丢个别数据;acks=-1,
一般用于传输和钱相关的数据, 对可靠性要求比较高的场景。
数据去重(来源 Leader接收到Producer发来的数据 ,还未做出ack就挂了,副本替代Leader再接收一边导致的)
就是生产者发送的消息
• 至少一次(At Least Once)= ACK级别设置为-1 + 分区副本大于等于2 + ISR里应答的最小副本数量大于等于2
• 最多一次(At Most Once)= ACK级别设置为0
• 总结:
At Least Once可以保证数据不丢失,但是不能保证数据不重复;
At Most Once可以保证数据不重复,但是不能保证数据不丢失。
• 精确一次(Exactly Once)(重要):对于一些非常重要的信息,比如和钱相关的数据,要求数据既不能重复也不丢失。
Kafka 0.11版本以后,引入了一项重大特性:幂等性和事务。
幂等性就是指Producer不论向Broker发送多少次重复数据,Broker端都只会持久化一条,保证了不重复。
精确一次(Exactly Once) = 幂等性 + 至少一次( ack=-1 + 分区副本数>=2 + ISR最小副本数量>=2) 。
上图解析
broker启动后 ,谁先注册谁先成为代理人 ,然后代理人监听brokers节点编号,后面才开始真正的选举Leader节点
ar和isr区别
假如没有因为延迟过长而掉队的 isr 可以说 isr = ar ,但是这是理想状态下 ,但是实际上 AR = ISR+OSR
AR(Assigned Repllicas):Kafka 分区中的所有副本
ISR,表示和 Leader 保持同步的 Follower 集合 如果 Follower 长时间未向 Leader 发送通信请求或同步数据,则该 Follower 将被踢出 ISR。默认30s
OSR,表示 Follower 与 Leader 副本同步时,延迟过多的副本。ISR+30s等于掉队
(1) Leader发生故障之后,会从ISR中选出一个新的Leader
(2)为保证多个副本之间的数据一致性,其余的Follower会先将各自的log文件高于HW的部分截掉,然后从新的Leader同步数据。
Topic是逻辑上的概念,而partition是物理上的概念,每个partition对应于一个log文件,该log文件中存储的就是Producer生产的数据。Producer生产的数据会被不断追加到该log文件末端,为防止log文件过大导致数据定位效率低下,Kafka采取了分片和索引机制,将每个partition分为多个segment。每个segment包括:“.index”文件、“.log”文件和.timeindex等文件。这些文件位于一个文件夹下,该文件夹的命名规则为topic名称+分区序号,例如:first-0。
index和log文件以当前segment的第一条消息的offset命名。
1.kafka本身是分布式集群,可以采用分区技术 ,并行度高
2.读数据是稀疏索引 可以定位要消费的数据
3.顺序写磁盘写的过程是一直追加到文件末端,这样可以能到600M/s
4.页缓存 + 零拷贝技术
零拷贝:Kafka的数据加工处理操作交由Kafka生产者和Kafka消费者处理。Kafka Broker应用层不关心存储的数据,所以就不用走应用层,传输效率高。
PageCache页缓存:Kafka重度依赖底层操作系统提供的PageCache功 能。当上层有写操作时,操作系统只是将数据写入PageCache。当读操作发生时,先从PageCache中查找,如果找不到,再去磁盘中读取。实际上PageCache是把尽可能多的空闲内存都当做了磁盘缓存来使用。
kafka的用途就是把生产者发来的发给消费者 不做任何处理 ,处理的是生产者 本身 和消费者本身 可以通过拦截器
consumer采用从broker中主动拉取数据。Kafka采用这种方式。
pull模式不足之处是,如 果Kafka没有数据,消费者可能会陷入循环中,一直返回空数据。
图中解析:
ConsunerNetworkClient 和kafka集群进行交互
sendfetch 抓取数据初始化 下面几个是他的默认值
通过send请求,onsuccess通过回调函数将集群中的数据拉取过来
然后反序列化,拦截器,然后处理数据
如果想完成Consumer端的精准一次性消费,那么需要Kafka消费端将消费过程和提交offset过程做原子绑定
下面是自己觉得比较重要的
offset是什么?
对于每一个topic,集群都会维持一个分区日志每个分区都是有序且顺序不可变的记录集,并且不断地追加到结构化的log文件。分区中的每一个记录都会分配一个id号来表示顺序,我们称之为offset,offset用来唯一的标识分区中每一条记录。
offset有什么用?
消费者在消费数据时,发生宕机后,再次重新启动后,消费的数据需要从宕机位置开始读取
如果从头读取,有一部分消息一定出现了重复消费
如果从宕机时的消费位置读取,就不会出现重复消费
因此kafka设计了offset可以用于处理这种情况
1、Last Committed Offset:consumer group 最新一次 commit 的 offset,表示这个 group 已经把 Last Committed Offset 之前的数据都消费成功了。
2、Current Position:consumer group 当前消费数据的 offset,也就是说,Last Committed Offset 到 Current Position 之间的数据已经拉取成功,可能正在处理,但是还未 commit。
3、Log End Offset(LEO):记录底层日志 (log) 中的下一条消息的 offset。, 对 producer 来说,就是即将插入下一条消息的 offset。
4、High Watermark(HW):已经成功备份到其他 replicas 中的最新一条数据的 offset,也就是说LEO与 HW 之间的数据已经写入到该 partition 的 leader 中,但是还未完全备份到其他的 replicas 中,consumer 是无法消费这部分消息 (未提交消息)。
Exactly Once = At Least Once + 幂等性 + Producer事务 精确一次(Exactly Once)= 幂等性 + 至少一次(ack=-1+分区副本数>=2+ISR最小副本数量>=2)+ Producer事务
生产者 +Kafka+ 消费者 整个流程要如何精确一次性消费? Producer事务+至少一次+幂等性+Consumer+下游消费者必须支持事务