我有一个基于事件的服务,该服务侦听Kafka主题并将状态保存在关系数据库中。
考虑此服务的适当还原策略(即,如何在灾难恢复方案中还原数据库),一种选择是将当前偏移量保存在数据库中,拍摄快照并从快照还原。在这种情况下,服务在“恢复模式”下启动时需要寻找偏移量。
我正在使用Spring Cloud Stream,并且想知道框架是否提供了寻求偏移量的任何机制?
我意识到还原的另一种选择是简单地从头开始播放所有事件,但这对于我的某些微服务来说不是一个理想的选择。
答案 0 :(得分:1)
如果您正在谈论灾难,是什么使您认为可以向DB写任何内容? 换句话说,您可能最终会在至少一个事件上处理重复数据删除(至少要考虑到这一点),如果是这样,那么重复数据删除仍然是您必须处理的事情。
我了解您对重播的担心(您根本不想从一开始就进行回复,但是您可以存储定期快照,以确保您有相对固定数量的事件可能需要重新处理/取消-弄翻了。
也就是说,Kafka会保持当前偏移量,因此您可以依靠Kafka的自然交易功能来确保下次启动微服务时,它将从最后一个未处理(成功)的偏移量开始。
答案 1 :(得分:0)
您可以使用KafkaBindingRebalanceListener接口
@Slf4j
@Component
public class KafkaRebalanceListener implements KafkaBindingRebalanceListener {
@Value("${config.kafka.topics.offsets:null}")
private String topicOffsets;
@Override
public void onPartitionsAssigned(String bindingName, Consumer<?, ?> consumer, Collection<TopicPartition> partitions, boolean initial) {
if (topicOffsets != null && initial) {
final Optional<Map<TopicPartition, Long>> offsetsOptional = parseOffset(topicOffsets);
if (offsetsOptional.isPresent()) {
final Map<TopicPartition, Long> offsetsMap = offsetsOptional.get();
partitions.forEach(tp -> {
if (offsetsMap.containsKey(tp)) {
final Long offset = offsetsMap.get(tp);
try {
log.info("Seek topic {} partition {} to offset {}", tp.topic(), tp.partition(), offset);
consumer.seek(tp, offset);
} catch (Exception e) {
log.error("Unable to set offset {} for topic {} and partition {}", offset, tp.topic(), tp.partition());
}
}
});
}
}
}
private Optional<Map<TopicPartition, Long>> parseOffset(String offsetParam) {
if (offsetParam == null || offsetParam.isEmpty()) {
return Optional.empty();
}
return Optional.of(Arrays.stream(offsetParam.split(","))
.flatMap(slice -> {
String[] items = slice.split("\\|");
String topic = items[0];
return Arrays.stream(Arrays.copyOfRange(items, 1, items.length))
.map(r -> {
String[] record = r.split(":");
int partition = Integer.parseInt(record[0]);
long offset = Long.parseLong(record[1]);
return new AbstractMap.SimpleEntry<>(new TopicPartition(topic, partition), offset);
});
}).collect(Collectors.toMap(AbstractMap.SimpleEntry::getKey, AbstractMap.SimpleEntry::getValue)));
}
}
config.kafka.topics.offsets 字段如下所示,但您可以使用任何格式
String topicOffsets = "topic2|1:100|2:120|3:140,topic3|1:1000|2:1200|3:1400";