Kakfa入门与使用
1、Kafka介绍
1.1 Kafka的概念
Kafka是一个分布式流处理平台
具有以下三个特性:
-
可以让你发布和订阅流式的记录。这一方面与消息队列或者企业消息系统类似。
-
可以储存流式的记录,并且有较好的容错性。
-
可以在流式记录产生时就进行处理。
1.2 Kafka的应用场景
-
构造实时流数据管道,它可以在系统或应用之间可靠地获取数据。 (相当于message queue)
-
构建实时流式应用程序,对这些流数据进行转换或者影响。 (就是流处理,通过kafka stream topic和topic之间内部进行变化)
-
跟踪网站活动,Kafka 的初始用例是将用户活动跟踪管道重建为一组实时发布-订阅源。 这意味着网站活动(浏览网页、搜索或其他的用户操作)将被发布到中心topic,其中每个活动类型有一个topic。 这些订阅源提供一系列用例,包括实时处理、实时监视、对加载到Hadoop或离线数据仓库系统的数据进行离线处理和报告等。
-
度量,通常用于监控数据。这涉及到从分布式应用程序中汇总数据,然后生成可操作的集中数据源。
-
日志处理系统包括(日志聚合,采集日志,提交日志)等
1.3 Kafka的特性
kafka是一款分布式消息发布和订阅系统,具有高性能,高吞吐量的特点而被广泛应用于大数据传输消息。
Kafka的架构组件
Broker:可以认为是Kafka的服务节点,Broker一般有多个,它们组成一个分布式高容错的集群。Broker的主要职责是接受Producer和Consumer的请求,并把消息持久化到本地磁盘。
Produce:生产者可以将数据发布到所选择的topic(主题)中。生产者负责将记录分配到topic的哪一个 partition(分区)中。
Consumer:消费者使用一个消费组标识,发布到topic中的每条记录被分配给订阅消费组中的一个消费者实例.消费者实例可以分布在多个进程中或者多个机器上。
Topic:数据主题,是数据记录发布的地方,可以用来区分业务系统。Kafka中的Topics总是多订阅者模式,一个topic可以拥有一个或者多个消费者来订阅它的数据。
Partion:分区,每一个topic, Kafka集群都会维持一个分区日志,每个分区都是有序且顺序不可变的记录集,并且不断地追加到结构化的commit log文件。分区中的每一个记录都会分配一个id号来表示顺序,我们称之为offset,offset用来唯一的标识分区中每一条记录。
常用消息中间件对比
2、Kafka的安装与使用
本人安装环境:
Ubuntu 18.04.3 LTS
Java 11.0.9.1
Kafka_2.13-2.6.0
1、安装Kafka
1.下载Kafka并解压,下载地址http://kafka.apache.org/downloads
tar -xzf kafka_2.13-2.6.0.tgz
cd kafka_2.13-2.6.0
2.启动服务器
Kafka使用ZooKeeper服务器,如果没有启动ZooKeeper服务器,需要先启动ZooKeeper服务器。可以使用自己安装的ZooKeeper,也可以使用Kafka内置的ZooKeeper,这里使用的是Kafka内置的ZooKeeper。
启动ZooKeeper服务器
> bin``/zookeeper-server-start``.sh config``/zookeeper``.properties
启动Kafka服务器
> bin``/kafka-server-start``.sh config``/server``.properties
在启动服务器时可能会遇到的一个问题:报 line 309: exec: java: not found,提示找不到java
我自己在第一次启动的时候也遇到了这个问题,在网上搜索了之后大概以下几种解决方案。
1、既然提示找不到,那就安装一个Java,直接在命令行中输入安装Java的命令,即使以前装了java,也可以重装一次,安装完成后,重新启动服务,就不会报错了。(这也是我用的解决办法)
2、Java的安装路径和Kafka默认的java安装目录不一致,需要修改java的安装路径。较麻烦
3、添加link到kafka默认的java安装目录: ln -s /usr/local/jdk1.8.0_251/bin/java /usr/bin/java
4、也有可能是Kafka所在文件夹的权限问题,用root用户操作或者将Kafka放到普通文件夹中。
2、基本功能使用
1、成功启动服务器遍可以创建topic
> bin``/kafka-topics``.sh --create --zookeeper localhost:2181 --replication-factor 1 --partitions 1 --topic ``test
创建名为test的topic,有一个分区和副本。
2、运行producer,发送消息
> bin``/kafka-console-producer``.sh --broker-list localhost:9092 --topic ``test hello kafka
运行 producer,然后在控制台输入一些消息以发送到服务器。
3、启动consumer,接收消息
> bin``/kafka-console-consumer``.sh --bootstrap-server localhost:9092 --topic ``test` `--from-beginning hello kafka
如果将上述命令在不同的终端中运行,那么现在就可以将消息输入到生产者终端中,并将它们在消费终端中显示出来。
4、设置多代理集群
kafka是天生支持分布式的,也是经常应用到分布式场景,单个节点的意义并不是很大。为了深入了解,在本地机器模拟把集群扩展到三个节点。
首先,为每个代理创建一个配置文件
>cp` `config``/server``.properties config``/server-1``.properties >cp` `config``/server``.properties config``/server-2``.properties
用vim进入到这两个配置文件中并修改如下属性:
config/server-1.properties: ``broker.id=1 ``listeners=PLAINTEXT://:9093 ``log.dir=/tmp/kafka-logs-1
config/server-2.properties: ``broker.id=2 ``listeners=PLAINTEXT://:9094 ``log.dir=/tmp/kafka-logs-2
broker.id属性是集群中每个节点的名称,具有唯一性和永久性。同时也必须重写端口和日志目录,因为是在同一台机器运行这些。重写端口可以保证所有的代理不会尝试这种同一个端口注册,重写日志目录则可以保证不会覆盖彼此的数据。
之前已经启动了Zookeeper和一个单节点,所以现在只需要启动两个新配置的节点:
> bin``/kafka-server-start``.sh config``/server-1``.properties
> bin``/kafka-server-start``.sh config``/server-2``.properties
创建一个副本为3的新topic
> bin``/kafka-topics``.sh --create --zookeeper localhost:2181 --replication-factor 3 --partitions 1 --topic my-replicated-topic
运行"describe topics"命令查看代理信息:
> bin``/kafka-topics``.sh --describe --zookeeper localhost:2181 --topic my-replicated-topic Topic:my-replicated-topic PartitionCount:1 ReplicationFactor:3 Configs: ``Topic: my-replicated-topic Partition: 0 Leader: 1 Replicas: 1,2,0 Isr: 1,2,0
leader是负责给定分区所有读写操作的节点。每个节点都是随机选择的分区的领导者。
replicas是复制分区日志的节点列表,包括leader节点和其他活着的节点。
isr是一组同步replicas,是replicas列表的子集,它活着并被指到leader。
上述示例中,leader节点为1。
发送消息给topic
> bin``/kafka-console-producer``.sh --broker-list localhost:9092 --topic my-replicated-topic my ``test` `message 1 my ``test` `message 2
消费消息
> bin``/kafka-console-consumer``.sh --bootstrap-server localhost:9092 --from-beginning --topic my-replicated-topic my ``test` `message 1 my ``test` `message 2
测试容错性,Broker 1 现在是 leader,让我们来杀了它:
> ``ps` `aux | ``grep` `server-1.properties 7564 ttys002 0:15.91 ``/System/Library/Frameworks/JavaVM``.framework``/Versions/1``.8``/Home/bin/java``... > ``kill` `-9 7564
再次查看代理信息,发现leader节点已经切换到另外一个节点,并且节点1也不在同步副本中了:
> bin``/kafka-topics``.sh --describe --zookeeper localhost:2181 --topic my-replicated-topic Topic:my-replicated-topic PartitionCount:1 ReplicationFactor:3 Configs: ``Topic: my-replicated-topic Partition: 0 Leader: 2 Replicas: 1,2,0 Isr: 2,0
Kafka的Broker选举机制是基于ZooKeeper的临时节点和watch机制来实现,具体就不在这里细聊了。感兴趣的同学可以去自行搜索。
但是即使原先写入消息的leader已经不在。这些消息仍可用于消费:
> bin``/kafka-topics``.sh --describe --zookeeper localhost:2181 --topic my-replicated-topic Topic:my-replicated-topic PartitionCount:1 ReplicationFactor:3 Configs: ``Topic: my-replicated-topic Partition: 0 Leader: 2 Replicas: 1,2,0 Isr: 2,0
3、Kafka结合springboot使用Demo
导入依赖
<dependency> <groupId>org.springframework.kafka</groupId> <artifactId>spring-kafka</artifactId> <version>2.4.1.RELEASE</version> </dependency>
配置application.properties
spring.kafka.consumer.group-id=foo spring.kafka.consumer.auto-offset-reset=earliest spring.kafka.listener.missing-topics-fatal=false
spring.kafka.consumer.group-id`指定消费者组id。
spring.kafka.consumer.auto-offset-reset`确保新的消费者组能获得我们之前发送的消息,为了测试方便(生产配置latest,只获取最新的消息)。
spring.kafka.listener.missing-topics-fatal` 监听的topic如果不存在,则不报错
主类
package com.example.demo; import org.apache.kafka.clients.consumer.ConsumerRecord; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.boot.CommandLineRunner; import org.springframework.boot.SpringApplication; import org.springframework.boot.autoconfigure.SpringBootApplication; import org.springframework.kafka.annotation.KafkaListener; import org.springframework.kafka.core.KafkaTemplate; import java.util.concurrent.CountDownLatch; import java.util.concurrent.TimeUnit; @SpringBootApplication public class DemoApplication implements CommandLineRunner { public static Logger logger = LoggerFactory.getLogger(DemoApplication.class); public static void main(String[] args) { SpringApplication.run(DemoApplication.class, args).close(); } @Autowired private KafkaTemplate<String, String> template; private final CountDownLatch latch = new CountDownLatch(3); @Override public void run(String... args) throws Exception { this.template.send("myTopic", "foo1"); this.template.send("myTopic", "foo2"); this.template.send("myTopic", "foo3"); latch.await(60, TimeUnit.SECONDS); logger.info("All received"); } @KafkaListener(topics = "myTopic") public void listen(ConsumerRecord<?, ?> cr) throws Exception { logger.info(cr.toString()); latch.countDown(); } }
本博文参考Kafka官方文档。