没想到简简单单几张图,就能把Kafka讲的如此透彻

今天咱们来聊聊 Kafka ,主要是带你从新认识一下 Kafka,聊一下 Kafka 中比较重要的概念和问题。在后面的文章中我会介绍:git

  1. Kafka 的一些高级特性好比工做流程。
  2. 使用 Docker 安装 Kafka 并简单使用其发送和消费消息。
  3. Spring Boot 程序如何使用 Kafka 做为消息队列。


咱们如今常常提到 Kafka 的时候就已经默认它是一个很是优秀的消息队列了,咱们也会常常拿它给 RocketMQ、RabbitMQ 对比。我以为 Kafka 相比其余消息队列主要的优点以下:数据库

  • 极致的性能 :基于 Scala 和 Java 语言开发,设计中大量使用了批量处理和异步的思想,最高能够每秒处理千万级别的消息。
  • 生态系统兼容性无可匹敌 :Kafka 与周边生态系统的兼容性是最好的没有之一,尤为在大数据和流计算领域。


实际上在早期的时候 Kafka 并非一个合格的消息队列,早期的 Kafka 在消息队列领域就像是一个衣衫褴褛的孩子同样,功能不完备而且有一些小问题好比丢失消息、不保证消息可靠性等等。固然,这也和 LinkedIn 最先开发 Kafka 用于处理海量的日志有很大关系,哈哈哈,人家原本最开始就不是为了做为消息队列滴,谁知道后面误打误撞在消息队列领域占据了一席之地。

随着后续的发展,这些短板都被 Kafka 逐步修复完善。因此,Kafka 做为消息队列不可靠这个说法已通过时!安全

初识 Kafka

先来看一下官网对其的介绍,应该是最权威和实时的了。是英文也没有关系,我已经将比较重要的信息都为你提取出来了。服务器


从官方介绍中咱们能够获得如下信息:

Kafka 是一个分布式流式处理平台。这究竟是什么意思呢?

流平台具备三个关键功能:架构

  • 消息队列:发布和订阅消息流,这个功能相似于消息队列,这也是 Kafka 也被归类为消息队列的缘由。
  • 容错的持久方式存储记录消息流:Kafka 会把消息持久化到磁盘,有效避免了消息丢失的风险·。
  • 流式处理平台: 在消息发布的时候进行处理,Kafka 提供了一个完整的流式处理类库。


Kafka 主要有两大应用场景:并发

  • 消息队列 :创建实时流数据管道,以可靠地在系统或应用程序之间获取数据。
  • 数据处理: 构建实时的流数据处理程序来转换或处理数据流。


关于 Kafka 几个很是重要的概念:负载均衡

  • Kafka 将记录流(流数据)存储在 topic 中。
  • 每一个记录由一个键、一个值、一个时间戳组成。

 

Kafka 消息模型

题外话:早期的 JMS 和 AMQP 属于消息服务领域权威组织所作的相关的标准,我在 JavaGuide的 《消息队列其实很简单》这篇文章中介绍过。可是,这些标准的进化跟不上消息队列的演进速度,这些标准实际上已经属于废弃状态。因此,可能存在的状况是:不一样的消息队列都有本身的一套消息模型。异步

队列模型:早期的消息模型


使用队列(Queue)做为消息通讯载体,知足生产者与消费者模式,一条消息只能被一个消费者使用,未被消费的消息在队列中保留直到被消费或超时。 好比:咱们生产者发送 100 条消息的话,两个消费者来消费通常状况下两个消费者会按照消息发送的顺序各自消费一半(也就是你一个我一个的消费。)

队列模型存在的问题:

假如咱们存在这样一种状况:咱们须要将生产者产生的消息分发给多个消费者,而且每一个消费者都能接收到完成的消息内容。

这种状况,队列模型就很差解决了。不少比较杠精的人就说:咱们能够为每一个消费者建立一个单独的队列,让生产者发送多份。这是一种很是愚蠢的作法,浪费资源不说,还违背了使用消息队列的目的。分布式

发布-订阅模型:Kafka 消息模型


发布-订阅模型主要是为了解决队列模型存在的问题。

发布订阅模型(Pub-Sub) 使用主题(Topic) 做为消息通讯载体,相似于广播模式;发布者发布一条消息,该消息经过主题传递给全部的订阅者,在一条消息广播以后才订阅的用户则是收不到该条消息的。

在发布 - 订阅模型中,若是只有一个订阅者,那它和队列模型就基本是同样的了。因此说,发布 - 订阅模型在功能层面上是能够兼容队列模型的。

Kafka 采用的就是发布 - 订阅模型。

RocketMQ 的消息模型和 Kafka 基本是彻底同样的。惟一的区别是 RocketMQ 中没有队列这个概念,与之对应的是 Partition(分区)。ide

Kafka 重要概念解读

Kafka 将生产者发布的消息发送到 Topic(主题) 中,须要这些消息的消费者能够订阅这些 Topic(主题),以下图所示:


Kafka Topic Partition

上面这张图也为咱们引出了,Kafka 比较重要的几个概念:

  • Producer(生产者):产生消息的一方。
  • Consumer(消费者):消费消息的一方。
  • Broker(代理):能够看做是一个独立的 Kafka 实例。多个 Kafka Broker 组成一个 Kafka Cluster。


同时,你必定也注意到每一个 Broker 中又包含了 Topic 以及 Partition 这两个重要的概念:

  • Topic(主题):Producer 将消息发送到特定的主题,Consumer 经过订阅特定的 Topic(主题) 来消费消息。
  • Partition(分区):Partition 属于 Topic 的一部分。一个 Topic 能够有多个 Partition ,而且同一 Topic 下的 Partition 能够分布在不一样的 Broker 上,这也就代表一个 Topic 能够横跨多个 Broker 。这正如我上面所画的图同样。


划重点:Kafka 中的 Partition(分区) 实际上能够对应成为消息队列中的队列。这样是否是更好理解一点?

另外,还有一点我以为比较重要的是 Kafka 为分区(Partition)引入了多副本(Replica)机制。分区(Partition)中的多个副本之间会有一个叫作 leader 的家伙,其余副本称为 follower。咱们发送的消息会被发送到 leader 副本,而后 follower 副本才能从 leader 副本中拉取消息进行同步。

生产者和消费者只与 leader 副本交互。你能够理解为其余副本只是 leader 副本的拷贝,它们的存在只是为了保证消息存储的安全性。当 leader 副本发生故障时会从 follower 中选举出一个 leader,可是 follower 中若是有和 leader 同步程度达不到要求的参加不了 leader 的竞选。

Kafka 的多分区(Partition)以及多副本(Replica)机制有什么好处呢?

  1. Kafka 经过给特定 Topic 指定多个 Partition, 而各个 Partition 能够分布在不一样的 Broker 上, 这样便能提供比较好的并发能力(负载均衡)。
  2. Partition 能够指定对应的 Replica 数, 这也极大地提升了消息存储的安全性, 提升了容灾能力,不过也相应的增长了所须要的存储空间。

 

ZooKeeper 在 Kafka 中的做用

要想搞懂 ZooKeeper 在 Kafka 中的做用 必定要本身搭建一个 Kafka 环境而后本身进 ZooKeeper 去看一下有哪些文件夹和 Kafka 有关,每一个节点又保存了什么信息。 必定不要光看不实践,这样学来的也终会忘记!

后面的文章中会介绍如何搭建 Kafka 环境,你且不要急,看了后续文章 3 分钟就能搭建一个 Kafka 环境。

这部份内容参考和借鉴了这篇文章:https://www.jianshu.com/p/a036405f989c 

下图就是个人本地 Zookeeper ,它成功和我本地的 Kafka 关联上(如下文件夹结构借助 idea 插件 ZooKeeper tool 实现)。


ZooKeeper 主要为 Kafka 提供元数据的管理的功能。

从图中咱们能够看出,Zookeeper 主要为 Kafka 作了下面这些事情:

  • Broker 注册 :在 Zookeeper 上会有一个专门用来进行 Broker 服务器列表记录的节点。每一个 Broker 在启动时,都会到 Zookeeper 上进行注册,即到/brokers/ids 下建立属于本身的节点。每一个 Broker 就会将本身的 IP 地址和端口等信息记录到该节点中去
  • Topic 注册 :在 Kafka 中,同一个Topic 的消息会被分红多个分区并将其分布在多个 Broker 上,这些分区信息及与 Broker 的对应关系也都是由 Zookeeper 在维护。好比我建立了一个名字为 my-topic 的主题而且它有两个分区,对应到 zookeeper 中会建立这些文件夹:/brokers/topics/my-topic/partitions/0、/brokers/topics/my-topic/partitions/1
  • 负载均衡 :上面也说过了 Kafka 经过给特定 Topic 指定多个 Partition, 而各个 Partition 能够分布在不一样的 Broker 上, 这样便能提供比较好的并发能力。对于同一个 Topic 的不一样 Partition,Kafka 会尽力将这些 Partition 分布到不一样的 Broker 服务器上。当生产者产生消息后也会尽可能投递到不一样 Broker 的 Partition 里面。当 Consumer 消费的时候,Zookeeper 能够根据当前的 Partition 数量以及 Consumer 数量来实现动态负载均衡。
  • ......

 

Kafka 如何保证消息的消费顺序?

咱们在使用消息队列的过程当中常常有业务场景须要严格保证消息的消费顺序,好比咱们同时发了 2 个消息,这 2 个消息对应的操做分别对应的数据库操做是:更改用户会员等级、根据会员等级计算订单价格。假如这两条消息的消费顺序不同形成的最终结果就会大相径庭。

咱们知道 Kafka 中 Partition(分区)是真正保存消息的地方,咱们发送的消息都被放在了这里。而咱们的 Partition(分区)又存在于 Topic(主题)这个概念中,而且咱们能够给特定 Topic 指定多个 Partition。


Kafka Topic Partitions Layout

每次添加消息到 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 中消息消费的顺序,有了下面两种方法:

  1. 1 个 Topic 只对应一个 Partition。
  2. (推荐)发送消息的时候指定 Key/Partition。


固然不只仅只有上面两种方法,上面两种方法是我以为比较好理解的,


最后给你们一套Kafka的学习资料。内容从最基础的架构直接讲到高级源码

目录

详细展现

消费者

深刻服务端

高级应用

Kafka与Spark的集成

相应的文章已经整理造成文档,git扫码获取资料看这里