kafka笔记(待整理)

本文详细介绍了Kafka的生产者和消费者的工作原理,包括异步传输提高效率、解耦合的设计、消息队列的削峰填谷功能。讨论了生产者的分区策略、确认策略以及配置参数,同时阐述了消费者的分区分配策略和数据一致性保证。此外,还涉及了Zookeeper在Kafka中的角色以及消费者组的管理。
摘要由CSDN通过智能技术生成

学习来源

尚硅谷

作用

1 异步,发送方发送完数据可以直接结束,而不用等服务器响应,提高效率
2 解耦,发送方和服务器之间接触绑定,使代码更清晰
3 削峰,消息队列有缓存功能,服务器可以根据自己的处理能力,而策略性地获取消息队列里的数据

先决条件

Linux NAT配置,Zookeeper集群,JDK配置,Kafka服务端安装
maven kafka 3.0 kafka-client

架构

生产者 ->缓存 -> broker -> 缓存-> 消费者

生产者模块

生产者流程

请添加图片描述
假设来了一个较大的对象,首先根据分区策略一批一批往Queue(也就是图中分区缓存)里面放入,满足一定推送条件,select线程会往broker推送。如果这一批和之前顺序正常,就会落盘,然后根据确认策略返回ack,顺序不正常,就会先放置而不落盘。一个分区对应的broker缓存最多可以存五批,如果没有到5批,允许select线程继续发送,如果到达了5批,就必须等待ack才能继续发送。

配置文件

bootstrap.server 选择消息队列主机,一般为了高可靠性,会选择两台及以上
serializer key/value 用于把传输数据给序列化成字节数组,需要key型和value型都配置
batch_size 批次大小,达到大小会直接发送
linger_ms 等待时长,达到时间会直接发送
compression 序列化后压缩形式,gzip、snappy、lz4 和 zstd
buffer_memory 缓存大小
partitioner 注册自定义策略,策略类需要实现partitioner接口

分区传输策略

如果指定分区,直接选择
如果没有指定,有key,使用hash选择
如果不指定,没有key,完全传输完一个分区之后才到下一个
除此之外,也可以自己重写策略类,并装入properties中

send传输

调用send方法,可以选择回调与否

kafkaProducer.send(new ProducerRecord<>("first", 
"atguigu " + i), new Callback() {
	@Override
	public void onCompletion(RecordMetadata metadata, Exception e) {
		if (e == null){
			System.out.println(" 主题: " + 
			metadata.topic() + "->" + "分区:" + metadata.partition()
		);
		}else {
			e.printStackTrace();
		}
	}
});

demo

import org.apache.kafka.clients.producer.KafkaProducer;
import org.apache.kafka.clients.producer.ProducerRecord;
import java.util.Properties;
public class CustomProducerParameters {
 public static void main(String[] args) throws 
InterruptedException {
	// 1. 创建 kafka 生产者的配置对象
	Properties properties = new Properties();
	
	// 2. 给 kafka 配置对象添加配置信息:bootstrap.servers
	properties.put(ProducerConfig.BOOTSTRAP_SERVERS_CONFIG, 
	"hadoop102:9092");
	
	// key,value 序列化(必须):key.serializer,value.serializer
	properties.put(ProducerConfig.KEY_SERIALIZER_CLASS_CONFIG, 
	"org.apache.kafka.common.serialization.StringSerializer");
	properties.put(ProducerConfig.VALUE_SERIALIZER_CLASS_CONFIG, 
	"org.apache.kafka.common.serialization.StringSerializer");
	
	// batch.size:批次大小,默认 16K
	properties.put(ProducerConfig.BATCH_SIZE_CONFIG, 16384);
	// linger.ms:等待时间,默认 0
	properties.put(ProducerConfig.LINGER_MS_CONFIG, 1);
	// RecordAccumulator:缓冲区大小,默认 32M:buffer.memory
	properties.put(ProducerConfig.BUFFER_MEMORY_CONFIG, 
	// compression.type:压缩,默认 none,可配置值 gzip、snappy、lz4 和 zstd
	properties.put(ProducerConfig.COMPRESSION_TYPE_CONFIG,"snappy");
	


	// 3. 根据之前属性创建 kafka 生产者对象
	KafkaProducer<String, String> kafkaProducer = new 
	KafkaProducer<String, String>(properties);
	// 4. 调用 send 方法,发送消息
	for (int i = 0; i < 5; i++) {
		kafkaProducer.send(new ProducerRecord<>("first","atguigu " + i));
	}
	// 5. 关闭资源
	kafkaProducer.close();
	}
}

确认策略

ack = 0,-1,1

ack = 0,生产者发送数据就不管了,可靠性差,效率低
ack = 1,会等待Leader提交后的应答,可以给一些允许个别丢失的数据设置,比如一些普通日志
ack = -1,会等待全部副本提交后等待应答,一般数据级别

完全可靠条件为: ack = -1,isr > 1,partition > 1

数据顺序问题

幂等性保证数据会话内不重复,通过pid(Producer ID),分区号,序列号来标识唯一批,PID是每台生产者生产时被分配的,如果pid和序列号组合已经出现过,就会去掉这个数据

而对于数据顺序问题

broker模块

服役和退役

先新建一个脚本,写入要更新的主题和它的brokerId
然后使用指令创造随机方案,满意后使用指令重新编排主机
达到服役和退役的效果,只需要在brokerId中删除或增加

Zookeeper的作用

ids 保存所有在线的brokerId
controller 保存目前Leader信息

Leader选举

AR=ISR+OSR
ISR是保证能和Leader同步的主机,包括Leader。OSR是不能和Leader同步的
Leader是AR中最前面,且在ISR中的节点
它会将自己的节点数据保存在zookeeper的controller模块

AR顺序

一开始是1234,然后会开始隔一个变成2341,然后再隔一个3412

一致性的保证

只有Leader可以读写,由它完成同步任务

通过HW和LEO(Log End Offset)来保证故障后的一致性,LEO是完成了落盘的数据最后offset的位置+1,也就是正在读取的位置,HW是全部副本最小的LEO
如果Leader故障,Follower会成为Leader,然后以自己设置为新的HW,如果目前HW高于自己,所有主机都会丢弃这部分,如果低于自己,就会跟上Leader
如果follower故障,follower重新上线时,会根据目前HW,把自己上次HW数据多读的数据都丢弃,然后去同步Leader的数据

文件策略

删除或压缩
删除有根据时间删除或者根据大小删除,一般是根据时间
压缩就是把相同key的数据合并,合并之后,会保留最后一次的offset,所以如果要取某个offset之后的数据,会往后找

高速传输

零拷贝-直接从内核缓存读到网卡,而不经过应用层,把数据处理交给消费者和生产者
追加读,每次读到log后面,这样可以保证顺序读而减少磁头移动时间

消费者模块

流程

先通过id%50获得自己的coodinate,向coordinate申请加入组
使用随机算法获得一个消费者作为Leader,并告知coodinate
coodinate把这个topic的分区情况告诉Leader
Leader制定好分配策略,将策略发给coordinate
coordinate发给组内所有consumer
consumer根据策略读取数据

如果消费者一段时间不应答Leader,或者一段时间没有读完数据,会被判定为无效消费者,那么就会把它剔除出消费者组,并重新分配它负责分区。后续如果还有任务也不会再分配给它,除非重新加入。
在读的过程中broker会随着consumer的读取进度移动offset,并且在固定一个时间段后就提交一次

消费组

每个消费者组都有自己的groupId,有的只有一个groupId,有的却有很多个,同一组的消费者不能消费其它消费者已经消费的分区,如果消费者少,那么一个消费者会负责多个分区,如果消费者多,那么会有空闲的消费者。

分区分配策略

range

根据分区数/消费者数=每个消费者需要读取分区数,如果除不尽,就将余数n分给前n个消费者
它会先把消费者A要完成的分区全给A,再到B,比如 1,2,3 给A;4,5,6 给B
如果某个消费者被判定为无效消费者,会把它的所有负责分区交给下一个消费者

缺点是在有余数时,前n个消费者任务重于其余消费者,这种行为被称为数据倾斜
并且失败的消费者会让下一个消费者压力骤增

轮询

将分区一个一个分给消费者,比如1给A,2给B,3给C,4给A,按顺序一直给
如果某个消费者被判定为无效消费者,会把它的所有负责分区一个一个交给其余消费者
在生产环境用得较多

sticky

根据分区数/消费者数=每个消费者需要读取分区数,如果除不尽,就将余数n分给前n个消费者
和分区不同的是,它会随机将每个分区给某个消费者,比如将1号随机给B,又将2号随机给A,直到消费者满了才会停止随机到该消费者
如果某个消费者被判定为无效消费者,会把它的所有负责分区随机交给其余消费者

数据读取方式方式

推:固定速率,对于kafka不合适
拉:根据客户端自身传输速率来选择,可能造成长期io阻塞等待,但比较适合

offset设置

kafka0.9后,offset以<groupId,topicId,partition>保存在系统主题中
默认5秒自动提交一次
可以更改为手动提交,也可以更改自动提交频率

  • 24
    点赞
  • 24
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值