本质上kafka只支持topic。
每个group中可以有多个consumer,每个consumer属于一个consumer group。
通常情况下,一个group中会包含多个consumer,这样不仅可以提高topic中消息的并发消费能力,而且还能提高“故障容错”性,如果group中的某个consumer失效,那么其消费的partitions将会有其他consumer自动接管。
对于topic中的一条特定的消息,只会被订阅此topic的每个group中的其中一个consumer消费,此消息不会发送给一个group的多个consumer。
那么一个group中所有的consumer将会交错的消费整个topic,每个group中consumer消费互相独立,我们可以认为一个group是一个订阅者。
在kafka中,一个partition中的消息只会被group中的一个consumer消费(同一时刻);一个topic中的每个partitions,只会被一个“订阅者”中的一个consumer消费,不过一个consumer可以同时消费多个partitions中的消息。
kafka的设计原理决定,对一个topic,同一个group中不能由多于partitions个数的consumer同时消费,否则将意味着某些consumer将无法得到消息。
kafka只能保证一个partition中的消息被某个consumer消费时是顺序的;事实上,从topic角度来说,当有多个partions时,消息仍不是全局有序的。
设置发送数据是否需要服务端的反馈,有三个值:0、1、-1
0:producer不会等待broker发送ack。
1:当leader介绍到消息之后发送ack。
-1:当所有的follower都同步消息成功后发送ack。
三种机制,性能依次递减(producer吞吐量降低),数据健壮性则依次递增。
request.required.acks=0
伪命题
每个分区内,每条消息都有一个offset,故只能保证分区内有序。
如果要全局有序,必须保证生产有序,存储有序,消费有序。
由于生产可以做集群,存储可以分片,消费可以设置为一个consumer group,要保证全局有序,就需要保证每个环节都有序。
只有一个可能,就是一个生产者,一个partition,一个消费者。这种场景和大数据应用场景相悖。
有两个数据源,一个记录的是广告投放给用户的日志,一个记录用户访问日志,另外还有一个固定的用户基础表记录用户基本信息(比如学历,年龄等等)。现在要分析广告投放对与哪类用户更有效,请采用熟悉的技术描述解决思路。另外如果两个数据源都是实时数据源(比如来自kafka),他们数据在时间上相差5分钟,需要哪些调整来解决实时分析问题?
可以使用flume+sqoop将数据源的数据拉取到hive中,统计广告投放用户的登陆数,对登陆数进行排名,分析排名分布,数据分布等等,如果不能简单判断,则可以按特征值分区统计登录数。如果有时间误差,可以根据时间戳进行时间分区(可能会至少有5分钟的延迟)。
Received是使用Kafka高级Consumer API实现的。与所有接收器一样,从Kafka通过Receiver接收的数据存储在Spark Executor的内存中,然后由Spark Streaming启动的job来处理数据。然而默认配置下,这种方式可能会因为底层的失败而丢失数据(请参阅接收器可靠性)。如果要启用高可靠机制,确保零数据丢失,要启用Spark Streaming的预写日志机制(Write Ahead Log,(已引入)在Spark 1.2)。该机制会同步地将接收到的Kafka数据保存到分布式文件系统(比如HDFS)上的预写日志中,以便底层节点在发生故障时也可以使用预写日志中的数据进行恢复。
在spark1.3之后,引入了Direct方式。不同于Receiver的方式,Direct方式没有receiver这一层,其会周期性的获取Kafka中每个topic的每个partition中的最新offsets,之后根据设定的maxRatePerPartition来处理每个batch。
这种方法相较于Receiver方式的优势在于:
简化的并行:在Receiver的方式中我们提到创建多个Receiver之后利用union来合并成一个Dstream的方式提高数据传输并行度。而在Direct方式中,Kafka中的partition与RDD中的partition是一一对应的并行读取Kafka数据,这种映射关系也更利于理解和优化。
高效:在Receiver的方式中,为了达到0数据丢失需要将数据存入Write Ahead Log中,这样在Kafka和日志中就保存了两份数据,浪费!而第二种方式不存在这个问题,只要我们Kafka的数据保留时间足够长,我们都能够从Kafka进行数据恢复。
精确一次:在Receiver的方式中,使用的是Kafka的高阶API接口从Zookeeper中获取offset值,这也是传统的从Kafka中读取数据的方式,但由于Spark Streaming消费的数据和Zookeeper中记录的offset不同步,这种方式偶尔会造成数据重复消费。而第二种方式,直接使用了简单的低阶Kafka API,Offsets则利用Spark Streaming的checkpoints进行记录,消除了这种不一致性。
请注意,此方法的一个缺点是它不会更新Zookeeper中的偏移量,因此基于Zookeeper的Kafka监视工具将不会显示进度。但是,您可以在每个批处理中访问此方法处理的偏移量,并自行更新Zookeeper。
高吞吐量:每秒数十万、上百万的高效分发。
持久化数据存储:将消息持久化到磁盘,因此可以用于批量消费,防止数据丢失。
分布式系统易于扩展:所有的producer、broker和consumer都会有多个,均为分布式的。无需停机即可扩展机器。
客户端状态维护:消息被处理的状态是在consumer端维护,而不是由server端维护。但失败时能自动平衡。
虽然kafka会持久化所有数据到磁盘,当本质上每次写入操作其实都只是把数据写入到操作系统的页缓存,然后由操作系统自行决定什么时候把页缓存中的数据写回磁盘。
kafka的作用是解耦,如果直接从日志服务器上采集的话,实时离线都要采集,等于要采集两份数据,而使用了kafka的话,只需要从日志服务器上采集一份数据,然后再kafka中使用不同的两个组读取就行了。
使用kafka manager进行监控
下载kafka-manager。
并修改配置文件conf/application.conf,编写服务启动脚本。
启动集群及kafka manager,访问webui进行相关管理。
快速持久化,可以在O(1)的系统开销下进行消息持久化;
高吞吐,在一台普通的服务器上既可以达到10W/s的吞吐速率;
完全的分布式系统,Broker、Producer、Consumer都原生自动支持分布式,自动实现复杂均衡;
支持Hadoop数据并行加载,对于像Hadoop的一样的日志数据和离线分析系统,但又要求实时处理的限制,这是一个可行的解决方案。Kafka通过Hadoop的并行加载机制来统一了在线和离线的消息处理
屏蔽细节管理。
屏蔽了每个Topic的每个Partition的Offset管理(自动读取zookeeper中该Consumer group的last offset )。
Broker失败转移以及增减Partition、Consumer时的负载均衡(当Partition和Consumer增减时,Kafka自动进行负载均衡)。
对于多个Partition,多个Consumer。如果consumer比partition多,是浪费,因为kafka的设计是在一个partition上是不允许并发的,所以consumer数不要大于partition数,如果consumer比partition少,一个consumer会对应于多个partitions,这里主要合理分配consumer数和partition数,否则会导致partition里面的数据被取的不均匀。最好partiton数目是consumer数目的整数倍,所以partition数目很重要,比如取24,就很容易设定consumer数目。
如果consumer从多个partition读到数据,不保证数据间的顺序性,kafka只保证在一个partition上数据是有序的,但多个partition,根据你读的顺序会有不同。
增减consumer,broker,partition会导致rebalance,所以rebalance后consumer对应的partition会发生变化
High-level接口中获取不到数据的时候是会block的
关于Offset初始值的问题:
先produce一些数据,然后再用consumer读的话,需要加上一句offset读取设置
props.put("auto.offset.reset", "smallest"); //必须要加,如果要读旧数据 1
因为初始的offset默认是非法的,然后这个设置的意思 是,当offset非法时,如何修正offset,默认是largest,即最新,所以不加这个配置,你是读不到你之前produce的数据的,而且这个 时候你再加上smallest配置也没用了,因为此时offset是合法的,不会再被修正了,需要手工或用工具改重置offset。
细节需要自己处理。
控制灵活性,作为底层的Consumer API,提供了消费Kafka Message更大的控制,跳读,Exactly Once原语,提供更大灵活控制是以复杂性为代价的:Offset不再透明,Broker自动失败转移需要处理,增加Consumer、Partition、Broker需要自己做负载均衡,(Offset自己管理),如果一个Partition有多个副本,那么Lead Partition所在的Broker就称为这个Partition的Lead Broker。
ISR(In-Sync Replicas)副本同步队列。ISR中包括leader和follower。
ISR 中的副本都是与 Leader 同步的副本,相反,不在 ISR 中的追随者副本就被认为是与 Leader 不同步的。
Leader 副本天然就在 ISR 中。
**ISR 是一个动态调整的集合,而非静态不变的。**如果同步时间超过replica.lag.time.max.ms则被认为不是同步的,应该踢出该副本存入OSR(Outof-Sync Replicas),如果同步时间在replica.lag.time.max.ms之内,则应该加入队列。
默认只有在队列里面的(被认定是实时同步的follower副本)才可能被选举为leader。(这个原则可以通过修改对应的参数配置来改变)
ISR(In-Sync Replicas):所有与leader副本保持一定程度同步的副本(包括Leader)组成ISR,ISR集合是AR集合中的一个子集。
OSR(Out-Sync Relipcas):与leader副本同步滞后过多的副本(不包括leader)副本,组成OSR。
AR(Assigned Repllicas):分区的所有副本。AR=ISR+OSR
LEO(Log End Offset):表示了当前日志文件中下一条待写入消息的offset。LEO的大小相当于当前日志分区中最后一条消息的offset值加1。
HW(High Watermak):表示了一个特定消息的偏移量(offset),消费者只能拉取到这个offset之前的消息。分区ISR集合中的每个副本都会维护自身的LEO,而ISR集合中最小的LEO即为分区的HW,对消费者而言只能消费HW之前的消息。
ps:
同步复制要求所有能工作的Follower副本都复制完,这条消息才会被确认为成功提交,这种复制方式影响了性能。
在异步复制的情况下, follower副本异步地从leader副本中复制数据,数据只要被leader副本写入就被认为已经成功提交。如果follower副本都没有复制完而落后于leader副本,如果突然leader副本宕机,则会造成数据丢失。
kafka使用ISR有效权衡了数据可靠性与性能之间的关系。
先提交offset,后消费,有可能造成数据的重复
在执行完脚本之后,Kafka 会在 log.dir 或 log.dirs 参数所配置的目录下创建相应的主题分区,默认情况下这个目录为/tmp/kafka-logs/。
在 ZooKeeper 的/brokers/topics/目录下创建一个同名的实节点,该节点中记录了该主题的分区副本分配方案。
触发Controller的监听程序
kafka Controller负责topic的创建工作,并更新metadata cache
可以增加,使用 kafka-topics 脚本,结合 --alter 参数来增加某个主题的分区数,命令如下:
bin/kafka-topics.sh --bootstrap-server broker_host:port --alter --topic --partitions <新分区数>
当分区数增加时,就会触发订阅该主题的所有 Group 开启 Rebalance。
首先,Rebalance 过程对 Consumer Group 消费过程有极大的影响。在 Rebalance 过程中,所有 Consumer 实例都会停止消费,等待 Rebalance 完成。这是 Rebalance 为人诟病的一个方面。
其次,目前 Rebalance 的设计是所有 Consumer 实例共同参与,全部重新分配所有分区。其实更高效的做法是尽量减少分配方案的变动。
最后,Rebalance 实在是太慢了。
不支持,因为删除的分区中的消息不好处理。
如果直接存储到现有分区的尾部,消息的时间戳就不会递增,如此对于 Spark、Flink 这类需要消息时间戳(事件时间)的组件将会受到影响;如果分散插入现有的分区,那么在消息量很大的时候,内部的数据复制会占用很大的资源,而且在复制期间,此主题的可用性又如何得到保障?与此同时,顺序性问题、事务性问题,以及分区和副本的状态机切换问题都是不得不面对的。
有,__consumer_offsets,保存消费者offset
controller主要依靠ZK完成对集群broker和分区的管理如集群broker信息、分区选举ISR等。
不能及时与leader同步,暂时踢出ISR,并加入OSR,等其追上leader之后再重新加入ISR。
高吞吐量、低延迟:kafka每秒可以处理几十万条消息,它的延迟最低只有几毫秒,每个topic可以分多个partition,consumer group对partition进行consume操作。
可扩展性:kafka集群支持热扩展
持久性、可靠性:消息被持久化到本地磁盘,并且支持数据备份防止数据丢失
容错性:允许集群中节点失败(若副本数量为n,则允许n-1个节点失败)。
高并发:支持数千个客户端同时读写。
分区对于kafka集群的好处:实现负载均衡。
分区对于消费者来说,可以提高并发度,提高效率。
producer可以将数据发送给多个broker上的多个partition,consumer也可以并行从多个broker上的不同paritition上读数据,实现了水平扩展 。
由于消息是以追加的形式添加到到分区中的,多个分区顺序写磁盘的总效率比随机写内存还要高
kafka中的每个partition中的消息在写入时都是有序的,而且消息带有offset偏移量,消费者按偏移量的顺序从前往后消费,从而保证了消息的顺序性。
但是分区之间的消息是不保证有序的。
kafka通过分区的多副本机制来保证消息的可靠性。
一致性就是说不论是老的 Leader 还是新选举的 Leader,Consumer 都能读到一样的数据。
所有在ISR中的副本都有个LEO(log end offset)偏移量,leader副本插入数据时,leaderLEO会增加,副本会复制leader新的数据,副本LEO也会增加,副本LEO不一样。
把ISR中的所有副本的最小LEO称为HW(high water mark),只有HW之前的数据才能被consumer消费。
producer端:
需要设置ack=all,如果发生leader出了问题,只有所有副本复制完成,producer才能写入成功,否则生产者会考虑重发消息。
consumer端:
因为consumer只能拉取HW之前的数据即ISR中所有副本都有的数据,所以如果此时发生leader选举,consumer不会拉取错误的数据,而是等到leader选举完成,HW发生变化,consumer才能重新消费。
使用HW这种模式兼顾了安全性和效率。当然主要还是用户按需求设置ack值。
ISR:In-Sync Replicas副本同步队列
OSR:Out-of-Sync Replicas同步超时队列
AR:Assigned Replicas所有副本。AR=ISR+OSR
ISR是由leader维护,follower从leader同步数据有一些延迟,超过相应阈值会把follower踢出ISR,存入OSR列表,新加入的follower也会先存放在OSR中。
LEO:是LogEndOffset的简称,代表当前日志文件中下一条。
HW:水位或水印(watermark)一词,也可称为高水位(high watermark),通常被用在流式处理领域(如flink,spark等),以表征元素或事件在基于时间层面上的精度。在kafka中,水位的概念反而与时间无关,而是与位置信息相关。
严格来说他表示的就是位置信息,即唯一(offset)。取partition对应的ISR中最小的LEO作为作为HW,consumer最多只能消费到HW所在的位置上一条信息。
LSO:是LastStableOffset的简称,对未完成的事务而言,LSO的值等于事务中第一条消息的位置(firstUnstableOffset),对已完成的事务而言,他的值等他HW。
LW:low watermark低水位,代表AR集合中最小的logStartOffset值。
leader副本对外提供服务(写入和读出),leader写入的数据的位置称为LEO(logendoffset),其它follower副本也有LEO,随着同步leader的数据副本的LEO会慢慢和leader的LEO同步。
在ISR列表里面所有副本的LEO最小的叫做HW(HighWatermark),consumer读取数据只能读取HW之前数据,如果在此期间发生leader选举,选举期间leader服务不可用,直到完成后,新leader重新对外提供服务。
ps:
producer生产数据需要设置ack=-1,只有接收到所有副本的ack后才算完成写入操作即更新了HW。保证了producer和partition的数据一致,
如果发生leader选举,leader只会在ISR列表中产生,ISR最小的LEO是HW,consumer只能消费HW之前的数据。这种HW机制保证了partition和consumer的数据一致
可以。kafkaconsumer消费消息时,向broker发出fetch请求去消费特定分区的消息,consumer指定消息在日志中的偏移量(offset),就可以消费从这个位置开始的消息,customer拥有了offset的控制权,可以向后回滚去重新消费之前的消息,这是很有意义的。
采用的pull模式。(producer将消息推送到broker,consumer从broker拉取消息。)
好处
consumer可以根据自己的消费能力进行消费,比如消费速率不一样,是否批量拉取数据。
缺点
如果broker没有可供消费的消息,将导致consumer不断在循环中轮询,直到消息到达。为避免这点,kafka有参数可以让consumer阻塞直到新消息到达。(也可以阻塞直到消息数量达到某个特定的量,实现批量发)
crc32(4B):crc32校验值。校验范围为magic至value之间。 magic(1B):消息格式版本号,此版本的magic值为0。 attributes(1B):消息的属性。总共占1个字节,低3位表示压缩类型:0表示NONE、1表示GZIP、2表示SNAPPY、3表示LZ4(LZ4自Kafka 0.9.x引入),其余位保留。 key length(4B):表示消息的key的长度。如果为-1,则表示没有设置key,即key=null。 key:可选,如果没有key则无此字段。 value length(4B):实际消息体的长度。如果为-1,则表示消息为空。 value:消息体。可以为空,比如tomnstone消息。
v1版本比v0版本多一个8B的timestamp字段;
timestamp字段作用:
内部而言:影响日志保存、切分策略;
外部而言:影响消息审计、端到端延迟等功能的扩展
相对v0和v1改动较大,引入了变长整形Varints和ZigZag编码。
Varints作用:根据数值的大小,调整占用的字节数,数值越小,占用的字节数就越小
0-63之间的数字占1个字节,64-8191之间的数字占2个字节,8192-1048575之间的数字占3个字节
kafka broker的配置message.max.bytes的默认大小为1000012(Varints编码占3个字节)
ZigZag编码:使绝对值较小的负数仍然享有较小的Varints编码值
V2版本消息集称为Record Batch(v0和v1称为Message Set),相较于V0、V1版本
(1)将多个消息(Record)打包存放到单个RecordBatch中,v2版本的单个Record Batch Header相较于v0、v1版本的多个Log_OVERHEAD(每个Record都会有1个LOG_OVERHEARD),会节省空间;
(2)引入变长整形Varints和ZigZag编码,能够灵活的节省空间
Kafka 0.10.x 对于非压缩的消息偏移量处理和 Kafka 0.8.x 一致,这里就不再介绍了。这里主要介绍 Kafka 0.10.x 对压缩消息偏移量处理逻辑。和 Kafka 0.8.x 处理内部消息偏移量逻辑不一样,这个版本对于内部消息偏移量使用的是相对偏移量,从0开始,依次到n-1,这里的n代表压缩消息的条数。
这个逻辑和 Kafka 0.8.x 处理逻辑一致,不再介绍。有一点需要注意,Kafka 0.10.x 会将消息的 magic 值设置为 1,用于区分其他版本的消息,后面会介绍这样设置的用处。
Broker 端接收到 Producer 发送过来的压缩消息,其也是先解压接收到的压缩消息,然后做一堆的判断,比如 消息的 magic 值是否大于0,压缩消息内部的消息偏移量值是否连续(0,1,2,3这样的)等,如果符合这些条件(inPlaceAssignment = true
),那么 Broker 会直接处理整个压缩消息外部的偏移量,内部消息的偏移量不需要设置,因为这个在 Producer 端已经设置好了;并不需要再次压缩消息,最后会将这条消息追加到 Log 文件中。
如果 inPlaceAssignment = false
,这时候会直接操作解压后的消息,并给压缩消息内部消息设置偏移量,最后设置整个压缩消息的偏移量;这时候会忽略掉 Producer 端为压缩消息设置的偏移量,包括内部消息和整个压缩消息的偏移量。整个处理逻辑分为两种情况:
(1)如果接收到的消息不是由 Kafka 0.10.x 版本Producer客户端发送过来的,那么消息的 magic 值会等于0,这时候 Broker 设置偏移量逻辑和 Kafka 0.8.x 处理逻辑一致,也就是不管内部消息还是整个压缩消息的偏移量都是使用绝对偏移量;
(2)如果接收到的消息是由 Kafka 0.10.x 版本Producer客户端发送过来的,那么消息的 magic 值会等于1,这时候 Broker 会将压缩消息内部的消息偏移量设置成相对的,从0开始,依次到 n-1 ,最后整个压缩消息的偏移量为nextOffset + n - 1
,其中n为压缩消息的条数。
偏移量设置完之后,对于inPlaceAssignment = false
,不管是由什么版本发送过来的消息, Broker 需要重新压缩刚刚解压好的消息,最后会将这条消息追加到 Log 文件中。
对不同版本的 Client 请求, Broker 会做出不同的判断:对于非 Kafka 0.10.x 版本的 Consumer,Broker 端消息的发送不会使用零拷贝技术;而如果是 Kafka 0.10.x 版本的 Consumer,Broker 端消息的发送才会使用零拷贝技术
我们知道,在启动 Kafka 集群之前,我们需要配置好 log.dirs 参数,其值是 Kafka 数据的存放目录,这个参数可以配置多个目录,目录之间使用逗号分隔,通常这些目录是分布在不同的磁盘上用于提高读写性能。当然我们也可以配置 log.dir 参数,含义一样。只需要设置其中一个即可。
如果 log.dirs 参数只配置了一个目录,那么分配到各个 Broker 上的分区肯定只能在这个目录下创建文件夹用于存放数据。
但是如果 log.dirs 参数配置了多个目录,那么 Kafka 会在哪个文件夹中创建分区目录呢?答案是:Kafka 会在含有分区目录最少的文件夹中创建新的分区目录,分区目录名为 Topic名+分区ID。注意,是分区文件夹总数最少的目录,而不是磁盘使用量最少的目录!也就是说,如果你给 log.dirs 参数新增了一个新的磁盘,新的分区目录肯定是先在这个新的磁盘上创建直到这个新的磁盘目录拥有的分区目录不是最少为止。
在Kafka中,当有新消费者加入或者订阅的topic数发生变化时,会触发Rebalance(再均衡:在同一个消费者组当中,分区的所有权从一个消费者转移到另外一个消费者)机制,Rebalance顾名思义就是重新均衡消费者消费。Rebalance的过程如下:
第一步:所有成员都向coordinator发送请求,请求入组。一旦所有成员都发送了请求,coordinator会从中选择一个consumer担任leader的角色,并把组成员信息以及订阅信息发给leader。
第二步:leader开始分配消费方案,指明具体哪个consumer负责消费哪些topic的哪些partition。一旦完成分配,leader会将这个方案发给coordinator。coordinator接收到分配方案之后会把方案发给各个consumer,这样组内的所有成员就都知道自己应该消费哪些分区了。
所以对于Rebalance来说,Coordinator起着至关重要的作用
在 Kafka 内部存在两种默认的分区分配策略:Range 和 RoundRobin。当以下事件发生时,Kafka 将会进行一次分区分配:
Range策略是对每个主题而言的,首先对同一个主题里面的分区按照序号进行排序,并对消费者按照字母顺序进行排序。
然后将partitions的个数除于消费者线程的总数来决定每个消费者线程消费几个分区。如果除不尽,那么前面几个消费者线程将会多消费一个分区。
缺点:如果有n个主题,并且都不能整除,排序前面的消费者会比其它消费者进程多消费n个分区。
使用RoundRobin策略有两个前提条件必须满足:
RoundRobin策略的工作原理:
将所有主题的分区组成 TopicAndPartition 列表,然后对 TopicAndPartition 列表按照 hashCode 进行排序。
最后按照round-robin风格将分区分别分配给不同的消费者线程。
因为根据hashcode排序,降低了同一个consumer分配到多个主题中的多余分区的概率。、
ps:
通过partition.assignment.strategy参数选择 range 或 roundrobin。partition.assignment.strategy参数默认的值是range。
推荐partition个数是consumer数的整数倍或者说consumer个数是partition个数的因子
Kafka是分布式消息系统,需要处理海量的消息,Kafka的设计是把所有的消息都写入速度低容量大的硬盘,以此来换取更强的存储能力,但实际上,使用硬盘并没有带来过多的性能损失。kafka主要使用了以下几个方式实现了超高的吞吐率:
比较流行的监控工具有:
KafkaOffsetMonitor
KafkaManager
Kafka Web Console
Kafka Eagle
JMX协议(可以用诸如jdk自带的jconsole来进行连接获取状态信息)
针对kafka 1.1.0以及之后的版本,建议单台broker上partition数量不超过4000, 整个集群partition数量不超过2000,000,主要原因还是上面讲过的controller选举和controller重新选举partition leader的耗时。
相对kafka 1.1.0之前版本,这个parition数量已经有了很大提高,这全部得益于controller处理broker shutdown流程的优化,主要是针对zk的写操作异步化,批量化,将新的metadata通知给没有shutdown的broker也批量化,减少RPC次数,但是最最主要的,大家肯定想不到,是减少了不必要的log, 具体可参考Apache Kafka Supports 200K Partitions Per Cluster
参见这篇文章:http://www.jasongj.com/kafka/transaction/
Kafka事务机制的实现主要是为了支持
Exactly Once
即正好一次语义幂等性发送
事务性保证
事务性消息传递
事务中Offset的提交
用于事务特性的控制型消息
事务过期机制
参见这篇文章:https://www.jianshu.com/p/b1599f46229b
Kafka在0.11.0.0版本支持增加了对幂等的支持。幂等是针对生产者的特性。幂等可以保证生产者发送的消息,不会丢失,而且不会重复。
HTTP/1.1中对幂等性的定义是:一次和多次请求某一个资源对于资源本身应该具有同样的结果(网络超时等问题除外)。也就是说,其任意多次执行对资源本身所产生的影响均与一次执行的影响相同。
实现幂等的关键点就是服务端可以区分请求是否重复,过滤掉重复的请求。要区分请求是否重复的有两点:
为了实现Producer的幂等性,Kafka引入了Producer ID(即PID)和Sequence Number。
Kafka可能存在多个生产者,会同时产生消息,但对Kafka来说,只需要保证每个生产者内部的消息幂等就可以了,所有引入了PID来标识不同的生产者。
对于Kafka来说,要解决的是生产者发送消息的幂等问题。也即需要区分每条消息是否重复。
Kafka通过为每条消息增加一个Sequence Numbler,通过Sequence Numbler来区分每条消息。每条消息对应一个分区,不同的分区产生的消息不可能重复。所有Sequence Numbler对应每个分区
Broker端在缓存中保存了这seq number,对于接收的每条消息,如果其序号比Broker缓存中序号大于1则接受它,否则将其丢弃。这样就可以实现了消息重复提交了。但是,只能保证单个Producer对于同一个
旧的 Kafka 消费者 API 主要包括:SimpleConsumer(简单消费者) 和 ZookeeperConsumerConnectir(高级消费者)。SimpleConsumer 名字看起来是简单消费者,但是其实用起来很不简单,可以使用它从特定的分区和偏移量开始读取消息。高级消费者和现在新的消费者有点像,有消费者群组,有分区再均衡,不过它使用 ZK 来管理消费者群组,并不具备偏移量和再均衡的可操控性。
现在的消费者同时支持以上两种行为,所以为啥还用旧消费者 API 呢?
我们可以使用 bin/kafka-topics.sh 命令对 Kafka 增加 Kafka 的分区数据,但是 Kafka 不支持减少分区数。
Kafka 分区数据不支持减少是由很多原因的,比如减少的分区其数据放到哪里去?是删除,还是保留?删除的话,那么这些没消费的消息不就丢了。如果保留这些消息如何放到其他分区里面?追加到其他分区后面的话那么就破坏了 Kafka 单个分区的有序性。如果要保证删除分区数据插入到其他分区保证有序性,那么实现起来逻辑就会非常复杂。
kafka通过 topic来分主题存放数据,主题内有分区,分区可以有多个副本,分区的内部还细分为若干个 segment。都是持久化到磁盘,采用零拷贝技术。
1、高效检索
分区下面,会进行分段操作,每个分段都会有对应的素引,这样就可以根据 offset二分查找定位到消息在哪一段,根据段的索引文件,定位具体的 mle ssage
2、分区副本可用性(1 eader选举,zk来协调
如果1eader宕机,选出了新的1eader,而新的 leader并不能保证已经完全同步了之前1eader的所有数据,只能保证HW(高水位设置)之前的数据是同步过的,此时所有的 follower都要将数据截断到W的位置,再和新的 leader同步数据,来保证数据一致。
当宕机的 leader恢复,发现新的1eader中的数据和自己持有的数据不一致,此时宕机的1 eader会将自己的数据截断到宕机之前的hw位置,然后同步新1 eader的数据。宕机的1eader活过来也像 follower一样同步数据,来保证数据的一致性。
1、分区性:存储不会受单一服务器存储空间的限制
2、高可用性:副本1 eader选举
3、消息有序性:一个分区内是有序的。
4、负载均衡性:分区内的一条消息,只会被消费组中的一个消费者消费,主题中的消息,会均衡的发送给消费者组中的所有消费者进行消费。
同步:这个生产者写一条消息的时候,它就立马发送到某个分区去。
异步:这个生产者写一条消息的时候,先是写到某个缓冲区,这个缓冲区里的数据还没写到 broker集群里的某个分区的时候,它就返回到 client去了
针对消息丢失:同步模式下,确认机制设置为-1,即让消息写入 Leader和 Fol lower之后再确认消息发送成功:
异步模式下,为防止缓冲区满,可以在配置文件设置不限制阻塞超时时间,当缓冲区满时让生产者一直处于阻塞状态
针对消息重复,将消息的唯一标识保存到外部介质中,每次消费时判断是否处理过即可