kafka传递⽂件_Kafka史上最详细原理总结下
3.Partition Replication原则
Kafka⾼效⽂件存储设计特点Kafka把topic中⼀个parition⼤⽂件分成多个⼩⽂件段,通过多个⼩⽂件段,就容易定期清除或删除已经消费完⽂件,减少磁盘占⽤。
通过索引信息可以快速定位message和确定response的最⼤⼤⼩。
通过index元数据全部映射到memory,可以避免segment file的IO磁盘操作。
通过索引⽂件稀疏存储,可以⼤幅降低index⽂件元数据占⽤空间⼤⼩。
1. Kafka集partition replication默认⾃动分配分析
下⾯以⼀个Kafka集中4个Broker举例,创建1个topic包含4个Partition,2 Replication;数据Producer流动如图所⽰:
(1)
image
(2)当集中新增2节点,Partition增加到6个时分布情况如下:
image
副本分配逻辑规则如下:在Kafka集中,每个Broker都有均等分配Partition的Leader机会。
上述图Broker Partition中,箭头指向为副本,以Partition-0为例:broker1中parition-0为Leader,Broker2中Partition-0为副本。
上述图种每个Broker(按照BrokerId有序)依次分配主Partition,下⼀个Broker为副本,如此循环迭代分配,多副本都遵循此规则。
副本分配算法如下:将所有N Broker和待分配的i个Partition排序.
将第i个Partition分配到第(i mod n)个Broker上.
将第i个Partition的第j个副本分配到第((i + j) mod n)个Broker上.
4.Kafka Broker⼀些特性
4.1 ⽆状态的Kafka Broker :
1. Broker没有副本机制,⼀旦broker宕机,该broker的消息将都不可⽤。
2. Broker不保存订阅者的状态,由订阅者⾃⼰保存。
3. ⽆状态导致消息的删除成为难题(可能删除的消息正在被订阅),kafka采⽤基于时间的SLA(服务⽔平保证),消息保存⼀定时间(通常为7天)后会被删除。
4. 消息订阅者可以rewind back到任意位置重新进⾏消费,当订阅者故障时,可以选择最⼩的offset进⾏重新读取消费消息。
4.2 message的交付与⽣命周期 :
1. 不是严格的JMS, 因此kafka对消息的重复、丢失、错误以及顺序型没有严格的要求。(这是与AMQ最⼤的区别)
2. kafka提供at-least-once delivery,即当consumer宕机后,有些消息可能会被重复delivery。
3. 因每个partition只会被consumer group内的⼀个consumer消费,故kafka保证每个partition内的消息会被顺序的订阅。
4. Kafka为每条消息为每条消息计算CRC校验,⽤于错误检测,crc校验不通过的消息会直接被丢弃掉。
4.3 压缩
Kafka⽀持以集合(batch)为单位发送消息,在此基础上,Kafka还⽀持对消息集合进⾏压缩,Producer端可以通过GZIP或Snappy格式对消息集合进⾏压缩。Producer端进⾏压缩之后,在Consumer端需进⾏解压。压缩的好处就是减少传输的数据量,减轻对⽹络传输的压⼒,在对⼤数据处理上,瓶颈往往体现在⽹络上⽽不是CPU。
gzip是什么文件夹那么如何区分消息是压缩的还是未压缩的呢,Kafka在消息头部添加了⼀个描述压缩属性字节,这个字节的后两位表⽰消息的压缩采⽤的编码,如果后两位为0,则表⽰消息未被压缩。
4.4 消息可靠性
在消息系统中,保证消息在⽣产和消费过程中的可靠性是⼗分重要的,在实际消息传递过程中,可能会出现如下三中情况:⼀个消息发送失败
⼀个消息被发送多次
最理想的情况:exactly-once ,⼀个消息发送成功且仅发送了⼀次
有许多系统声称它们实现了exactly-once,但是它们其实忽略了⽣产者或消费者在⽣产和消费过程中有可能失败的情况。⽐如虽然⼀个Producer成功发送⼀个消息,但是消息在发送途中丢失,或者成功发送到broker,也被consumer成功取⾛,但是这个consumer在处理取过来的消息时失败了。
从Producer端看:Kafka是这么处理的,当⼀个消息被发送后,Producer会等待broker成功接收到消息的反馈(可通过参数控制等待时间),如果消息在途中丢失或是其中⼀个broker挂掉,Producer会重新发送(我们知道Kafka有备份机制,可以通过参数控制是否等待所有备份节点都收到消息)。
从Consumer端看:前⾯讲到过partition,broker端记录了partition中的⼀个offset值,这个值指向Consumer下⼀个即将消费message。当Consumer收到了消息,但却在处理过程中挂掉,此时Consumer可以通过这个offset值重新到上⼀个消息再进⾏处理。Consumer还有权限控制这个offset值,对持久化到broker端的消息做任意处理。
4.5 备份机制
备份机制是Kafka0.8版本的新特性,备份机制的出现⼤⼤提⾼了Kafka集的可靠性、稳定性。有了备份机制后,Kafka允许集中的节点挂掉后⽽不影响整个集⼯作。⼀个备份数量为n的集允许n-1个节点失败。在所有备份节点中,有⼀个节点作为lead节点,这个节点保存了其它备份节点列表,并维持各个备份间的状体同步。下⾯这幅图解释了Kafka的备份机制:
image
4.6 Kafka⾼效性相关设计
4.6.1 消息的持久化
Kafka⾼度依赖⽂件系统来存储和缓存消息(AMQ的nessage是持久化到mysql数据库中的),因为⼀般的⼈认为磁盘是缓慢的,这导致⼈们对持久化结构具有竞争性持怀疑态度。其实,磁盘的快或者慢,这决定于我们如何使⽤磁盘。因为磁盘线性写的速度远远⼤于随机写。线性读写在⼤多数应⽤场景下是可以预测的。
4.6.2 常数时间性能保证
每个Topic的Partition的是⼀个⼤⽂件夹,⾥⾯有⽆数个⼩⽂件夹segment,但partition是⼀个队列,队列中的元素是segment,消费的时候先从第0个segment开始消费,新来message存在最后⼀个消息队列中。对于segment也是对队列,队列元素是message,有对应的offsite标识是哪个message。消费的时候先从这个segment的第⼀个message开始消费,新来的message存在segment的最后。
消息系统的持久化队列可以构建在对⼀个⽂件的读和追加上,就像⼀般情况下的⽇志解决⽅案。它有⼀个优点,所有的操作都是常数时间,并且读写之间不会相互阻塞。这种设计具有极⼤的性能优势:
最终系统性能和数据⼤⼩完全⽆关,服务器可以充分利⽤廉价的硬盘来提供⾼效的消息服务。
事实上还有⼀点,磁盘空间的⽆限增⼤⽽不影响性能这点,意味着我们可以提供⼀般消息系统⽆法提供的特性。⽐如说,消息被消费后不是⽴马被删除,我们可以将这些消息保留⼀段相对⽐较长的时间(⽐如⼀个星期)。
5.Kafka ⽣产者-消费者
消息系统通常都会由⽣产者,消费者,Broker三⼤部分组成,⽣产者会将消息写⼊到Broker,消费者会从Broker中读取出消息,不同的MQ实现的Broker实现会有所不同,不过Broker的本质都是要负责将消息落地到服务端的存储系统中。具体步骤如下:⽣产者客户端应⽤程序产⽣消息:客户端连接对象将消息包装到请求中发送到服务端
服务端的⼊⼝也有⼀个连接对象负责接收请求,并将消息以⽂件的形式存储起来
服务端返回响应结果给⽣产者客户端
消费者客户端应⽤程序消费消息:客户端连接对象将消费信息也包装到请求中发送给服务端
服务端从⽂件存储系统中取出消息
服务端返回响应结果给消费者客户端
客户端将响应结果还原成消息并开始处理消息图4-1 客户端和服务端交互
5.1 Producers
Producers直接发送消息到broker上的leader partition,不需要经过任何中介或其他路由转发。为了实现这个特性,kafka集中的每个broker都可以响应producer的请求,并返回topic的⼀些元信息,这些元信息包括哪些机器是存活的,topic的leader partition都在哪,现阶段哪些leader partition是可以直接被访问的。
Producer客户端⾃⼰控制着消息被推送到哪些partition。实现的⽅式可以是随机分配、实现⼀类随机负载均衡算法,或者指定⼀些分区算法。Kafka提供了接⼝供⽤户实现⾃定义的partition,⽤户可以为每个消息指定⼀个partitionKey,通过这个key来实现⼀些hash分区算法。⽐如,把userid作为partitionkey的话,相同userid的消息将会被推送到同⼀个partition。
以Batch的⽅式推送数据可以极⼤的提⾼处理效率,kafka Producer 可以将消息在内存中累计到⼀定数量后作为⼀个batch发送请求。Batch的数量⼤⼩可以通过Producer的参数控制,参数值可以设置为累计的消息的数量(如500条)、累计的时间间隔(如100ms)或者累计的数据⼤⼩(64KB)。通过增加batch的⼤⼩,可以减少⽹络请求和磁盘IO的次数,当然具体参数设置需要在效率和时效性⽅⾯做⼀个权衡。
Producers可以异步的并⾏的向kafka发送消息,但是通常producer在发送完消息之后会得到⼀个future响应,返回的是offset值或者发送过程中遇到的错误。这其中有个⾮常重要的参数“acks”,这个参数决定了producer要求leader partition 收到确认的副本个数,如果acks设置数量为0,表⽰producer不会等待broker的响应,所以,producer⽆法知道消息是否发送成功,这样有可能会导致数据丢失,但同时,acks值为0会得到最⼤的系统吞吐量。
若acks设置为1,表⽰producer会在leader partition收到消息时得到broker的⼀个确认,这样会有更好的可靠性,因为客户端会等待直到broker确认收到消息。若设置为-1,producer会在所有备份的partition收到消息时得到broker的确认,这个设置可以得到最⾼的可靠性保证。
Kafka 消息有⼀个定长的header和变长的字节数组组成。因为kafka消息⽀持字节数组,也就使得kafka可以⽀持任何⽤户⾃定义的序列号格式或者其它已有的格式如Apache Avro、protobuf等。Kafka没有限定单个消息的⼤⼩,但我们推荐消息⼤⼩不要超过1MB,通常⼀般消息⼤⼩都在1~10kB之前。
发布消息时,kafka client先构造⼀条消息,将消息加⼊到消息集set中(kafka⽀持批量发布,可以往消息集合中添加多条消息,⼀次⾏发布),send消息时,producer client需指定消息所属的topic。
5.2 Consumers
Kafka提供了两套consumer api,分为high-level api和sample-api。Sample-api 是⼀个底层的API,它维持了⼀个和单⼀broker的连接,并且这个API是完全⽆状态的,每次请求都需要指定offset值,因此,这套API也是最灵活的。
在kafka中,当前读到哪条消息的offset值是由consumer来维护的,因此,consumer可以⾃⼰决定如何读取kafka中的数据。⽐
如,consumer可以通过重设offset值来重新消费已消费过的数据。不管有没有被消费,kafka会保存数据⼀段时间,这个时间周期是可配置的,只有到了过期时间,kafka才会删除这些数据。(这⼀点与AMQ不⼀样,AMQ的message⼀般来说都是持久化到mysql中的,消费完的message会被delete掉)
High-level API封装了对集中⼀系列broker的访问,可以透明的消费⼀个topic。它⾃⼰维持了已消费消息的状态,即每次消费的都是下⼀个消息。
High-level API还⽀持以组的形式消费topic,如果consumers有同⼀个组名,那么kafka就相当于⼀个队列消息服务,⽽各个consumer 均衡的消费相应partition中的数据。若consumers有不同的组名,那么此时kafka就相当与⼀个⼴播服务,会把topic中的所有消息⼴播到每个consumer。
High level api和Low level api是针对consumer⽽⾔的,和producer⽆关。
High level api是consumer读的partition的offsite是存在zookeeper上。High level api 会启动另外⼀个线程去每隔⼀段时间,offsite⾃动同步到zookeeper上。换句话说,如果使⽤了High level api, 每个message只能被读⼀次,⼀旦读了这条message之后,⽆论我consumer的处理是否ok。High level api的另外⼀个线程会⾃动的把offiste+1同步到zookeeper上。如果consumer读取数据出了问题,offsite也会在zookeeper上同步。因此,如果consumer处理失败了,会继续执⾏下⼀条。这往往是不对的⾏为。因此,Best Practice是⼀旦consumer处理失败,直接让整个conusmer group抛Exception终⽌,但是最后读的这⼀条数据是丢失了,因为在zookeeper⾥⾯的offsite已经+1了。等再次启动conusmer group的时候,已经从下⼀条开始读取处理了。
Low level api是consumer读的partition的offsite在consumer⾃⼰的程序中维护。不会同步到zookeeper上。但是为了kafka manager 能够⽅便的监控,⼀般也会⼿动的同步到zookeeper上。这样的好处是⼀旦读取某个message的consumer失败了,这条message的offsite我们⾃⼰维护,我们不会+1。下次再启动的时候,还会从这个offsite开始读。这样可以做到exactly once对于数据的准确性有保证。
对于Consumer group:
1. 允许consumer group(包含多个consumer,如⼀个集同时消费)对⼀个topic进⾏消费,不同的consumer group之间独⽴消费。
2. 为了对减⼩⼀个consumer group中不同consumer之间的分布式协调开销,指定partition为最⼩的并⾏消费单位,即⼀个group内的consumer只能消费不同的partition。
image
Consumer与Partition的关系:如果consumer⽐partition多,是浪费,因为kafka的设计是在⼀个partition上是不允许并发的,所以consumer数不要⼤于partition数
如果consumer⽐partition少,⼀个consumer会对应于多个partitions,这⾥主要合理分配consumer数和partition数,否则会导致partition⾥⾯的数据被取的不均匀
如果consumer从多个partition读到数据,不保证数据间的顺序性,kafka只保证在⼀个partition上数据是有序的,但多个partition,根据你读的顺序会有不同
增减consumer,broker,partition会导致rebalance,所以rebalance后consumer对应的partition会发⽣变化
High-level接⼝中获取不到数据的时候是会block的
负载低的情况下可以每个线程消费多个partition。但负载⾼的情况下,Consumer 线程数最好和Partitio
n数量保持⼀致。如果还是消费不过来,应该再开 Consumer 进程,进程内线程数同样和分区数⼀致。
消费消息时,kafka client需指定topic以及partition number(每个partition对应⼀个逻辑⽇志流,如topic代表某个产品线,partition代表产品线的⽇志按天切分的结果),consumer client订阅后,就可迭代读取消息,如果没有消息,consumer client会阻塞直到有新的消息发布。consumer可以累积确认接收到的消息,当其确认了某个offset的消息,意味着之前的消息也都已成功接收到,此时broker会更新zookeeper上地offset registry。
5.3 ⾼效的数据传输发布者每次可发布多条消息(将消息加到⼀个消息集合中发布), consumer每次迭代消费⼀条消息。
不创建单独的cache,使⽤系统的page cache。发布者顺序发布,订阅者通常⽐发布者滞后⼀点点,直接使⽤Linux的page cache效果也⽐较后,同时减少了cache管理及垃圾收集的开销。
使⽤sendfile优化⽹络传输,减少⼀次内存拷贝。
6.Kafka 与 Zookeeper
6.1 Zookeeper 协调控制管理broker与consumer的动态加⼊与离开。(Producer不需要管理,随便⼀台
计算机都可以作为Producer向Kakfa Broker发消息)
触发负载均衡,当broker或consumer加⼊或离开时会触发负载均衡算法,使得⼀
个consumer group内的多个consumer的消费负载平衡。(因为⼀个comsumer消费⼀个或多个partition,⼀个partition只能被⼀个consumer消费)
维护消费关系及每个partition的消费信息。
版权声明:本站内容均来自互联网,仅供演示用,请勿用于商业和其他非法用途。如果侵犯了您的权益请与我们联系QQ:729038198,我们将在24小时内删除。
发表评论