第十四章 Kafka

14.1 Kafka架构 14.2 应用

14.1 Kafka架构

基于TCP,一个分布式流处理平台
处理大数据,scala编写高水平扩展,高吞吐量分布式消息系统

数据以Topic归类,Producer,Consumer
kafka集群由多个kafka实例组成,每个服务器称broker
依赖Zookeeper保证系统可用,为集群保存一些meta元信息
每条记录包含一个key,一个value和一个timestamp(保存文件,JAVA Object序列化)
kafka不支持事务,支持Zookeeper动态扩容,处理海量数据

4大API

Producers API (一个应用程序一串流式数据到一个或多个kafka topic)
Consumers API (一个应用程序订阅一个或多个topic,并对发布的流数据处理)
Stream API (一个应用程序作为一个流处理器,消费输入流,输入流到输出流有效转换)
Connectors API (允许构建并运行可重用的生产者或消费者,并将topic连到已存在程序或系统中(如连数据库,捕捉表变更内容))
后面具体介绍

Kafka类似AMQP协议

producer ->(push) broker (pull)<-  consumer

Topics

Topics是数据主题,数据记录发布的地方。
Topics总是多订阅模式,一个topic可以有一或多消费者订阅他数据

每个topic会维持一个分区(partition)日志
writes写入多个Partition
Parition1: 0 1 2 3 4 5 <--
Parition2: 0 1 2 3 4 <-- writes
Parition3: 0 1 2 3  <--

Paritition

0 1 2 3 4 5 6 <-- (producers writes追加7写入)
ConsumerA的offset可能为4,ConsumerB的offset可能为6

老版本offset存在Zookeeper中,zk压力太大。新版offset由消费者自己维护,zk记录最后一次offset

日志分区分布集群到多个服务器上,每个服务器处理它的分区。根据配置每个分区还可以复制到其他服务器上备份容错。每个分区有一个leader,零或多个follower。leader处理读写,follower被动复制数据。一台服务器可能同时一个分区leader,又是另一个分区follower来达到平衡负载。

Producers

负责发布到Topic上哪一个分区,开发者选择分区算法。默认Hash轮询

Consumers

在这里插入图片描述

1 所有消费者在同一个group中,消费记录会负载均衡每一个消费者实例
2 所有消费者不在同一group中,会广播所有消费者进程。Parition只对同一组group中一个消费者有效

架构

在这里插入图片描述

kafka支持点对点(1对1)模式,和发布订阅(多对多)模式

因为队列,所以顺序消费,每个partition只能由消费者group中一个消费者消费
一个paritition可以被不同group中两个消费者消费,但不能被同一个group中两个消费者消费

14.2 应用

服务器上kafka配置启动

1 下载kafka并解压

2 启动kafka
配置参数在文件中
	broker.id = ~
	log.dirs = ~ //kafka日志存放路径
	num.partitions= 1 //topic在当前broker上分区个数
	delete.topic.enable = true
	zookeeper.connect = localhost:2180 //zk集群地址
启动
	bin/kafka-server-start.sh config/server.properties (集群配置文件)

3 创建topic
	创建一个叫test的topic,配置一个分区,一个副本
	.>bin/kafka-topics.sh--create-zookeeper localhost:2180--replication(副本)--factor 1--partitions(分区) 1--topic test(名称)

4 发送消息
>bin/kafka-console-producer.sh --broker-list localhost:9092 --topic test
>输入hello

5 消费者接受消息
>bin/kafka-console-consumer.sh --bootstrap-server localhost:9092 --topic test --from-beginning
>输出hello

JAVA端应用

Producer

public static void producerSend(){
	Properties properties = new Properties();
	properties.put(ProducerConfig.BOOTSTRAP_SERVERS_CONFIG,"192.168.220.128:9092");
	properties.put(ProducerConfig.ACK_CONFIG,"all");
	properties.put(ProducerConfig.BATCH_SIZE_CONFIG,"1024");
	...//properties配置信息
	Producer<String,String> producer = new KafkaProducer<>(properties); //主对象
	ProducerRecord<String,String> record = new ~<>(TOPIC_NAME,0,"value"); //消息对象

	//1 正常发送消息
	producer.send(record);

	//2 future返回异步对线发送消息
	Future<RecordMetadata> send = producer.send(record);
	RecordMetadata record = send.get();
	System.out.println(record.partition()+record.offset());

	//3 异步回调发送
	producer.send(record,new Callback(){
		@Override
		~ onCompletion(RecordMetadata, Execption ~){
			//返回record.partition()和record.offset()
		}
	})
}

Producer简单源码

线程安全
1 MetricConfig配置信息
2 加载负载均衡器 (partition)
3 初始化Serializer (序列化)
4 初始化 RecordAccumlator 类似计数器
5 启动newSender 守护线程,线程安全,批量发送

producer.send(record)
	计算分区,消息进哪个分区
	计算批次,accumlator.append批量发送
	守护线程,批量到一定数量则发送

自定义分区负载均衡

properties.put(ProducerConfig.PARTITIONER_CLASS_CONFIG,"xxx.samplePartition");

public class samplePartition implements Partitioner{
	@Override{
		//具体逻辑
	}
}

消息传递保障

properties.put(ProducerConfig.ACK_CONFIG,"all");

ACK有 0,1,all三个选择
0表示发出后就不管了
1表示必须获得leader响应(如果follwer还未备份,leader挂了,数据会丢失)
all表示必须获得leader和follower的响应

Consumer

//1 自动提交
Properties props = new ~;
props.setProperty("bootstrap.servers","localhost:9092");
props.setProperty("group.id","test");
props.setProperty("enable.auto.commit","true");
...
KafkaConsumer<String,String> consumer = new ~(props);
//consumer.subscribe(某topic) 也可以订阅某topic下某个分区
while(true){
	ConsumerRecord<String,String> record = consumer.poll(Duration.ofMills(10000));
	输出记录offset key value
}

//2 手动提交
props.setProperty("enable.auto.commit","false");

while(true){
	ConsumerRecord<String,String> records = consumer.poll(Duration.ofMills(10000));
	for(ConsumerRecord<String,String> record:records){
		//保存数据到MYSQL,如果保存失败,则不提交		
		consumer.commitAsync();//保存成功则手动提交
	}
}

//手动提交offset并控制partition
while(true){
	ConsumerRecord<String,String> records = consumer.poll(Duration.ofMills(10000));
	for(TopicPartition partition : records.partitions()){//分区单独处理
		ConsumerRecord<String,String> pRecord = records.records(partition);
		for(ConsumerRecord<String,String> record : pRecord){
			//单个分区中offset并提交
			Map<TopicPartition,OffsetAndMetadata> offset = new ~;
			offset.put(partition,pRecord.get(pRecord.size()-1).offset()+1)
			consumer.commitSync(offset);
		}
	}
}
kafka Consumer线程不安全,需要自己解决
1 每个线程单独创建一个kafkaConsumer保证线程安全,但是会创建太多
2 用线程池

Consumer限流
	拿桶令牌

zookeeper会自动动态扩容

Kafka Stream

是处理分析存储在kafka数据客户端程序库,通过state store可高效状态操作。支持processor和高层抽象DSL

各种快捷的流操作

Kafka Connector

连接SQL等,下载connector包,配置mysql写入kafkaConnectSource,kafka可写入mysql

Kafka下领导者选举

kafka不是投票选举,因为大数据速度慢,分区消息也会不一致
kafka动态维护一组leader数据副本 (ISR), leader挂了后,ISP中谁和Zookeeper连接快谁当leader
如果leader和ISR都挂了,会unclean leader选举,一般禁用。手动知道最小ISR

相关问题

什么是Producer、Consumer、Broker、Topic、Partition?
ack三种机制
Zookeeper对于kafka作用
kafka高可用机制
上面都已经回答过

kafka如何不重复消费数据 -- 每个消费者会记录自己offset,zk也会保存他们最终offset
怎么保证消息队列消费的幂等性
	--偶尔offset失灵了,比如redis天然幂等,mysql可以检查是否已经存在这个数据
	--kafka也提供了保证幂等性的配置,会通过执行的唯一id和是否已执行过两个变量来处理。
	当配置事务时,自动开启幂等性配置

kafka分布式下如何保证消息顺序消费
	-一个topic只有一个partition,不推荐
	--通过相同key值定义,都是一个key可以保证都在同一个partition上并按照顺序排列

Kafka 如何保证消息不丢失 -- future异步/回调

kafka主从同步机制
	0.11版本前根据水位线,水位线代表所有从节点都已经同步到的数据点。之后改成leader epoch,主节点维护leader epoch并保存在zk中
	主未收到从fetch请求,或者一段时间仍赶上leader同步速度则剔除该从节点

kafka吞吐量高?
零拷贝,顺序写入(不是mysql那种插入写入),
每个log有专门index文件可以通过offset index快速定位
  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

我爱肉肉

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值