kafka核心介绍(版本:kafka_2.11-2.0.0.tgz)
(1)消息中间件(MQ)
--异步调用
同步变异步
--应用解耦
提供基于数据的接口层
--流量削峰
缓解瞬时高流量压力
(2)消息中间件的术语
Broker:消息服务器,提供核心服务
Producer:消息生产者
Consumer:消息消费者
Topic:主题,发布订阅模式下的消息统一汇集地
Queue:队列,P2P模式下的消息队列
(3)Apache Kafka
--Kafka是一种高吞吐量的分布式发布-订阅 消息系统,专为超高吞吐量的实时日志采集、实时数据同步、实时数据计算等场景来设计
快速,单Broker每秒几百MB读取
不停机扩集群
消息副本冗余
实时数据管道
--使用Scala编写
(4)Kafka Topic
Topic
主题是已发布消息的类别名称
发布和订阅数据必须指定主题
主题副本数量不大于Brokers个数
Partition
一个主题包含多个分区,默认按Key Hash分区
每个Partition对应一个文件夹<topic_name>-<partition_id>
每个Partition被视为一个有序的日志文件(LogSegment)
Replication策略是基于Partition,而不是Topic
每个Partition都有一个Leader,0或多个Followers
![在这里插入图片描述](https://i-blog.csdnimg.cn/blog_migrate/748a68021dcc199ef5d4567fabb5d54e.png)
(5)Kafka数据流
--副本同步
ISR(In-Sync Replica)
--容灾
Leader Partition
--高并发
--读写性能
Consumer Group
--负载均衡
![在这里插入图片描述](https://i-blog.csdnimg.cn/blog_migrate/3062b64e6edba4c09f85186681afed0f.png)
(6)ZooKeeper在Kafka中的作用
--Broker注册并监控状态
/brokers/ids
--Topic注册
/brokers/topics
--生产者负载均衡
每个Broker启动时,都会完成Broker注册过程,生产者会通过该节点的变化来动态地感知到Broker服务器列表的变更
--offset维护
Kafka早期版本使用ZooKeeper为每个消费者存储offset,由于ZooKeeper写入性能较差,从0.10版本后,Kafka使用自己的内部主题维护offset
(7)Kafka的高吞吐量是如何实现的
1.顺序读写
Kafka 的消息是不断追加到文件中的,这个特性使Kafka 可以充分利用磁盘的顺序读写性能。 顺序读写不需要硬盘磁头的寻道时间,只需很少的扇区旋转时间,所以速度远快于随机读写。
2.零拷贝
在 Linux kernel2.2 之后出现了一种叫做"零拷贝(zero-copy)"系统调用机制,就是跳过“用户 缓冲区”的拷贝,建立一个磁盘空间和内存的直接映射,数据不再复制到“用户态缓冲区”。
零拷贝并不是不需要拷贝,而是减少不必要的拷贝次数。通常是说在 IO 读写过程中。“零 拷贝技术”只用将磁盘文件的数据复制到页面缓存中一次,然后将数据从页面缓存直接发送 到网络中。
3.分区
Kafka 的队列 topic 被分为了多个区 partition,每个 partition 又分为多个段 segment,所以一 个队列中的消息实际上是保存在 N 多个片段文件中通过分段的方式,每次文件操作都是对 一个小文件的操作,非常轻便,同时也增加了并行处理能力。
4.批量发送
Kafka 允许进行批量发送消息,先将消息缓存在内存中,然后一次请求批量发送出去比如可 以指定缓存的消息达到某个量的时候就发出去,或者缓存了固定的时间后就发送出去如 100 条消息就发送,或者每 5 秒发送一次这种策略将大大减少服务端的 I/O 次数。
5.数据压缩
Kafka 还支持对消息集合进行压缩,Producer 可以通过 GZIP 或 Snappy 格式对消息集合进行 压缩压缩的好处就是减少传输的数据量,减轻对网络传输的压力。
6.Consumer 的负载均衡
当一个 group 中,有 consumer 加入或者离开时,会触发 partitions 均衡.均衡的最终目的,是提升 topic 的并发消费能力。
![在这里插入图片描述](https://i-blog.csdnimg.cn/blog_migrate/21ba61ccea018ed17d5b1c508b48b86f.png)
(8)Kafka操作命令
开启服务:(服务开启前必须先开启zookeeper服务:zkServer.sh start)
kafka-server-start.sh /opt/soft/kafka211/config/server.properties
开启服务:(守护者模式)
kafka-server-start.sh -daemon /opt/soft/kafka211/config/server.properties
查看主题列表:
kafka-topics.sh --zookeeper zhangqi:2181 --list
查看某主题信息描述:
kafka-topics.sh --zookeeper zhangqi:2181 --describe --topic test0818
创建主题topic-demo:
kafka-topics.sh --create --zookeeper zhangqi:2181 --replication-factor 1 --partitions 1 --topic AA
开启生产者:
kafka-console-producer.sh --broker-list zhangqi:9092 --topic AA
开启消费者:
kafka-console-consumer.sh --bootstrap-server zhangqi:9092 --from-beginning --topic AA
设置可以删除主题:server-properties
delete.topic.enable=true
删除主题
kafka-topics.sh --delete --zookeeper zhangqi:2181 --topic test20200819
查看某一主题的分区的文件大小
kafka-run-class.sh kafka.tools.GetOffsetShell --topic AA --time -1 --broker-list zhangqi:9092 --partitions 0
查看某一主题的所有分区的文件大小
kafka-run-class.sh kafka.tools.GetOffsetShell --topic AA --time -1 --broker-list zhangqi:9092
将同组的游标移到文件开头,使得同组用户可以重新读
kafka-consumer-groups.sh --bootstrap-server zhangqi:9092 --group customer --reset-offsets --all-topics --to-earliest --execute
(9)Java API
生产者(producer)
package cn.kgc.homework;
import org.apache.kafka.clients.producer.KafkaProducer;
import org.apache.kafka.clients.producer.ProducerConfig;
import org.apache.kafka.clients.producer.ProducerRecord;
import java.util.Properties;
public class ProducerLian05 {
public static void main(String[] args) {
//创建配置
Properties prop = new Properties();
//指定kafka服务器的地址
prop.put(ProducerConfig.BOOTSTRAP_SERVERS_CONFIG,"zhangqi:9092");
// acks 确保生产者可靠性设置 默认-1
// acks=0: 不等待成功返回
// acks=1: 等Leader写成功返回
// acks=all: 等Leader和所有ISR中的Follower写成功返回,all也可以用-1代替
prop.put(ProducerConfig.ACKS_CONFIG,"all");
//指定序列化,因为kafka接收的数据默认是键值对,如果不给键,则自动为Null
prop.put(ProducerConfig.KEY_SERIALIZER_CLASS_CONFIG,"org.apache.kafka.common.serialization.StringSerializer");
prop.put(ProducerConfig.VALUE_SERIALIZER_CLASS_CONFIG,"org.apache.kafka.common.serialization.StringSerializer");
//创建一个kafka producer
KafkaProducer<String,String> producer = new KafkaProducer<>(prop);
// 通过producer向topic发送数据
// Integer.toString(i)和"value"+i是因为producer的泛型所致<String,String>
for (int i = 0; i <100 ; i++) {
producer.send(new ProducerRecord<String,String>("test04",Integer.toString(i),"value"+i));
}
producer.close();
}
}
消费者(consumer)
package cn.kgc.homework;
import org.apache.kafka.clients.consumer.ConsumerConfig;
import org.apache.kafka.clients.consumer.ConsumerRecord;
import org.apache.kafka.clients.consumer.ConsumerRecords;
import org.apache.kafka.clients.consumer.KafkaConsumer;
import org.apache.kafka.common.TopicPartition;
import java.text.MessageFormat;
import java.util.Arrays;
import java.util.Properties;
public class ConsumerLian05 {
public static void main(String[] args) {
//创建配置
Properties prop = new Properties();
//kafka服务器配置
prop.put(ConsumerConfig.BOOTSTRAP_SERVERS_CONFIG,"zhangqi:9092");
//设置消费者的组
prop.put(ConsumerConfig.GROUP_ID_CONFIG,"test");
//反序列化,键值对
prop.put(ConsumerConfig.KEY_DESERIALIZER_CLASS_CONFIG,"org.apache.kafka.common.serialization.StringDeserializer");
prop.put(ConsumerConfig.VALUE_DESERIALIZER_CLASS_CONFIG,"org.apache.kafka.common.serialization.StringDeserializer");
//offset自动提交给zookeeper进行管理
prop.put(ConsumerConfig.ENABLE_AUTO_COMMIT_CONFIG,"true");
//自动提交offset的时间间隔:毫秒
prop.put(ConsumerConfig.AUTO_COMMIT_INTERVAL_MS_CONFIG,"5000");
//创建consumer对象
KafkaConsumer<String,String> consumer = new KafkaConsumer<String, String>(prop);
// 第一种消费方式:subscirbe消费者只能指定主题
// consumer.subscribe(Arrays.asList("test04"));
// 第二种消费方式:assign消费者既能指定主题,还能指定分区号
TopicPartition partition = new TopicPartition("test04",2);
consumer.assign(Arrays.asList(partition));
while(true){
//消费者用poll的方式去kafka拉取数据
ConsumerRecords<String, String> records = consumer.poll(1000);
for (ConsumerRecord<String, String> record : records) {
String message = MessageFormat.format("partition:{0},key:{1},value:{2}",record.partition(),record.key(),record.value());
System.out.println(message);
}
}
}
}