Kafka 是我在疫情期间在游戏之余学的。虽然以前用过 ActiveMQ 和 RabbitMQ,可是在 Kafka 这门技术面前我也算是一个初学者。文章中如有说法有点完善或者不许确的地方敬请指出。linux
今天咱们来聊聊 Kafka ,主要是带你从新认识一下 Kafka,聊一下 Kafka 中比较重要的概念和问题。在后面的文章中我会介绍:git
咱们如今常常提到 Kafka 的时候就已经默认它是一个很是优秀的消息队列了,咱们也会常常拿它给 RocketMQ、RabbitMQ 对比。我以为 Kafka 相比其余消息队列主要的优点以下:程序员
实际上在早期的时候 Kafka 并非一个合格的消息队列,早期的 Kafka 在消息队列领域就像是一个衣衫褴褛的孩子同样,功能不完备而且有一些小问题好比丢失消息、不保证消息可靠性等等。固然,这也和 LinkedIn 最先开发 Kafka 用于处理海量的日志有很大关系,哈哈哈,人家原本最开始就不是为了做为消息队列滴,谁知道后面误打误撞在消息队列领域占据了一席之地。github
随着后续的发展,这些短板都被 Kafka 逐步修复完善。因此,Kafka 做为消息队列不可靠这个说法已通过时!面试
先来看一下官网对其的介绍,应该是最权威和实时的了。是英文也没有关系,我已经将比较重要的信息都为你提取出来了。spring
从官方介绍中咱们能够获得如下信息:数据库
Kafka 是一个分布式流式处理平台。这究竟是什么意思呢?apache
流平台具备三个关键功能:后端
Kafka 主要有两大应用场景:安全
关于 Kafka 几个很是重要的概念:
topic
中。题外话:早期的 JMS 和 AMQP 属于消息服务领域权威组织所作的相关的标准,我在 JavaGuide的 《消息队列其实很简单》这篇文章中介绍过。可是,这些标准的进化跟不上消息队列的演进速度,这些标准实际上已经属于废弃状态。因此,可能存在的状况是:不一样的消息队列都有本身的一套消息模型。
使用队列(Queue)做为消息通讯载体,知足生产者与消费者模式,一条消息只能被一个消费者使用,未被消费的消息在队列中保留直到被消费或超时。 好比:咱们生产者发送 100 条消息的话,两个消费者来消费通常状况下两个消费者会按照消息发送的顺序各自消费一半(也就是你一个我一个的消费。)
假如咱们存在这样一种状况:咱们须要将生产者产生的消息分发给多个消费者,而且每一个消费者都能接收到完成的消息内容。
这种状况,队列模型就很差解决了。不少比较杠精的人就说:咱们能够为每一个消费者建立一个单独的队列,让生产者发送多份。这是一种很是愚蠢的作法,浪费资源不说,还违背了使用消息队列的目的。
发布-订阅模型主要是为了解决队列模型存在的问题。
发布订阅模型(Pub-Sub) 使用主题(Topic) 做为消息通讯载体,相似于广播模式;发布者发布一条消息,该消息经过主题传递给全部的订阅者,在一条消息广播以后才订阅的用户则是收不到该条消息的。
在发布 - 订阅模型中,若是只有一个订阅者,那它和队列模型就基本是同样的了。因此说,发布 - 订阅模型在功能层面上是能够兼容队列模型的。
Kafka 采用的就是发布 - 订阅模型。
RocketMQ 的消息模型和 Kafka 基本是彻底同样的。惟一的区别是 Kafka 中没有队列这个概念,与之对应的是 Partition(分区)。
Kafka 将生产者发布的消息发送到 Topic(主题) 中,须要这些消息的消费者能够订阅这些 Topic(主题),以下图所示:
上面这张图也为咱们引出了,Kafka 比较重要的几个概念:
同时,你必定也注意到每一个 Broker 中又包含了 Topic 以及 Partition 这两个重要的概念:
划重点:Kafka 中的 Partition(分区) 实际上能够对应成为消息队列中的队列。这样是否是更好理解一点?
另外,还有一点我以为比较重要的是 Kafka 为分区(Partition)引入了多副本(Replica)机制。分区(Partition)中的多个副本之间会有一个叫作 leader 的家伙,其余副本称为 follower。咱们发送的消息会被发送到 leader 副本,而后 follower 副本才能从 leader 副本中拉取消息进行同步。
生产者和消费者只与 leader 副本交互。你能够理解为其余副本只是 leader 副本的拷贝,它们的存在只是为了保证消息存储的安全性。当 leader 副本发生故障时会从 follower 中选举出一个 leader,可是 follower 中若是有和 leader 同步程度达不到要求的参加不了 leader 的竞选。
Kafka 的多分区(Partition)以及多副本(Replica)机制有什么好处呢?
要想搞懂 zookeeper 在 Kafka 中的做用 必定要本身搭建一个 Kafka 环境而后本身进 zookeeper 去看一下有哪些文件夹和 Kafka 有关,每一个节点又保存了什么信息。 必定不要光看不实践,这样学来的也终会忘记!
后面的文章中会介绍如何搭建 Kafka 环境,你且不要急,看了后续文章 3 分钟就能搭建一个 Kafka 环境。
这部份内容参考和借鉴了这篇文章:www.jianshu.com/p/a036405f9… 。
下图就是个人本地 Zookeeper ,它成功和我本地的 Kafka 关联上(如下文件夹结构借助 idea 插件 Zookeeper tool 实现)。
ZooKeeper 主要为 Kafka 提供元数据的管理的功能。
从图中咱们能够看出,Zookeeper 主要为 Kafka 作了下面这些事情:
/brokers/topics/my-topic/Partitions/0
、/brokers/topics/my-topic/Partitions/1
咱们在使用消息队列的过程当中常常有业务场景须要严格保证消息的消费顺序,好比咱们同时发了 2 个消息,这 2 个消息对应的操做分别对应的数据库操做是:更改用户会员等级、根据会员等级计算订单价格。假如这两条消息的消费顺序不同形成的最终结果就会大相径庭。
咱们知道 Kafka 中 Partition(分区)是真正保存消息的地方,咱们发送的消息都被放在了这里。而咱们的 Partition(分区) 又存在于 Topic(主题) 这个概念中,而且咱们能够给特定 Topic 指定多个 Partition。
每次添加消息到 Partition(分区) 的时候都会采用尾加法,如上图所示。Kafka 只能为咱们保证 Partition(分区) 中的消息有序,而不能保证 Topic(主题) 中的 Partition(分区) 的有序。
消息在被追加到 Partition(分区)的时候都会分配一个特定的偏移量(offset)。Kafka 经过偏移量(offset)来保证消息在分区内的顺序性。
因此,咱们就有一种很简单的保证消息消费顺序的方法:1 个 Topic 只对应一个 Partition。这样固然能够解决问题,可是破坏了 Kafka 的设计初衷。
Kafka 中发送 1 条消息的时候,能够指定 topic, partition, key,data(数据) 4 个参数。若是你发送消息的时候指定了 Partition 的话,全部消息都会被发送到指定的 Partition。而且,同一个 key 的消息能够保证只发送到同一个 partition,这个咱们能够采用表/对象的 id 来做为 key 。
总结一下,对于如何保证 Kafka 中消息消费的顺序,有了下面两种方法:
固然不只仅只有上面两种方法,上面两种方法是我以为比较好理解的,
做者的其余开源项目推荐: