Kafka中的客户端

阅读以下内容你将了解到:
1.消费者的分区分配策略
2.消息中间件的传输保障层级
3.Kafka中的幂等(幂等只对单个生产者中单分区生效)
4.4.Kafka中的事务(实现流程)
5.事务在生产者与消费者的语义区别

1.消费者的分区分配策略

RangeAssignor分配策略
分区数整除以消费者总数来分配,如果有余数,那么靠前的消费者会多分配一个分区
带来的问题:比如有消费者C0,C1,订阅了2个主题,且这2个主题都只有3个分区,分配结果为:
消费者C0:t0p0,t0p1,t1p0,t1p1(t0p0意为topic编号为0,此topic的partition编号为0的分区,下同)
消费者C1:t0p2,t0p2
很明显会造成分配不均匀的情况。

RoundRobinAssignor分配策略
将消费者组内所有消费者及消费者订阅的主题排序,轮询将分区分配给消费者。
看似很完美的分配策略,但是如果一个消费组内的消费者订阅信息不同,还是会造成分配不均匀。
举个栗子:
某消费者组内有3个消费者(C0,C1,C2),C0订阅了t0,C1订阅了t0和t1,C2订阅了t0、t1和t2,这三个主题分别有1、2、3三个分区。那么最终结果为
消费者C0: t0p0(t0p0意为topic编号为0,此topic的partition编号为0的分区,下同)
消费者C1: t1p0
消费者C2: t1p1、t2p0、t2p1、t2p2

StickyAssignor分配策略
此分配策略有两个目的
1.分区分配尽可能均匀
2.分区分配尽可能与上次分配的保持相同(当与第一点冲突时,优先第一点)

这种分区策略的代码实现异常复杂,但是也更加优异,其中一个优点就是使分区分配具有“粘性”,减少不必要的分区移动

当然我们也可以自定义其他的分配策略,通过自定义逻辑,可以做到一个分区在组内广播的逻辑。
注意:每个消费者都可以设置自己的分区分配策略,一个消费组内的分区分配策略可以看做被各个消费者支持的最多的策略。

2.消息中间件的传输保障层级

一般而言,对于消息中间件(注意不只包括Kafka)的消息传输保障有三个层级
1.at most once:至多一次。消息可能会丢失,但是绝对不会重复传输。
(类比于消费者先提交消费后进行消息处理,中间消费者宕机的情况)
2.at least once:至少一次,消息绝不会丢失,但可能会重复传输。
(类比于Kafka中的重试机制,或者消费者先处理消息后提交消费,中间消费者宕机的情况)
3.exactly once:恰好一次,每条消息肯定会被传输一次且仅传输一次。
(在0.11.0.0版本开始引入幂等和事务的概念,以此来实现“恰好一次”)

3.Kafka中的幂等

实现幂等的原理和注意的点:
每个生产者实例在初始化的时候回分配到一个PID,对于每个PID来说,消息发送到每一个分区都有对应的序列号,broker会在内存中会有<PID,分区>——序列号的映射关系.

此时,对于每一条消息,我们可以比较他的序列号值(SN_new)比broker中对于的序列号刚好大1,才会被接收,如果SN_new<SN_old+1,说明消息被重复写入,直接丢弃即可。如果SN_new>SN_old+1,则可能有消息丢失,这是比较严重的问题,会直接报错异常。

注意:阅读上面一段文字时,你应该注意到实现幂等是对于每一对<PID,分区>而言的,也就是说,Kafka的幂等只能保证单个生产者会话中单分区的幂等。

4.Kafka中的事务

幂等性并不能跨分区运作,而事务可以弥补这个缺陷。

事务可以保证多个分区写入操作的原子性。(事务要求生产者开启幂等特性)
Kafka中的事务可以使应用程序将消息消费、生产消息、提交消费位移当做原子操作来处理,同时成功或失败,即时该生产或消费会跨多个分区。(需要应用程序提供唯一的transactionlId)
transactionlId与上文幂等中提到的PID类似,不过transactionlId是由我们来显示的设置,而PID是Kafka内部分配的。需要保证新的生产者启动后具有相同的transactionlId的旧生产者立即失效。(也就是说,事务是针对一个生产者多个分区的)
transactionlId主要用来找到特定的事务协调器

具体实现如下:
每个生产者都会被指派一个特定的TransactionCoordinator(事务协调器),这个协调器会把事务的状态持久化到内部主题_transaction_state中。
1.先通过transactionlId找到自己的TransactionCoordinator(通过对transactionlId进行hash取模找到对应的分区,再通过分区leader副本来确定broker节点)
2.为当前生产者分配一个PID,并将transactionlId和对应的PID保存到主题_transaction_state中 (注意,如果没有开启事务而只开启了幂等,任意的broker都可以来分配PID)
3.开启事务, 接下来才是重头戏,当生产者给一个新的分区发数据前,会把<transactionlId,TopicPartition>的对应关系存储在主题_transaction_state中,有了这个对照关系我们就可以在后续的步骤里为每个分区设置COMMIT或ABORT标记。
4.通过sendOffsetsToTransaction()方法可以在一个事务批次里处理消息的消费和发送
5.一旦消息被写入成功(失败),就可以调用commitTransaction()方法或者abortTransaction()方法来结束当前事务。
此时就准备进行事务最后的操作了。
(1)将PREPARE_COMMIT或PREPARE_ABORT消息写入主题_transaction_state(用来存储事务的状态)
(2)将COMMIT或ABORT信息写入用户所使用的普通主题和_consumer_offsets
(3)将COMMIT_COMMIT或者COMPLETE_ABORT信息写入内部主题
_transaction_state。此时便可以删除主题_transaction_state中所有关于该事务的消息了。(这个主题中采用的清理策略为日志压缩,将相应消息设置为墓碑消息即可)

再简单梳理一遍:事务的实现需要有一个特定的事务协调器来实现,还会把transactionlId(主要用来找到特定的事务协调器)、PID(用来确定唯一的分区)、TopicPartition(事务中发送消息的频道和分区)之间的映射关系保存下来,此时就可以开始事务了,等消息被成功(失败)写入,来COMMIT或者ABORT。

以COMMIT为例,先要在_transaction_state设置PREPARE_COMMIT的标记以后再来COMMIT普通主题(这样做是为了保证事务的持久性,如果断电后仍可以保证这个事务再Kafka重启后被正确提交),等普通消息都COMMIT提交完成后再将_transaction_state设置设置为COMMIT_COMMIT。此时便可以将关于这个事务的消息删除了(这个主题中采用的清理策略为日志压缩,将相应消息设置为墓碑消息即可)。

5.事务在生产者与消费者的语义区别

通过事务,Kafka可以保证生产者会话的消息幂等发送,以及跨生产者会话的事务恢复。
而对于消费者而言,事务的语义相对偏弱。Kafka并不能保证已提交的事务的中所有消息都能被消费:
因为我们的事务只保证写入的成功。

1.对于采用日志压缩的主题而言,事务中某些消息可能被清理(相同的key消息后来的消息覆盖前面的消息)
2.对于采用日志删除的主题而言,事务中消息可能分布在不同的日志分段,当老的日志分段被删除时候,相应的消息也会丢失。
3.消费者通过seek()访问到任意offset的消息,从而可能遗漏事务中的部分消息(比如从事务的中间段开始消费)
4.消费者再消费的时候没有被分配到事务内的所有分区。

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

推荐阅读更多精彩内容