我们需要对弹性搜索执行批量写入。我们想知道是否有更好的批处理数据方式,并避免了批处理时数据丢失
public void consume() {
logger.debug("raw consume......");
String topic = "json.incoming";
String consGroup = "rConsumerGroup";
Properties props = new Properties();
props.put("enable.auto.commit", "false");
props.put("session.timeout.ms", "20000");
props.put("max.poll.records", "10000");
consumer = new GenericConsumer<String, JsonNode>().initialize(topic, consGroup, STREAMSERDE.STRINGDESER, STREAMSERDE.JSONDESER, props);
logger.debug("Kafka Consumer Initialized......");
buffer = new ArrayList<MessageVO>();
while (true) {
try {
ConsumerRecords<String, JsonNode> records = consumer.poll(100);
Date startTime = Calendar.getInstance()
.getTime();
if (records.count() == 0 && !buffer.isEmpty()) {
lastSeenZeroPollCounter++;
}
if (records.count() > 0) {
logger.debug(">>records count = " + records.count());
for (ConsumerRecord<String, JsonNode> record : records) {
logger.debug("record.offset() = " + record.offset() + " : record.key() = " + record.key());
JsonNode jsonMessage = record.value();
logger.debug("incoming Message = " + jsonMessage);
ObjectMapper objectMapper = new ObjectMapper();
MessageVO rawMessage = objectMapper.convertValue(jsonMessage, MessageVO.class);
logger.info("Size of the buffer is " + buffer.size());
buffer.add(rawMessage);
}
Date endTime = Calendar.getInstance()
.getTime();
long durationInMilliSec = endTime.getTime() - startTime.getTime();
logger.debug("Number of Records:: " + records.count() + " Time took to process poll :: " + durationInMilliSec);
}
if ((buffer.size() >= 1000 && buffer.size() <= 3000) || (buffer.size() > 0 && lastSeenZeroPollCounter >= 3000)) {
lastSeenZeroPollCounter = 0;
List<RawSyslogMessageVO> clonedBuffer = deepCopy(buffer);
logger.info("The size of clonedBuffer is ::: " + clonedBuffer.size());
writerService.writeRaw(clonedBuffer);
buffer.clear();
}
consumer.commitSync();
} catch (Throwable throwable) {
logger.error("Error occured while processing message", throwable);
throwable.printStackTrace();
}
}
}
用于克隆数据以避免丢失数据的代码
private List<MessageVO> deepCopy(List<MessageVO> messages) {
List<MessageVO> listOfMessages = new ArrayList<>();
logger.debug("DeepClone :: listOfMessages size ::: " + listOfMessages.size());
listOfMessages.addAll(messages);
return Collections.unmodifiableList(messages);
}
感谢您的帮助。谢谢。
答案 0 :(得分:1)
比自己编写更好的方法是使用Apache Kafka的Kafka Connect API-它是专门为从系统到Kafka的流集成以及从Kafka到其他系统的流集成而构建的:-)
Elasticsearch connector会将数据从Kafka主题流传输到Elasticsearch,并具有可配置的批处理大小等,以及一次精确的传递语义,可伸缩的处理等。
免责声明:我为Confluent工作。
答案 1 :(得分:0)
我们通过稍微简化应用程序的设计来处理相同的用例:我们基本上执行以下步骤
BatchAcknowledgingMessageListener
进行抓取
根据要求设置了max.poll.records
的记录通过采用这种简单的设计,我们意识到大多数批量提交将具有所需的记录数。对于Kafka主题没有为批量索引所需的记录数目多的消息的情况,我们决定在任何情况下都对单个访存中可用的任何内容进行索引,而不是在应用程序中显式处理提交状态,管理缓冲区等。
Elasticsearch批量提交是一种优化-我找不到任何理由可以精确说明每个单个批量请求的记录总数。 (也请参见this guide)。
PS:我们需要编写代码而不是使用连接器或现成的解决方案,因为我们的输入来自不同主题的多种主题,例如protobuf,zip XML,Json等,我们需要在进行索引之前进行格式转换和复杂的反序列化数据