目录
0、相关文章链接
1、了解Kafka
1.1、Kafka是什么?有什么用?
-
是什么?
1) Apache Kafka 是一个消息队列(生产者消费者模式)
2) Apache Kafka 目标:构建企业中统一的、高通量、低延时的消息平台。
3) 大多的是消息队列(消息中间件)都是基于JMS标准实现的,Apache Kafka 类似于JMS的实现。
-
有什么用?
1) 作为缓冲,来异构、解耦系统。
1.2、kafka的特性
-
消息持久化(Kafka 基于文件系统来存储和缓存消息)。
-
高吞吐量(Kafka 将数据写到磁盘,但是在底层采用了零拷贝技术,所以速度比较快)。
-
高扩展性(Kafka 依赖ZooKeeper来对集群进行协调管理,同时在机器扩展时无需将整个集群停机)。
-
多客户端支持(Kafka 核心模块用Scala 语言开发,但提供多种开发语言接入,包括Java,Python等)。
-
安全机制(支持代理与ZooKeeper 连接身份验证,客户端读、写权限认证)。
-
数据备份(Kafka 可以为每个主题指定副本数,对数据进行持久化备份)。
-
轻量级(Kafka 的实例是无状态的,同时集群本身几乎不需要生产者和消费者的状态信息)。
-
消息压缩(Kafka 支持Gzip, Snappy 、LZ4 这3 种压缩方式,把多条消息压缩成MessageSet)。
1.3、消息队列有什么用?
-
解耦,异构
2、Kafka的架构
-
Kafka Cluster:由多个服务器组成。每个服务器单独的名字broker(掮客)。
-
Kafka Producer:生产者、负责生产数据。
-
Kafka consumer:消费者、负责消费数据。
-
Kafka Topic: 主题,一类消息的名称。存储数据时将一类数据存放在某个topci下,消费数据也是消费一样。
-
ZooKeeper:Kafka的元数据都是存放在zookeeper中。
3、操作Kafka集群的两种方式
3.1、使用控制台运行 Kafka
-
创建一个topic(主题):
bin/kafka-topics.sh --create --zookeeper zk01:2181 --replication-factor 1 --partitions 1 --topic order
-
启动一个生产者,用来生产数据 :
bin/kafka-console-producer.sh --broker-list kafka01:9092 --topic order
-
启动给一个消费者,消费数据:
bin/kafka-console-consumer.sh --zookeeper zk01:2181 --from-beginning --topic order
3.2、使用JavaAPI操作Kafka
-
JavaAPI操作Kafka所需要的依赖:
<groupId>org.apache.kafka</groupId> <artifactId>kafka-clients</artifactId> <version>0.11.0.1</version>
-
生产者相关操作:
//创建Properties配置参数对象,并设置参数 Properties props = new Properties(); props.put("bootstrap.servers", "node01:9092"); props.put("acks", "all"); //创建一个KafkaProducer,Kafka生产者对象 KafkaProducer<String, String> kafkaProducer = new KafkaProducer<String, String>(props); for (int i = 0; i < 1000; i++) { // 发送数据 ,需要一个producerRecord对象,最少参数 String topic, V value kafkaProducer.send(new ProducerRecord<String, String>("order", "订单信息!"+i)); Thread.sleep(100); } }
-
消费者相关操作:
// 1、创建配置参数对象,并连接集群 Properties props = new Properties(); props.put("bootstrap.servers", "node01:9092"); props.put("group.id", "test"); props.put("enable.auto.commit", "true"); props.put("auto.commit.interval.ms", "1000"); props.put("key.deserializer","org.apache.kafka.common.serialization.StringDeserializer"); props.put("value.deserializer","org.apache.kafka.common.serialization.StringDeserializer"); //2、创建Kafka的消费者对象 KafkaConsumer<String, String> kafkaConsumer = new KafkaConsumer<String, String>(props); //3、订阅一个主题,订阅主题需传入List格式 kafkaConsumer.subscribe(Arrays.asList("order")); //4、使用死循环不停拉取数据 while (true) { ConsumerRecords<String, String> consumerRecords = kafkaConsumer.poll(100); for (ConsumerRecord<String, String> record : consumerRecords) { System.out.println("消费的数据为:" + record.value()); } }
-
topic相关操作:
由于主题的元数据信息是注册在 ZooKeeper 相应节点之中,所以对主题的操作实质是对ZooKeeper中记录主题元数据信息相关路径的操作。Kafka将对ZooKeeper的相关操作封装成一 个ZkUtils 类,井封装了一个AdrninUtils类调用ZkClient类的相关方法以实现对 Kafka 元数据 的操作,包括对主题、代理、消费者等相关元数据的操作。对主题操作的相关API调用较简单,相应操作都是通过调用AdminUtils类的方法来完成的。
-
创建topic(一般常用方法一):
方法一: //参数:zookeeper的地址,session超时时间,连接超时时间,是否启用zookeeper安全机制 zkUtils = ZkUtils.apply("node01:2181", 30000, 3000, JaasUtils.isZkSecurityEnabled()); 方法二: //参数:zkUtils,topic名称,partition数量,副本数量,参数,机架感知模式 AdminUtils.createTopic(zkUtils, topicName, 1, 1, new Properties(), AdminUtils.createTopic$default$6());
-
删除topic:
//参数:zkUtils,topic名称,partition数量,副本数量,参数,机架感知模式 AdminUtils.deleteTopic(zkUtils, topicName);
-
判断是否存在:
AdminUtils.topicExists(zkUtils, topicName);
-
4、Apache Kafka的工作原理
4.1、分片与副本机制
-
分区:当数据量非常大的时候,一个服务器存放不了,就将数据分成两个或者多个部分,存放在多台服务器上。每个服务器上的数据,叫做一个分区。
-
副本:当数据只保存一份时,有丢失风险。为了更好的容错和容灾,将数据拷贝几份,保存到其他机器上。
-
设置分区和副本的方法:
-
控制台上:--replication-factor 1 --partitions 3
-
API代码:AdminUtils.createTopic(zkUtils, topicName, 3, 1, new Properties(),
AdminUtils.createTopic$default$6());
-
4.2、消息不丢失机制
-
生产者消息不丢失机制:
-
发送消息的同步和异步模式:
-
同步模式:生产者重试3次,如果还没有响应,就报错。生产者等待10S,如果broker没有给出ack响应,就认为失败。
-
异步模式:先将数据保存在生产者端的buffer中。Buffer大小是2万条。发送一批数据的大小是500条。满足数据阈值或者数量阈值其中的一个条件就可以发送数据。
-
-
消息确认的三个状态:
-
0状态:生产者只负责发送数据,不管Kafka的broker是否接收到数据;
-
1状态:某个partition的leader收到数据给出响应;
-
-1状态:某个partition的所有副本都收到数据后给出响应
-
-
-
Borker端消息不丢失机制:
broker端的消息不丢失,其实就是用partition副本机制来保证。Producer ack -1. 能够保证所有的副本都同步好了数据。其中一台机器挂了,并不影像数据的完整性。
-
消费者端消息不丢失:
如果有一个外部存储能够记录每个consumer消费partition的offset值。就不会造成数据丢失,只会有重复消费的可能。而在Kafka0.8以后,offset值可以存放到Kafka内置的topic中。
4.3、消息存储和查询机制
4.3.1、消息存储机制
-
Kafka作为消息中间件,只负责消息的临时存储,并不是永久存储,需要删除过期的数据;
-
如果一个partition中有10T数据,是如何存放的?是存放在一个文件中,还是存放在多个文件中?
Kafka时采用存储到多个文件中的方式。因为如果将所有数据都存放在一个文件中,需要删除过期数据的时候,就比较麻烦。因为文件有日期属性,删除过期数据,只需要根据文件的日期属性删除就好。
-
Kafka的数据是存储在/export/data/kafka(可以自己设置)目录下,存储时是将数据划分为一个个的segment段,在segment段中有两个核心的文件,一个是log,一个是index。当log文件等于1G时,新的会写入到下一个segment中。
4.3.2、消息查询机制
-
在Kafka中进行消息查询时,首先会查找segment中的index索引文件,index索引文件是以起始来命名的,根据查询索引文件能很快的定位到具体文件。
-
当根据index索引文件定位到需要查询的具体文件时,就会去查找log文件,在该文件中按顺序查找到目标文件
4.4、生产者数据分发策略
-
kafka在数据生产的时候,有一个数据分发策略。默认的情况使用DefaultPartitioner.class类。如果用户制定了partition,生产就不会调用DefaultPartitioner.partition()方法。
-
当用户指定key,就会使用hash算法来确定发往那个patition。如果key一直不变,同一个key算出来的hash值是个固定值。如果是固定值,这种hash取模就没有意义。
例:Utils.toPositive(Utils.murmur2(keyBytes)) % numPartitions
-
还可以指定将数据发往哪个partition。当ProducerRecord 的构造参数中有partition的时候,就可以发送到对应partition上。
例:public ProducerRecord(String topic, Integer partition, K key, V value)
-
如果既没有指定partition,也没有key的情况下,那就使用轮询的方式发送数据。
4.5、消费者的负载均衡机制
一个partition只能被一个组中的成员消费。所以如果消费组中有多于partition数量的消费者,那么一定会有消费者无法消费数据。如果消费组中的消费组小于partition,那么消费的数据就不完整,会造成错误。
5、Spring-Kafka
5.1、Spring-Kafka的概述和依赖
-
概述:Spring对kafka做了支持,以便简化我们的开发工作,官网:Spring for Apache Kafka
-
依赖:
<dependency> <groupId>org.springframework.kafka</groupId> <artifactId>spring-kafka</artifactId> <version>2.1.7.RELEASE</version> </dependency> <dependency> <groupId>org.springframework</groupId> <artifactId>spring-test</artifactId> <version>5.0.6.RELEASE</version> </dependency>
5.2、Spring-Kafka生产者示例代码
第一步:编写application-kafka-producer.xml文件
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns:context="http://www.springframework.org/schema/context"
xsi:schemaLocation="http://www.springframework.org/schema/beans
http://www.springframework.org/schema/beans/spring-beans.xsd
http://www.springframework.org/schema/context
http://www.springframework.org/schema/context/spring-context.xsd">
<bean id="producerConfig" class="java.util.HashMap">
<constructor-arg>
<map>
<entry key="bootstrap.servers" value="node01:9092,node02:9092"/>
<!--设置json序列化-->
<entry key="key.serializer" value="org.springframework.kafka.support.serializer.JsonSerializer"/>
<entry key="value.serializer" value="org.springframework.kafka.support.serializer.JsonSerializer"/>
</map>
</constructor-arg>
</bean>
<!-- 定义生产者的工厂 -->
<bean id="producerFactory" class="org.springframework.kafka.core.DefaultKafkaProducerFactory">
<constructor-arg ref="producerConfig"/>
</bean>
<!-- 定义KafkaTemplate,通过KafkaTemplate即可实现发送消息等功能 -->
<bean class="org.springframework.kafka.core.KafkaTemplate">
<constructor-arg index="0" ref="producerFactory"/>
<!--指定默认的topic-->
<property name="defaultTopic" value="my-kafka-topic"/>
</bean>
</beans>
第二步:编写java代码 TestSpringKafkaProducer
//类上方添加如下注释
@RunWith(SpringJUnit4ClassRunner.class)
@ContextConfiguration(value = {"classpath:application-kafka-producer.xml"})
//注入一个KafkaTemplate对象
@Autowired
private KafkaTemplate kafkaTemplate;
//使用注入的对象发送数据到Kafka(发送的数据可以是对象,会自动进行json转换)
kafkaTemplate.sendDefault(order);
5.3、Spring-Kafka消费者示例代码
第一步:编写application-kafka-consumer.xml文件
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns:context="http://www.springframework.org/schema/context"
xsi:schemaLocation="http://www.springframework.org/schema/beans
http://www.springframework.org/schema/beans/spring-beans.xsd
http://www.springframework.org/schema/context
http://www.springframework.org/schema/context/spring-context.xsd">
<bean id="consumerConfig" class="java.util.HashMap">
<constructor-arg>
<map>
<entry key="bootstrap.servers" value="node01:9092,node02:9092"/>
<entry key="group.id" value="my-group-spring-spring-3"/>
<entry key="client.id" value="my-test-client-spring-3"/>
<entry key="enable.auto.commit" value="true"/>
<entry key="auto.commit.interval.ms" value="1000"/>
<!--反序列化器,这里要注意设置的是字符串的反序列化-->
<entry key="key.deserializer" value="org.apache.kafka.common.serialization.StringDeserializer"/>
<entry key="value.deserializer" value="org.apache.kafka.common.serialization.StringDeserializer"/>
</map>
</constructor-arg>
</bean>
<!-- 定义消费者的工厂 -->
<bean id="consumerFactory" class="org.springframework.kafka.core.DefaultKafkaConsumerFactory">
<constructor-arg ref="consumerConfig"/>
</bean>
<!--定义消息监听器,用于接收消息-->
<bean id="myMessageListener" class="cn.itcast.kafka.MyMessageListener"/>
<bean id="containerProperties" class="org.springframework.kafka.listener.config.ContainerProperties">
<!--设置消费的topic,这里可以指定多个topic-->
<constructor-arg value="my-kafka-topic" type="java.lang.String[]"/>
<property name="messageListener" ref="myMessageListener"/>
</bean>
<!--创建Listener容器-->
<bean class="org.springframework.kafka.listener.KafkaMessageListenerContainer" init-method="start">
<constructor-arg index="0" ref="consumerFactory"/>
<constructor-arg index="1" ref="containerProperties"/>
</bean>
</beans>
第二步:创建一个类,注入上述配置文件即可接收
@RunWith(SpringJUnit4ClassRunner.class)
@ContextConfiguration(value = {"classpath:application-kafka-consumer.xml"})
public class TestSpringKafkaConsumer {
@Test
public void testConsumer() {
}
}
6、Kafka和Kafka-manager
-
Kafka Manager 由 yahoo 公司开发,该工具可以方便查看集群 主题分布情况,同时支持对 多个集群的管理、分区平衡以及创建主题等操作。
-
Kafka和Kafka-manager的详细安装和部署,请详看其安装部署文件。
-
启动Kafka-manager:
cd /export/servers/kafka-manager-1.3.3.17/bin ./kafka-manager -Dconfig.file=../conf/application.conf
注:其他相关文章链接由此进 -> 大数据基础知识点 文章汇总