Kafka是什么?
Apache Kafka是一个分布式发布-订阅消息传递系统和一个健壮的消息队列,可以处理海量数据,使您能够将消息快速从一个端点传递到另一个端点。Kafka适合离线和在线信息消费。Kafka式的消息被保存在磁盘上,并在集群中复制,以防止数据丢失。Kafka是建立在zookeeper同步服务之上的。它与Apache Storm和Spark集成得非常好,可用于实时流数据分析。
优势
Kafka的一些优势如下
-
可靠性:Kafka是分布式的、分区的、复制的和容错的。
-
扩展性:Kafka式消息系统无需停机即可轻松扩展..
-
持久性:Kafka使用分布式提交日志,这意味着消息尽可能快地保存在磁盘上,因此它是持久的。
-
性能:Kafka对于发布和订阅消息都有很高的吞吐量。即使存储了许多TB的消息,它也能保持稳定的性能。
Kafka速度非常快,保证零停机时间和零数据丢失。
用例
Kafka可以用在许多用例中。其中一些列举如下:
度量:Kafka通常用于运营监控数据。这包括聚集来自分布式应用程序的统计数据,以产生操作数据的集中馈送。
日志聚合方案:Kafka可以在整个组织中使用,从多个服务中收集日志,并以标准格式提供给多个消费者。
流处理:流行的框架,如 Storm和Spark可以从一个主题中读取数据,对其进行处理,并将处理后的数据写入一个新的主题,以便用户和应用程序使用。Kafka的强大耐用性在流处理领域也非常有用。
Kafka的需求
Kafka是处理所有实时数据馈送的统一平台。Kafka支持低延迟的消息传递,并保证机器出现故障时有一定的容错能力。它有能力处理大量不同的消费者。Kafka速度非常快,每秒执行200万次写操作。Kafka将所有数据保存到磁盘上,这实际上意味着所有的写入都将进入操作系统的页面缓存。这使得将数据从页面缓存传输到网络套接字非常有效。
名词解释
题(Topic)
属于特定类别的消息流称为主题。数据存储在主题中。
主题被分成多个分区。对于每一个话题,Kafka都对一个分区保持最小化。每个这样的分区包含不可变有序序列的消息。分区被实现为一组大小相等的段文件。
分区(Partition)
主题可能有许多分区,因此它可以处理任意数量的数据。
分区偏移量
每个分区的消息都有一个唯一的序列id,称为偏移量。
分区副本
副本只不过是分区的备份。副本绝不是读写数据。它们用于防止数据丢失。
经纪人(Broker)
经纪人是负责维护发布数据的系统。每个代理的每个主题可能有零个或多个分区。假设,如果一个主题中有N个分区和N个代理,每个代理将有一个分区。
假设一个主题中有N个分区和超过N个代理(n + m),第一个N个代理将有一个分区,下一个M个代理将没有该特定主题的任何分区。
假设一个主题中有N个分区,并且少于N个代理(n-m),那么每个代理之间将有一个或多个分区共享。由于代理之间的负载分配不平等,因此不建议使用这种情况。
Kafka集群
Kafka集群包含多个经纪人。Kafka集群可以在不停机的情况下扩展。这些集群用于管理消息数据的持久性和复制。
生产者(Producer)
生产者是一个或多个Kafka主题的信息发布者。生产者向Kafka经纪人发送数据。每当生产者向代理发布消息时,代理只需将消息附加到最后一个段文件。实际上,消息将被附加到一个分区。生产者也可以向他们选择的分区发送消息。
消费者(Consumer)
消费者从经纪人那里读取数据。消费者订阅一个或多个主题,并通过从代理获取数据来消费已发布的消息。
Leader
Leader是负责指定分区的节点的读写。每个分区都有一台服务器充当领导者。
Follower
遵循Leader指令的节点称为Follower。如果Leader失败,其中一个Follower将自动成为新的Leader。Follower充当普通消费者,获取消息并更新自己的数据存储。
单机模式
下载 官网 http://kafka.apache.org/downloads
准备环境
- java 1.8
- zookeeper 3.5.6
- kafka 2.4.0
本人因为安装了Elasticsearch 7.4.0 ,所以选择了ES自带的jdk,下篇博客里有讲这些。
https://blog.csdn.net/qq_41520636/article/details/115916766
如果想要使用原生jdk安装,那么可以参照下篇博客
https://blog.csdn.net/qq_41520636/article/details/111878044
然后直接搜索 JDK1.8配置 即可查阅。
zookeeper的安装参照
https://blog.csdn.net/qq_41520636/article/details/114959972
直接搜索 zookeeper的安装 即可查阅。
不过,kafka里面内置了zookeeper,也可以不用再去安装zookeeper。
后面集群模式下,最好安装hadoop,使用大数据来构建接收数据。
Apache Kafka安装
上传到本机linux上,而后解压
tar -zxvf kafka_2.11-2.4.0.tgz -C /opt
下面你可以有几种选择,一种是在host文件,修改主机名和ip,然后使用主机名修改下面的配置;另一种方式直接使用ip修改配置,两者选一种即可。
# 进入配置目录
cd /opt/kafka_2.11-2.4.0/config
# 修改配置
vim server.properties
# ===========================================
# 经纪人id,该属性必须唯一,用于配置集群
broker.id=0
# 监听地址,PLAINTEXT://ip地址:9092(9092默认端口)
listeners=PLAINTEXT://192.168.135.145:9092
# log地址,不要使用默认的/tmp/kafka-logs/地址,启动会报错
log.dirs=/tmp/kafka-logs-0/
# zookeeper连接地址,默认本地即可,这里如果是集群模式,需要配置多个zookeeper
zookeeper.connect=localhost:2181
# zookeeper连接超时秒数
zookeeper.connection.timeout.ms=6000
# 无须重启即可删除主题
delete.topic.enable=true
# 设置了listeners其实可以不用设置host.name
host.name=192.168.135.145
修改环境变量
vim /etc/profile
# kafka配置
export KAFKA_HOME=/opt/kafka_2.11-2.4.0
export PATH=$KAFKA_HOME/bin:$PATH
source /etc/profile
这样可以不用跳转到目标目录下,才能启动命令。
启动命令-前台启动
kafka-server-start.sh config/server.properties
停止命令-前台启动
kafka-server-stop.sh config/server.properties
启动命令-后台启动
nohup kafka-server-start.sh config/server.properties &
后台启动后,ctrl+c无法关闭。
压力测试
kafka-producer-perf-test.sh --topic test --num-records 100 --record-size 1 --throughput 100 --producer-props bootstrap.servers=localhost:9092
查看kafka启动进程
输入 jps 命令查看,QuorumPeerMain是zookeeper守护线程。
[root@localhost config]# jps
38786 QuorumPeerMain
22562 Kafka
56121 Jps
Apache Kafka 基本操作
准备
本机ip:192.168.135.145
关闭防火墙:systemctl stop firewalld
启动Zookeeper
zookeeper-server-start.sh config/zookeeper.properties
启动Kafka Broker
kafka-server-start.sh config/server.properties
创建主题Topic
kafka-topics.sh --create --zookeeper localhost:2181 --replication-factor 1 -- partitions 1 --topic test
输出
Created topic test.
查看主题Topic
kafka-topics.sh --list --zookeeper localhost:2181
输出
test
修改主题Topic
修改分区数Partition
kafka-topics.sh --zookeeper localhost:2181 --alter --topic topicName --partitions 8
增加配置
kafka-topics.sh --zookeeper localhost:2181 --alter --topic test --config flush.messages=1
删除配置
kafka-topics.sh --zookeeper localhost:2181 --alter --topic test --delete-config flush.messages
删除主题Topic
kafka-topics.sh --zookeeper localhost:2181 --delete --topic topicName
生产者
kafka-console-producer.sh --broker-list 192.168.135.145:9092 --topic test
消费者
kafka-console-consumer.sh --bootstrap-server 192.168.135.145:9092 --topic test --from-beginning
例子:
注意:ip不能写错,否则无法建立连接。
集群模式
克隆两台虚拟机
复制两个配置文件
cd /opt/kafka_2.11-2.4.0/
cp config/server.properties config/server-1.properties
cp config/server.properties config/server-2.properties
vim config/server-1.properties
broker.id=0
listeners=PLAINTEXT://192.168.135.145:9092
log.dirs=/tmp/kafka-logs-0
zookeeper.connect=192.168.135.145:2181,192.168.135.146:2181,192.168.135.147:2181
host.name=192.168.135.145
vim config/server-1.properties
broker.id=1
listeners=PLAINTEXT://192.168.135.146:9092
log.dirs=/tmp/kafka-logs-0
zookeeper.connect=192.168.135.145:2181,192.168.135.146:2181,192.168.135.147:2181
host.name=192.168.135.146
vim config/server-2.properties
broker.id=1
listeners=PLAINTEXT://192.168.135.147:9092
log.dirs=/tmp/kafka-logs-0
zookeeper.connect=192.168.135.145:2181,192.168.135.146:2181,192.168.135.147:2181
host.name=192.168.135.147
克隆三个窗口
Broker1
kafka-server-start.sh config/server.properties
Broker2
kafka-server-start.sh config/server-1.properties
Broker3
kafka-server-start.sh config/server-2.properties
创建主题
创建三个分区,两个副本
kafka-topics.sh --create --zookeeper 192.168.135.145:2181 --replication-factor 2 -- partitions 3 --topic test
查看主题
kafka-topics.sh --list --zookeeper 192.168.135.145:2181,192.168.135.146:2181,192.168.135.147:2181
生产者
kafka-console-producer.sh --broker-list 192.168.135.145:9092,192.168.135.146:9092,192.168.135.147:9092 --topic test
消费者
kafka-console-consumer.sh --from-beginning --topic test --zookeeper 192.168.135.145:2181,192.168.135.146:2181,192.168.135.147:2181
查看各节点运行情况
kafka-topics.sh --describe --zookeeper 192.168.135.145:2181 --topic test
输出
Topic: test PartitionCount: 3 ReplicationFactor: 2 Configs:
Topic: test Partition: 0 Leader: 0 Replicas: 0,2,1 Isr: 0,2,1
查看主题消费进度
bin/kafka-run-class.sh kafka.tools.ConsumerOffsetChecker --group pv
Group Topic Pid Offset logSize Lag Owner
pv page_visits 0 21 21 0 none
pv page_visits 1 19 19 0 none
pv page_visits 2 20 20 0 none
topic:创建时topic名称
pid:分区编号
offset:表示该parition已经消费了多少条message
logSize:表示该partition已经写了多少条message
Lag:表示有多少条message没有被消费。
Owner:表示消费者
Java API
pom
<dependencies>
<!-- https://mvnrepository.com/artifact/org.apache.kafka/kafka-clients -->
<dependency>
<groupId>org.apache.kafka</groupId>
<artifactId>kafka-clients</artifactId>
<version>2.4.0</version>
</dependency>
<dependency>
<groupId>org.apache.kafka</groupId>
<artifactId>kafka-streams</artifactId>
<version>2.4.0</version>
</dependency>
</dependencies>
<build>
<plugins>
<!-- java编译插件 -->
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-compiler-plugin</artifactId>
<version>3.2</version>
<configuration>
<source>1.8</source>
<target>1.8</target>
<encoding>UTF-8</encoding>
</configuration>
</plugin>
</plugins>
</build>
生产者
public class SimpleProducer {
public static void main(String[] args) {
//Assign topicName to string variable
String topicName = "my-topic";
// create instance for properties to access producer configs
Properties props = new Properties();
//Assign localhost id
props.put("bootstrap.servers", "192.168.135.145:9092");
//Set acknowledgements for producer requests.
props.put("acks", "all");
//If the request fails, the producer can automatically retry,
props.put("retries", 0);
//Specify buffer size in config
props.put("batch.size", 16384);
//Reduce the no of requests less than 0
props.put("linger.ms", 1);
//The buffer.memory controls the total amount of memory available to the producer for buffering.
props.put("buffer.memory", 33554432);
props.put("key.serializer", "org.apache.kafka.common.serialization.StringSerializer");
props.put("value.serializer", "org.apache.kafka.common.serialization.StringSerializer");
Producer<String, String> producer = new KafkaProducer<> (props);
for (int i = 0; i < 10; i++) {
// 发送消息
producer.send(new ProducerRecord<>(topicName,"hello world->"+ Integer.toString(i)));
}
System.out.println("Message sent successfully");
producer.close();
}
}
消费者
public class SimpleConsumer {
public static void main(String[] args) {
String topic = "my-topic";
String group = "test";
Properties props = new Properties();
props.put("bootstrap.servers", "192.168.135.145:9092");
props.put("group.id", group);
props.put("enable.auto.commit", "true");
props.put("auto.commit.interval.ms", "1000");
props.put("session.timeout.ms", "30000");
props.put("key.deserializer", "org.apache.kafka.common.serialization.StringDeserializer");
props.put("value.deserializer", "org.apache.kafka.common.serialization.StringDeserializer");
KafkaConsumer<String, String> consumer = new KafkaConsumer<String, String>(props);
consumer.subscribe(Arrays.asList(topic));
System.out.println("Subscribed to topic " + topic);
while (true) {
ConsumerRecords<String, String> records = consumer.poll(100);
for (ConsumerRecord<String, String> record : records) {
// 接收消息
System.out.printf("offset = %d, key = %s, value = %s\n", record.offset(), record.key(), record.value());
}
}
}
}
注意:测试之前一定要关闭防火墙,否则建立不了连接。
输出
offset = 16, key = null, value = hello world->0
offset = 17, key = null, value = hello world->1
offset = 18, key = null, value = hello world->2
offset = 19, key = null, value = hello world->3
offset = 20, key = null, value = hello world->4
offset = 21, key = null, value = hello world->5
offset = 22, key = null, value = hello world->6
offset = 23, key = null, value = hello world->7
offset = 24, key = null, value = hello world->8
offset = 25, key = null, value = hello world->9