当前位置: 首页 > 科技观察

入门!大白话带你认识卡夫卡!

时间:2023-03-13 03:26:03 科技观察

前言《疫情期间学了Kafka,虽然之前用过ActiveMQ和RabbitMQ,但对Kafka技术还是初学者,如果文章中有些表述有点完善或者不准确的地方请指出”今天我们来聊一聊Kafka,主要是带大家重新认识Kafka,聊一聊Kafka中比较重要的概念和问题。在后面的文章中我会介绍:Kafka的一些高级特性比如工作流。用Docker安装Kafka和简单的用它来发送和消费消息。SpringBoot程序是如何使用Kafka作为消息队列的。现在我们经常提到Kafka的时候,已经默认它是一个非常好的消息队列,经常拿它和RocketMQ、RabbitMQ做比较。认为Kafka相较于其他消息队列的主要优势如下:极致性能:基于Scala和Java语言开发,设计中大量采用批处理和异步思想,每秒可处理上千万条消息无与伦比的生态系统兼容性:Kafka与周边生态系统的兼容性是最好的之一,尤其是在大数据和流计算领域。其实在早期,Kafka并不是一个合格的mes圣人队列。早期的Kafka在消息队列领域就像一个衣衫褴褛的孩子,功能不完善,还存在一些消息丢失、消息可靠性不可靠等小问题等等。当然,这也与LinkedIn最早开发Kafka处理海量日志有很大关系。哈哈哈,一开始人家可不是把它当成消息队列用的。随着后续的发展,这些缺点逐渐被Kafka修复和完善。所以**,Kafka作为消息队列不可靠的说法已经过时了!**初识Kafka,先看看官网对它的介绍,应该是最权威和实时的。是不是英文也没关系,重要的信息我都已经给你提取出来了。从官方介绍中,我们可以得到如下信息:Kafka是一个分布式流处理平台。这到底是什么意思?Streaming平台有3个关键功能:消息队列:发布和订阅消息流,这个功能类似于消息队列,这也是Kafka也被归类为消息队列的原因。容错持久化的消息流存储和记录方式:Kafka会将消息持久化到磁盘,有效避免消息丢失的风险。流处理平台:为了在消息发布时进行处理,Kafka提供了完整的流处理库。Kafka主要有两个应用场景:消息队列:建立实时流式数据管道,可靠地在系统或应用程序之间获取数据。数据处理:构建实时流数据处理程序来转换或处理数据流。关于Kafka的几个非常重要的概念:Kafka将recordstreams(流数据)存储在topic中。每条记录都包含一个键、一个值和一个时间戳。Kafka消息模型》题外话:早期的JMS和AMQP属于消息服务领域权威机构制定的相关标准,我在JavaGuide的《消息队列其实很简单》一文中介绍过,但是这些标准的演进跟不上消息“队列。进化的速度,这些标准其实已经过时了。因此,可能会出现一种情况:不同的消息队列有自己的一套消息模型。”队列模型:早期的消息模型使用队列(Queue)作为消息通信的载体,满足生产者和消费者模式。一条消息只能由一个消费者使用。未被消费的消息一直保留在队列中,直到它们被消费或超时。例如:如果我们的生产者发送100条消息,将有两个消费者消费它们。一般两个消费者会按照消息发送的顺序消费一半(也就是你一个一个消费)队列模型的问题如果我们有这样的情况:我们需要分发生成的消息由生产者发送给多个消费者,每个消费者都能收到完整的消息内容。这种情况下队列模型不好解决。很多比较高明的人说:我们可以为每个消费者创建一个单独的队列,让生产者发送多份。这是一种非常愚蠢的做法,不说浪费资源,而且也违背了使用消息队列的初衷。发布订阅模型:Kafka消息模型发布订阅模型主要是为了解决队列模型的问题。发布订阅模型(Pub-Sub)以主题(Topic)作为消息传播载体,类似于广播模式;发布者发布消息,消息通过主题传递给所有订阅者,消息广播后订阅的用户没有收到消息。在发布-订阅模型中,如果只有一个订阅者,则与队列模型基本相同。因此,发布-订阅模型在功能上与队列模型兼容。Kafka使用发布-订阅模型。如下图所示:“RocketMQ的消息模型与Kafka的消息模型基本一致,唯一不同的是RocketMQ中没有队列的概念,对应的是Partition(分区)。”Kafka的重要概念解读消息发送给Topics,需要这些消息的消费者可以订阅这些Topics,如下图:KafkaTopicPartition上图也为我们介绍了Kafka的几个重要概念:生产者(Producer):产生消息的一方。Consumer(消费者):消费消息的一方。Broker(代理):可以看作是一个独立的Kafka实例。多个KafkaBrokers组成一个Kafka集群。同时,你还必须注意到,每个Broker都包含Topic和Partion两个重要的概念:Topic(主题):Producer向特定的topic发送消息,Consumer通过订阅特定的Topic(主题)来消费消息。Partion(分区):Partion是Topic的一部分。一个Topic可以有多个Partition,同一个Topic下的Partition可以分布在不同的Broker上,也就是说一个Topic可以跨越多个Broker。这就像我上面画的图一样。《划重点:Kafka中的Partition(分区)其实可以是消息队列中的队列,这样是不是更好理解?另外,我觉得更重要的是Kafka引入了多副本(Replica)机制。分区(Partion)中的多个副本中会有一个家伙叫做leader,其他的副本叫做followers。我们发送的消息会被发送到leader副本,然后follower副本可以从leader副本拉取消息进行同步。“生产者和消费者只和leader副本交互,你可以理解为其他副本只是leader副本的副本,它们的存在只是为了保证消息存储的安全。当leader副本失败时,会从followers中选举出一个leader,但是如果有任何一个follower与leader同步不满足要求,则无法参与leader选举。《Kafka的多分区(Partition)和多副本(Replica)机制有什么好处?Kafka为特定的Topic指定多个Partition,每个Partition可以分布在不同的Brokers上,可以提供更好的并发性(Loadbalancing).partition可以指定相应数量的Replicas,大大提高了消息存储的安全性和容灾能力,同时也相应增加了所需的存储空间《Kafka中Zookeeper的作用》如果想了解Kafka中Zookeeper的作用,必须自己搭建一个kafka环境,然后进入zookeeper查看有哪些文件夹和kafka相关,每个节点保存了哪些信息。不要光看不练,学的东西终究会被遗忘!”下面的文章将介绍如何搭建Kafka环境。别着急,看完后续文章3分钟就可以搭建好Kafka环境。》这部分内容参考借鉴了这篇文章:https://www.jianshu.com/p/a036405f989c。”下图是我本地的Zookeeper,成功关联到我本地的Kafka(下面的文件夹结构是借助idea插件Zookeeper工具实现的),ZooKeeper主要为Kafka提供元数据管理功能。从图中可以看到,Zookeeper主要为Kafka做了以下几件事:Broker注册:Zookeeper上会有一个专门记录Broker服务器列表的节点,每个Broker启动时都会向Zookeeper注册,即到/brokers/在ids下创建自己的节点。每个Broker都会将自己的IP地址、端口等信息记录到节点中进行Topic注册:在Kafka中,同一个Topic的消息会被分成多个partition,分布在多个Broker上。这些信息以及与Broker的对应关系也由Zookeeper维护。例如,我创建了一个名为my-topic的主题,它有两个分区,对应的这些文件夹将在zookeeper中创建:/brokers/topics/my-topic/partions/0,/brokers/topics/my-topic/partions/1负载均衡:如前所述,Kafka为一个特定的Topic指定了多个Partition,每个Partition可以分布在不同的Brokers上,可以提供更好的并发能力。对于同一个Topic的不同Partition,Kafka会尽量将这些Partition分布到不同的Broker服务器上。当生产者产生一条消息时,它会尝试将消息投递到不同Brokers的Partition中。当Consumer消费时,Zookeeper可以根据当前Partition数量和Consumers数量实现动态负载均衡。......Kafka是如何保证消息的消费顺序的?我们在使用消息队列的过程中经常会有业务场景需要严格保证消息的消费顺序。比如我们同时发送两条消息,这两条消息对应的操作对应的数据库操作是:更改用户会员级别,根据会员级别计算下单价格。如果这两条消息的消费顺序不同,最终的结果就会完全不同。我们知道Kafka中的Partition(分区)是真正保存消息的地方,我们发送的所有消息都放在这里。而我们的Partition(分区)存在于Topic(主题)的概念中,我们可以为一个具体的Topic指定多个Partition。KafkaTopicPartitionsLayout在每次向Partition中添加一条消息时都会使用tailaddition,如上图所示。Kafka只能为我们保证Partition(分区)中消息的顺序,而不能保证Partition(分区)在Topic(主题)中的顺序。“当一条消息被附加到一个Partition(分区)时,它会被分配一个特定的偏移量(offset)。Kafka使用偏移量(offset)来保证分区中消息的顺序。”因此,我们有一个非常简单的方法来保证消息消费的顺序:1个Topic只对应1个Partion。这固然可以解决问题,但是却破坏了Kafka的设计初衷。在Kafka中发送消息时,可以指定四个参数:topic、partition、key、data(数据)。如果在发送消息时指定partion,则所有消息都会发送到指定的partion。而且,同一个key的消息只能发送到同一个partition,所以我们可以使用table/object的id作为key。总结一下,Kafka中保证消息消费顺序的方式有两种:1个Topic只对应1个Partion。(推荐)发送消息时指定key/partion。当然,不止有以上两种方法,以上两种方法是我比较理解的。