Kafka 笔记01

0 背景

最近接手了几个接口的维护工作,涉及到Kafka的相关知识.于是我恶补了之前简单过了一遍的《Kafka权威指南》,结合我自己了解到的部门的Kafka情况,总结了一些知识点。个人感触是,结合实际,才能更好理解知识点。之前一味啃书,只能说囫囵吞枣;在实际中使用+review知识,让我对Kafka架构的了解更加深入。本篇只更新到消费者的配置部分,后续会继续不定期更新。

1 生产者

我们需要关注的:消息的丢失?消息的重复?消息的重复?延迟和吞吐量?

1.1 生产者概览

假如我们发送北京上海广州和西安的数据,这包含了目标主题,内容,分区;
首先创建对象,并序列化成为字节数组
然后数据传送给分区器。
我们这里以北京为例,选好分区后,数据分别发送给北京城六区分区0和郊区分区1
服务器收到消息后,返回响应
在这里插入图片描述

1.2 创建kafka生产者

这里生产者需要一些必选属性:
bootstrap.servers 地址清单
key.serializer key的序列化器
value.serializer value的序列化器
定义语句如下

private Properties kafkaProps = new Properties();

kafkaProps.put("bootstrap.servers", "broker1:9092,broker2:9092");

kafkaProps.put("key.serializer", "org.apache.kafka.common.serialization.StringSerializer");

kafkaProps.put("value.serializer", "org.apache.kafka.common.serialization.StringSerializer");

producer = new KafkaProducer<String, String>(kafkaProps); 

1.3 发送消息三种方式:

发送并且忘记,不关心是否达到
同步发送,等待消息抵达的回信
异步发送

1.4 生产者的其他配置

acks 参数指定了必须要有多少个分区副本收到消息,生产者才会认为消息写入是成功的
0, 不需要等待,发过去就默认抵达
1, 只要leader收到消息,生产者收到成功响应
all, 所有参与复制的节点全部收到消息,生产者收到成功响应
buffer.memory 生产者内存缓冲区的大小
compression.type 压缩类型
retries 生产者重发消息的次数
retry.backoff.ms 重发消息的时间间隔
batch.size 一个批次可以使用的内存大小,按照字节计数
linger.ms 等待更多消息加入批次的时间
client.id 消息来源
max.in.flight.requests.per.connection 生产者在收到服务器响应之前可以发送多少个消息.它的值越高,就会占用
越多的内存,不过也会提升吞吐量.
timeout.ms 生产者在发送数据时等待服务器返回响应的时间
request.timeout.ms 生产者在获取元数据(比如目标分区的首领是谁)时等待服务器返回响应的时间

1.5 序列化器

许多其他框架都涉及了序列化器,比如Hive,就有相关内容

1.6 分区

ProducerRecord 对象包含了目标主题,键和值.
Kafka消息是一个个键值对,Map格式. ProducerRecord对象可以只包含目标主题和值,键可以为null
键:作为消息的附加信息,或者确定分区;键包含了相同分区信息会被分配到相同分区

ProducerRecord<Integer, String> record = new ProducerRecord<>("CustomerCountry", "Laboratory Equipment", "USA");

ProducerRecord<Integer, String> record =new ProducerRecord<>("CustomerCountry", "USA");

如果键值为 null,并且使用了默认的分区器,那么记录将被随机地发送到主题内各个可用的分区上.分区器使用轮询(Round Robin)算法将消息均衡地分布到各个分区上.

同一个键总是被映射到同一个分区上,所以在进行映射时,我们会使用主题所有的分区,而不仅仅是可用的分区.这也意味着,如果写入数据的分区是不可用的,那么就会发生错误.
只有在不改变主题分区数量的情况下,键与分区之间的映射才能保持不变.

在这里插入图片描述
如我们的图所示,北上广西安四个城市的数据,分为4个topic,北上广西安;北京上海广州分别包含了2个partition,这里按照各个区分成2个partition;西安只有一个partition;
然后,3个broker,分别是leader和follwer;

2 消费者

2.1 消费者概念

如我们的图所示,消费者可以分为几个消费者群组,一个群组订阅的是同一个主题,每一个消费者接收主题一部分分区(或者全部分区)的消息.
我们的图中,包括北上广西安四个topic;北上广包括2个partition,西安只有1个partition;消费者群组,北上1个群组包括2个消费者;广西安1个消费者群组只有1个消费者
因此,北上的1个消费者只消费一个分区;广州的消费者消费2个分区,西安消费1个;

消费者群组:北京的消费者群组,都消费北京的GDP;
在均衡:现在广州的GDP溢出了,1个消费者消费不了,需要需要加一个消费者分担一下;那么整个广州的GDP需要再均衡;其实这样是不太好的,我们不太希望再平衡,更希望一开始就分配两个消费者分担

消费者向 群组协调器 broker, 掮客,中介,负责促成交易的人, 发送心跳(短信), 以表明自己还活着,可以继续消费;如果长时间不发送短信,中介会默认挂机,会重新分配GDP

2.2 创建消费者

3 个必要的属性: bootstrap.servers, key.deserializer 和 value.deserializer.

Properties props = new Properties();

props.put("bootstrap.servers", "broker1:9092,broker2:9092");

props.put("group.id", "CountryCounter");

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);

2.3 订阅主题

相当于,指定消费者去消费.比如,图中,李世民和李隆基负责北京片区;这里的消费,我们可以换成,管理.北京城六区由李世民负责管理;郊区由李隆基负责;这俩哥们是一个群组的;
上海浦东新区,刘彻管理;其他区,刘邦管理;这俩哥们是一个群组的;广州,朱元璋管理;西安,刘秀管理.

consumer.subscribe(Collections.singletonList("customerCountries")); 

调用 subscribe() 方法时传入一个正则表达式.正则表达式可以匹配多个主题,从而订阅多个主题

2.4 轮询

消息轮询是消费者 API 的核心,通过一个简单的轮询向服务器请求数据.

try {
	while (true) { 
		ConsumerRecords<String, String> records = consumer.poll(100); 
		for (ConsumerRecord<String, String> record : records) 
		{
			log.debug("topic = %s, partition = %s, offset = %d, customer = %s, country = %s\n", 
				record.topic(), record.partition(), record.offset(), record.key(), record.value());
			int updatedCount = 1;
			if (custCountryMap.countainsValue(record.value())) {
				updatedCount = custCountryMap.get(record.value()) + 1;
				}
			custCountryMap.put(record.value(), updatedCount)
			JSONObject json = new JSONObject(custCountryMap);
			System.out.println(json.toString(4)) 
		}
	}
} finally {
	consumer.close(); 
}

while true:这是一个无限循环.消费者实际上是一个长期运行的应用程序, 它通过持续轮询向 Kafka 请求数据
poll 消费者必须持续对 Kafka 进行轮询,否则会被认为已经死亡,它的分区会被移交给群组里的其他消费者.
传给poll() 方法的参数是一个超时时间,用于控制 poll() 方法的阻塞时间(在消费者的缓冲区里没有可用数据时会发生阻塞).
如果该参数被设为 0, poll() 会立即返回,否则它会在指定的毫秒数内一直等待 broker 返回数据.
poll() 方法返回一个记录列表.每条记录都包含了记录所属主题的信息、记录所在分区的信息、记录在分区里的偏移量,以及记录的键值对.

println()意味着把结果保存起来或者对已有的记录进行更新,处理过程也随之结束.
在退出应用程序之前使用 close() 方法关闭消费者.

2.5 消费者的配置

fetch.min.bytes 该属性指定了消费者从服务器获取记录的最小字节数

fetch.max.wait.ms feth.max.wait.ms 则用于指定 broker 的等待时间,默认是 500ms.

max.partition.fetch.bytes 该属性指定了服务器从每个分区里返回给消费者的最大字节数

session.timeout.ms 该属性指定了消费者在被认为死亡之前可以与服务器断开连接的时间

auto.offset.reset 该属性指定了消费者在读取一个没有偏移量的分区或者偏移量无效的情况下(因消费者长时间失效,包含偏移量的记录已经过时并被删除)该作何处理.

enable.auto.commit 是否自动提交偏移量,默认值是 true

partition.assignment.strategy range, round robin

client.id

max.poll.records 该属性用于控制单次调用 call() 方法能够返回的记录数量

receive.buffer.bytes 和 send.buffer.bytes socket 在读写数据时用到的 TCP 缓冲区也可以设置大小.

下半部分,见链接: Kafka 笔记02.

参考书籍:《Kafka权威指南》

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值