首页
学习
活动
专区
工具
TVP
发布
社区首页 >专栏 >Kafka漫游记

Kafka漫游记

作者头像
java达人
发布2018-03-26 15:53:15
9980
发布2018-03-26 15:53:15
举报
文章被收录于专栏:java达人java达人

我是一条消息,从我被生产者发布到topic的时候,我就清楚自己的使命:被消费者获取消费。但我一直很纳闷,把我直接推送给消费者不就行了,为什么一定要先推送到类似队列的topic中呢,消息队列的作用到底是什么呢?

在消息队列出现以前,服务之间的矛盾由来已久,服务A调用服务B,经常要等待服务B处理完后续流程再返回结果,因此服务A常常抱怨服务B接收处理能力太慢,服务B也常常把某些责任推卸给服务A,于是,消息队列出现了,让服务A只管往队列里面放消息,后续的处理流程都不用管,而服务B负责往队列里面取消息,通过巧妙的办法,抛开了等待的过程,明确了两者的职责,从此,服务A和服务B各自专心于自己的事物,也不相互抱怨推诿责任了,用砖家的话说,就是实现了解耦和异步通信。kafka就是消息系统中的代表性成员。

我一开始以为kafka不过是一条细长的管道,我们这些消息一个个往里面放,先进者先出,等我真正进入生产环境的消息系统之后,才发现原来是自己道行不够,真实情况往往比我们想象中的要复杂。那是一个非常宏伟的建筑:

图片来源:极客学院

这幅图包含了消息系统使用中的各个角色,这里重点讲解下消费者,kafka使用Consumer high level API时,同一Topic的一条消息只能被同一个Consumer Group内的一个Consumer消费,但多个Consumer Group可同时消费这一消息。

这可以实现广播和单播模式,如果所有的consumer都具有相同的group,我们会被其中一个cosumer fetch(单播);如果所有的consumer都有不同的group,那这就是"发布-订阅",我们将会被广播给所有的consumer。

上图中,broker持有topic,一个topc切分成多个partitions,这些partitions分布在多个不同的broker(kafka服务器)中,这样避免了消息文件达到单机限制,同时也提高了并发消息的能力,消息被路由到哪个partition上,由producer客户端决定,比如可以采用"key-hash"等方法。一个partition又有多个segments,当segment文件尺寸达到一定阀值时,将会创建一个新的文件。我们就藏在segment中,但kafka总能通过offset找到我们,经典方法是二分查找法。读到这里,您肯定头晕了,下面是术语解释!

topic:被发布消息的一个类别,逻辑上可以被认为是一个queue,一个topic可以有一个或多个消费者订阅。

图片来自官网

partition:物理上把Topic分成一个或多个Partition,每个Partition在物理上对应一个文件夹,该文件夹下存储这个Partition的所有消息和索引文件。每个Partition都是一个有序的、不可变的记录序列,它不断被追加到一个结构化的commit日志中。Partition中的记录被分配到一个顺序的id号,称为offset(偏移量),它惟一地标识Partition中的每个记录。

log:比如topic名称为"my_topic",它有2个partitions,那么日志将会保存在my_topic_0和my_topic_1两个目录中;日志文件中保存了一序列"log entries"(日志条目),每个log entry格式为"4个字节的数字N表示消息的长度" + "N个字节的消息内容";每个日志都有一个offset来唯一的标记一条消息,offset的值为8个字节的数字,表示此消息在此partition中所处的起始位置..每个partition在物理存储层面,有多个log file组成(称为segment).segmentfile的命名为"最小offset".kafka.例如"00000000000.kafka";其中"最小offset"表示此segment中起始消息的offset。

放大镜下的log:

图片来自官网

二分查找:首先,假设表中元素是按升序排列,将表中间位置记录的关键字与查找关键字比较,如果两者相等,则查找成功;否则利用中间位置记录将表分成前、后两个子表,如果中间位置记录的关键字大于查找关键字,则进一步查找前一子表,否则进一步查找后一子表。重复以上过程,直到找到满足条件的记录,使查找成功,或直到子表不存在为止,此时查找不成功。

生产者把我们推到消息队列后,剩下的就是等待kafka消费者fetch,这是kafka的一个特点,而在JMS实现中,一般是push模式,由broker主动推送给消费者,可见broker的任务是相当的轻的。

为了防止我们随时可能挂了,kafka还精心设计了备份机制,即将partition克隆复制几份,放到其他broker上,这些partitions中有leader,负责日常事务,其他follower只是按照leader节奏,同步信息即可,一旦leader挂了,就要选择一个follower来顶上。

除了备份机制,还有消息传送机制,可选的有以下三种:

1、at most once: 最多一次,发送一次,无论成败,将不会重发。

读取消息,然后在log中保存它的位置,最后处理消息。而消息被处理之前,消费者进程可能会崩溃。在这种情况下,处理的过程将从保存的位置开始,即使在该位置之前的一些消息还没有被处理。这就是“at most once”语义。

2、 at least once: 消息至少发送一次,如果消息未能接受成功,可能会重发,直到接收成功。

读取消息,处理消息,最后保存它的位置。在这种情况下,消费者进程可能在处理消息后崩溃,此时其位置还没有保存。在这种情况下,新进程会接收到已经被处理的几条消息。这就是“at least once”。在许多情况下,消息有一个主键,因此更新是幂等(接收相同的消息两次,只是用一个副本覆盖一条记录)。

3、exactly once: 消息只会发送一次。

元数据存储—zookeeper

上面建筑图右边还有一个叫zookeeper的家伙,Kafka通过zookeeper来存储管理元数据,zookeeper的工作包括但不限于:

1、选择controller。controller是其中的一个broker,负责维护所有partitions的leader/follower关系。当一个节点关闭时,controller通知其他副本成为partition leader,以替换原节点的partition leader。zookeeper选择controller,确保只有一个controller,如果它崩溃了,zookeeper会选择一个新的。

2、管理集群成员—哪些broker是alive状态的,是集群的一部分?这也是通过zookeeper来管理的。

3、topic配置—哪些topic是存在的,每个有多少partitions,副本在哪里,其中哪个是优先选择的leader,每个topic都配置了什么。

4、存在哪些consumer group,他们有哪些成员,以及每个group从每个partiton获得的最新offset。在kafka中,一个partition中的消息只会被group中的一个consumer消费。

kafka初次漫游到此结束,可能有些地方看得不是很全很细,下次继续

本文参与 腾讯云自媒体分享计划,分享自微信公众号。
原始发表:2018-03-05,如有侵权请联系 cloudcommunity@tencent.com 删除

本文分享自 java达人 微信公众号,前往查看

如有侵权,请联系 cloudcommunity@tencent.com 删除。

本文参与 腾讯云自媒体分享计划  ,欢迎热爱写作的你一起参与!

评论
登录后参与评论
0 条评论
热度
最新
推荐阅读
相关产品与服务
消息队列 CMQ 版
消息队列 CMQ 版(TDMQ for CMQ,简称 TDMQ CMQ 版)是一款分布式高可用的消息队列服务,它能够提供可靠的,基于消息的异步通信机制,能够将分布式部署的不同应用(或同一应用的不同组件)中的信息传递,存储在可靠有效的 CMQ 队列中,防止消息丢失。TDMQ CMQ 版支持多进程同时读写,收发互不干扰,无需各应用或组件始终处于运行状态。
领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档