全网最通俗易懂的Kafka入门

前言

只有光头才能变强。

文本已收录至我的GitHub仓库,欢迎Star:https://github.com/ZhongFuCheng3y/3y

众所周知,消息队列的产品有好几种,这里我选择学习Kafka的原因,无他,公司在用。

我司使用的是Kafka和自研的消息队列(Kafka和RocketMQ)改版,于是我就想学学Kafka这款消息队列啦。本篇文章对Kafka入门,希望对大家有所帮助。

本文知识点提前预览:

这篇文章花了我很长时间画图,目的是希望以最通俗易懂的方式带大家入门,如果觉得不错,希望能给我点个赞

一、什么是Kafka?

首先我们得去官网看看是怎么介绍Kafka的:

  • https://kafka.apache.org/intro

在收集资料学习的时候,已经发现有不少的前辈对官网的介绍进行翻译和总结了,所以我这里就不重复了,贴下地址大家自行去学习啦:

  • https://scala.cool/2018/03/learning-kafka-1/
  • https://colobu.com/2014/08/06/kafka-quickstart/

我之前写过的消息队列入门文章也提到了,要做一个消息队列可能要考虑到以下的问题:

  • 使用消息队列不可能是单机的(必然是分布式or集群)
  • 数据写到消息队列,可能会存在数据丢失问题,数据在消息队列需要持久化(磁盘?数据库?Redis?分布式文件系统?)
  • 想要保证消息(数据)是有序的,怎么做?
  • 为什么在消息队列中重复消费了数据

下面我以Kafka为例对这些问题进行简单的解答,进而入门Kafka。

1.1 Kafka入门

众所周知,Kafka是一个消息队列,把消息放到队列里边的叫生产者,从队列里边消费的叫消费者

一个消息中间件,队列不单单只有一个,我们往往会有多个队列,而我们生产者和消费者就得知道:把数据丢给哪个队列,从哪个队列消息。我们需要给队列取名字,叫做topic(相当于数据库里边的概念)

现在我们给队列取了名字以后,生产者就知道往哪个队列丢数据了,消费者也知道往哪个队列拿数据了。我们可以有多个生产者往同一个队列(topic)丢数据,多个消费者往同一个队列(topic)拿数据

为了提高一个队列(topic)的吞吐量,Kafka会把topic进行分区(Partition)

所以,生产者实际上是往一个topic名为Java3y中的分区(Partition)丢数据,消费者实际上是往一个topic名为Java3y的分区(Partition)取数据

一台Kafka服务器叫做Broker,Kafka集群就是多台Kafka服务器:

一个topic会分为多个partition,实际上partition会分布在不同的broker中,举个例子:

由此得知:Kafka是天然分布式的

如果不了解分布式/集群,以及基本的分布式概念的同学,可以关注我的GitHub:https://github.com/ZhongFuCheng3y/3y

现在我们已经知道了往topic里边丢数据,实际上这些数据会分到不同的partition上,这些partition存在不同的broker上。分布式肯定会带来问题:“万一其中一台broker(Kafka服务器)出现网络抖动或者挂了,怎么办?”

Kafka是这样做的:我们数据存在不同的partition上,那kafka就把这些partition做备份。比如,现在我们有三个partition,分别存在三台broker上。每个partition都会备份,这些备份散落在不同的broker上。

红色块的partition代表的是分区,紫色的partition块代表的是备份分区。生产者往topic丢数据,是与分区交互,消费者消费topic的数据,也是与主分区交互。

备份分区仅仅用作于备份,不做读写。如果某个Broker挂了,那就会选举出其他Broker的partition来作为主分区,这就实现了高可用

另外值得一提的是:当生产者把数据丢进topic时,我们知道是写在partition上的,那partition是怎么将其持久化的呢?(不持久化如果Broker中途挂了,那肯定会丢数据嘛)。

Kafka是将partition的数据写在磁盘的(消息日志),不过Kafka只允许追加写入(顺序访问),避免缓慢的随机 I/O 操作。

  • Kafka也不是partition一有数据就立马将数据写到磁盘上,它会先缓存一部分,等到足够多数据量或等待一定的时间再批量写入(flush)。

上面balabala地都是讲生产者把数据丢进topic是怎么样的,下面来讲讲消费者是怎么消费的。既然数据是保存在partition中的,那么消费者实际上也是从partition中取数据。

生产者可以有多个,消费者也可以有多个。像上面图的情况,是一个消费者消费三个分区的数据。多个消费者可以组成一个消费者组

本来是一个消费者消费三个分区的,现在我们有消费者组,就可以每个消费者去消费一个分区(也是为了提高吞吐量)

按图上所示的情况,这里想要说明的是:

  • 如果消费者组中的某个消费者挂了,那么其中一个消费者可能就要消费两个partition了
  • 如果只有三个partition,而消费者组有4个消费者,那么一个消费者会空闲
  • 如果多加入一个消费者组,无论是新增的消费者组还是原本的消费者组,都能消费topic的全部数据。(消费者组之间从逻辑上它们是独立的)

前面讲解到了生产者往topic里丢数据是存在partition上的,而partition持久化到磁盘是IO顺序访问的,并且是先写缓存,隔一段时间或者数据量足够大的时候才批量写入磁盘的。

消费者在读的时候也很有讲究:正常的读磁盘数据是需要将内核态数据拷贝到用户态的,而Kafka 通过调用sendfile()直接从内核空间(DMA的)到内核空间(Socket的),少做了一步拷贝的操作。

有的同学可能会产生疑问:消费者是怎么知道自己消费到哪里的呀?Kafka不是支持回溯吗?那是怎么做的呀?

  • 比如上面也提到:如果一个消费者组中的某个消费者挂了,那挂掉的消费者所消费的分区可能就由存活的消费者消费。那存活的消费者是需要知道挂掉的消费者消费到哪了,不然怎么玩。

这里要引出offset了,Kafka就是用offset来表示消费者的消费进度到哪了,每个消费者会都有自己的offset。说白了offset就是表示消费者的消费进度

在以前版本的Kafka,这个offset是由Zookeeper来管理的,后来Kafka开发者认为Zookeeper不合适大量的删改操作,于是把offset在broker以内部topic(__consumer_offsets)的方式来保存起来。

每次消费者消费的时候,都会提交这个offset,Kafka可以让你选择是自动提交还是手动提交。

既然提到了Zookeeper,那就多说一句。Zookeeper虽然在新版的Kafka中没有用作于保存客户端的offset,但是Zookeeper是Kafka一个重要的依赖。

  • 探测broker和consumer的添加或移除。
  • 负责维护所有partition的领导者/从属者关系(主分区和备份分区),如果主分区挂了,需要选举出备份分区作为主分区。
  • 维护topic、partition等元配置信息
  • ….

最后

通过这篇文章,文章开头那几个问题估计多多少少都懂一些啦。我来简要回答一下:

使用消息队列不可能是单机的(必然是分布式or集群)

Kafka天然是分布式的,往一个topic丢数据,实际上就是往多个broker的partition存储数据

数据写到消息队列,可能会存在数据丢失问题,数据在消息队列需要持久化(磁盘?数据库?Redis?分布式文件系统?)

Kafka会将partition以消息日志的方式(落磁盘)存储起来,通过 顺序访问IO和缓存(等到一定的量或时间)才真正把数据写到磁盘上,来提高速度。

想要保证消息(数据)是有序的,怎么做?

Kafka会将数据写到partition,单个partition的写入是有顺序的。如果要保证全局有序,那只能写入一个partition中。如果要消费也有序,消费者也只能有一个。

为什么在消息队列中重复消费了数据

凡是分布式就无法避免网络抖动/机器宕机等问题的发生,很有可能消费者A读取了数据,还没来得及消费,就挂掉了。Zookeeper发现消费者A挂了,让消费者B去消费原本消费者A的分区,等消费者A重连的时候,发现已经重复消费同一条数据了。(各种各样的情况,消费者超时等等都有可能…)

如果业务上不允许重复消费的问题,最好消费者那端做业务上的校验(如果已经消费过了,就不消费了)


这篇文章主要是Kafka入门,Kafka还涉及到别的概念,以及还有别的东西。在我感觉中,很多的面试题都跟配置有关,所以在解决某些问题的时候,先看看能不能通过现有配置解决掉(学多了框架,你就会发现很多官方的就已经支持解决了,你做的可能改改配置/参数就完事了)。

Image placeholder
sunniness
未设置
  56人点赞

没有讨论,发表一下自己的看法吧

推荐文章
可能是全网最好的MySQL重要知识点

什么是MySQL?MySQL是一种关系型数据库,在Java企业级开发中非常常用,因为MySQL是开源免费的,并且方便扩展。阿里巴巴数据库系统也大量用到了MySQL,因此它的稳定性是有保障的。MySQL

面试题总结:可能是全网最好的MySQL重要知识点

作者:Snailclimb 整理编辑:SegmentFault本文原载于SegmentFault专栏JavaGuide,如侵删。标题有点标题党的意思,但希望你在看了文章之后不会有这个想法——这篇文章是

Linux中的Kdump服务

我们知道在Linux中系统分为内核态和用户态,一般用户行为都发生在用户态,内核自我管理。但如果内核出现错误崩溃了,可以使用Kdump来分析错误原因。Kdump服务提供了内核的崩溃转储机制,可以在内核崩

终于有篇看的懂的 B 树文章了!

索引,相信大多数人已经相当熟悉了,很多人都知道MySQL的索引主要以B+树为主,但是要问到为什么用B+树,恐怕很少有人能把前因后果讲述完整。本文就来从头到尾介绍下数据库的索引。索引是一种数据结构,用于

宝宝也能看懂的 leetcode 周赛 - 169 - 2

1305.AllElementsinTwoBinarySearchTreesHi大家好,我是张小猪。欢迎来到『宝宝也能看懂』系列之leetcode题解。这里是第169期的第2题,也是题目列表中的第13

宝宝也能看懂的 leetcode 周赛 - 169 - 1

1304.FindNUniqueIntegersSumuptoZeroHi大家好,我是张小猪。欢迎来到『宝宝也能看懂』系列之leetcode题解。这里是第169期的第1题,也是题目列表中的第1304题

宝宝也能看懂的 leetcode 周赛 - 169 - 3

1306.JumpGameIIIHi大家好,我是张小猪。欢迎来到『宝宝也能看懂』系列之leetcode题解。这里是第169期的第3题,也是题目列表中的第1306题--『JumpGameIII』题目描述

宝宝也能看懂的 leetcode 周赛 - 169 - 4

1307.VerbalArithmeticPuzzleHi大家好,我是张小猪。欢迎来到『宝宝也能看懂』系列之leetcode题解。这里是第169期的第4题,也是题目列表中的第1307题--『Verba

如何基于 Kafka 构建一个关系型数据库

在这篇文章里,我将分享如何通过扩展KCache(https://github.com/rayokota/kcache)来实现一个全功能的关系型数据库,我把这个数据库叫作KarelDB(https://

Spring Cloud Stream整合Kafka

引入依赖 org.springframework.cloud spring-cloud-stream-binder-kafka 或 org.springframework.cloud spr

Kafka 优秀的架构设计!它的高性能是如何保证的?

应大部分的小伙伴的要求,今天这篇咱们用大白话带你认识Kafka。Kafka 基础消息系统的作用大部分小伙伴应该都清楚,这里用机油装箱举个例子:所以消息系统就是如上图我们所说的仓库,能在中间过程作为缓存

迟来的干货 | Kafka权限管理实战

今年有很多小伙伴在公众号或者微信留言问能不能整一篇有关Kafka权限管理的文章,迫于工作关系,这个需求一直拖后。后来知道我的好友兼Kafka高玩——【一岁小宝】他一直在弄这一块的东西,所以我就厚着fa

Knative 实战:基于 Kafka 实现消息推送

导读:当前在Knative中已经提供了对Kafka事件源的支持,那么如何基于Kafka实现消息推送呢?本文作者将以阿里云Kafka产品为例,给大家解锁这一新的姿势。作者| 元毅 阿里云智能事业群高级开

Kafka 如何优化内存缓冲机制造成的频繁 GC 问题?

目录1、Kafka的客户端缓冲机制2、内存缓冲造成的频繁GC问题3、Kafka设计者实现的缓冲池机制4、总结一下“ 这篇文章,给大家聊一个硬核的技术知识,我们通过Kafka内核源码中的一些设计思想,来

Kafka 集群在马蜂窝大数据平台的优化与应用扩展

马蜂窝技术原创文章,更多干货请订阅公众号:mfwtechKafka是当下热门的消息队列中间件,它可以实时地处理海量数据,具备高吞吐、低延时等特性及可靠的消息异步传递机制,可以很好地解决不同系统间数据的

通过一个示例了解kafka connect连接器

什么是kafka连接器connect在实际工作中使用kafka,有时候会有类似这样的场景。我们需要把某些数据源的数据导入到kafka,或者把kafka作为数据源导出数据。或者两种场景的需求都要。这算是

分布式场景下Kafka消息顺序性的思考

在业务中使用kafka发送消息异步消费的场景,并且需要实现在消费时实现顺序消费,利用kafka在partition内消息有序的特点,实现消息消费时的有序性。1、在发送消息时,通过指定partition

iOS开发60分钟入门

===============本文面向已有其它语言(如Java,C,PHP,Javascript)编程经验的iOS开发初学者,初衷在于让我的同事一小时内了解如何开始开发iOSApp,学习目标包括: 能

Shell脚本编程30分钟入门

什么是Shell脚本 示例 看个例子吧: #!/bin/sh cd~ mkdirshell_tut cdshell_tut for((i=0;ibash 但在MacOS上不是,/bin/sh和/

从零开始入门 K8s:应用编排与管理

一、需求来源 背景问题 首先来看一下背景问题。如下图所示:如果我们直接管理集群中所有的Pod,应用A、B、C的Pod,其实是散乱地分布在集群中。 现在有以下的问题: 首先,如何保证集群内可用Pod的

Python入门教程_1. 开胃菜

如果你在计算机上做大量的工作,最终你会发现你想要可以自动完成一些任务。例如,你可能希望对大量文本文件执行搜索和替换,或者以复杂的方式重命名和重新排列一堆照片文件。又或许你想编写一个小型自定义数据库,或

Python入门教程_2. 使用 Python 解释器

2.1.调用解释器 Python解释器通常安装在目标机器上的/usr/local/bin/python3.7目录下;把/usr/local/bin目录放进你的Unixshell的搜索路径里,确保它可以

Python入门教程_3. Python 简介

在下面的例子中,输入和输出分别由大于号和句号提示符(>>>和...)标注:如果想重现这些例子,就要在解释器的提示符后,输入(提示符后面的)那些不包含提示符的代码行。需要注意的是在练习中遇到的从属提示符

Python入门教程_4. 深入 Python 流程控制

除了刚刚介绍的while语句,Python还有一些在其他语言中常见的控制流语句,并做了一些改动。 4.1.if语句 也许最著名的语句是if语句了。 例如: >>>x=int(input("Please

Python入门教程_5. 数据结构

这个章节将更详细地描述一些你已经了解的内容,并且添加了一些新的内容。 5.1.深入列表对象 List数据类型包含更多的方法,下面是List对象包含的所有方法: list.append(*x*) 将一个