Kafka概述及基础架构

目录

一、kafka定义:

二、两种消息队列

1、消息队列概述

2、异步处理(即使用消息队列)的优点

2、点对点消息系统

3、发布/订阅消息系统

三、kafka基础架构

1、kafka架构:

2、整体数据流程:

①数据生产过程

②数据消费过程(Consume)


一、kafka定义:

Kafka 是一个分布式的基于发布/订阅模式消息队列Message Queue,简称MQ),主要应用于大数据实时处理领域。

这里有几个关键字,我们抓一下:

①、分布式的:说明kafka的使用要依赖于集群,这也说明kafka这个消息队列是可拓展的,即当数据量过大,kafka过载时,可以通过增加集群机器来提升kafka的性能。

②、发布/订阅模式:这个我后面会介绍,消息队列分为点对点消息系统和发布/订阅消息系统

③、消息队列:说明kafka是一个消息队列,负责的功能是将数据从一个应用程序传输到另一个应用程序,使得应用程序可以专注于数据,但不担心如何共享它。大多数消息模式或者说消息队列遵循 pub-sub 即发布/订阅消息系统

二、两种消息队列

1、消息队列概述

①消息队列的应用场景

我们之前说过消息队列的作用是将数据从一个应用程序传输到另一个应用程序

那么传输消息就可以分为同步处理与异步处理

我们举一个简单的例子:同步处理就相当于你去剃头,你必须等到你剃完头才算完成一次通信,即一次通信就相当于一个事务,你必须完成这个事务才能处理另一个事务,就导致发消息的这方,即剃头的这方需要等待很久,且服务器容易崩溃。

异步处理(即消息队列)就相当于你去修手表,直接将手表给中介公司(及消息队列)然后对方告诉你什么时候来取,这样可以减少界面响应时间。就可以有效的避免服务器崩溃,即当一次性消息过多时,可以将这些消息放入消息队列中,等服务器空闲时再去处理他们

2、异步处理(即使用消息队列)的优点

1)解耦

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

2)可恢复性

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

3)缓冲

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

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

在访问量剧增的情况下,应用仍然需要继续发挥作用,但是这样的突发流量并不常见。如果为以能处理这类峰值访问为标准来投入资源随时待命无疑是巨大的浪费。使用消息队列能够使关键组件顶住突发的访问压力,而不会因为突发的超负荷的请求而完全崩溃。

5)异步通信

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

2、点对点消息系统

消息生产者生产消息发送到Queue中,然后消息消费者从Queue中取出并且消费消息。消息被消费以后,queue 中不再有存储,所以消息消费者不可能消费到已经被消费的消息。Queue 支持存在多个消费者,但是对一个消息而言,只会有一个消费者可以消费。这就导致消息不可复用,若有多个消费者需要用到这个消息,那么消息队列就得传n次这个消息。在一些只能消费一次的消息系统中适用,如滴滴的打车模式,一个订单只能由一个司机接收。

3、发布/订阅消息系统

消息生产者(发布)将消息发布到 topic 中,同时有多个消息消费者(订阅)消费该消息。和点对点方式不同,发布到 topic 的消息可以被所有订阅者消费,kafka就是基于这种模式的。

此时又产生问题了,这个消息既可以是队列主动推给消费者(因为它订阅了这个消息)也可以是消费者主动拉取消息(kafka就是这个工作原理)

我们来分析一下这两种模式的优劣:

①队列主动推送消息:

优点:有消息来就可以直接推送给消费者,无需消费者询问

缺点:消费者消费速度不同,可能推送速度恒为50M/s但有些消费者消费速度为10M/s有些为100M/s,就会导致一些消费者消息过载导致崩溃,一些消费者却有资源剩余

②消费者主动拉取数据:

优点:解决了推送数据的缺点

缺点:需要定时去询问消息队列是否有新消息产生

三、kafka基础架构

可能通过以上的描述并不是能让你很清楚的知道kafka到底是干嘛的,我们现在从kafka的底层来分析一下kafka的工作原理

1、kafka架构:

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

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

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

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

5Topic 可以理解为一个队列,生产者和消费者面向的都是一个 topic一个 topic 里保存的是同一类消息,相当于对消息的分类,每个 producer 将消息发送到 kafka 中,都需要指明要存的 topic 是哪个,也就是指明这个消息属于哪一类 

6Partition为了实现扩展性,一个非常大的 topic 可以分布到多个 broker(即服务器)上,一个 topic 可以分为多个 partition(分区),每个 partition 是一个有序的队列,每个 partition 在存储层面是 append log 文件。任何发布到此 partition 的消息都会被直接追加到 log 文件的尾部。为什么要进行分区呢?最根本的原因就是:kafka基于文件进行存储,当文件内容大到一定程度时,很容易达到单个磁盘的上限,因此,采用分区的办法,一个分区对应一个文件,这样就可以将数据分别存储到不同的server上去,另外这样做也可以负载均衡,容纳更多的消费者。 

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

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

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

10)Offset(偏移量):一个分区对应一个磁盘上的文件,而消息在文件中的位置就称为 offset(偏移量),offset 为一个 long 型数字,它可以唯一标记一条消息。由于kafka 并没有提供其他额外的索引机制来存储 offset,文件只能顺序的读写,所以在kafka中几乎不允许对消息进行“随机读写”。

2、整体数据流程:

①数据生产过程

对于生产者要写入的一条记录,可以指定四个参数:分别是 topic、partition、key 和 value,其中 topic(要写入的队列) 和 value(要写入的数据)是必须要指定的,而 key 和 partition 是可选的。

对于一条记录,先对其进行序列化,然后按照 Topic 和 Partition,放进对应的发送队列中。如果 Partition 没填,那么情况会是这样的:

        a、Key 有填。按照 Key 进行哈希,相同 Key 去一个 Partition。

        b、Key 没填。Round-Robin 来选 Partition。

producer 将会和Topic下所有 partition leader 保持 socket 连接,消息由 producer 直接通过 socket 发送到 broker。其中 partition leader 的位置( host : port )注册在 zookeeper 中,producer 作为 zookeeper client,已经注册了 watch 用来监听 partition leader 的变更事件,因此,可以准确的知道谁是当前的 leader。

  producer 端采用异步发送:将多条消息暂且在客户端 buffer 起来,并将他们批量的发送到 broker,小数据 IO 太多,会拖慢整体的网络延迟,批量延迟发送事实上提升了网络效率。

②数据消费过程(Consume)

对于消费者,不是以单独的形式存在的,每一个消费者属于一个 consumer group,一个 group 包含多个 consumer。特别需要注意的是:订阅 Topic 是以一个消费组来订阅的,发送到 Topic 的消息,只会被订阅此 Topic 的每个 group 中的一个 consumer 消费

如果所有的 Consumer 都具有相同的 group,那么就像是一个点对点的消息系统;如果每个 consumer 都具有不同的 group,那么消息会广播给所有的消费者。

具体说来,这实际上是根据 partition 来分的,一个 Partition,只能被消费组里的一个消费者消费,但是可以同时被多个消费组消费,消费组里的每个消费者是关联到一个 partition 的,因此有这样的说法:对于一个 topic,同一个 group 中不能有多于 partitions 个数的 consumer 同时消费,否则将意味着某些 consumer 将无法得到消息。

同一个消费组的两个消费者不会同时消费一个 partition。

在 kafka 中,采用了 pull 方式,即 consumer 在和 broker 建立连接之后,主动去 pull(或者说 fetch )消息,首先 consumer 端可以根据自己的消费能力适时的去 fetch 消息并处理,且可以控制消息消费的进度(offset)。

  partition 中的消息只有一个 consumer 在消费,且不存在消息状态的控制,也没有复杂的消息确认机制,可见 kafka broker 端是相当轻量级的。当消息被 consumer 接收之后,需要保存 Offset 记录消费到哪,以前保存在 ZK 中,由于 ZK 的写性能不好,以前的解决方法都是 Consumer 每隔一分钟上报一次,在 0.10 版本后,Kafka 把这个 Offset 的保存,从 ZK 中剥离,保存在一个名叫 consumeroffsets topic 的 Topic 中,由此可见,consumer 客户端也很轻量级。