java - 在 Spark 执行器上向 Kafka 提交偏移量

标签 java apache-spark elasticsearch apache-kafka

我从 Kafka 获取事件,在 Spark 上丰富/过滤/转换它们,然后将它们存储在 ES 中。我将偏移量提交回 Kafka

我有两个问题:

(1) 我当前的 Spark 作业非常慢

我有 50 个主题分区和 20 个执行程序。每个执行器有 2 个核心和 4g 内存。我的驱动有8g内存。我每秒消耗 1000 个事件/分区,并且我的批处理间隔为 10 秒。这意味着,我在 10 秒内消耗了 500000 个事件

我的ES集群如下:

20 个分片/索引

3 个主实例 c5.xlarge.elasticsearch

12 个实例 m4.xlarge.elasticsearch

磁盘/节点 = 1024 GB,因此总共 12 TB

我遇到了巨大的调度和处理延迟

(2) 如何在执行器上提交偏移量?

目前,我在执行器上丰富/转换/过滤我的事件,然后使用 BulkRequest 将所有内容发送到 ES。这是一个同步过程。如果我得到积极的反馈,我会将偏移列表发送给驱动程序。如果没有,我会发回一个空列表。在驱动程序上,我向 Kafka 提交偏移量。我相信,应该有一种方法,我可以在执行器上提交偏移量,但我不知道如何将 kafka Stream 传递给执行器:

((CanCommitOffsets) kafkaStream.inputDStream()).commitAsync(offsetRanges, this::onComplete);

这是向 Kafka 提交偏移量的代码,需要 Kafka Stream

这是我的整体代码:

 kafkaStream.foreachRDD( // kafka topic
                rdd -> { // runs on driver
                    rdd.cache();
                    String batchIdentifier =
                            Long.toHexString(Double.doubleToLongBits(Math.random()));

                    LOGGER.info("@@ [" + batchIdentifier + "] Starting batch ...");

                    Instant batchStart = Instant.now();

                    List<OffsetRange> offsetsToCommit =
                            rdd.mapPartitionsWithIndex( // kafka partition
                                    (index, eventsIterator) -> { // runs on worker

                                        OffsetRange[] offsetRanges = ((HasOffsetRanges) rdd.rdd()).offsetRanges();

                                        LOGGER.info(
                                                "@@ Consuming " + offsetRanges[index].count() + " events" + " partition: " + index
                                        );

                                        if (!eventsIterator.hasNext()) {
                                            return Collections.emptyIterator();
                                        }

                                        // get single ES documents
                                        List<SingleEventBaseDocument> eventList = getSingleEventBaseDocuments(eventsIterator);

                                        // build request wrappers
                                        List<InsertRequestWrapper> requestWrapperList = getRequestsToInsert(eventList, offsetRanges[index]);

                                        LOGGER.info(
                                                "@@ Processed " + offsetRanges[index].count() + " events" + " partition: " + index + " list size: " + eventList.size()
                                        );

                                        BulkResponse bulkItemResponses = elasticSearchRepository.addElasticSearchDocumentsSync(requestWrapperList);

                                        if (!bulkItemResponses.hasFailures()) {
                                            return Arrays.asList(offsetRanges).iterator();
                                        }

                                        elasticSearchRepository.close();
                                        return Collections.emptyIterator();
                                    },
                                    true
                            ).collect();

                    LOGGER.info(
                            "@@ [" + batchIdentifier + "] Collected all offsets in " + (Instant.now().toEpochMilli() - batchStart.toEpochMilli()) + "ms"
                    );

                    OffsetRange[] offsets = new OffsetRange[offsetsToCommit.size()];

                    for (int i = 0; i < offsets.length ; i++) {
                        offsets[i] = offsetsToCommit.get(i);
                    }

                    try {
                        offsetManagementMapper.commit(offsets);
                    } catch (Exception e) {
                        // ignore
                    }

                    LOGGER.info(
                            "@@ [" + batchIdentifier + "] Finished batch of " + offsetsToCommit.size() + " messages " +
                                    "in " + (Instant.now().toEpochMilli() - batchStart.toEpochMilli()) + "ms"
                    );
                    rdd.unpersist();
                });

最佳答案

您可以将偏移逻辑移至 rdd 循环上方...我使用下面的模板以获得更好的偏移处理和性能

JavaInputDStream<ConsumerRecord<String, String>> kafkaStream = KafkaUtils.createDirectStream(jssc,
                LocationStrategies.PreferConsistent(),
                ConsumerStrategies.<String, String>Subscribe(topics, kafkaParams));



        kafkaStream.foreachRDD( kafkaStreamRDD -> {
            //fetch kafka offsets for manually commiting it later
            OffsetRange[] offsetRanges = ((HasOffsetRanges) kafkaStreamRDD.rdd()).offsetRanges();

            //filter unwanted data
            kafkaStreamRDD.filter(
                    new Function<ConsumerRecord<String, String>, Boolean>() {
                @Override
                public Boolean call(ConsumerRecord<String, String> kafkaRecord) throws Exception {
                    if(kafkaRecord!=null) {
                        if(!StringUtils.isAnyBlank(kafkaRecord.key() , kafkaRecord.value())) {
                            return Boolean.TRUE;
                        }
                    }
                    return Boolean.FALSE;
                }
            }).foreachPartition( kafkaRecords -> {

                // init connections here

                while(kafkaRecords.hasNext()) {
                    ConsumerRecord<String, String> kafkaConsumerRecord = kafkaRecords.next();
                    // work here
                }

            });
            //commit offsets
            ((CanCommitOffsets) kafkaStream.inputDStream()).commitAsync(offsetRanges);
        });

关于java - 在 Spark 执行器上向 Kafka 提交偏移量,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/58131904/

相关文章:

c# - 在Elastic/Nest 6+中滚动和分页

elasticsearch - 设置大小对性能的影响

java - AWS Managed ElasticSearch 上的 Elastic Transport 客户端

java - Python 中的++i 运算符

Java 继承 - 请解释

java - 使用 JSoup,你能得到 html 中节点的位置/索引吗?

JavaIO : Using scanner and printWriter to copy the contents of a text file and put them in another text file

java - 无法使用 Java 启动 Spark

apache-spark - Spark ML 中的 Param[] 和 Params[] 是什么

eclipse - Scala Word计数 jar 未在 Spark 中运行