一、kafka入门-基础概念和组件

概述

简介

Kafka是最初由Linkedin公司开发,是一个分布式、支持分区的(partition)、多副本的(replica),基于zookeeper协调的分布式消息系统,它的最大的特性就是可以实时的处理大量数据以满足各种需求场景:比如基于hadoop的批处理系统、低延迟的实时系统、storm/Spark流式处理引擎,web/nginx日志、访问日志,消息服务等等,用scala语言编写,Linkedin于2010年贡献给了Apache基金会并成为顶级开源 项目。

特点

  • 持久性、可靠性:消息被持久化到本地磁盘,并且支持数据备份防止数据丢失
  • 容灾性:允许集群中节点失败(若副本数量为n,则允许n-1个节点失败)
  • 高吞吐量、低延迟:kafka每秒可以处理几十万条消息,它的延迟最低只有几毫秒,每个topic可以分多个partition, consumer group 对partition进行consume操作。
  • 可扩展性:kafka集群支持热扩展,broker节点可以水平扩展,partition也可以水平增加,partition replica也可以水平增加
  • 高并发:支持数千个客户端同时读写
  • 异步通信:提供消息异步消费能力,使得Producer和Consumer之间异步的操作,系统之间解耦,解决生产和消费速率不同步问题;
  • 插件支持:现在不少活跃的社区已经开发出不少插件来拓展Kafka的功能,如用来配合Storm、Hadoop、flume相关的插件。

适用场景

  • 消息系统:缓存消息,解耦和生产者和消费者;
  • 日志收集:一个公司可以用Kafka可以收集各种服务的log,通过kafka以统一接口服务的方式开放给各种consumer,例如hadoop、Hbase、Solr等。
  • 用户活动跟踪:Kafka经常被用来记录web用户或者app用户的各种活动,如浏览网页、搜索、点击等活动,这些活动信息被各个服务器发布到kafka的topic中,然后订阅者通过订阅这些topic来做实时的监控分析,或者装载到hadoop、数据仓库中做离线分析和挖掘。
  • 运营指标:Kafka也经常用来记录运营监控数据。包括收集各种分布式应用的数据,生产各种操作的集中反馈,比如报警和报告。
  • 流式处理:比如spark streaming和storm
  • 事件源

通信模式

点对点消息传递

在点对点消息系统中,消息持久化到一个队列中。此时,将有一个或多个消费者消费队列中的数据。但是一条消息只能被消费一次。当一个消费者消费了队列中的某条数据之后,该条数据则从消息队列中删除。该模式即使有多个消费者同时消费数据,也能保证数据处理的顺序。生产者发送一条消息到queue,只有一个消费者能收到。这种架构描述示意图如下:

发布-订阅消息传递

在发布-订阅消息系统中,消息被持久化到一个topic中。与点对点消息系统不同的是,消费者可以订阅一个或多个topic,消费者可以消费该topic中所有的数据,同一条数据可以被多个消费者消费,数据被消费后不会立马删除。在发布-订阅消息系统中,消息的生产者称为发布者,消费者称为订阅者。该模式的示例图如下:

架构

1 broker

Kafka 集群包含一个或多个服务器,每个服务器节点称为broker。具有以下特性:

  • 每个broker节点具有平等关系,节点本身不具有主次关系。
  • Kafka集群中多个broker,有一个会被选举为controller leader,负责管理整个集群中分区和副本的状态,比如partition的leader 副本故障,由controller 负责为该partition重新选举新的leader 副本。具体可参考:https://blog.csdn.net/zhanglh046/article/details/72821995
  • 节点可以动态的增加删除。

2 Topic & Partition

每条发布到Kafka集群的消息都有一个类别,这个类别被称为Topic。topic代表kafka中消息的主题,kafka将消息存储在不同的主题中,主题是生产和消费的前提,存储和消费前必须指定消息的主题。

topic是一个逻辑概念,代表着类型一类的消息的集合,topic中的数据分割为一个或多个partition。每个topic至少有一个partition。partion具有以下属性:

  • partition中的数据是有序的,不同partition间的数据丢失了数据的顺序,单个partition可以保留写顺序。如果topic有多个partition,消费数据时就不能保证数据的顺序。在需要严格保证消息的消费顺序的场景下,需要将partition数目设为1。
  • 一个Topic的Partition数量大于等于Broker的数量,可以提高吞吐率。同一个Partition的Replica尽量分散到不同的机器,高可用。
  • 当add a new partition的时候,partition里面的message不会重新进行分配,原来的partition里面的message数据不会变,新加的这个partition刚开始是空的,随后进入这个topic的message就会重新参与所有partition的load balance

topic与partition分布关系如下:

  • broker存储topic的数据。如果某topic有N个partition,集群有N个broker,那么每个broker存储该topic的一个partition。
  • 如果某topic有N个partition,集群有(N+M)个broker,那么其中有N个broker存储该topic的一个partition,剩下的M个broker不存储该topic的partition数据。
  • 如果某topic有N个partition,集群中broker数目少于N个,那么一个broker存储该topic的一个或多个partition。在实际生产环境中,尽量避免这种情况的发生,这种情况容易导致Kafka集群数据不均衡。

3 Partition Replica

partition可以在其他节点上存副本Replica,存副本的方式是按照kafka broker的顺序存。

Topic分配partition和partition replica的算法:(1)将Broker(size=n)和待分配的Partition排序。(2)将第i个Partition分配到第(i%n)个Broker上。(3)将第i个Partition的第j个Replica分配到第((i + j) % n)个Broker上。例如有5个broker节点,某个topic有3个partition,每个partition存2个副本,那么partition1存broker1,broker2,partition2存broker2,broker3。。。以此类推。

replica副本数目不能大于kafka broker节点的数目,否则报错。replica副本数越高,系统虽然越稳定,但是回来带资源和性能上的下降;replica副本少的话,也会造成系统丢数据的风险。

1)leader和follower

分区副本有leader和follower之分。其中leader是主分区,多副本中有且仅有一个作为Leader,leader由同分区所有的follower通过选举产生,当leader所在的broker节点宕机,其他的follower会重新选择leader,该过程由broker controller管理。

leader和follower主要区别在于读写数据集的先后性,生产者保存数据时总是将数据传送给leader,由leader通知各个follower,再由其他的follower从leader拉取数据。

leader内部维护一个同步队列“in sync replicas”(ISR),里面存放和leader信息同步的follower,与leader副本同步滞后过多的副本(不包括leader)副本组成OSR(Out-Sync Relipcas),分区中的所有副本统称为AR(Assigned Repllicas),AR=ISR+OSR

2)ISR

ISR与生产数据时leader和follower之间数据保存方式有关以及副本出现故障重启后各个副本之间恢复数据一致性有关。

Leader副本负责维护和跟踪ISR集合中所有的follower副本的滞后状态,当follower副本落后太多或者失效时,判断是否同步取决与时间阈值replica.lag.time.max.ms,leader副本会把它从ISR集合中剔除。

Kafka在启动的时候会开启两个与ISR相关的定时任务,名称分别为“isr-expiration"和”isr-change-propagation",具体参考https://blog.csdn.net/weixin_43975220/article/details/93190906

4 数据存储

每个partiton相当于是一个子queue。在物理结构上,每个partition对应一个物理的目录(文件夹),文件夹命名是[topicname]_[partition]_[序号],分区数据可以通过参数num.partitions控制,也可以创建Topic时通过参数指定parittion数量;

分区数据目录中使用多个segment存储,每个segment核心文件有两个,xxx.index和xxx.log,xxx代表当前当前segment中数据最小的偏移量,index中存放数据的索引,log中存放的实际数据,结构图如下

5 数据一致性

在运行过程中,无论是leader还是follower都会有出现故障的可能,为了确保数据一致性,kafka在每个log文件内保存了两个特殊的参数:LEO和HW。

  • LEO:每个副本当前已经保存的最后一个offset,每个副本保存各自的值
  • HW:消费者能见到的最大的offset,ISR中最小的LEO,ISR中所有副本统一值

在处理不同故障时有不同的方式:

follower出现故障后。会被踢出ISR列表,待该follower恢复后,follower会读取本地磁盘上记录的上次HW记录,并将log文件中高于HW的记录截掉,从HW开始从leader同步数据,等待该follower的LEO不小于该分区的HW后,将follower加入ISR中;

leader出现故障后,会从ISR中选举出一个新的leader,只有在ISR中的follower才有资格选举leader(这个原则可以通过修改对应的参数配置来改变),为保证数据一致性,各个follower会将自己高于HW的数据截掉,重新从leader同步数据。

注意:该过程其实只是保证各个副本的数据一致性,并不能保证消费者读取数据时数据重复问题。

6 Producer

生产者即数据的发布者,该角色将消息发布到Kafka的topic中。生产的每条信息必须指定topic,partition和时间戳为可选值。Kafka支持以消息集合为单位进行批量发送,以提高push效率。

1)生成数据流程

  • 根据分区算法确定数据的分区,可以指定,默认存在key情况下默认分区采取 hash(key) % [broker数量] 方式选取分区,没有key时采用随机和轮询方式选取不同的partition。
  • producer将数据交给leader,leader将数据保存,依赖实际配置确定是立即写入磁盘还是暂存在系统的缓存中
  • leader通知各个follower同步当前数据,依赖配置ack方式,同步数据
  • leader返回给producer确认信息

2)分区方式

3)Partition ack

当生产者写入消息时,会将消息发送给leader,等待leader返回ack确认信息,ack信息有三种方式:

  • 当ack=0,表示leader成功后,broker就返回成功,无论其他的partition follower是否写成功。
  • 当ack=1,表示leader和其他半数follower成功的时候,broker就返回成功,无论其他的partition follower是否写成功。
  • 当ack=-1,表示leader和ISR中全部follower写成功的时候,才算成功,kafka broker才返回成功信息。这里需要注意的是,如果ack=1的时候,一旦有个broker宕机导致partition的follower和leader切换,会导致丢数据。

kafka通过partition ack来控制是否发送成功并把信息返回给producer,producer可以有任意多的thread,这些kafka服务器端是不care的。

4)Exactly once

Producer端的delivery guarantee默认是At least once的,ack=-1。也可以设置Producer异步发送实现At most once,ack=0。At least once可以确保数据不丢失,但不能保证数据不重复;At most once保证数据不重复但不保证数据不丢失;但对于一些重要的数据需要保证不丢失也不重复保存,比如交易数据,Producer可以用主键幂等性实现Exactly once。

在0.11版本后kafka加入一个重大特性:幂等性。Producer无论想集群发送多少次数据,Server端都是会保存一次。幂等性结合At least once构成Exactly once:   At least once + 幂等性 = Exactly once

要启动幂等性需要将Producer中参数enable.idompotence设置为true。kafka幂等性就是将原来由消费端过滤重复数据功能移到生产端。开启幂等性的Producer在初始化时获取唯一PID,发往同一个partition的数据会加上Sequence Number。而broker会对数据<PID, Partition, SeqNumber>做缓存,当具有相同主键数据提交时只会保存一条。

消息在broker上的可靠性,因为消息会持久化到磁盘上,所以如果正常stop一个broker,其上的数据不会丢失;但是如果不正常stop,可能会使存在页面缓存来不及写入磁盘的消息丢失,这可以通过配置flush页面缓存的周期、阈值缓解,但是同样会频繁的写磁盘会影响性能,根据实际情况配置。

但PID重启就会变化,同时不同的partition具有不同的主键,所以幂等性无法保证夸分区夸会话的Exactly once。

7 Consumer

消费者可以从broker中读取数据,实际是读取topic每个分区内的数据。Consumer读取partition的消息O(1)顺序读取的,需要保存读取数据的偏移量,同时每个Consumer属于一个特定的Consumer Group,可以指定分组,若不指定则默认分组,分组与消费消息模式有关。单个消费者可以同时消费多个topic中数据,同时单个topic可以同时被多个消费者读取数据,即topic中一个分区可以同时被多个消费组中的消费者读取数据。

1) Consumer Group

单播和广播

  • 可为每个Consumer指定group name,若不指定group name则属于默认的group。这是kafka用来实现一个topic消息的广播(发给所有的consumer)和单播(发给任意一个consumer)的手段。
  • 一个topic可以有多个CG。topic的消息会复制给consumer。如果需要实现广播,只要每个consumer有一个独立的CG就可以了。要实现单播只要所有的consumer在同一个CG。用CG还可以将consumer进行自由的分组而不需要多次发送消息到不同的topic。

读取partition数据

  • partition的一条message头同时可以被多个Consumer Group消费,但同一时刻一个Consumer Group组内只能有一个Consumer thread消费partition的消息,consumer group的多个consumer不能同时消费一个partition
  • 多个consumer的消费都必须是顺序读取partition里面的message,新启动的consumer默认从partition队列最头端最新的地方开始阻塞的读message。
  • 当启动一个consumer group去消费一个topic的时候,无论topic里面有多个少个partition,无论我们consumer group里面配置了多少个consumer thread,这个consumer group下面的所有consumer thread一定会消费全部的partition;即便这个consumer group下只有一个consumer thread,那么这个consumer thread也会去消费所有的partition。因此,最优的设计就是,consumer group下的consumer thread的数量等于partition数量,这样效率是最高的。

读取举例

当consumer group里面的consumer数量小于这个topic下的partition数量的时候,如下图groupA,groupB,就会出现一个conusmer thread消费多个partition的情况,总之是这个topic下的partition都会被消费。如果consumer group里面的consumer数量等于这个topic下的partition数量的时候,如下图groupC,此时效率是最高的,每个partition都有一个consumer thread去消费。当consumer group里面的consumer数量大于这个topic下的partition数量的时候,如下图GroupD,就会有一个consumer thread空闲。因此,我们在设定consumer group的时候,只需要指明里面有几个consumer数量即可,无需指定对应的消费partition序号,consumer会自动进行rebalance。

如果producer的流量增大,当前的topic的parition数量=consumer数量,这时候的应对方式就是很想扩展:增加topic下的partition,同时增加这个consumer group下的consumer。

2)分区方式

分区方式轮询和range,默认range。

轮询是以消费者组为单位,topic会将自身所有分区依次发送给消费者组的所有消费者,无论消费者是否订阅该主题;

3)offset保存

Consumer读取partition的消息O(1)顺序读取的,所以必须维护读取位置offsite信息。维护方式两种:

  • high level API,0.10之前offset存于Zookeeper中,但频繁读写zk影响zk的效率,0.10之后kafka将offsite信息保存在一个独立的topic中, _comsumer_topic
  • low level API的offset由自己维护。一般来说都是使用high level api的。

Consumer读取消息后需要提交当前读取位置,即delivery gurarantee,提交方式有三种的:

  • At most once消息可能会丢,绝对不会重复传输,读完message先commmit再处理message,autocommit默认是true,这时候先commit就会更新offsite+1,一旦处理失败,offsite已经+1,这个时候就会丢message
  • At least once 消息绝对不会丢,但是可能会重复传输,也可以配置成读完消息处理再commit,这种情况下consumer端的响应就会比较慢的,需要等处理完才行
  • Exactly once每条信息肯定会被传输一次且仅传输一次,这是用户想要的。

8 message

message状态:在Kafka中,消息的状态被保存在consumer中,broker不会关心哪个消息被消费了被谁消费了,只记录一个offset值(指向partition中下一个要被消费的消息位置),这就意味着如果consumer处理不好的话,broker上的一个消息可能会被消费多次。

message持久化:Kafka中会把消息持久化到本地文件系统中,并且保持o(1)极高的效率。我们众所周知IO读取是非常耗资源的性能也是最慢的,这就是为了数据库的瓶颈经常在IO上,需要换SSD硬盘的原因。但是Kafka作为吞吐量极高的MQ,却可以非常高效的message持久化到文件。这是因为Kafka是顺序写入o(1)的时间复杂度,速度非常快。也是高吞吐量的原因。由于message的写入持久化是顺序写入的,因此message在被消费的时候也是按顺序被消费的,保证partition的message是顺序消费的。一般的机器,单机每秒100k条数据。

message有效期:Kafka会长久保留其中的消息,以便consumer可以多次消费,当然其中很多细节是可配置的。

9 事务性

pruducer事务

特性

Kafka集群中broker之间的关系:不是主从关系,各个broker在集群中地位一样,我们可以随意的增加或删除任何一个broker节点。

负载均衡方面: Kafka提供了一个 metadata API来管理broker之间的负载(对Kafka0.8.x而言,对于0.7.x主要靠zookeeper来实现负载均衡)。

同步异步:Producer采用异步push方式,极大提高Kafka系统的吞吐率(可以通过参数控制是采用同步还是异步方式)。

分区机制partition:Kafka的broker端支持消息分区partition,Producer可以决定把消息发到哪个partition,在一个partition 中message的顺序就是Producer发送消息的顺序,一个topic中可以有多个partition,具体partition的数量是可配置的。partition的概念使得kafka作为MQ可以横向扩展,吞吐量巨大。partition可以设置replica副本,replica副本存在不同的kafka broker节点上,第一个partition是leader,其他的是follower,message先写到partition leader上,再由partition leader push到parition follower上。所以说kafka可以水平扩展,也就是扩展partition。

实时数据与离线数据:kafka既支持离线数据也支持实时数据,因为kafka的message持久化到文件,并可以设置有效期,因此可以把kafka作为一个高效的存储来使用,可以作为离线数据供后面的分析。当然作为分布式实时消息系统,大多数情况下还是用于实时的数据处理的,但是当consumer消费能力下降的时候可以通过message的持久化在淤积数据在kafka。

 

参考:

https://www.cnblogs.com/frankdeng/p/9310684.html  Kafka的简介与架构

https://blog.csdn.net/qq_32297447/article/details/80811127  kafka简述

https://blog.csdn.net/uniquecapo/article/details/79292965  Kafka史上最详细原理总结

https://www.cnblogs.com/alan319/p/8651434.html  kafka参数设置

https://blog.csdn.net/u013332124/article/category/7667120  kafka总结

https://blog.csdn.net/qq_36807862/article/category/7888889 kafka总结

https://blog.csdn.net/stark_summer/article/details/50144591 kafka高吞吐量

https://blog.csdn.net/xiaoguozi0218/article/details/93310587 kafka高吞吐低延迟

 

 

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值