主要对一些名词进行说明讲解。
订阅模式:sub/pub和负载均衡
消费topic的对象是group。而具体的patition消费是由group中的consumer决定的。这是负载分摊。
如果有多个group都订阅了该topic,那么topic是以广播的形式将数据给所有的group。
确认消费
和TCP的ask请求相似。每次消费后,要向kafka发出一个ask的确认信息。
该确认信息是为了维护offset。一个是当前取消息所在的consume offset,一个是处理完毕,发送ack之后所确定的committed offset。也就是官方所说的偏移量和消费者的位置。偏移量是已经安全的被提交的最后偏移量,而消费者的位置则是通过poll的到的数据的偏移量,是已获得的最后一条数据的offset+1。
在异步情况下前者肯定是先于后者的。(获取信息->处理->发送确认)
那么如果出现了怠机,下一次消费会从committed offset开始。那就造成了重复消费。
应对重复消费应采用手动提交的方式。即props.put("enable.auto.commit", "false");
用consumer.commitSync()或者commitASync()手动发送ask信息,来达到效果。
值得注意的是,每次发来的一条信息,里面有多条数据,对所有数据处理完后,统一发送ask确认信息。
offset保存
尽管使用了ask同步保存,但是还是会出现非原子性操作带来的影响。所以offset最好由我们自己管理(官方建议)。
Consume message and record the topic partitions
ConsumerRecords<String, String> records = consumer.poll();
if (records != null && !records.isEmpty()) {
for (ConsumerRecord<String, String> record : records) {
TopicPartition tp = new TopicPartition(record.topic(), record.partition());
offsetMap.put(tp, record.offset());
}
}
因为怠机重启后,我们可以用consumser.seek函数进行数据offset的重新读取。它的两个参数是分区和offset。所以我们可以选择自己创建一个offsetMap来存储这两个量,每次消费结束后就保存。
consumer瓜分partition策略
当一个group订阅一个topic后,会得到该主题的所有分区。它也有对应的三种计算方法:
1.A=(partition数量/同分组消费者总个数)
2.M=对上面所得到的A值小数点第一位向上取整
3.计算出该消费者拉取数据的patition合集:Ci = [P(M*i ),P((i + 1) * M -1)]
对于consumers>partition,可由公式算出,一个分区对应一个consumers。但是有多余的consumer不能对应到分区,所以这些consumer不能消费主题
当consumers<partition,可以得出一个分区对应一个consumer。。
等于情况当然就是一个对一个了。
由这些就可以看出,分区就应该多与consumer,不然多余的consumer只占用资源却没有作用。
订阅内容
一般来说consumer订阅的都是整个topic,但是也可以制定主题中的某些分区。使用函数assign(Collection),参数放入指定的分区TopicPartition则可。但是手动分配和自动不能同时存在。
指定消费
kafka允许实时消费和过去消费。实时消费就跳过以前的数据,直接对目前的数据进行消费。而过去消费则是对那些存在磁盘上的内容进行消费,他们属于以前的数据。
kafka使用seek(TopicPartition, long)指定新的消费位置。用于查找服务器保留的最早和最新的offset的特殊的方法也可用(seekToBeginning(Collection) 和 seekToEnd(Collection))。
消费模式
一个topic可以被多个消费应用消费(该应用可能是一个消费者也可能是一个消费组),当一个topic被一个消费组消费的时候,每个分区只能被一个消费者(消费组中的某个消费者)消费。
往群组里增加消费者是横向伸缩消费能力的主要方式。 Kafka 消费者经常会做一些高延迟的操作,比如把数据写到数据库或 HDFS,或者使用数据进行比较耗时的计算。在这些情况下,单个消费者无法跟上数据生成的速度,所以可以增加更多的消费者,让它们分担负载,每个消费者只处理部分分区的消息,这就是横向伸缩的主要手段。我们有必要为主题创建大量的分区,在负载增长时可以加入更多的消费者。不过要性意,不要让消费者的数量超过主题分区的数量,多余的消费者只会被闲置。
除了通过增加消费者来横向伸缩单个应用程序外,还经常出现多个应用程序从同一个主题读取数据的情况。实际上, Kafka 设计的主要目标之一 ,就是要让 Kafka 主题里的数据能够满足企业各种应用场景的需求。在这些场景里,每个应用程序可以获取到所有的消息, 而不只是其中的 一部分。只要保证每个应用程序有自己的消费者群组,就可以让它们获取到主题所有的消息。不同于传统的消息系统,横向伸缩 Kafka消费者和消费者群组并不会对性能造成负面影响。
网友评论