1、Kafka介绍
Kafka最初由Linkedin公司开发,是一个分布式的、⽀持分区的(partition)、多副本的(replica)、多订阅者,基于zookeeper协调的分布式消息系统(也可以当做MQ系统),也是一个分布式流处理平台(Distributed Streaming Platform)。常用于web/nginx日志、访问日志、消息服务等等,Linkedin于2010年贡献给了Apache基金会并成为顶级开源项目。
1.1、Kafka是一个分布式数据流平台,可以从如下几个层面来理解:
- 我们可以向kafka发布数据以及从kafka订阅数据,即 我们可以将kafka看做一个消息队列,所起到的作用:缓冲(消峰限流),实现生产与消费的解耦。
- Kafka可以存储数据,并提供容错机制,即:数据丢失后可以进行恢复。
- 当数据到达kafka之后,可以马上的被消费处理,即 kafka的延迟很低。
- Kafka的数据,无论消费与否,数据会一直存在,不会删除。
1.2、kafka版本命名
前面的版本号:是编译 Kafka 源代码的 Scala 编译器版本,示例中为:2.12。
真正的 Kafka 版本号,示例中为: :2.5.0
那么这个 2.5.0 又表示什么呢?
前面的 2 表示大版本号,即 Major Version;
中间的 5 表示小版本号或次版本号,即 Minor Version;
最后的 1 表示修订版本号,也就是 Patch 号。
2、kafka的特性
- 高吞吐量、低延迟:kafka每秒可以处理几十万条消息,它的延迟最低只有几毫秒;
- 可扩展性:kafka集群支持热扩展;
- 持久性、可靠性:消息被持久化到本地磁盘,并且支持数据备份防止丢失;
- 容错性:允许集群中的节点失败(若分区副本数量为n,则允许n-1个节点失败);
- 高并发:单机可支持数千个客户端同时读写;
3、kafka的相关概念
3.1、Broker :kafka节点
一台kafka服务器就是一个broker。一个集群由多个broker组成。一个broker可以容纳多个topic。
Kafka代理(broker)是无状态的,即代理并不知道消费者是否已经使用了该消息,当消息在代理中超过一定时间后,将会被自动删除。
集群中每个broker都有一个唯一broker_id,不得重复。
3.2、Producer:消息生产者
向主题发布消息的客户端应用程序,称为生产者(Producer),生产者用于持续不断的向某个主题发送消息。
数据的分发策略由producer决定,默认是:
defaultPartition = Utils.abs(key.hashCode) % numPartitions
生产者可以发布数据到指定的主题(topic)中,并可以指定在主题(topic)中哪些消息分配到哪些分区。
生产者直接把消息发送给对应分区的broker,而不需要任何路由层。
批处理发送:当message积累到一定数量或等待一定时间后进行发送。
3.3、Consumer:消息消费者
消息传递通常由两种模式,queuing(队列)和publish-subscribe (发布-订阅)
- queuing:每个Consumer从消息队列中取走一个消息。
- pub-scrib:消息被广播到每个Consumer。
Kafka通过提供了一个对Consumer的抽象来同时实现这两种模式--ConsumerGroup。
Consumer实例需要给自己指定一个ConsumerGroup的名字,如果所有的实例都用同一个ConsumerGroup名字,那么这些Consumer就会以queuing的模式工作;如果所有的实例分别用的不同的ConsumerGroup名字,那么它们就以public-subscribe模式工作。
如下图所示:两台server的集群一共有p0~p3四个Partition,两个Consumer Group,在Group内部是以queuing的模式消费Partition,在Group之间是以pub-scrib模式消费。
消息顺序性:
Kafka是如何确保消息消费的顺序性的呢?消息在一个Partition中的顺序是有序的,但是Kafka只保证消息在一个Partition中有序,如果要想使整个topic中的消息有序,那么一个topic仅设置一个Partition即可。
3.4、Consumer Group:消费者组
- Consumer Group可以有多个,每个Consumer Group消费的数据都是一样的。可以把多个consumer划分为一个组,组里面所有成员共同消费一个topic的数据,组员之间不能重复消费。
3.5、Topic :主题
- 通过对消息指定主题(topic)可以将消息分类,消费者可以只关注自己需要的Topic中的消息。 这是一个逻辑上的概念,落到磁盘上是一个partition的目录。partition的目录中有多个segment组合(index,log)。一个Topic对应多个partition[0,1,2,3…],一个partition对应多个segment组合。一个segment有默认的大小是1G。
- 每个partition可以设置多个副本(replication-factor 1), 会从所有的副本中选取一个leader出来。所有读写操作都是通过leader来进行的。特别强调,在kafka中读写操作都是leader。无论发布的消息是否被消费,kafka都会持久化一定时间(可配置,默认7天),每个消费者都会持久化offset到日志中,且offset的位置由消费者控制。
3.6、Partition:分区
- 在topic基础上做了进一步区分,
- 为了实现扩展性,一个非常大的topic可以分布到多个broker(即服务器)上,一个topic可以分为多个partition(partition是一个磁盘目录),每个partition是一个FIFO的队列。partition中的每条消息都会被分配一个有序的id(offset)。kafka只保证按一个partition中的顺序将消息发给consumer,不保证一个topic的整体(多个partition间)的顺序。
3.7、offset :偏移量
- kafka为每条在分区的消息保存一个偏移量offset,这也是消费者在分区的位置。比如一个偏移量是5的消费者,表示已经消费了从0-4偏移量的消息,下一个要消费的消息的偏移量是5。
kafka的存储文件都是按照offset.kafka来命名,用offset做名字的好处是方便查找。例如你想找位于2049的位置,只要找到2048.kafka的文件即可。当然the first offset就是00000000000.kafka
上图所示,从分区中消费数据,kafka底层有一个offset机制。Kafka会记录消费者的offset(消费的位置偏移量),便于下一次从正确的位置进行消费。
- Kafka 0.9 版本之前,consumer 默认将 offset 保存在 Zookeeper 中。存在的问题:会频繁的和zookeeper进行通信交互,即可能为zookeeper带来较高的访问负载。
- 从 0.9 版本开始,consumer 默认将 offset 保存在 Kafka 一个内置的 topic 中,该 topic 为__consumer_offsets
Offset验证思路:
- 启动一个消费者线程(需要带有消费者组 属性)
sh kafka-console-consumer.sh --bootstrap-server localhost:90923 --topic book --from-beginning --group 20220707
- 会发现多出了一些目录,是因为 kafka底层是通过一个主题来进行管理offset的,主题名为:__consumer_offsets ,该主题有50个分区。
- 某个消费者组的offset就存在这50个分区目录中的其中一个。
存储规则:
Math.abs(groupId.hashCode())%50 该结果在:0~49之间
说明:Math.abs()返回指定数字的绝对值。
4、Topic & Partition
- Topic相当于传统消息系统MQ中的一个队列queue,producer端发送的message必须指定是发送到哪个topic,但是不需要指定topic下的哪个partition,因为kafka会把收到的message进行load balance,均匀的分布在这个topic下的不同的partition上(hash(message) % [broker数量] )。
- 物理存储上,这个topic会分成一个或多个partition,每个partiton相当于是一个子queue。在物理结构上,每个partition对应一个物理的目录(文件夹),文件夹命名是[topicname]_[partition]_[序号],一个topic可以有无数多的partition,根据业务需求和数据量来设置。在kafka配置文件中可随时更改num。partitions参数来配置更改topic的partition数量,在 创建Topic时通过参数指定parittion数量。 Topic创建之后通过Kafka提供的工具也可以修改partiton数量。
一般来说,
- (1)一个Topic的Partition数量大于等于Broker的数量, 可以提高吞吐率。
- (2)同一个Partition的Replica尽量分散到不同的机器, 高可用。
当add a new partition的时候,partition里面的message不会重新进行分配,原来的partition里面的message数据不会变,新加的这个partition刚开始是空的,随后进入这个topic的message就会重新参与所有partition的load balance
Partition Replica:每个partition可以在其他的kafka broker节点上存副本,以便某个kafka broker节点宕机不会影响这个kafka集群。存replica副本的方式是按照kafka broker的顺序存。
- 例如有5个kafka broker节点,某个topic有3个partition,每个partition存2个副本,那么partition1存broker1,broker2,partition2存broker2,broker3。。。以此类推(replica副本数目不能大于kafka broker节点的数目,否则报错。这里的replica数其实就是partition的副本总数,其中包括一个leader,其他的就是copy副本)。这样如果某个broker宕机,其实整个kafka内数据依然是完整的。但是,replica副本数越高,系统虽然越稳定,但是回来带资源和性能上的下降;replica副本少的话,也会造成系统丢数据的风险。
- 如上图所示,向一个主题生产数据,数据最终是存储到各个分区中。
分区从逻辑上来看,实际上是一个队列。
分区从物理上来看,实际上是一个分区目录。
向分区中存储数据,最终是存到分区目录下的log文件中。
底层实际上是数据磁盘的顺序写操作。(即:往文件末尾追加。)所以kafka的写入性能较高。
5、kafka的应用场景
日志收集:一个公司可以用Kafka收集各种服务的log,通过kafka以统一接口开放给各种消费端,例如hadoop、Hbase、Solr等。
消息系统:解耦生产者和消费者、缓存消息等。
用户活动跟踪:Kafka经常被用来记录web用户或者app用户的各种活动,如浏览网页、搜索记录、点击等活动,这些活动信息被各个服务器发布到kafka的topic中,然后订阅者通过订阅这些topic来做实时的监控分析,或者装载到hadoop、数据仓库中做离线分析和挖掘。
运营指标:Kafka也经常用来记录运营监控数据。
流式处理。
6、知识点
6.1、controller : 控制进程
- kafka集群中,controller控制进程会随机在某台broker上启动,此进程用于leader的选举,以及失败恢复。Controller进程的信息由zookeeper来维护,如果controller宕机后,会在其他剩下的broker服务器上启动。
6.2、zookeeper
Zookeeper :负责管理、监控kafka集群运行(临时节点+监听机制),包括存储一些元数据信息(比如:主题名、主题的分区数、分区的副本数、副本leader的位置信息、controller位置等)
- 示例说明:
①进入zookeeper客户端:进入bin目录,执行sh zkCli.sh,进入zookerper客户端,查看kafka节点信息。
6.3、分区的副本机制
- kafka支持数据的容错机制,即分区数据丢失后,可以恢复,通过副本冗余机制来实现,即我们在创建主题时,可以指定每个分区有多个副本。
分区的副本机制,是为了数据容错。
补充说明:
- 分区副本的数量不能超过broker服务器数量。
- 分区的副本数不宜过多,副本数量越多,集群磁盘的利用率越低,比如:3个副本,集群磁盘的利用率只有33%。
- 在实际生产环境下,一般3个副本足够了,2个副本也可以。如果副本数是1,则没有容错机制。
综上,kafka最基础、最核心的概念就是topic主题。因为无论是向kafka生产数据,还是从kafka消费数据,都需要指定主题。
主题topic的属性:
- 主题名 topic
- 分区数量 partition
- 分区的副本数量 replication
6.4、分区副本知识点
- kafka是有leader和follower概念的。注意:是针对分区的副本而言的,不是针对broker来说的。
- 分区的副本leader的作用:无论是生产数据,还是消费数据,都是和分区副本的leader交互的。
- 如果分区副本的leader挂掉了,kafka会从剩余的follower中选出新的leader。