kafka原理

http://blog.csdn.net/stark_summer/article/details/50144591

消息队列优势:异步、削峰、解耦。

Kafka是一个开源的分布式消息系统,Kafka中的核心概念有:

• Kafka用 topic 对消息(message)归类。例如,在网页活动跟踪中,每个活动种类(包括网页浏览、搜

索、点击等)的消息都可以发布到一个各自的topic中。

• 向Topic发布消息的进程称为producer。

• 向Topic订阅消息并处理已发布消息的进程称为consumer。一个group中只能一个consumer消费一个topic,所以当所有consumer都是一个组时就是点对点模式,当每个consumer各属于一个组时,就是消息订阅模式。

• Kafka运行在一台或多台机器组成的集群上,Kafka集群中的节点称为 broker,端口9092。

Kafka的工作流程大致如下:producer向topic发布消息,Kafka集群对发布的消息进行处理后传给consumer。

发布给一个topic的消息可以在Kafka集群中分割成多个 partition,每个parititon都是一个log,log中的消息

按发布的顺序排成一个消息列 (message sequence),Kafka不断地向log的末尾写入新的消息。每

个partition中的消息都有一个在partition中唯一的ID,称为offset,也就是相对log开头的偏移

量,Consumer在读取消息的时候会记住当前消息的offset。一个有三个partition的topic内部结构如下所

示:

1)一个topic中的每个partition都可以分给Kafka集群中的一个broker来处理(一个broker可以处理多

个partitions),这样的设计让Kafka可以方便地横向扩展,同时也提高了并行度。Kafka可以对每

个partition进行备份(replicate),备份数量(replication factor)可以设置,将备份分散到集群中不

同的broker上来实现HA。对每个partition来说都有一个作为 leader (领导者)的broker和零到多个

follower (跟随者)。Leader负责所有对partition的读写请求,follower则被动地复制leader的操作。如

果leader失效,follower之一会自动成为新的leader。

Producer可以依据一些规则来选择将消息分发给topic中的哪个partition,常见的规则有轮流分发、按哈希

值分发等等。

2)传统的消息分发模式一般有两种:queueing(队列)模式和publish-subscribe(发布订阅)模式。

在queueing模式中,消息列中的消息会依次被consumer读取。在publish-subscribe模式中,每条消息会广播(broadcast)给所有的consumer,各个consumer根据预先定义好的方式订阅所有被广播的消息的一部

分。Kafka使用 Consumer Group 实现了这两种模式的结合。

在Kafka中,一个或多个consumer组成consumer group。Consumer group表现为“逻辑的订阅者(logical subscriber)”——所有topic收到的消息都会广播给所有的consumer group,而每个consumer group选择订阅一个或多个topic中的消息,也就是说consumer group外部的消息分发模式是publish-subscribe模式。而同一个consumer group内部的consumer则遵循queueing模式。这个混合的消息分发模式有两个极限情况:

1. 所有consumer都在同一个consumer group中:这种情况是纯粹的queueing模式。

2. 每个consumer都在不同的consumer group中:这种情况是纯粹的publish-subscribe模式。

当同一个消息列中的消息被多个consumer读取时,会出现消息到达consumer的顺序和在消息列中的顺序不同的情况,所以在Kafka中,一个topic中的每个partition都只能被订阅它的各个consumer group中的 一个

consumer读取(但是一个consumer可以读多个partition),以保证在各consumer group内,各partition的消息按发布的顺序被读取。因此,一个consumer group中的consumer个数不能多于它订阅的topic中

的partition个数。在下图中,一个两节点的Kafka集群在分发四个partition的消息,每个节点负责两

个partition的分发。Kafka集群将消息分发给两个consumer group:Consumer Group A中有两

个consumer,Consumer Group B中有四个consumer。

注意,Kafka只保持partition中的消息顺序不变,并不保证topic中的消息顺序不变。要保证topic中消息顺

序不变,可以让topic只有一个partition,但是这样会牺牲并行度。

3)前面我们提到,Kafka对消息以partition为单位进行备份,一个备份称为一个replica。一个partition

的replica总数称为replication factor,replication factor按topic设置。一个partition的所有replica

中会有一个leader和零到若干个follower,所有的读写请求都由leader处理,follower像consumer一样接

收leader上的消息,写进自己的log中,保持自己的log和leader的log一致(offset一致、消息一致、消息顺

序一致)。

在Kafka中,一个replica和leader同步的标准有两个:

1. 和Zookeeper的session没有终止(通过Zookeeper的心跳机制)。

2. 如果这个replica是一个follower,它相对leader的延迟不能“太多”(可容忍的延迟可以设置)。

一个replica如果满足这两个标准,它则被称为一个 in sync replica (ISR)。Leader会记录ISR的列表,并将这

个列表存在Zookeeper上,如果有replica失效或者延迟过多,则会被leader移出ISR列表。

只有当所有的ISR都接收到了一条消息并将这条消息写进自己的log中,这条消息才算被提交(committed),而broker只会将被提交的消息发给consumer,这就保证了只要有一个ISR还在工作,提交过的消息就不会丢失。当leader失效,ISR中的一个replica将被选举为新的leader。对Kafka中一些概念的简单介绍到此结束。您可以通过开源社区的资料了解更多关于Kafka的细节。

消息队列,不像flume,它还可以存储数据,并提供对数据的管理,不用用户关心很多细节,分布式,高并发,replica容错,kafka集群由zookeeper协调

broker: kafka集群中的每一个服务器进程(节点)一般一个,kafka server,监听一些端口,下面有topic,每个topic存在可能在不同的物理机上,其他follower只是单纯的复制消息,实现冗余,每个topic有多个partition,partition可能在不同节点,每个节点相同partition只有一个,partition可有多副本,即replication,建议大于1,每条消息在partiton中有offset来唯一标识,partiton一appendlog形式存在,只能append,不支持随机读写。

producer:向kafka发送数据的程序

consumer:从kafka接收数据的程序,分两种,一种一条一条的读数据,另一种需指定partition和offset

消息在kafka中无论是否被消费,将保存7天(默认),然后将被清除,释放磁盘。按照offset顺序消费信息,重置offset可随机读,offset保存在zookeeper中。zookeeper负责维护producer和consumer。consumer group

jms有两种模型,一种是queue(队列模型),消息按队列方式顺序消费,消息只能被消费一次,一个consumer获得该消息,其他consumer不能获得该消息,另一种是topic(订阅模型),所有订阅该消息的consumer都获得该消息。kafka将这两种模型结合,只有topic模型,但是增加了consumer group概念,并且规定,一个消息在一个组里面只有一个consumer消费,那么极端情况就是所有consumer在一个组里,那就是queue模式,所有consumer分别是一个组,那就是topic模型。

对于日志来说,一条记录以"\n"结尾,或者通过其它特定的分隔符分隔,这样就可以从文件中拆分出一条一条的记录,不过这种格式更适用于文本,对于Kafka来说,需要的是二进制的格式。kafka以offset来记录数据的位置,大小,offset有zookeeper维护。

发布给一个topic的消息可以在Kafka集群中分割成多个 partition,每个parititon都是一个log,log中的消息按发布的顺序排成一个消息列 (message sequence),Kafka不断地向log的末尾写入新的消息。每个partition中的消息都有一个在partition中唯一的ID,称为 offset,也就是相对log开头的偏移量,Consumer在读取消息的时候会记住当前消息offset。

一个topic中的每个partition都可以分给Kafka集群中的一个broker来处理(一个broker可以处理多个partitions),这样的设计让Kafka可以方便地横向扩展,同时也提高了并行度。Kafka可以对每个partition进行备份(replicate),备份数量(replication factor)可以设置,将备份分散到集群中不同的broker上来实现HA。对每个partition来说都有一个作为 leader (领导者)的broker和零到多个 follower (跟随者)。Leader负责所有对partition的读写请求,follower则被动地复制leader的操作。如果leader失效,follower之一会自动成为新的leader。Producer可以依据一些规则来选择将消息分发给topic中的哪个partition,常见的规则有轮流分发、按哈希值分发等等。

kafka 的consumer 有组的概念,每个组中的消费者只能有一个消费一个topic ,所以极限情况分别为所有消费者都在同一个组,那就是队列模式,另一个是所有消费者分别在一个组,那就是订阅模式。kafka 通过topic和组将java 的队列和订阅两种模式jms 统一。

生产者不需要在zookeeper中注册,它属于客户端。

Kafka是由LinkedIn开发的一个分布式的消息系统,使用Scala编写,它以可水平扩展和高吞吐率而被广泛使用。

Broker

Kafka集群包含一个或多个服务器,这种服务器被称为broker

Topic

每条发布到Kafka集群的消息都有一个类别,这个类别被称为Topic。(物理上不同Topic的消息分开存储,逻辑上一个Topic的消息虽然保存于一个或多个broker上但用户只需指定消息的Topic即可生产或消费数据而不必关心数据存于何处)

Partition

Parition是物理上的概念,每个Topic包含一个或多个Partition.增加吞吐量,实现性能现行扩展。一条message只能在一个partition,追加的方式写到日志文件,偏移量offset记录每条消息相对于日志头的位置。同一个分区内,消息追加写,有序,但不同分区间无法保证有序。若是既需要kafka的吞吐量,又需要某些场景分区间有序。可通过重写partitioner.class的partition方法,自定义分区方式(默认采取轮训方式,类似于取余,根据partition数实现负载均衡),比如按照消息的某些列做特殊处理,让具有某些特征的消息进入同一分区,从而保证有序性。

List<PartitionInfo> partitions = cluster.partitionsForTopic(topic);

return Math.abs(key.hashCode()) % partitions.size();

如果指定了 Key,那么默认实现按消息键保序策略;如果没有指定 Key,则使用轮询策略。轮训即按照partition数量均匀分布,类似取余,是默认策略,有利于负债均衡和吞吐量。

Producer

负责发布消息到Kafka broker

Consumer

消息消费者,向Kafka broker读取消息的客户端。

Consumer Group

每个Consumer属于一个特定的Consumer Group(可为每个Consumer指定group name,若不指定group name则属于默认的group)。

Kafka通过Zookeeper管理集群配置,选举leader,以及在Consumer Group发生变化时进行rebalance。Producer使用push模式将消息发布到broker,Consumer使用pull模式从broker订阅并消费消息。

为了使得Kafka的吞吐率可以线性提高,物理上把Topic分成一个或多个Partition,每个Partition在物理上对应一个【文件夹】,段segment由index和data文件组成,两个文件成对出现,分别存储索引和数据。

即xxx.index和xxx.log,该文件夹下存储这个Partition的所有消息和索引文件。

segment文件命名规则:对于所有的partition来说,segment名称从0开始,之后的每一个segment名称为上一个segment文件最后一条消息的offset值。

先找到该message所在的segment文件,通过二分查找的方式寻找小于等于345552的offset,假如叫S的segment符合要求,如果S等于345552则S上一个segment的最后一个message即为所求;如果S小于345552则依次遍历当前segment即可找到。

实际上offset的存储采用了稀疏索引,这样对于稠密索引来说节省了存储空间,但代价是查找费点时间。

Kafka提供两种策略删除旧数据。一是基于时间,二是基于Partition文件大小。例如可以通过配置$KAFKA_HOME/config/server.properties,让Kafka删除一周前的数据,也可在Partition文件超过1GB时删除旧数据,配置如下所示。

# The minimum age of a log file to be eligible for deletion #默认一周,删除过期文件与提高Kafka性能无关。

1. 基于时间:log.retention.hours=168

2. 基于大小:log.retention.bytes=1073741824

offset由Consumer控制。正常情况下Consumer会在消费完一条消息后递增该offset。当然,Consumer也可将offset设成一个较小的值,重新消费一些消息。因为offet由Consumer控制,所以Kafka broker是无状态的,它不需要标记哪些消息被哪些消费过,

也不需要通过broker去保证同一个Consumer Group只有一个Consumer能消费某一条消息,因此也就不需要锁机制,这也为Kafka的高吞吐率提供了有力保障。

Producer发送消息到broker时,会根据Paritition机制选择将其存储到哪一个Partition。如果Partition机制设置合理,所有消息可以均匀分布到不同的Partition里,这样就实现了负载均衡。

通过配置项【num.partitions】来指定新建Topic的默认Partition数量,也可在创建Topic时通过参数指定,同时也可以在Topic创建之后通过Kafka提供的工具修改。

1. 指定了 patition,则直接使用;

2. 未指定 patition 但指定 key,通过对 key 的 value 进行hash 选出一个 patition

3. patition 和 key 都未指定,使用轮询选出一个 patition。

发送消息流程:

1. producer 先从 zookeeper 的 "/brokers/.../state" 节点找到该 partition 的 leader

2. producer 将消息发送给该 leader

3. leader 将消息写入本地 log

4. followers 从 leader pull 消息,写入本地 log 后 leader 发送 ACK

5. leader 收到所有 ISR 中的 replica 的 ACK 后,增加 HW(high watermark,最后 commit 的 offset) 并向 producer 发送 ACK

producer可以通过指定key的方式决定数据发往哪个partition:

在发送一条消息时,可以指定这条消息的key,Producer根据这个key和Partition机制来判断应该将这条消息发送到哪个Parition。Paritition机制可以通过指定Producer的paritition. class这一参数来指定,该class必须实现kafka.producer.Partitioner接口。

本例中如果key可以被解析为整数则将对应的整数与Partition总数取余,该消息会被发送到该数对应的Partition。(每个Parition都会有个序号,序号从0开始)

使用Consumer high level API时,同一Topic的一条消息只能被同一个Consumer Group内的一个Consumer消费,但多个Consumer Group可同时消费这一消息。

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 212,332评论 6 493
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 90,508评论 3 385
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 157,812评论 0 348
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 56,607评论 1 284
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 65,728评论 6 386
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 49,919评论 1 290
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 39,071评论 3 410
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 37,802评论 0 268
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 44,256评论 1 303
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 36,576评论 2 327
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 38,712评论 1 341
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 34,389评论 4 332
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 40,032评论 3 316
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 30,798评论 0 21
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 32,026评论 1 266
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 46,473评论 2 360
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 43,606评论 2 350

推荐阅读更多精彩内容

  • MQ(消息队列)是跨进程通信的方式之一,可理解为异步rpc,上游系统对调用结果的态度往往是重要不紧急。使用消息队列...
    allin8116阅读 502评论 0 0
  • Kafka的基本介绍 Kafka最初由Linkedin公司开发,是一个分布式、分区、多副本、多订阅者,基于zook...
    join_a922阅读 1,403评论 0 1
  • 一、为什么需要消息系统 1.解耦:允许你独立的扩展或修改两边的处理过程,只要确保它们遵守同样的接口约束。2.冗余:...
    piziyang12138阅读 270评论 0 0
  • 一、为什么需要消息系统 1.解耦:允许你独立的扩展或修改两边的处理过程,只要确保它们遵守同样的接口约束。2.冗余:...
    数据萌新阅读 246评论 0 0
  • 昨天, 有个做新闻的朋友让我帮忙转发G20文艺晚会清单, 我假装没看见他的留言, 别说政要开会了, 之前的奥运会我...
    石小露阅读 771评论 0 0