@

前言:为什么需要Kafka

举个例子:麦当劳点餐时,当我们选择外带的时候,餐厅制作好餐之后会放在一个取餐台,而且取餐台是按照不同的取餐码尾号分开放置的,按照餐品的产出顺序进行放置的。这时候我们可以在我们空闲的时候去取餐,而餐厅也不用等待我们拿完餐再生产。而这个取餐台就像一个消息队列。我们现在想想如果没有这个取餐台会发生什么?餐厅不断需要顾客及时取走,不然会严重影响到餐厅的出餐和订单处理。那消费者也要关注取餐的信息,自己的时间安排自由度就下降了。so,取餐台这个中间缓冲的对象就可以接触消费者和餐厅的强绑定关系,让餐厅和消费者都可以自由化做各自的事情。

Kafka所扮演的角色就是类似当前取餐台的功能,当然起作用不仅仅是缓冲,在接下来的内容中一起揭开kafka的面纱,一窥其工作机理和设计思想。

1.初识kafka

我们先来看看Kafka是怎么定义的?

kafka是一个分布式的基于发布/订阅模式的消息队列。

那啥是消息队列啊。如我们开篇讲到的那个取餐台就是一个消息队列。就是在消息传输过程中保存消息的容器。其本质就是:

消息发送者(我们称之为生产者,多形象)——>MQ(message queue消息队列,消息保存的容器)——>消息接受者(消息的消费者)

消息队列就是可以接受生产者发送的消息并保存起来,队列Queue,按照消息接受的顺序存储,然后等待消费者进行消费消息。消息队列的作用就是保存消息并转发消息。

1.1 消息队列的好处:

1)解耦

允许我们独立的扩展或修改两边的处理过程,只要确保它们遵守同样的接口约束。

2)可恢复性

系统的一部分组件失效时,不会影响到整个系统。消息队列降低了进程间的耦合度,所以即使一个处理消息的进程挂掉,加入队列中的消息仍然可以在系统恢复后被处理。

3)缓冲

有助于控制和优化数据流经过系统的速度,解决生产消息和消费消息的处理速度不一致的情况。

4)灵活性 & 峰值处理能力 (削峰)

在访问量剧增的情况下,应用仍然需要继续发挥作用,但是这样的突发流量并不常见。如果为以能处理这类峰值访问为标准来投入资源随时待命无疑是巨大的浪费。使用消息队列能够使关键组件顶住突发的访问压力,而不会因为突发的超负荷的请求而完全崩溃。比如:618,双十一等活动,00:00 大量的手速点击访问,如果没有消息队列作为缓冲,所有请求都打到Redis,mysql等服务器,他们也扛不住啊。

5)异步通信

很多时候,用户不想也不需要立即处理消息。消息队列提供了异步处理机制,允许用户把一个消息放入队列,但并不立即处理它。想向队列中放入多少消息就放多少,然后在需要的时候再去处理它们。

1.2 消息队列的两种模式

(1)点对点模式(一对一,消费者主动拉取数据,消息收到后消息清除)

消息生产者生产消息发送到Queue中,然后消息消费者从Queue中取出并且消费消息。

消息被消费以后,queue中不再有存储,所以消息消费者不可能消费到已经被消费的消息。Queue支持存在多个消费者,但是对一个消息而言,只会有一个消费者可以消费。

女朋友看了也懂的Kafka(上篇)-LMLPHP

2)发布/订阅模式(一对多,消费者消费数据之后不会清除消息)

消息生产者(发布)将消息发布到topic中,同时有多个消息消费者(订阅)消费该消息。和点对点方式不同,发布到topic的消息会被所有订阅者消费。

女朋友看了也懂的Kafka(上篇)-LMLPHP

我们看看传统的MQ有什么问题?

没有消息队列我们怎么做?

假设现在我们的应用程序需要往别处发送监控信息,可以直接在应用程序和另一个可以在仪表盘上显示度量指标的应用程序之间建立连接 然后通过这个连接推送度量指标,

我们可以这样做:

女朋友看了也懂的Kafka(上篇)-LMLPHP

这是刚接触监控系统时简单问题的应对方案。过了不久,你需要分析更长时间片段的度量指标,而此时的仪表盘程序满足不了需求,于是,你启动了一个新的服务来接收度盘指标。该服务把度量指标保存起来,然后进行分析。与此同时,你修改了原来的应用程序, 把度量指标同时发送到两个仪表盘系统上。

现在,你又多了3个可以生成度量指标 应用 程序,它们都与这两个服务直接相连。而你的同事认为最好可以对这些服务进行轮询以便 获得告警功能,于是你为每一个应用程序增加了一个服务器,用于提供度量指标。再过一阵子,有更多的应用程序出于各自的目的,都从这些服务器获取度主指标。这时的架构看起来就像下图所示一样,节点间的连接一团糟。

女朋友看了也懂的Kafka(上篇)-LMLPHP

传统MQ怎么做?

我们创建一个基于发布订阅的消息队列, 用于接收来自其他应用程序的度量指标,井为其他系统提供了一个查询服务器。

女朋友看了也懂的Kafka(上篇)-LMLPHP

这时候一切都看起来这么清爽和简单,但是当我们和度量指标进行了一轮“艰苦奋战”之后,其他同事也要和各自的任务进行battle。另一个同事也正在跟日志消息奋战。还有另一个同事正在跟踪网站用户的行为,为负责机器学习开发的同事提供信息 ,同时为管理团队生成报告。你和同事们使用相同的方式创建这些系统,解辑信息的发布者和订阅者。然后发现世界好像又不美好了?看图:

女朋友看了也懂的Kafka(上篇)-LMLPHP

由于不同的业务任务,我们产生了多个消息队列进行各自业务的处理,但是这里有很多重复的地方。而且由于不同的业务模块,开发人员需要为各自的业务指标任务维护一套内容,而且之后或许还有其他的业务需要构建新的消息队列进行处理,资源浪费且每天维护这些内容,出现BUG的排查等等都会带来极大的不便性。但是又因为传统消息队列中的一个消息只能被消费一次,这时候我们就想,如果消息队列可以对于不同的业务的消费者看做不同的消费者,他们都可以消费消息队列中的消息就可以共用这些消息系统了。岂不是美滋滋,即便是后边需要增加业务,也不用独立的使用新的消息队列,世界又变得美好万分。

这时候,Kafka就”闪亮登场“了

Kafka的数据按照一定的顺序持久化保存,可以按需读取,通过对于不同的群组的消费者重新数据的消费状态实现多消费者共同消费消息等。具体的数据一致性保证以及生产者消费者写入和读取数据是怎么进行的,在后边的内容会与展开讲述。

2. Kafka基本架构

2.1 前备知识

1.消息和批次

Kafka 的数据单元被称为消息。消息由字节数组组成,所以对于Kafka来说,消息里的数据没有特别的格式或含义。消息可以有一个可选的元数据,也就是键。键也是一个字节数组,与消息一样,对于Kafka来说也没有特殊的含义。消息以一种可控的方式写入不同的分区时,会用到键。最简单的例子就是为键生成一个一致性散列值,然后使用散列值对主题分区数进行取模,为消息选取分区。

\[patitionnum = mod(hash(key) , partitions)\]

这样可以保证具有相同键的消息总是被写到相同的分区上。为了提高效率,消息被分批次写入 Kafka 。批次就是一组消息,这些消息属于同一个主题和分区。如果每 个消息都单独在网络传输,会导致大量的网络开销,把消息分成批次传输可以减少网络开销。不过,这要在时间延迟和吞吐量之间作出权衡:批次越大,单位时间内处理的消息就越多,单个消息的传输时间就越长。批次数据会被压缩,这样可以提升数据的传输和存储能力,但要做更多的计算处理。

2.消息模式

对于Kafka而言,消息的底层是一组字节数组,是我们难以辨识的内容。为了更好的理解这些消息,就有开发者提出用额外的一种结构来定义消息内容。比如常见的JSON和XML。这些结构不仅易用,且可读性好。Kafka一般采用Avro。Avro提供了一种紧凑的序列化格式,其模式和消息体是分开的。另外Avro也是由Doug Cutting创建的哦。因为Avro的一些特性,很适合Kafka这样的消息队列。消除了消息读写操作之间的耦合性。

如果读写操作紧密地耦合在一起,消息订阅者需要升级应用程序才能同时处理新旧两种数据格式。在消息订阅者升级了之后,消息发布者才能跟着升级,以便使用新的数据格式。新的 应用程序如果需要使用数据,就要与消息发布者发生耦合,导致开发者需要做很多繁杂操作。

女朋友看了也懂的Kafka(上篇)-LMLPHP

在对于当前架构进行拆分看待前,我们先来关注一些Kafka独到的机制和单元:
图片引用来自知乎老刘

2.2 架构分析

1)Producer :消息生产者,就是向kafka broker发消息的客户端

2)Consumer :消息消费者,向kafka broker取消息的客户端

3)Consumer Group (CG):消费者组,由多个consumer组成。消费者组内每个消费者负责消费不同分区的数据,一个分区只能由一个组内消费者消费;消费者组之间互不影响。所有的消费者都属于某个消费者组,即消费者组是逻辑上的一个订阅者。

**4)Broker **:一台kafka服务器就是一个broker。一个集群由多个broker组成。一个broker可以容纳多个topic。

5)Topic :可以理解为一个队列,生产者和消费者面向的都是一个topic

6)Partition:为了实现扩展性,一个非常大的topic可以分布到多个broker(即服务器)上,一个topic可以分为多个partition,每个partition是一个有序的队列;

7)Replica:副本,为保证集群中的某个节点发生故障时,该节点上的partition数据不丢失,且kafka仍然能够继续工作,kafka提供了副本机制,一个topic的每个分区都有若干个副本,一个leader和若干个follower

8)leader:每个分区多个副本的“主”,生产者发送数据的对象,以及消费者消费数据的对象都是leader。

9)follower:每个分区多个副本中的“从”,实时从leader中同步数据,保持和leader数据的同步。leader发生故障时,某个follower会成为新的leader。

2.3Kafka 特点

1.多个生产者

Kafka 可以无缝地支持多个生产者,不管客户端在使用单个主题还是多个主题。所以它很适合用来从多个前端系统收集数据,并以统 的格式对外提供数据。

2.多个消费者

Kafka 也支持多个消费者从一个单独的消息流上读取数据,而且消费者之间互不影响。这与其他队列系统不同,其他队列系统的消息一旦被一个客户端读 取,其他客户端就无法再读取它。另外,多个消费者可以组成一个群组,它们共享一个消息流,并保证整个群组对每个给定的消息只处理一次。

3.基于磁盘的数据存储

Kafka 的数据 保留特性。消息被提交到磁盘,根据设置的保留规则进行保存。每个主题可以设置单独的保留规则,以便满足不同消费者的需求,各个主题可以保留不同数量的消息。消费者可能会因为处理速度慢或突发的流量高峰导致无陆及时读取消息,而持久化数据可以保证数据 不会丢失。消费者可以在进行应用程序维护时离线一小段时间,而无需担心消息丢失或堵塞在生产者端。消费者可以被关闭,但消息会继续保留在 Kafka 里。消费者可以从上次中 断的地方继续处理消息。

4.伸缩性

为了能够轻松处理大量数据, Kafka 一开始就被设计成一个具有灵活伸缩性的系统。用户在开发阶段可以先使用单个 broker ,再扩展到包含3个 broker 的小型开发集群,然后随着数据量不断增长,部署到生产环境的集群可能包含上百个 broker 。对在线集群进行扩展丝毫不影响整体系统的可用性。也就是说,一个包含多个 broker 的集群,即使个别Broker失效,仍然可以持续地为客户提供服务。

5.高性能

前面提到的所有特性,让 Kafka 成为了一个高性能的发布与订阅消息系统。通过横向扩展生产者、消费者和 broker, Kafka 可以轻松处理巨大的消息流。在处理大量数据的同时, 它还能保证亚秒级的消息延迟。

3 总结

我们通过麦当劳的例子开始进入消息队列,并从点对点业务到发布订阅的消息队列以及他们存在的弊端引入Kafka。我们知道了Kafka是一个流平台,将数据看做是持续变化和不断增长的流,可以通过发布和订阅数据流,并把他们保存起来进行处理的数据系统。我们称之为数据系统是因为kafka有别于消息系统的分布式部署方式,可以自由伸缩、处理企业内所有的应用程序。kafka不仅仅是传递消息,其还可以数据的可复制、持久化,其保留时长由我们来进行设置。

也了解了Kafka的基础架构,Kafka的组成以及自个的作用和简单做了什么事情。对于Kafka大致有一个比较简单的了解,在下篇内容中我们将走入Kafka内部到底是做了什么。以及生产者消费者如何写入和消费数据的,如何在写入和消费的时候保证的数据一致性。解决节点失效以及内部的选举机制。

我们要仰望星空,亦需脚踏实地。怕什么真理无穷,进一寸有一寸的欢喜。我是清风,希望这篇文章对你有帮助。如有不准确之处,还请评论区留言讨论。

06-06 17:50